[nautilus] files-view: add context menu actions for extracting files



commit 9f0c9a9f1243e650d5f023f110151640e91e875b
Author: Razvan Chitu <razvan ch95 gmail com>
Date:   Fri Aug 19 12:18:30 2016 +0300

    files-view: add context menu actions for extracting files
    
    The context menu actions are similar to the ones offered by file-roller, but
    make use of the internal extract operation.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=768646

 src/nautilus-file.c                                |   36 +---
 src/nautilus-files-view.c                          |  273 ++++++++++++++++++++
 .../ui/nautilus-files-view-context-menus.ui        |   10 +
 3 files changed, 288 insertions(+), 31 deletions(-)
---
diff --git a/src/nautilus-file.c b/src/nautilus-file.c
index b380d39..60e2f9b 100644
--- a/src/nautilus-file.c
+++ b/src/nautilus-file.c
@@ -51,6 +51,7 @@
 #include <glib/gstdio.h>
 #include <gio/gio.h>
 #include <glib.h>
+#include <gnome-autoar/gnome-autoar.h>
 #include <gdesktop-enums.h>
 #include <libnautilus-extension/nautilus-file-info.h>
 #include <libnautilus-extension/nautilus-extension-private.h>
@@ -7012,38 +7013,11 @@ real_is_special_link (NautilusFile *file)
 gboolean
 nautilus_file_is_archive (NautilusFile *file)
 {
-       char *mime_type;
-       int i;
-       static const char * archive_mime_types[] = { "application/x-gtar",
-                                                    "application/x-zip",
-                                                    "application/x-zip-compressed",
-                                                    "application/zip",
-                                                    "application/x-zip",
-                                                    "application/x-tar",
-                                                    "application/x-7z-compressed",
-                                                    "application/x-rar",
-                                                    "application/x-rar-compressed",
-                                                    "application/x-jar",
-                                                    "application/x-java-archive",
-                                                    "application/x-war",
-                                                    "application/x-ear",
-                                                    "application/x-arj",
-                                                    "application/x-gzip",
-                                                    "application/x-bzip-compressed-tar",
-                                                    "application/x-compressed-tar" };
-
-       g_return_val_if_fail (file != NULL, FALSE);
-
-       mime_type = nautilus_file_get_mime_type (file);
-       for (i = 0; i < G_N_ELEMENTS (archive_mime_types); i++) {
-               if (!strcmp (mime_type, archive_mime_types[i])) {
-                       g_free (mime_type);
-                       return TRUE;
-               }
-       }
-       g_free (mime_type);
+        g_autofree char *mime_type;
 
-       return FALSE;
+        mime_type = nautilus_file_get_mime_type (file);
+
+        return autoar_check_mime_type_supported (mime_type);
 }
 
 
diff --git a/src/nautilus-files-view.c b/src/nautilus-files-view.c
index a47c2cf..40f575a 100644
--- a/src/nautilus-files-view.c
+++ b/src/nautilus-files-view.c
@@ -683,6 +683,16 @@ nautilus_files_view_supports_creating_files (NautilusFilesView *view)
 }
 
 static gboolean
