changeset 1392:d1b32a69b40a

dnd in keywords tree improved dnd in advanced exif
author nadvornik
date Sun, 08 Mar 2009 09:56:40 +0000
parents 9e0df7903581
children 79b32088ecc4
files src/advanced_exif.c src/bar_exif.c src/bar_keywords.c src/dnd.h src/metadata.c src/metadata.h
diffstat 6 files changed, 341 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/src/advanced_exif.c	Sat Mar 07 17:02:59 2009 +0000
+++ b/src/advanced_exif.c	Sun Mar 08 09:56:40 2009 +0000
@@ -45,7 +45,6 @@
 	GtkWidget *listview;
 
 	FileData *fd;
-	gchar *sel_key;
 };
 
 enum {
@@ -230,13 +229,31 @@
 static gint n_exif_drag_types = 1;
 
 
-static void advanced_exif_dnd_get(GtkWidget *entry, GdkDragContext *context,
+static void advanced_exif_dnd_get(GtkWidget *listview, GdkDragContext *context,
 				     GtkSelectionData *selection_data, guint info,
 				     guint time, gpointer data)
 {
 	ExifWin *ew = data;
+	GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(listview)); 
+	GtkTreeIter iter;
 
-	gtk_selection_data_set_text(selection_data, ew->sel_key, -1);
+	if (gtk_tree_selection_get_selected(sel, NULL, &iter)) 
+		{
+		GtkTreeModel *store = gtk_tree_view_get_model(GTK_TREE_VIEW(listview));
+		gchar *key;
+
+		gtk_tree_model_get(store, &iter, EXIF_ADVCOL_NAME, &key, -1);
+		gtk_selection_data_set_text(selection_data, key, -1);
+		printf("%s\n",key);
+		g_free(key);
+		}
+
+}
+
+static void advanced_exif_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
+{
+	GtkWidget *window = data;
+	gtk_widget_destroy(window);
 }
 
 static void advanced_exif_dnd_begin(GtkWidget *listview, GdkDragContext *context, gpointer data)
@@ -244,24 +261,30 @@
 	ExifWin *ew = data;
 	GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(listview)); 
 	GtkTreeIter iter;
-	ew->sel_key = NULL;
 
 	if (gtk_tree_selection_get_selected(sel, NULL, &iter)) 
 		{
 		GtkTreeModel *store = gtk_tree_view_get_model(GTK_TREE_VIEW(listview));
+		gchar *key;
+		GtkWidget *window;
+		GtkWidget *label;
 
-		gtk_tree_model_get(store, &iter, EXIF_ADVCOL_NAME, &ew->sel_key, -1);
-		printf("%s\n",ew->sel_key);
+		gtk_tree_model_get(store, &iter, EXIF_ADVCOL_NAME, &key, -1);
+
+		window = gtk_window_new(GTK_WINDOW_POPUP);
+		gtk_widget_realize (window);
+
+		label = gtk_label_new(key);
+		gtk_container_add(GTK_CONTAINER (window), label);
+		gtk_widget_show(label);
+		gtk_drag_set_icon_widget(context, window, -15, 10);
+		g_signal_connect(G_OBJECT(listview), "drag_end",
+				 G_CALLBACK(advanced_exif_dnd_end), window);
+
+		g_free(key);
 		}
-		
 }
 
-static void advanced_exif_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
-{
-	ExifWin *ew = data;
-	g_free(ew->sel_key);
-	ew->sel_key = NULL;
-}
 
 
 static void advanced_exif_add_column(GtkWidget *listview, const gchar *title, gint n, gint sizable)
@@ -343,8 +366,6 @@
 
 	gtk_tree_view_set_search_column(GTK_TREE_VIEW(ew->listview), EXIF_ADVCOL_NAME);
 
-//	advanced_exif_add_column_check(ew->listview, "", EXIF_ADVCOL_ENABLED);
-
 	advanced_exif_add_column(ew->listview, _("Description"), EXIF_ADVCOL_DESCRIPTION, FALSE);
 	advanced_exif_add_column(ew->listview, _("Value"), EXIF_ADVCOL_VALUE, TRUE);
 	advanced_exif_add_column(ew->listview, _("Name"), EXIF_ADVCOL_NAME, FALSE);
@@ -352,18 +373,16 @@
 	advanced_exif_add_column(ew->listview, _("Format"), EXIF_ADVCOL_FORMAT, FALSE);
 	advanced_exif_add_column(ew->listview, _("Elements"), EXIF_ADVCOL_ELEMENTS, FALSE);
 
