[gthumb] folder tree: better drag&drop support



commit 45e2d19a6cafebafc06588246e2f7d6789037b77
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Mon Nov 4 08:58:19 2019 +0100

    folder tree: better drag&drop support
    
    Allow to move a catalog into a library, and a library into
    another library; show an error if the drop operation is
    not possible.

 extensions/catalogs/gth-file-source-catalogs.c     |  59 ++++++++++
 extensions/file_manager/callbacks.c                | 127 ++++++++++++---------
 extensions/selections/gth-file-source-selections.c |  32 ++++++
 gthumb/gth-browser.c                               |  50 +-------
 gthumb/gth-file-source-vfs.c                       |  19 +++
 gthumb/gth-file-source.c                           |  19 +++
 gthumb/gth-file-source.h                           |   6 +
 7 files changed, 207 insertions(+), 105 deletions(-)
---
diff --git a/extensions/catalogs/gth-file-source-catalogs.c b/extensions/catalogs/gth-file-source-catalogs.c
index 0646b342..85d12cf7 100644
--- a/extensions/catalogs/gth-file-source-catalogs.c
+++ b/extensions/catalogs/gth-file-source-catalogs.c
@@ -1445,6 +1445,64 @@ gth_file_source_catalogs_deleted_from_disk (GthFileSource *file_source,
 }
 
 
+static GdkDragAction
+gth_file_source_catalogs_get_drop_actions (GthFileSource *file_source,
+                                          GFile         *destination,
+                                          GFile         *file)
+{
+       GdkDragAction  actions = 0;
+       char          *dest_uri;
+       char          *dest_scheme;
+       const char    *dest_ext;
+       gboolean       dest_is_catalog;
+       char          *file_uri;
+       char          *file_scheme;
+       const char    *file_ext;
+       gboolean       file_is_catalog;
+
+       dest_uri = g_file_get_uri (destination);
+       dest_scheme = _g_uri_get_scheme (dest_uri);
+       dest_ext = _g_uri_get_file_extension (dest_uri);
+       dest_is_catalog = (g_strcmp0 (dest_ext, ".catalog") == 0) || (g_strcmp0 (dest_ext, ".search") == 0);
+
+       file_uri = g_file_get_uri (file);
+       file_scheme = _g_uri_get_scheme (file_uri);
+       file_ext = _g_uri_get_file_extension (file_uri);
+       file_is_catalog = (g_strcmp0 (file_ext, ".catalog") == 0) || (g_strcmp0 (file_ext, ".search") == 0);
+
+       if ((g_strcmp0 (dest_scheme, "catalog://") == 0)
+               && dest_is_catalog
+               && (g_strcmp0 (file_scheme, "file://") == 0))
+       {
+               /* Copy files into a catalog. */
+               actions = GDK_ACTION_COPY;
+       }
+
+       else if ((g_strcmp0 (file_scheme, "catalog://") == 0)
+               && file_is_catalog
+               && (g_strcmp0 (dest_scheme, "catalog://") == 0)
+               && ! dest_is_catalog)
+       {
+               /* Move a catalog into a library. */
+               actions = GDK_ACTION_MOVE;
+       }
+
+       else if ((g_strcmp0 (file_scheme, "catalog://") == 0)
+               && ! file_is_catalog
+               && (g_strcmp0 (dest_scheme, "catalog://") == 0)
+               && ! dest_is_catalog)
+       {
+               /* Move a library into another library. */
+               actions = GDK_ACTION_MOVE;
+       }
+
+       g_free (file_uri);
+       g_free (dest_uri);
+
+       return actions;
+}
+
+
 static void
 gth_file_source_catalogs_finalize (GObject *object)
 {
@@ -1481,6 +1539,7 @@ gth_file_source_catalogs_class_init (GthFileSourceCatalogsClass *class)
        file_source_class->reorder = gth_file_source_catalogs_reorder;
        file_source_class->remove = gth_file_source_catalogs_remove;
        file_source_class->deleted_from_disk = gth_file_source_catalogs_deleted_from_disk;
+       file_source_class->get_drop_actions = gth_file_source_catalogs_get_drop_actions;
 }
 
 