+nautilus_files_view_supports_extract_here (NautilusFilesView *view)
+{
+        g_return_val_if_fail (NAUTILUS_IS_FILES_VIEW (view), FALSE);
+
+        return nautilus_files_view_supports_creating_files (view)
+                && !nautilus_directory_is_remote (view->details->model)
+                && !nautilus_view_is_searching (NAUTILUS_VIEW (view));
+}
+
+static gboolean
 nautilus_files_view_is_empty (NautilusFilesView *view)
 {
         g_return_val_if_fail (NAUTILUS_IS_FILES_VIEW (view), FALSE);
@@ -5360,6 +5370,238 @@ action_rename (GSimpleAction *action,
         real_action_rename (NAUTILUS_FILES_VIEW (user_data));
 }
 
+typedef struct {
+        NautilusFilesView *view;
+        GHashTable *added_locations;
+} ExtractData;
+
+static void
+extract_done (GList    *outputs,
+              gpointer  user_data)
+{
+        ExtractData *data;
+        GList *l;
+        gboolean all_files_acknowledged;
+
+        data = user_data;
+
+        if (data->view == NULL) {
+                goto out;
+        }
+
+        g_signal_handlers_disconnect_by_func (data->view,
+                                              G_CALLBACK (track_newly_added_locations),
+                                              data->added_locations);
+
+        if (outputs == NULL) {
+                goto out;
+        }
+
+        all_files_acknowledged = TRUE;
+        for (l = outputs; l && all_files_acknowledged; l = l->next) {
+                all_files_acknowledged = g_hash_table_contains (data->added_locations,
+                                                                l->data);
+        }
+
+        if (all_files_acknowledged) {
+                GList *selection = NULL;
+
+                for (l = outputs; l != NULL; l = l->next) {
+                        selection = g_list_prepend (selection,
+                                                    nautilus_file_get (l->data));
+                }
+
+                nautilus_files_view_set_selection (NAUTILUS_VIEW (data->view),
+                                                   selection);
+                nautilus_files_view_reveal_selection (data->view);
+
+                nautilus_file_list_free (selection);
+        } else {
+                for (l = outputs; l != NULL; l = l->next) {
+                        gboolean acknowledged;
+
+                        acknowledged = g_hash_table_contains (data->added_locations,
+                                                              l->data);
+
+                        g_hash_table_insert (data->view->details->pending_reveal,
+                                             nautilus_file_get (l->data),
+                                             GUINT_TO_POINTER (acknowledged));
+                }
+        }
+out:
+        g_hash_table_destroy (data->added_locations);
+
+        if (data->view != NULL) {
+                g_object_remove_weak_pointer (G_OBJECT (data->view),
+                                              (gpointer *) &data->view);
+        }
+
+        g_free (data);
+}
+
+static void
+extract_files (NautilusFilesView *view,
+               GList             *files,
+               GFile             *destination_directory)
+{
+        GList *locations = NULL;
+        GList *l;
+        gboolean extracting_to_current_directory;
+
+        if (files == NULL) {
+                return;
+        }
+
+        for (l = files; l != NULL; l = l->next) {
+                locations = g_list_prepend (locations,
+                                            nautilus_file_get_location (l->data));
+        }
+
+        locations = g_list_reverse (locations);
+
+        extracting_to_current_directory = g_file_equal (destination_directory,
+                                                        nautilus_view_get_location (NAUTILUS_VIEW (view)));
+
+        if (extracting_to_current_directory) {
+                ExtractData *data;
+
+                data = g_new (ExtractData, 1);
+                data->view = view;
+                data->added_locations = g_hash_table_new_full (g_file_hash,
+                                                               (GEqualFunc)g_file_equal,
+                                                               g_object_unref, NULL);
+
+
+                g_object_add_weak_pointer (G_OBJECT (data->view),
+                                           (gpointer *) &data->view);
+
+                g_signal_connect_data (view,
+                                       "add-file",
+                                       G_CALLBACK (track_newly_added_locations),
+                                       data->added_locations,
+                                       NULL,
+                                       G_CONNECT_AFTER);
+
+                nautilus_file_operations_extract_files (locations,
+                                                        destination_directory,
+                                                        nautilus_files_view_get_containing_window (view),
+                                                        extract_done,
+                                                        data);
+        } else {
+                nautilus_file_operations_extract_files (locations,
+                                                        destination_directory,
+                                                        nautilus_files_view_get_containing_window (view),
+                                                        NULL,
+                                                        NULL);
+        }
+
+        g_list_free_full (locations, g_object_unref);
+}
+
+typedef struct {
+        NautilusFilesView *view;
+        GList *files;
+} ExtractToData;
+
+static void
+on_extract_destination_dialog_response (GtkDialog *dialog,
+                                        gint       response_id,
+                                        gpointer   user_data)
+{
+        ExtractToData *data;
+
+        data = user_data;
+
+        if (response_id == GTK_RESPONSE_OK) {
+                g_autoptr (GFile) destination_directory;
+
+                destination_directory = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
+
+                extract_files (data->view, data->files, destination_directory);
+        }
+
+        gtk_widget_destroy (GTK_WIDGET (dialog));
+        nautilus_file_list_free (data->files);
+        g_free (data);
+}
+
+static void
+extract_files_to_chosen_location (NautilusFilesView *view,
+                                  GList             *files)
+{
+        ExtractToData *data;
+        GtkWidget *dialog;
+        g_autofree char *uri = NULL;
+
+        if (files == NULL) {
+                return;
+        }
+
+        data = g_new (ExtractToData, 1);
+
+        dialog = gtk_file_chooser_dialog_new (_("Select Extract Destination"),
+                                              GTK_WINDOW (nautilus_files_view_get_window (view)),
+                                              GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
+                                              _("_Cancel"), GTK_RESPONSE_CANCEL,
+                                              _("_Select"), GTK_RESPONSE_OK,
+                                              NULL);
+        gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (dialog), FALSE);
+
+        gtk_dialog_set_default_response (GTK_DIALOG (dialog),
+                                         GTK_RESPONSE_OK);
+
+        gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
+        gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
+
+        uri = nautilus_directory_get_uri (view->details->model);
+        gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog), uri);
+
+        data->view = view;
+        data->files = nautilus_file_list_copy (files);
+
+        g_signal_connect (dialog, "response",
+                          G_CALLBACK (on_extract_destination_dialog_response),
+                          data);
+
+        gtk_widget_show_all (dialog);
+}
+
+static void
+action_extract_here (GSimpleAction *action,
+                     GVariant      *state,
+                     gpointer       user_data)
+{
+        NautilusFilesView *view;
+        GList *selection;
+
+        view = NAUTILUS_FILES_VIEW (user_data);
+
+        selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
+
+        extract_files (view, selection,
+                       nautilus_view_get_location (NAUTILUS_VIEW (view)));
+
+        nautilus_file_list_free (selection);
+}
+
+static void
+action_extract_to (GSimpleAction *action,
+                   GVariant      *state,
+                   gpointer       user_data)
+{
+        NautilusFilesView *view;
+        GList *selection;
+
+        view = NAUTILUS_FILES_VIEW (user_data);
+
+        selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
+
+        extract_files_to_chosen_location (view, selection);
+
+        nautilus_file_list_free (selection);
+}
+
+
 #define BG_KEY_PRIMARY_COLOR      "primary-color"
 #define BG_KEY_SECONDARY_COLOR    "secondary-color"
 #define BG_KEY_COLOR_TYPE         "color-shading-type"
