# HG changeset patch # User nadvornik # Date 1236986398 0 # Node ID 985366bccfb8852705af4e7cd84a72fbcfc2d187 # Parent 3019f5d3a3c719805a996f80b4754454b255d28f do not allow to add keywords with the same name as siblings diff -r 3019f5d3a3c7 -r 985366bccfb8 src/bar_keywords.c --- a/src/bar_keywords.c Fri Mar 13 16:45:21 2009 +0000 +++ b/src/bar_keywords.c Fri Mar 13 23:19:58 2009 +0000 @@ -514,6 +514,53 @@ { } + +static gboolean bar_pane_keywords_dnd_can_move(GtkTreeModel *keyword_tree, GtkTreeIter *src_kw_iter, GtkTreeIter *dest_kw_iter) +{ + gchar *src_name; + GtkTreeIter parent; + + if (dest_kw_iter && keyword_same_parent(keyword_tree, src_kw_iter, dest_kw_iter)) + { + return TRUE; /* reordering of siblings is ok */ + } + if (!dest_kw_iter && !gtk_tree_model_iter_parent(keyword_tree, &parent, src_kw_iter)) + { + return TRUE; /* reordering of top-level siblings is ok */ + } + + src_name = keyword_get_name(keyword_tree, src_kw_iter); + if (keyword_exists(keyword_tree, NULL, dest_kw_iter, src_name, FALSE)) + { + g_free(src_name); + return FALSE; + } + g_free(src_name); + return TRUE; +} + +static gboolean bar_pane_keywords_dnd_skip_existing(GtkTreeModel *keyword_tree, GtkTreeIter *dest_kw_iter, GList **keywords) +{ + /* we have to find at least one keyword that does not already exist as a sibling of dest_kw_iter */ + GList *work = *keywords; + while (work) + { + gchar *keyword = work->data; + if (keyword_exists(keyword_tree, NULL, dest_kw_iter, keyword, FALSE)) + { + GList *next = work->next; + g_free(keyword); + *keywords = g_list_delete_link(*keywords, work); + work = next; + } + else + { + work = work->next; + } + } + return !!*keywords; +} + static void bar_pane_keywords_dnd_receive(GtkWidget *tree_view, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, @@ -580,10 +627,22 @@ if ((pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE || pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER) && !gtk_tree_model_iter_has_child(keyword_tree, &dest_kw_iter)) { + /* the node has no children, all keywords can be added */ gtk_tree_store_append(GTK_TREE_STORE(keyword_tree), &new_kw_iter, &dest_kw_iter); } else { + if (src_valid && !bar_pane_keywords_dnd_can_move(keyword_tree, &src_kw_iter, &dest_kw_iter)) + { + /* the keyword can't be moved if the same name already exist */ + return; + } + if (new_keywords && !bar_pane_keywords_dnd_skip_existing(keyword_tree, &dest_kw_iter, &new_keywords)) + { + /* the keywords can't be added if the same name already exist */ + return; + } + switch (pos) { case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE: @@ -596,9 +655,20 @@ break; } } + } else { + if (src_valid && !bar_pane_keywords_dnd_can_move(keyword_tree, &src_kw_iter, NULL)) + { + /* the keyword can't be moved if the same name already exist */ + return; + } + if (new_keywords && !bar_pane_keywords_dnd_skip_existing(keyword_tree, NULL, &new_keywords)) + { + /* the keywords can't be added if the same name already exist */ + return; + } gtk_tree_store_append(GTK_TREE_STORE(keyword_tree), &new_kw_iter, NULL); } @@ -611,8 +681,10 @@ work = new_keywords; while (work) { - keyword_set(GTK_TREE_STORE(keyword_tree), &new_kw_iter, work->data, TRUE); + gchar *keyword = work->data; + keyword_set(GTK_TREE_STORE(keyword_tree), &new_kw_iter, keyword, TRUE); work = work->next; + if (work) { GtkTreeIter add; @@ -705,7 +777,8 @@ if (cdd->edit_existing) { - if (keywords && keywords->data) /* there should be one keyword */ + if (keywords && keywords->data && /* there should be one keyword */ + !keyword_exists(keyword_tree, NULL, &kw_iter, keywords->data, TRUE)) { keyword_set(GTK_TREE_STORE(keyword_tree), &kw_iter, keywords->data, cdd->is_keyword); } @@ -717,6 +790,11 @@ while (work) { GtkTreeIter add; + if (keyword_exists(keyword_tree, NULL, have_dest ? &kw_iter : NULL, work->data, FALSE)) + { + work = work->next; + continue; + } if (have_dest) { gtk_tree_store_insert_after(GTK_TREE_STORE(keyword_tree), &add, NULL, &kw_iter); diff -r 3019f5d3a3c7 -r 985366bccfb8 src/metadata.c --- a/src/metadata.c Fri Mar 13 16:45:21 2009 +0000 +++ b/src/metadata.c Fri Mar 13 23:19:58 2009 +0000 @@ -765,6 +765,66 @@ return ret; } +gboolean keyword_same_parent(GtkTreeModel *keyword_tree, GtkTreeIter *a, GtkTreeIter *b) +{ + GtkTreeIter parent_a; + GtkTreeIter parent_b; + + gboolean valid_pa = gtk_tree_model_iter_parent(keyword_tree, &parent_a, a); + gboolean valid_pb = gtk_tree_model_iter_parent(keyword_tree, &parent_b, b); + + if (valid_pa && valid_pb) + { + return keyword_compare(keyword_tree, &parent_a, &parent_b) == 0; + } + else + { + return (!valid_pa && !valid_pb); /* both are toplevel */ + } +} + +gboolean keyword_exists(GtkTreeModel *keyword_tree, GtkTreeIter *parent_ptr, GtkTreeIter *sibling, const gchar *name, gboolean exclude_sibling) +{ + GtkTreeIter parent; + GtkTreeIter iter; + gboolean toplevel = FALSE; + gboolean ret; + gchar *casefold; + + if (parent_ptr) + { + parent = *parent_ptr; + } + else if (sibling) + { + toplevel = !gtk_tree_model_iter_parent(keyword_tree, &parent, sibling); + } + else + { + toplevel = TRUE; + } + + if (!gtk_tree_model_iter_children(GTK_TREE_MODEL(keyword_tree), &iter, toplevel ? NULL : &parent)) return FALSE; + + casefold = g_utf8_casefold(name, -1); + ret = FALSE; + + while (TRUE) + { + if (!(exclude_sibling && sibling && keyword_compare(keyword_tree, &iter, sibling) == 0)) + { + gchar *iter_casefold = keyword_get_casefold(keyword_tree, &iter); + ret = strcmp(casefold, iter_casefold) == 0; + g_free(iter_casefold); + } + if (ret) break; + if (!gtk_tree_model_iter_next(keyword_tree, &iter)) break; + } + g_free(casefold); + return ret; +} + + void keyword_copy(GtkTreeStore *keyword_tree, GtkTreeIter *to, GtkTreeIter *from) { diff -r 3019f5d3a3c7 -r 985366bccfb8 src/metadata.h --- a/src/metadata.h Fri Mar 13 16:45:21 2009 +0000 +++ b/src/metadata.h Fri Mar 13 23:19:58 2009 +0000 @@ -60,6 +60,8 @@ gboolean keyword_get_is_keyword(GtkTreeModel *keyword_tree, GtkTreeIter *iter); gboolean keyword_compare(GtkTreeModel *keyword_tree, GtkTreeIter *a, GtkTreeIter *b); +gboolean keyword_same_parent(GtkTreeModel *keyword_tree, GtkTreeIter *a, GtkTreeIter *b); +gboolean keyword_exists(GtkTreeModel *keyword_tree, GtkTreeIter *parent_ptr, GtkTreeIter *sibling, const gchar *name, gboolean exclude_sibling); void keyword_copy(GtkTreeStore *keyword_tree, GtkTreeIter *to, GtkTreeIter *from); void keyword_copy_recursive(GtkTreeStore *keyword_tree, GtkTreeIter *to, GtkTreeIter *from);