do not allow to add keywords with the same name as siblings
authorVladimir Nadvornik <nadvornik@suse.cz>
Fri, 13 Mar 2009 23:19:58 +0000 (23:19 +0000)
committerVladimir Nadvornik <nadvornik@suse.cz>
Fri, 13 Mar 2009 23:19:58 +0000 (23:19 +0000)
src/bar_keywords.c
src/metadata.c
src/metadata.h

index 5d25f42..fc9d0ca 100644 (file)
@@ -514,6 +514,53 @@ static void bar_pane_keywords_dnd_end(GtkWidget *widget, GdkDragContext *context
 {
 }
 
+
+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 @@ static void bar_pane_keywords_dnd_receive(GtkWidget *tree_view, GdkDragContext *
                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 @@ static void bar_pane_keywords_dnd_receive(GtkWidget *tree_view, GdkDragContext *
                                        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 @@ static void bar_pane_keywords_dnd_receive(GtkWidget *tree_view, GdkDragContext *
        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 @@ static void bar_pane_keywords_edit_ok_cb(GenericDialog *gd, gpointer data)
        
        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 @@ static void bar_pane_keywords_edit_ok_cb(GenericDialog *gd, gpointer data)
                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);
index 0c1f523..22bc8fc 100644 (file)
@@ -765,6 +765,66 @@ gboolean keyword_compare(GtkTreeModel *keyword_tree, GtkTreeIter *a, GtkTreeIter
        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)
 {
 
index 0e31eed..49e78cf 100644 (file)
@@ -60,6 +60,8 @@ gchar *keyword_get_casefold(GtkTreeModel *keyword_tree, GtkTreeIter *iter);
 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);