From 2874d15e958da779066951a0bde3bafe3f9654cb Mon Sep 17 00:00:00 2001 From: Vladimir Nadvornik Date: Sun, 8 Mar 2009 09:56:40 +0000 Subject: [PATCH] dnd in keywords tree improved dnd in advanced exif --- src/advanced_exif.c | 61 ++++++++----- src/bar_exif.c | 2 +- src/bar_keywords.c | 204 +++++++++++++++++++++++++++++++++++++++++++- src/dnd.h | 2 + src/metadata.c | 89 ++++++++++++++++++- src/metadata.h | 8 ++ 6 files changed, 341 insertions(+), 25 deletions(-) diff --git a/src/advanced_exif.c b/src/advanced_exif.c index dcc07eaf..667f3327 100644 --- a/src/advanced_exif.c +++ b/src/advanced_exif.c @@ -45,7 +45,6 @@ struct _ExifWin GtkWidget *listview; FileData *fd; - gchar *sel_key; }; enum { @@ -230,13 +229,31 @@ static GtkTargetEntry advanced_exif_drag_types[] = { 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; + + 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); + } + +} - gtk_selection_data_set_text(selection_data, ew->sel_key, -1); +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 @@ static void advanced_exif_dnd_begin(GtkWidget *listview, GdkDragContext *context 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, &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); - gtk_tree_model_get(store, &iter, EXIF_ADVCOL_NAME, &ew->sel_key, -1); - printf("%s\n",ew->sel_key); + 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 @@ GtkWidget *advanced_exif_new(void) 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 @@ GtkWidget *advanced_exif_new(void) 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); diff --git a/src/bar_exif.c b/src/bar_exif.c index 37f3b2f6..03b68cee 100644 --- a/src/bar_exif.c +++ b/src/bar_exif.c @@ -350,7 +350,7 @@ static void bar_pane_exif_dnd_init(GtkWidget *pane) 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); } diff --git a/src/bar_keywords.c b/src/bar_keywords.c index ea98a414..a5dade20 100644 --- a/src/bar_keywords.c +++ b/src/bar_keywords.c @@ -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 @@ static void bar_pane_keywords_keyword_toggle(GtkCellRendererToggle *toggle, cons 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 @@ void bar_pane_keywords_filter_modify(GtkTreeModel *model, GtkTreeIter *iter, GVa 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 void bar_pane_keywords_mark_edited(GtkCellRendererText *cell, const gchar */ } + +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 @@ GtkWidget *bar_pane_keywords_new(const gchar *title, const gchar *key, gboolean 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); diff --git a/src/dnd.h b/src/dnd.h index 2091c17e..17ccfcd8 100644 --- a/src/dnd.h +++ b/src/dnd.h @@ -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 }; diff --git a/src/metadata.c b/src/metadata.c index 31c142ef..5c2b3726 100644 --- a/src/metadata.c +++ b/src/metadata.c @@ -729,6 +729,93 @@ void keyword_set(GtkTreeStore *keyword_tree, GtkTreeIter *iter, const gchar *nam 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 @@ void keyword_tree_set(GtkTreeModel *keyword_tree, GtkTreeIter *iter_ptr, GList * 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 @@ static void keyword_tree_reset1(GtkTreeModel *keyword_tree, GtkTreeIter *iter, G if (found) { *kw_list = g_list_remove(*kw_list, found); - printf("remove %s\n", found); g_free(found); } g_free(name); diff --git a/src/metadata.h b/src/metadata.h index 2783fc4d..a1ce98e9 100644 --- a/src/metadata.h +++ b/src/metadata.h @@ -54,6 +54,14 @@ extern GtkTreeStore *keyword_tree; 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); -- 2.20.1