diff --git a/extensions/file_manager/callbacks.c b/extensions/file_manager/callbacks.c
index b557db46..6f31fcf4 100644
--- a/extensions/file_manager/callbacks.c
+++ b/extensions/file_manager/callbacks.c
@@ -945,86 +945,101 @@ fm__gth_browser_folder_tree_drag_data_received_cb (GthBrowser    *browser,
                                                   GList         *file_list,
                                                   GdkDragAction  action)
 {
-       GthFileSource *file_source;
+       int            n_files;
+       GthFileSource *destination_source;
+       GFile         *first_file;
+       GthFileSource *file_list_source;
+       gboolean       move_files;
        GtkWidget     *dialog;
        GthTask       *task;
+       char          *message;
        int            response;
 
        if (destination == NULL)
                return;
 
-       file_source = gth_main_get_file_source (destination->file);
-       if (file_source == NULL)
+       n_files = g_list_length (file_list);
+       if (n_files == 0)
+               return;
+
+       if ((action != GDK_ACTION_MOVE) && (action != GDK_ACTION_COPY))
+               return;
+
+       destination_source = gth_main_get_file_source (destination->file);
+       if (destination_source == NULL)
+               return;
+
+       first_file = G_FILE (file_list->data);
+       file_list_source = gth_main_get_file_source (first_file);
+       if (file_list_source == NULL)
                return;
 
+       if (action == GDK_ACTION_MOVE)
+               action |= GDK_ACTION_COPY;
+
+       action = action & gth_file_source_get_drop_actions (destination_source, destination->file, 
first_file);
+       if (action == 0) {
+               _gtk_error_dialog_run (GTK_WINDOW (browser),
+                                      "%s",
+                                      _("Could not perform the operation"));
+               return;
+       }
+
+       move_files = (action & GDK_ACTION_MOVE) != 0;
+
        /* ask confirmation */
 
        response = GTK_RESPONSE_OK;
-       if ((action == GDK_ACTION_MOVE) || (action == GDK_ACTION_COPY)) {
-               int   n_files;
-               char *message;
-
-               n_files = g_list_length (file_list);
-               g_return_if_fail (n_files >= 1);
-
-               if (n_files == 1) {
-                       char *filename = _g_file_get_display_name ((GFile *) file_list->data);
-                       if (action == GDK_ACTION_MOVE)
-                               message = g_strdup_printf (_("Do you want to move “%s” to “%s”?"), filename, 
g_file_info_get_display_name (destination->info));
-                       else
-                               message = g_strdup_printf (_("Do you want to copy “%s” to “%s”?"), filename, 
g_file_info_get_display_name (destination->info));
-                       g_free (filename);
-               }
-               else {
-                       if (action == GDK_ACTION_MOVE)
-                               message = g_strdup_printf (_("Do you want to move the dragged files to 
“%s”?"), g_file_info_get_display_name (destination->info));
-                       else
-                               message = g_strdup_printf (_("Do you want to copy the dragged files to 
“%s”?"), g_file_info_get_display_name (destination->info));
-               }
-               dialog = _gtk_message_dialog_new (GTK_WINDOW (browser),
-                                                 GTK_DIALOG_MODAL,
-                                                 _GTK_ICON_NAME_DIALOG_QUESTION,
-                                                 message,
-                                                 NULL,
-                                                 _GTK_LABEL_CANCEL, GTK_RESPONSE_CANCEL,
-                                                 ((action == GDK_ACTION_MOVE) ? _("Move") : _("_Copy")), 
GTK_RESPONSE_OK,
-                                                 NULL);
-               response = gtk_dialog_run (GTK_DIALOG (dialog));
-               gtk_widget_destroy (dialog);
-
-               g_free (message);
+       if (n_files == 1) {
+               GFileInfo  *info;
+               char       *filename;
+
+               info = gth_file_source_get_file_info (file_list_source, first_file, 
G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME);
+               if (info != NULL)
+                       filename = g_strdup (g_file_info_get_display_name (info));
+               else
+                       filename = _g_file_get_display_name (first_file);
+
+               if (move_files)
+                       message = g_strdup_printf (_("Do you want to move “%s” to “%s”?"), filename, 
g_file_info_get_display_name (destination->info));
+               else
+                       message = g_strdup_printf (_("Do you want to copy “%s” to “%s”?"), filename, 
g_file_info_get_display_name (destination->info));
+
+               g_free (filename);
+               _g_object_unref (info);
+       }
+       else {
+               if (move_files)
+                       message = g_strdup_printf (_("Do you want to move the dragged files to “%s”?"), 
g_file_info_get_display_name (destination->info));
+               else
+                       message = g_strdup_printf (_("Do you want to copy the dragged files to “%s”?"), 
g_file_info_get_display_name (destination->info));
        }
+       dialog = _gtk_message_dialog_new (GTK_WINDOW (browser),
+                                         GTK_DIALOG_MODAL,
+                                         _GTK_ICON_NAME_DIALOG_QUESTION,
+                                         message,
+                                         NULL,
+                                         _GTK_LABEL_CANCEL, GTK_RESPONSE_CANCEL,
+                                         (move_files ? _("Move") : _("_Copy")), GTK_RESPONSE_OK,
+                                         NULL);
+       response = gtk_dialog_run (GTK_DIALOG (dialog));
+       gtk_widget_destroy (dialog);
+       g_free (message);
 
        if (response != GTK_RESPONSE_OK)
                return;
 
-       if ((action == GDK_ACTION_MOVE) && ! gth_file_source_can_cut (file_source, (GFile *) 
file_list->data)) {
-               dialog = _gtk_message_dialog_new (GTK_WINDOW (browser),
-                                                 GTK_DIALOG_MODAL,
-                                                 _GTK_ICON_NAME_DIALOG_QUESTION,
-                                                 _("Could not move the files"),
-                                                 _("Files cannot be moved to the current location, as 
alternative you can choose to copy them."),
-                                                 _GTK_LABEL_CANCEL, GTK_RESPONSE_CANCEL,
-                                                 _GTK_LABEL_COPY, GTK_RESPONSE_OK,
-                                                 NULL);
-               response = gtk_dialog_run (GTK_DIALOG (dialog));
-               gtk_widget_destroy (dialog);
-
-               if (response == GTK_RESPONSE_CANCEL)
-                       return;
-
-               action = GDK_ACTION_COPY;
-       }
+       /* exec task */
 
-       task = gth_copy_task_new (file_source,
+       task = gth_copy_task_new (destination_source,
                                  destination,
-                                 (action == GDK_ACTION_MOVE),
+                                 move_files,
                                  file_list,
                                  -1);
        gth_browser_exec_task (browser, task, GTH_TASK_FLAGS_DEFAULT);
 
        g_object_unref (task);
-       g_object_unref (file_source);
+       g_object_unref (destination_source);
 }
 
 
diff --git a/extensions/selections/gth-file-source-selections.c 
b/extensions/selections/gth-file-source-selections.c
index 8fff091d..45c96c04 100644
--- a/extensions/selections/gth-file-source-selections.c
+++ b/extensions/selections/gth-file-source-selections.c
@@ -284,6 +284,37 @@ gth_file_source_selections_shows_extra_widget (GthFileSource *file_source)
 }
 
 
+static GdkDragAction
+gth_file_source_selections_get_drop_actions (GthFileSource *file_source,
+                                            GFile         *destination,
+                                            GFile         *file)
+{
+       GdkDragAction  actions = 0;
+       char          *dest_uri;
+       char          *dest_scheme;
+       char          *file_uri;
+       char          *file_scheme;
+
+       dest_uri = g_file_get_uri (destination);
+       dest_scheme = _g_uri_get_scheme (dest_uri);
+
+       file_uri = g_file_get_uri (file);
+       file_scheme = _g_uri_get_scheme (file_uri);
+
+       if ((g_strcmp0 (dest_scheme, "selection://") == 0)
+               && (g_strcmp0 (file_scheme, "file://") == 0))
+       {
+               /* Copy files into a selection. */
+               actions = GDK_ACTION_COPY;
+       }
+
+       g_free (file_uri);
+       g_free (dest_uri);
+
+       return actions;
+}
+
+
 static void
 gth_file_source_selections_class_init (GthFileSourceSelectionsClass *class)
 {
@@ -304,6 +335,7 @@ gth_file_source_selections_class_init (GthFileSourceSelectionsClass *class)
        file_source_class->remove = gth_file_source_selections_remove;
        file_source_class->deleted_from_disk = gth_file_source_selections_deleted_from_disk;
        file_source_class->shows_extra_widget = gth_file_source_selections_shows_extra_widget;
+       file_source_class->get_drop_actions = gth_file_source_selections_get_drop_actions;
 }
 
 
diff --git a/gthumb/gth-browser.c b/gthumb/gth-browser.c
index 522ef839..89b8c524 100644
--- a/gthumb/gth-browser.c
+++ b/gthumb/gth-browser.c
@@ -2661,7 +2661,6 @@ folder_tree_drag_motion_cb (GtkWidget      *file_view,
        GthBrowser              *browser = user_data;
        GtkTreePath             *path;
        GtkTreeViewDropPosition  pos;
-       GdkDragAction            action;
 
        if (gdk_drag_context_get_suggested_action (context) == GDK_ACTION_ASK) {
                gdk_drag_status (context, GDK_ACTION_ASK, time);
@@ -2694,8 +2693,6 @@ folder_tree_drag_motion_cb (GtkWidget      *file_view,
 
        gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (file_view), path, pos);
 
-       action = GDK_ACTION_MOVE;
-
        if ((browser->priv->folder_tree_last_dest_row == NULL) || gtk_tree_path_compare (path, 
browser->priv->folder_tree_last_dest_row) != 0) {
                gtk_tree_path_free (browser->priv->folder_tree_last_dest_row);
                browser->priv->folder_tree_last_dest_row = gtk_tree_path_copy (path);
@@ -2705,52 +2702,7 @@ folder_tree_drag_motion_cb (GtkWidget      *file_view,
                browser->priv->folder_tree_open_folder_id = g_timeout_add (AUTO_OPEN_FOLDER_DELAY, 
folder_tree_open_folder_cb, browser);
        }
 
-       /* use COPY if dropping a file in a catalog */
-
-       if (action == GDK_ACTION_MOVE) {
-               GthFileData *destination;
-
-               destination = gth_folder_tree_get_file (GTH_FOLDER_TREE (browser->priv->folder_tree), path);
-               if (destination != NULL) {
-                       GthFileSource *file_source = gth_main_get_file_source (destination->file);
-
-                       _g_object_unref (destination);
-                       if (file_source != NULL) {
-                               if (gth_file_source_is_reorderable (file_source))
-                                       action = GDK_ACTION_COPY;
-                       }
-                       else
-                               action = 0;
-
-                       _g_object_unref (file_source);
-               }
-               else
-                       action = 0;
-       }
-
-       /* use COPY when dragging a file from a catalog to a directory */
-
-       if (action == GDK_ACTION_MOVE) {
-               gboolean  source_is_reorderable;
-               GList    *targets;
-               GList    *scan;
-
-               source_is_reorderable = FALSE;
-               targets = gdk_drag_context_list_targets (context);
-               for (scan = targets; scan; scan = scan->next) {
-                       GdkAtom target = scan->data;
-
-                       if (target == gdk_atom_intern_static_string ("gthumb/reorderable-list")) {
-                               source_is_reorderable = TRUE;
-                               break;
-                       }
-               }
-
-               if (source_is_reorderable)
-                       action = GDK_ACTION_COPY;
-       }
-
-       gdk_drag_status (context, action, time);
+       gdk_drag_status (context, GDK_ACTION_MOVE, time);
        gtk_tree_path_free (path);
 
        return TRUE;
diff --git a/gthumb/gth-file-source-vfs.c b/gthumb/gth-file-source-vfs.c
index dfa4275b..dcc1c4e7 100644
--- a/gthumb/gth-file-source-vfs.c
+++ b/gthumb/gth-file-source-vfs.c
@@ -883,6 +883,24 @@ gth_file_source_vfs_remove (GthFileSource *file_source,
 }
 
 
+static GdkDragAction
+gth_file_source_vfs_get_drop_actions (GthFileSource *file_source,
+                                     GFile         *destination,
+                                     GFile         *file)
+{
+       char *dest_scheme;
+       char *file_scheme;
+
+       dest_scheme = g_file_get_uri_scheme(destination);
+       file_scheme = g_file_get_uri_scheme(file);
+
+       if ((g_strcmp0 (dest_scheme, "file") == 0) && (g_strcmp0 (file_scheme, "file") == 0))
+               return GDK_ACTION_COPY | GDK_ACTION_MOVE;
+       else
+               return 0;
+}
+
+
 static void
 gth_file_source_vfs_finalize (GObject *object)
 {
@@ -926,6 +944,7 @@ gth_file_source_vfs_class_init (GthFileSourceVfsClass *class)
        file_source_class->monitor_entry_points = gth_file_source_vfs_monitor_entry_points;
        file_source_class->monitor_directory = gth_file_source_vfs_monitor_directory;
        file_source_class->remove = gth_file_source_vfs_remove;
+       file_source_class->get_drop_actions = gth_file_source_vfs_get_drop_actions;
 }
 
 
diff --git a/gthumb/gth-file-source.c b/gthumb/gth-file-source.c
index 40db3d66..504de529 100644
--- a/gthumb/gth-file-source.c
+++ b/gthumb/gth-file-source.c
@@ -900,6 +900,15 @@ base_shows_extra_widget (GthFileSource *file_source)
 }
 
 
+static GdkDragAction
+base_get_drop_actions (GthFileSource *file_source,
+                      GFile         *destination,
+                      GFile         *file)
+{
+       return 0; /* no action supported by default. */
+}
+
+
 static void
 gth_file_source_finalize (GObject *object)
 {
@@ -938,6 +947,7 @@ gth_file_source_class_init (GthFileSourceClass *class)
        class->deleted_from_disk = base_deleted_from_disk;
        class->get_free_space = base_get_free_space;
        class->shows_extra_widget = base_shows_extra_widget;
+       class->get_drop_actions = base_get_drop_actions;
 }
 
 
@@ -1436,3 +1446,12 @@ gth_file_source_shows_extra_widget (GthFileSource *file_source)
 {
        return GTH_FILE_SOURCE_GET_CLASS (G_OBJECT (file_source))->shows_extra_widget (file_source);
 }
+
+
+GdkDragAction
+gth_file_source_get_drop_actions (GthFileSource *file_source,
+                                 GFile         *destination,
+                                 GFile         *file)
+{
+       return GTH_FILE_SOURCE_GET_CLASS (G_OBJECT (file_source))->get_drop_actions (file_source, 
destination, file);
+}
diff --git a/gthumb/gth-file-source.h b/gthumb/gth-file-source.h
index 717f94a4..67fbbd66 100644
--- a/gthumb/gth-file-source.h
+++ b/gthumb/gth-file-source.h
@@ -139,6 +139,9 @@ struct _GthFileSourceClass
                                               SpaceReadyCallback    callback,
                                               gpointer              data);
        gboolean     (*shows_extra_widget)    (GthFileSource        *file_source);
+       GdkDragAction(*get_drop_actions)      (GthFileSource        *file_source,
+                                              GFile                *destination,
+                                              GFile                *file);
 };
 
 GType          gth_file_source_get_type              (void) G_GNUC_CONST;
@@ -230,6 +233,9 @@ void           gth_file_source_get_free_space        (GthFileSource        *file
                                                      SpaceReadyCallback    callback,
                                                      gpointer              data);
 gboolean       gth_file_source_shows_extra_widget    (GthFileSource        *file_source);
+GdkDragAction  gth_file_source_get_drop_actions      (GthFileSource        *file_source,
+                                                     GFile                *destination,
+                                                     GFile                *file);
 
 /*< protected >*/
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]