changeset 1429:985366bccfb8

do not allow to add keywords with the same name as siblings
author nadvornik
date Fri, 13 Mar 2009 23:19:58 +0000
parents 3019f5d3a3c7
children 7718e351bc45
files src/bar_keywords.c src/metadata.c src/metadata.h
diffstat 3 files changed, 142 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- 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);
--- 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)
 {
 
--- 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);