@@ -5796,6 +6038,8 @@ const GActionEntry view_entries[] = {
         { "restore-from-trash", action_restore_from_trash},
         { "paste-into", action_paste_files_into },
         { "rename", action_rename},
+        { "extract-here", action_extract_here },
+        { "extract-to", action_extract_to },
         { "properties", action_properties},
         { "set-as-wallpaper", action_set_as_wallpaper },
         { "mount-volume", action_mount_volume },
@@ -6033,6 +6277,21 @@ all_in_trash (GList *files)
         return TRUE;
 }
 
+static gboolean
+can_extract_all (GList *files)
+{
+        NautilusFile *file;
+        GList *l;
+
+        for (l = files; l != NULL; l = l->next) {
+                file = l->data;
+                if (!nautilus_file_is_archive (file)) {
+                        return FALSE;
+                }
+        }
+        return TRUE;
+}
+
 GActionGroup *
 nautilus_files_view_get_action_group (NautilusFilesView *view)
 {
@@ -6060,6 +6319,8 @@ real_update_actions_state (NautilusFilesView *view)
         gboolean can_copy_files;
         gboolean can_link_from_copied_files;
         gboolean can_paste_files_into;
+        gboolean can_extract_files;
+        gboolean can_extract_here;
         gboolean item_opens_in_view;
         gboolean is_read_only;
         GAction *action;
@@ -6107,6 +6368,9 @@ real_update_actions_state (NautilusFilesView *view)
         can_paste_files_into = (!selection_contains_recent &&
                                 selection_count == 1 &&
                                 can_paste_into_file (NAUTILUS_FILE (selection->data)));
+        can_extract_files = selection_count != 0 &&
+                            can_extract_all (selection);
+        can_extract_here = nautilus_files_view_supports_extract_here (view);
          settings_show_delete_permanently = g_settings_get_boolean (nautilus_preferences,
                                                                     
NAUTILUS_PREFERENCES_SHOW_DELETE_PERMANENTLY);
          settings_show_create_link = g_settings_get_boolean (nautilus_preferences,
@@ -6131,6 +6395,15 @@ real_update_actions_state (NautilusFilesView *view)
         }
 
         action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
+                                             "extract-here");
+        g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
+                                     can_extract_files && can_extract_here);
+
+        action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
+                                             "extract-to");
+        g_simple_action_set_enabled (G_SIMPLE_ACTION (action), can_extract_files);
+
+        action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
                                              "open-item-location");
 
         g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
diff --git a/src/resources/ui/nautilus-files-view-context-menus.ui 
b/src/resources/ui/nautilus-files-view-context-menus.ui
index b40d242..564201f 100644
--- a/src/resources/ui/nautilus-files-view-context-menus.ui
+++ b/src/resources/ui/nautilus-files-view-context-menus.ui
@@ -235,6 +235,16 @@
     </section>
     <section>
       <attribute name="id">extensions</attribute>
+      <item>
+        <attribute name="label" translatable="yes">_Extract Here</attribute>
+        <attribute name="action">view.extract-here</attribute>
+        <attribute name="hidden-when">action-disabled</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">E_xtract to…</attribute>
+        <attribute name="action">view.extract-to</attribute>
+        <attribute name="hidden-when">action-disabled</attribute>
+      </item>
     </section>
     <section>
       <item>


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