-	gtk_tree_view_enable_model_drag_source(GTK_TREE_VIEW(ew->listview),
-					       GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
-					       advanced_exif_drag_types, n_exif_drag_types,
-					       GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
+	gtk_drag_source_set(ew->listview,
+			   GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
+			   advanced_exif_drag_types, n_exif_drag_types,
+			   GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
 
 	g_signal_connect(G_OBJECT(ew->listview), "drag_data_get",
 			 G_CALLBACK(advanced_exif_dnd_get), ew);
 
 	g_signal_connect(G_OBJECT(ew->listview), "drag_begin",
 			 G_CALLBACK(advanced_exif_dnd_begin), ew);
-	g_signal_connect(G_OBJECT(ew->listview), "drag_end",
-			 G_CALLBACK(advanced_exif_dnd_end), ew);
 
 	ew->scrolled = gtk_scrolled_window_new(NULL, NULL);
 	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(ew->scrolled), GTK_SHADOW_IN);
--- a/src/bar_exif.c	Sat Mar 07 17:02:59 2009 +0000
+++ b/src/bar_exif.c	Sun Mar 08 09:56:40 2009 +0000
@@ -350,7 +350,7 @@
 	gtk_drag_dest_set(pane,
 			  GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP,
 			  bar_pane_exif_drop_types, n_exif_entry_drop_types,
-			  GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_ASK);
+			  GDK_ACTION_COPY | GDK_ACTION_MOVE);
 	g_signal_connect(G_OBJECT(pane), "drag_data_received",
 			 G_CALLBACK(bar_pane_exif_dnd_receive), NULL);
 }
--- a/src/bar_keywords.c	Sat Mar 07 17:02:59 2009 +0000
+++ b/src/bar_keywords.c	Sun Mar 08 09:56:40 2009 +0000
@@ -27,6 +27,7 @@
 #include "ui_menu.h"
 #include "rcfile.h"
 #include "layout.h"
+#include "dnd.h"
 
 static const gchar *keyword_favorite_defaults[] = {
 	N_("Favorite"),
@@ -285,7 +286,10 @@
 		
 	keyword_list_push(pkd->keyword_view, list);
 	string_list_free(list);
+	/*
+	  keyword_list_push triggers bar_pane_keywords_change which calls bar_keyword_tree_sync, no need to do it again
 	bar_keyword_tree_sync(pkd);
+	*/
 }
 
 void bar_pane_keywords_filter_modify(GtkTreeModel *model, GtkTreeIter *iter, GValue *value, gint column, gpointer data)
@@ -293,7 +297,7 @@
 	PaneKeywordsData *pkd = data;
 	GtkTreeModel *keyword_tree = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(model));
 	GtkTreeIter child_iter;
-	
+
 	gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(model), &child_iter, iter);
 	
 	memset(value, 0, sizeof (GValue));
@@ -440,6 +444,180 @@
 */
 }
 
+
+static GtkTargetEntry bar_pane_keywords_drag_types[] = {
+	{ TARGET_APP_KEYWORD_PATH_STRING, GTK_TARGET_SAME_WIDGET, TARGET_APP_KEYWORD_PATH },
+	{ "text/plain", 0, TARGET_TEXT_PLAIN }
+};
+static gint n_keywords_drag_types = 2;
+
+
+static GtkTargetEntry bar_pane_keywords_drop_types[] = {
+	{ TARGET_APP_KEYWORD_PATH_STRING, GTK_TARGET_SAME_WIDGET, TARGET_APP_KEYWORD_PATH },
+	{ "text/plain", 0, TARGET_TEXT_PLAIN }
+};
+static gint n_keywords_drop_types = 2;
+
+
+static void bar_pane_keywords_dnd_get(GtkWidget *tree_view, GdkDragContext *context,
+				     GtkSelectionData *selection_data, guint info,
+				     guint time, gpointer data)
+{
+	GtkTreeIter iter;
+	GtkTreeModel *model;
+	GtkTreeIter child_iter;
+	GtkTreeModel *keyword_tree;
+
+	GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)); 
+
+        if (!gtk_tree_selection_get_selected(sel, &model, &iter)) return;
+
+	keyword_tree = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(model));
+	gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(model), &child_iter, &iter);
+
+	switch (info)
+		{
+		case TARGET_APP_KEYWORD_PATH:
+			{
+			GList *path = keyword_tree_get_path(keyword_tree, &child_iter);
+			gtk_selection_data_set(selection_data, selection_data->target,
+					       8, (gpointer) &path, sizeof(path));
+			break;
+			}
+
+		case TARGET_TEXT_PLAIN:
+		default:
+			{
+			gchar *name = keyword_get_name(keyword_tree, &child_iter);
+			gtk_selection_data_set_text(selection_data, name, -1);
+printf("name %s\n", name);
+			g_free(name);
+			}
+			break;
+		}
+}
+
+static void bar_pane_keywords_dnd_begin(GtkWidget *treeview, GdkDragContext *context, gpointer data)
+{
+}
+
+static void bar_pane_keywords_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
+{
+}
+
+static void bar_pane_keywords_dnd_receive(GtkWidget *tree_view, GdkDragContext *context,
+					  gint x, gint y,
+					  GtkSelectionData *selection_data, guint info,
+					  guint time, gpointer data)
+{
+	GtkTreePath *tpath = NULL;
+        GtkTreeViewDropPosition pos;
+	GtkTreeModel *model;
+
+	GtkTreeModel *keyword_tree;
+	gboolean src_valid = FALSE;
+	gchar *new_keyword = NULL;
+
+	/* iterators for keyword_tree */
+	GtkTreeIter src_kw_iter;
+	GtkTreeIter dest_kw_iter;
+	GtkTreeIter new_kw_iter;
+
+	g_signal_stop_emission_by_name(tree_view, "drag_data_received");
+
+	gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW(tree_view), NULL, pos);
+
+	model = gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view));
+	keyword_tree = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(model));
+
+	gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(tree_view), x, y, &tpath, &pos);
+
+
+	switch (info)
+		{
+		case TARGET_APP_KEYWORD_PATH:
+			{
+			GList *path = *(gpointer *)selection_data->data;
+			src_valid = keyword_tree_get_iter(keyword_tree, &src_kw_iter, path);
+			string_list_free(path);
+			break;
+			}
+		default:
+			new_keyword = (gchar *)selection_data->data;
+			break;
+		}
+
+	if (tpath)
+		{
+		GtkTreeIter dest_iter;
+                gtk_tree_model_get_iter(model, &dest_iter, tpath);
+		gtk_tree_path_free(tpath);
+		gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(model), &dest_kw_iter, &dest_iter);
+
+
+		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))
+			{
+			gtk_tree_store_append(GTK_TREE_STORE(keyword_tree), &new_kw_iter, &dest_kw_iter);
+			}
+		else
+			{
+			switch (pos)
+				{
+				case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
+				case GTK_TREE_VIEW_DROP_BEFORE:
+					gtk_tree_store_insert_before(GTK_TREE_STORE(keyword_tree), &new_kw_iter, NULL, &dest_kw_iter);
+					break;
+				case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
+				case GTK_TREE_VIEW_DROP_AFTER:
+					gtk_tree_store_insert_after(GTK_TREE_STORE(keyword_tree), &new_kw_iter, NULL, &dest_kw_iter);
+					break;
+				}
+			}
+		}
+	else
+		{
+		gtk_tree_store_append(GTK_TREE_STORE(keyword_tree), &new_kw_iter, NULL);
+		}
+		
+		
+	if (src_valid)
+		{
+		keyword_move_recursive(GTK_TREE_STORE(keyword_tree), &new_kw_iter, &src_kw_iter);
+		}
+	
+	if (new_keyword)
+		{
+		keyword_set(GTK_TREE_STORE(keyword_tree), &new_kw_iter, new_keyword, TRUE);
+		}
+}
+
+static gint bar_pane_keywords_dnd_motion(GtkWidget *tree_view, GdkDragContext *context,
+					gint x, gint y, guint time, gpointer data)
+{
+	GtkTreePath *tpath = NULL;
+        GtkTreeViewDropPosition pos;
+	gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(tree_view), x, y, &tpath, &pos);
+	if (tpath)
+		{
+		GtkTreeModel *model;
+		GtkTreeIter dest_iter;
+		model = gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view));
+                gtk_tree_model_get_iter(model, &dest_iter, tpath);
+		if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE && gtk_tree_model_iter_has_child(model, &dest_iter))
+			pos = GTK_TREE_VIEW_DROP_BEFORE;
+		
+		if (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER && gtk_tree_model_iter_has_child(model, &dest_iter))
+			pos = GTK_TREE_VIEW_DROP_AFTER;
+		}
+
+	gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW(tree_view), tpath, pos);
+	gtk_tree_path_free(tpath);
+	gdk_drag_status(context, GDK_ACTION_COPY, time);
+	return TRUE;
+}
+
+
 void bar_pane_keywords_close(GtkWidget *bar)
 {
 	PaneKeywordsData *pkd;
@@ -591,6 +769,30 @@
 	gtk_tree_view_append_column(GTK_TREE_VIEW(pkd->keyword_treeview), column);
 	gtk_tree_view_set_expander_column(GTK_TREE_VIEW(pkd->keyword_treeview), column);
 
+	gtk_drag_source_set(pkd->keyword_treeview,
+			    GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
+			    bar_pane_keywords_drag_types, n_keywords_drag_types,
+			    GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
+
+	g_signal_connect(G_OBJECT(pkd->keyword_treeview), "drag_data_get",
+			 G_CALLBACK(bar_pane_keywords_dnd_get), pkd);
+
+	g_signal_connect(G_OBJECT(pkd->keyword_treeview), "drag_begin",
+			 G_CALLBACK(bar_pane_keywords_dnd_begin), pkd);
+	g_signal_connect(G_OBJECT(pkd->keyword_treeview), "drag_end",
+			 G_CALLBACK(bar_pane_keywords_dnd_end), pkd);
+
+	gtk_drag_dest_set(pkd->keyword_treeview,
+			  GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP,
+			  bar_pane_keywords_drop_types, n_keywords_drop_types,
+			  GDK_ACTION_COPY | GDK_ACTION_MOVE);
+			  
+	g_signal_connect(G_OBJECT(pkd->keyword_treeview), "drag_data_received",
+			 G_CALLBACK(bar_pane_keywords_dnd_receive), pkd);
+
+	g_signal_connect(G_OBJECT(pkd->keyword_treeview), "drag_motion",
+			 G_CALLBACK(bar_pane_keywords_dnd_motion), pkd);
+
 	gtk_container_add(GTK_CONTAINER(scrolled), pkd->keyword_treeview);
 	gtk_widget_show(pkd->keyword_treeview);
 
--- a/src/dnd.h	Sat Mar 07 17:02:59 2009 +0000
+++ b/src/dnd.h	Sun Mar 08 09:56:40 2009 +0000
@@ -16,10 +16,12 @@
 
 #define TARGET_APP_COLLECTION_MEMBER_STRING "application/x-" GQ_APPNAME_LC "-collection-member"
 #define TARGET_APP_EXIF_ENTRY_STRING "application/x-" GQ_APPNAME_LC "-exif-entry"
+#define TARGET_APP_KEYWORD_PATH_STRING "application/x-" GQ_APPNAME_LC "-keyword-path"
 
 enum {
 	TARGET_APP_COLLECTION_MEMBER,
 	TARGET_APP_EXIF_ENTRY,
+	TARGET_APP_KEYWORD_PATH,
 	TARGET_URI_LIST,
 	TARGET_TEXT_PLAIN
 };
--- a/src/metadata.c	Sat Mar 07 17:02:59 2009 +0000
+++ b/src/metadata.c	Sun Mar 08 09:56:40 2009 +0000
@@ -729,6 +729,93 @@
 	g_free(casefold);
 }
 
+void keyword_copy(GtkTreeStore *keyword_tree, GtkTreeIter *to, GtkTreeIter *from)
+{
+
+	gchar *mark, *name, *casefold;
+	gboolean is_keyword;
+
+	gtk_tree_model_get(GTK_TREE_MODEL(keyword_tree), from, KEYWORD_COLUMN_MARK, &mark,
+						KEYWORD_COLUMN_NAME, &name,
+						KEYWORD_COLUMN_CASEFOLD, &casefold,
+						KEYWORD_COLUMN_IS_KEYWORD, &is_keyword, -1);
+
+	gtk_tree_store_set(keyword_tree, to, KEYWORD_COLUMN_MARK, mark,
+						KEYWORD_COLUMN_NAME, name,
+						KEYWORD_COLUMN_CASEFOLD, casefold,
+						KEYWORD_COLUMN_IS_KEYWORD, is_keyword, -1);
+	g_free(mark);
+	g_free(name);
+	g_free(casefold);
+}
+
+void keyword_copy_recursive(GtkTreeStore *keyword_tree, GtkTreeIter *to, GtkTreeIter *from)
+{
+	GtkTreeIter from_child;
+	
+	keyword_copy(keyword_tree, to, from);
+	
+	if (!gtk_tree_model_iter_children(GTK_TREE_MODEL(keyword_tree), &from_child, from)) return;
+	
+	while (TRUE)
+		{
+		GtkTreeIter to_child;
+		gtk_tree_store_append(keyword_tree, &to_child, to);
+		keyword_copy_recursive(keyword_tree, &to_child, &from_child);
+		if (!gtk_tree_model_iter_next(GTK_TREE_MODEL(keyword_tree), &from_child)) return;
+		}
+}
+
+void keyword_move_recursive(GtkTreeStore *keyword_tree, GtkTreeIter *to, GtkTreeIter *from)
+{
+	keyword_copy_recursive(keyword_tree, to, from);
+	gtk_tree_store_remove(keyword_tree, from);
+}
+
+GList *keyword_tree_get_path(GtkTreeModel *keyword_tree, GtkTreeIter *iter_ptr)
+{
+	GList *path = NULL;
+	GtkTreeIter iter = *iter_ptr;
+	
+	while (TRUE)
+		{
+		GtkTreeIter parent;
+		path = g_list_prepend(path, keyword_get_name(keyword_tree, &iter));
+		if (!gtk_tree_model_iter_parent(keyword_tree, &parent, &iter)) break;
+		iter = parent;
+		}
+	return path;
+}
+
+gboolean keyword_tree_get_iter(GtkTreeModel *keyword_tree, GtkTreeIter *iter_ptr, GList *path)
+{
+	GtkTreeIter iter;
+
+	if (!gtk_tree_model_get_iter_first(keyword_tree, &iter)) return FALSE;
+	
+	while (TRUE)
+		{
+		GtkTreeIter children;
+		while (TRUE)
+			{
+			gchar *name = keyword_get_name(keyword_tree, &iter);
+			if (strcmp(name, path->data) == 0) break;
+			g_free(name);
+			if (!gtk_tree_model_iter_next(keyword_tree, &iter)) return FALSE;
+			}
+		path = path->next;
+		if (!path) 
+			{
+			*iter_ptr = iter;
+			return TRUE;
+			}
+			
+	    	if (!gtk_tree_model_iter_children(keyword_tree, &children, &iter)) return FALSE;
+	    	iter = children;
+		}
+}
+
+
 static gboolean keyword_tree_is_set_casefold(GtkTreeModel *keyword_tree, GtkTreeIter iter, GList *casefold_list)
 {
 	if (!casefold_list) return FALSE;
@@ -798,7 +885,6 @@
 			if (!find_string_in_list_utf8nocase(*kw_list, name))
 				{
 				*kw_list = g_list_append(*kw_list, name);
-				printf("set %s\n", name);
 				}
 			else
 				{
@@ -823,7 +909,6 @@
 	if (found)
 		{
 		*kw_list = g_list_remove(*kw_list, found);
-		printf("remove %s\n", found);
 		g_free(found);
 		}
 	g_free(name);
--- a/src/metadata.h	Sat Mar 07 17:02:59 2009 +0000
+++ b/src/metadata.h	Sun Mar 08 09:56:40 2009 +0000
@@ -54,6 +54,14 @@
 gchar *keyword_get_name(GtkTreeModel *keyword_tree, GtkTreeIter *iter);
 gchar *keyword_get_casefold(GtkTreeModel *keyword_tree, GtkTreeIter *iter);
 gboolean keyword_get_is_keyword(GtkTreeModel *keyword_tree, GtkTreeIter *iter);
+
+void keyword_copy(GtkTreeStore *keyword_tree, GtkTreeIter *to, GtkTreeIter *from);
+void keyword_copy_recursive(GtkTreeStore *keyword_tree, GtkTreeIter *to, GtkTreeIter *from);
+void keyword_move_recursive(GtkTreeStore *keyword_tree, GtkTreeIter *to, GtkTreeIter *from);
+
+GList *keyword_tree_get_path(GtkTreeModel *keyword_tree, GtkTreeIter *iter_ptr);
+gboolean keyword_tree_get_iter(GtkTreeModel *keyword_tree, GtkTreeIter *iter_ptr, GList *path);
+
 void keyword_set(GtkTreeStore *keyword_tree, GtkTreeIter *iter, const gchar *name, gboolean is_keyword);
 gboolean keyword_tree_is_set(GtkTreeModel *keyword_tree, GtkTreeIter *iter, GList *kw_list);
 void keyword_tree_set(GtkTreeModel *keyword_tree, GtkTreeIter *iter_ptr, GList **kw_list);