[nautilus/wip/razvan/compression-support: 23/23] files-view: add menu action and dialog for compression



commit fcf9389ecb69d5a0893f0cb702b093bcfe99c7db
Author: Razvan Chitu <razvan ch95 gmail com>
Date:   Sun Aug 21 23:02:54 2016 +0300

    files-view: add menu action and dialog for compression
    
    Add an context menu action for compression and a dialog for selecting the file
    name and compression format. Add a controller class for managing the compression
    dialog.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=770199

 src/Makefile.am                                    |    2 +
 src/nautilus-compress-dialog-controller.c          |  294 ++++++++++++++++++++
 src/nautilus-compress-dialog-controller.h          |   17 ++
 src/nautilus-files-view.c                          |  202 ++++++++++++++
 src/resources/nautilus.gresource.xml               |    1 +
 src/resources/ui/nautilus-compress-dialog.ui       |  143 ++++++++++
 .../ui/nautilus-files-view-context-menus.ui        |    5 +
 7 files changed, 664 insertions(+), 0 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 6532c01..c925f41 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -278,6 +278,8 @@ nautilus_no_main_sources = \
        nautilus-rename-file-popover-controller.h \
        nautilus-new-folder-dialog-controller.c \
        nautilus-new-folder-dialog-controller.h \
+       nautilus-compress-dialog-controller.c \
+       nautilus-compress-dialog-controller.h \
        nautilus-operations-ui-manager.c \
        nautilus-operations-ui-manager.h \
        nautilus-file-operations.c \
diff --git a/src/nautilus-compress-dialog-controller.c b/src/nautilus-compress-dialog-controller.c
new file mode 100644
index 0000000..177bc03
--- /dev/null
+++ b/src/nautilus-compress-dialog-controller.c
@@ -0,0 +1,294 @@
+#include <glib/gi18n.h>
+#include <gnome-autoar/gnome-autoar.h>
+
+#include <eel/eel-vfs-extensions.h>
+
+#include "nautilus-compress-dialog-controller.h"
+
+#include "nautilus-global-preferences.h"
+
+#define ZIP_DESCRIPTION       _("Compatible with all operating systems")
+#define TAR_XZ_DESCRIPTION    _("Linux and Mac only but more efficient")
+#define SEVEN_ZIP_DESCRIPTION _("Efficient but must be installed on Windows and Mac")
+
+struct _NautilusCompressDialogController {
+        NautilusFileNameWidgetController parent_instance;
+
+        GtkWidget *compress_dialog;
+        GtkWidget *description_label;
+        GtkWidget *name_entry;
+        GtkWidget *zip_radio_button;
+        GtkWidget *tar_xz_radio_button;
+        GtkWidget *seven_zip_radio_button;
+
+        const char *extension;
+
+        gint response_handler_id;
+};
+
+G_DEFINE_TYPE (NautilusCompressDialogController, nautilus_compress_dialog_controller, 
NAUTILUS_TYPE_FILE_NAME_WIDGET_CONTROLLER);
+
+static gboolean
+nautilus_compress_dialog_controller_name_is_valid (NautilusFileNameWidgetController  *self,
+                                                   gchar                             *name,
+                                                   gchar                            **error_message)
+{
+        if (strlen (name) == 0) {
+                return FALSE;
+        }
+
+        if (strstr (name, "/") != NULL) {
+                *error_message = _("Archive names cannot contain “/”.");
+        } else if (strcmp (name, ".") == 0){
+                *error_message = _("An archive cannot be called “.”.");
+        } else if (strcmp (name, "..") == 0){
+                *error_message = _("An archive cannot be called “..”.");
+        }
+
+        return *error_message == NULL;
+}
+
+static gchar *
+nautilus_compress_dialog_controller_get_new_name (NautilusFileNameWidgetController *controller)
+{
+        NautilusCompressDialogController *self;
+        g_autofree gchar *basename;
+        gchar *error_message = NULL;
+        gboolean valid_name;
+
+        self = NAUTILUS_COMPRESS_DIALOG_CONTROLLER (controller);
+
+        basename = NAUTILUS_FILE_NAME_WIDGET_CONTROLLER_CLASS 
(nautilus_compress_dialog_controller_parent_class)->get_new_name (controller);
+        /* Do not check or add the extension if the name is invalid */
+        valid_name = nautilus_compress_dialog_controller_name_is_valid (controller,
+                                                                        basename,
+                                                                        &error_message);
+
+        if (!valid_name) {
+                return g_strdup (basename);
+        }
+
+        if (g_str_has_suffix (basename, self->extension)) {
+                return g_strdup (basename);
+        }
+
+        return g_strconcat (basename, self->extension, NULL);
+}
+
+static void
+compress_dialog_controller_on_response (GtkDialog *dialog,
+                                        gint       response_id,
+                                        gpointer   user_data)
+{
+        NautilusCompressDialogController *controller;
+
+        controller = NAUTILUS_COMPRESS_DIALOG_CONTROLLER (user_data);
+
+        if (response_id != GTK_RESPONSE_OK) {
+                g_signal_emit_by_name (controller, "cancelled");
+        }
+}
+
+static void
+update_selected_format (NautilusCompressDialogController *self,
+                        NautilusCompressionFormat         format)
+{
+        const char *extension;
+        const char *description;
+        GtkWidget *active_button;
+
+        switch (format) {
+                case NAUTILUS_COMPRESSION_ZIP:
+                        extension = ".zip";
+                        description = ZIP_DESCRIPTION;
+                        active_button = self->zip_radio_button;
+                        break;
+                case NAUTILUS_COMPRESSION_TAR_XZ:
+                        extension = ".tar.xz";
+                        description = TAR_XZ_DESCRIPTION;
+                        active_button = self->tar_xz_radio_button;
+                        break;
+                case NAUTILUS_COMPRESSION_7ZIP:
+                        extension = ".7z";
+                        description = SEVEN_ZIP_DESCRIPTION;
+                        active_button = self->seven_zip_radio_button;
+                        break;
+                default:
+                        g_assert_not_reached ();
+                        break;
+        }
+
+        self->extension = extension;
+
+        gtk_label_set_text (GTK_LABEL (self->description_label),
+                            description);
+
+        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (active_button),
+                                      TRUE);
+
+        g_settings_set_enum (nautilus_compression_preferences,
+                             NAUTILUS_PREFERENCES_DEFAULT_COMPRESSION_FORMAT,
+                             format);
+        /* Since the extension changes when the button is toggled, force a
+         * verification of the new file name by simulating an entry change
+         */
+        g_signal_emit_by_name (self->name_entry, "changed");
+}
+
+static void
+zip_radio_button_on_toggled (GtkToggleButton *toggle_button,
+                             gpointer         user_data)
+{
+        NautilusCompressDialogController *controller;
+
+        controller = NAUTILUS_COMPRESS_DIALOG_CONTROLLER (user_data);
+
+        if (!gtk_toggle_button_get_active (toggle_button)) {
+                return;
+        }
+
+        update_selected_format (controller,
+                                NAUTILUS_COMPRESSION_ZIP);
+}
+
+static void
+tar_xz_radio_button_on_toggled (GtkToggleButton *toggle_button,
+                                gpointer         user_data)
+{
+        NautilusCompressDialogController *controller;
+
+        controller = NAUTILUS_COMPRESS_DIALOG_CONTROLLER (user_data);
+
+        if (!gtk_toggle_button_get_active (toggle_button)) {
+                return;
+        }
+
+        update_selected_format (controller,
+                                NAUTILUS_COMPRESSION_TAR_XZ);
+}
+
+static void
+seven_zip_radio_button_on_toggled (GtkToggleButton *toggle_button,
+                                   gpointer         user_data)
+{
+        NautilusCompressDialogController *controller;
+
+        controller = NAUTILUS_COMPRESS_DIALOG_CONTROLLER (user_data);
+
+        if (!gtk_toggle_button_get_active (toggle_button)) {
+                return;
+        }
+
+        update_selected_format (controller,
+                                NAUTILUS_COMPRESSION_7ZIP);
+}
+
+NautilusCompressDialogController *
+nautilus_compress_dialog_controller_new (GtkWindow         *parent_window,
+                                         NautilusDirectory *destination_directory,
+                                         gchar             *initial_name)
+{
+        NautilusCompressDialogController *self;
+        g_autoptr (GtkBuilder) builder;
+        GtkWidget *compress_dialog;
+        GtkWidget *error_label;
+        GtkWidget *name_entry;
+        GtkWidget *activate_button;
+        GtkWidget *description_label;
+        GtkWidget *zip_radio_button;
+        GtkWidget *tar_xz_radio_button;
+        GtkWidget *seven_zip_radio_button;
+        NautilusCompressionFormat format;
+
+        builder = gtk_builder_new_from_resource ("/org/gnome/nautilus/ui/nautilus-compress-dialog.ui");
+        compress_dialog = GTK_WIDGET (gtk_builder_get_object (builder, "compress_dialog"));
+        error_label = GTK_WIDGET (gtk_builder_get_object (builder, "error_label"));
+        name_entry = GTK_WIDGET (gtk_builder_get_object (builder, "name_entry"));
+        activate_button = GTK_WIDGET (gtk_builder_get_object (builder, "activate_button"));
+        zip_radio_button = GTK_WIDGET (gtk_builder_get_object (builder, "zip_radio_button"));
+        tar_xz_radio_button = GTK_WIDGET (gtk_builder_get_object (builder, "tar_xz_radio_button"));
+        seven_zip_radio_button = GTK_WIDGET (gtk_builder_get_object (builder, "seven_zip_radio_button"));
+        description_label = GTK_WIDGET (gtk_builder_get_object (builder, "description_label"));
+
+        gtk_window_set_transient_for (GTK_WINDOW (compress_dialog),
+                                      parent_window);
+
+        self = g_object_new (NAUTILUS_TYPE_COMPRESS_DIALOG_CONTROLLER,
+                             "error-label", error_label,
+                             "name-entry", name_entry,
+                             "activate-button", activate_button,
+                             "containing-directory", destination_directory, NULL);
+
+        self->compress_dialog = compress_dialog;
+        self->zip_radio_button = zip_radio_button;
+        self->tar_xz_radio_button = tar_xz_radio_button;
+        self->seven_zip_radio_button = seven_zip_radio_button;
+        self->description_label = description_label;
+        self->name_entry = name_entry;
+
+        self->response_handler_id = g_signal_connect (compress_dialog,
+                                                      "response",
+                                                      (GCallback)compress_dialog_controller_on_response,
+                                                      self);
+
+        gtk_builder_add_callback_symbols (builder,
+                                          "zip_radio_button_on_toggled",
+                                          G_CALLBACK (zip_radio_button_on_toggled),
+                                          "tar_xz_radio_button_on_toggled",
+                                          G_CALLBACK (tar_xz_radio_button_on_toggled),
+                                          "seven_zip_radio_button_on_toggled",
+                                          G_CALLBACK (seven_zip_radio_button_on_toggled),
+                                          NULL);
+        gtk_builder_connect_signals (builder, self);
+
+        format = g_settings_get_enum (nautilus_compression_preferences,
+                                      NAUTILUS_PREFERENCES_DEFAULT_COMPRESSION_FORMAT);
+
+        update_selected_format (self, format);
+
+        if (initial_name != NULL) {
+                gtk_entry_set_text (GTK_ENTRY (name_entry), initial_name);
+        }
+
+        gtk_widget_show_all (compress_dialog);
+
+        return self;
+}
+
+static void
+nautilus_compress_dialog_controller_init (NautilusCompressDialogController *self)
+{
+
+}
+
+static void
+nautilus_compress_dialog_controller_finalize (GObject *object)
+{
+        NautilusCompressDialogController *self;
+
+        self = NAUTILUS_COMPRESS_DIALOG_CONTROLLER (object);
+
+        if (self->compress_dialog != NULL) {
+                if (self->response_handler_id > 0) {
+                        g_signal_handler_disconnect (self->compress_dialog,
+                                                     self->response_handler_id);
+                        self->response_handler_id = 0;
+                }
+                gtk_widget_destroy (self->compress_dialog);
+                self->compress_dialog = NULL;
+        }
+
+        G_OBJECT_CLASS (nautilus_compress_dialog_controller_parent_class)->finalize (object);
+}
+
+static void
+nautilus_compress_dialog_controller_class_init (NautilusCompressDialogControllerClass *klass)
+{
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+        NautilusFileNameWidgetControllerClass *parent_class = NAUTILUS_FILE_NAME_WIDGET_CONTROLLER_CLASS 
(klass);
+
+        object_class->finalize = nautilus_compress_dialog_controller_finalize;
+
+        parent_class->get_new_name = nautilus_compress_dialog_controller_get_new_name;
+        parent_class->name_is_valid = nautilus_compress_dialog_controller_name_is_valid;
+}
diff --git a/src/nautilus-compress-dialog-controller.h b/src/nautilus-compress-dialog-controller.h
new file mode 100644
index 0000000..b33767c
--- /dev/null
+++ b/src/nautilus-compress-dialog-controller.h
@@ -0,0 +1,17 @@
+#ifndef NAUTILUS_COMPRESS_DIALOG_CONTROLLER_H
+#define NAUTILUS_COMPRESS_DIALOG_CONTROLLER_H
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+#include "nautilus-file-name-widget-controller.h"
+#include "nautilus-directory.h"
+
+#define NAUTILUS_TYPE_COMPRESS_DIALOG_CONTROLLER nautilus_compress_dialog_controller_get_type ()
+G_DECLARE_FINAL_TYPE (NautilusCompressDialogController, nautilus_compress_dialog_controller, NAUTILUS, 
COMPRESS_DIALOG_CONTROLLER, NautilusFileNameWidgetController)
+
+NautilusCompressDialogController * nautilus_compress_dialog_controller_new (GtkWindow         *parent_window,
+                                                                            NautilusDirectory 
*destination_directory,
+                                                                            gchar             *initial_name);
+
+#endif /* NAUTILUS_COMPRESS_DIALOG_CONTROLLER_H */
diff --git a/src/nautilus-files-view.c b/src/nautilus-files-view.c
index d35b2cd..cd7aa27 100644
--- a/src/nautilus-files-view.c
+++ b/src/nautilus-files-view.c
@@ -54,6 +54,7 @@
 #include <glib/gi18n.h>
 #include <glib/gstdio.h>
 #include <gio/gio.h>
+#include <gnome-autoar/gnome-autoar.h>
 #include <math.h>
 #include <string.h>
 #include <sys/types.h>
@@ -81,6 +82,7 @@
 #include "nautilus-file-name-widget-controller.h"
 #include "nautilus-rename-file-popover-controller.h"
 #include "nautilus-new-folder-dialog-controller.h"
+#include "nautilus-compress-dialog-controller.h"
 #include "nautilus-global-preferences.h"
 #include "nautilus-link.h"
 #include "nautilus-metadata.h"
@@ -177,6 +179,7 @@ struct NautilusFilesViewDetails
 
         NautilusRenameFilePopoverController *rename_file_controller;
         NautilusNewFolderDialogController *new_folder_controller;
+        NautilusCompressDialogController *compress_controller;
 
         gboolean supports_zooming;
 
@@ -1897,6 +1900,188 @@ nautilus_files_view_new_folder_dialog_new (NautilusFilesView *view,
         nautilus_directory_unref (containing_directory);
 }
 
+typedef struct {
+        NautilusFilesView *view;
+        GHashTable *added_locations;
+} CompressData;
+
+static void
+compress_done (GFile    *new_file,
+               gboolean  success,
+               gpointer  user_data)
+{
+        CompressData *data;
+        NautilusFilesView *view;
+        NautilusFile *file;
+
+        data = user_data;
+        view = data->view;
+
+        if (view == NULL) {
+                goto out;
+        }
+
+        g_signal_handlers_disconnect_by_func (view,
+                                              G_CALLBACK (track_newly_added_locations),
+                                              data->added_locations);
+
+        if (!success) {
+                goto out;
+        }
+
+        file = nautilus_file_get (new_file);
+
+        if (g_hash_table_contains (data->added_locations, new_file)) {
+                /* The file was already added */
+                nautilus_files_view_select_file (view, file);
+                nautilus_files_view_reveal_selection (view);
+        } else {
+                g_hash_table_insert (view->details->pending_reveal,
+                                     file,
+                                     GUINT_TO_POINTER (TRUE));
+        }
+
+        nautilus_file_unref (file);
+ 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
+compress_dialog_controller_on_name_accepted (NautilusFileNameWidgetController *controller,
+                                             gpointer                          user_data)
+{
+        NautilusFilesView *view;
+        g_autofree gchar *name;
+        GList *selection;
+        GList *source_files = NULL;
+        GList *l;
+        CompressData *data;
+        g_autoptr (GFile) output;
+        NautilusCompressionFormat compression_format;
+        AutoarFormat format;
+        AutoarFilter filter;
+
+        view = NAUTILUS_FILES_VIEW (user_data);
+
+        selection = nautilus_files_view_get_selection_for_file_transfer (view);
+
+        for (l = selection; l != NULL; l = l->next) {
+                source_files = g_list_prepend (source_files,
+                                               nautilus_file_get_location (l->data));
+        }
+        source_files = g_list_reverse (source_files);
+
+        name = nautilus_file_name_widget_controller_get_new_name (controller);
+        output = g_file_get_child (view->details->location, name);
+
+        data = g_new (CompressData, 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);
+
+        compression_format = g_settings_get_enum (nautilus_compression_preferences,
+                                                  NAUTILUS_PREFERENCES_DEFAULT_COMPRESSION_FORMAT);
+
+        switch (compression_format) {
+                case NAUTILUS_COMPRESSION_ZIP:
+                        format = AUTOAR_FORMAT_ZIP;
+                        filter = AUTOAR_FILTER_NONE;
+                        break;
+                case NAUTILUS_COMPRESSION_TAR_XZ:
+                        format = AUTOAR_FORMAT_TAR;
+                        filter = AUTOAR_FILTER_XZ;
+                        break;
+                case NAUTILUS_COMPRESSION_7ZIP:
+                        format = AUTOAR_FORMAT_7ZIP;
+                        filter = AUTOAR_FILTER_NONE;
+                        break;
+                default:
+                        g_assert_not_reached ();
+        }
+
+        nautilus_file_operations_compress (source_files, output,
+                                           format,
+                                           filter,
+                                           nautilus_files_view_get_containing_window (view),
+                                           compress_done,
+                                           data);
+
+        nautilus_file_list_free (selection);
+        g_list_free_full (source_files, g_object_unref);
+        g_clear_object (&view->details->compress_controller);
+}
+
+static void
+compress_dialog_controller_on_cancelled (NautilusNewFolderDialogController *controller,
+                                         gpointer                           user_data)
+{
+        NautilusFilesView *view;
+
+        view = NAUTILUS_FILES_VIEW (user_data);
+
+        g_clear_object (&view->details->compress_controller);
+}
+
+
+static void
+nautilus_files_view_compress_dialog_new (NautilusFilesView *view)
+{
+
+        NautilusDirectory *containing_directory;
+        GList *selection;
+        g_autofree char *common_prefix = NULL;
+
+        if (view->details->compress_controller != NULL) {
+                return;
+        }
+
+        containing_directory = nautilus_directory_get_by_uri (nautilus_files_view_get_backing_uri (view));
+
+        selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
+
+        if (g_list_length (selection) == 1) {
+                g_autofree char *display_name;
+
+                display_name = nautilus_file_get_display_name (selection->data);
+
+                common_prefix = eel_filename_strip_extension (display_name);
+        } else {
+                common_prefix = nautilus_get_common_filename_prefix (selection,
+                                                                     MIN_COMMON_FILENAME_PREFIX_LENGTH);
+        }
+
+        view->details->compress_controller = nautilus_compress_dialog_controller_new 
(nautilus_files_view_get_containing_window (view),
+                                                                                      containing_directory,
+                                                                                      common_prefix);
+
+        g_signal_connect (view->details->compress_controller,
+                          "name-accepted",
+                          (GCallback)compress_dialog_controller_on_name_accepted,
+                          view);
+        g_signal_connect (view->details->compress_controller,
+                          "cancelled",
+                          (GCallback)compress_dialog_controller_on_cancelled,
+                          view);
+
+        nautilus_file_list_free (selection);
+}
+
 static void
 nautilus_files_view_new_folder (NautilusFilesView *directory_view,
                                 gboolean           with_selection)
@@ -2709,6 +2894,7 @@ nautilus_files_view_finalize (GObject *object)
         g_clear_object (&view->details->toolbar_menu_sections->extended_section);
         g_clear_object (&view->details->rename_file_controller);
         g_clear_object (&view->details->new_folder_controller);
+        g_clear_object (&view->details->compress_controller);
         g_free (view->details->toolbar_menu_sections);
 
         g_hash_table_destroy (view->details->non_ready_files);
@@ -5640,6 +5826,16 @@ action_extract_to (GSimpleAction *action,
         nautilus_file_list_free (selection);
 }
 
+static void
+action_compress (GSimpleAction *action,
+                 GVariant      *state,
+                 gpointer       user_data)
+{
+        NautilusFilesView *view = user_data;
+
+        nautilus_files_view_compress_dialog_new (view);
+}
+
 
 #define BG_KEY_PRIMARY_COLOR      "primary-color"
 #define BG_KEY_SECONDARY_COLOR    "secondary-color"
@@ -6079,6 +6275,7 @@ const GActionEntry view_entries[] = {
         { "rename", action_rename},
         { "extract-here", action_extract_here },
         { "extract-to", action_extract_to },
+        { "compress", action_compress },
         { "properties", action_properties},
         { "set-as-wallpaper", action_set_as_wallpaper },
         { "mount-volume", action_mount_volume },
@@ -6451,6 +6648,11 @@ real_update_actions_state (NautilusFilesView *view)
                                       can_extract_here));
 
         action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
+                                             "compress");
+        g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
+                                     !can_extract_files && can_create_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/nautilus.gresource.xml b/src/resources/nautilus.gresource.xml
index a5917fc..05b9a4d 100644
--- a/src/resources/nautilus.gresource.xml
+++ b/src/resources/nautilus.gresource.xml
@@ -9,6 +9,7 @@
     <file>ui/nautilus-toolbar-menu.ui</file>
     <file>ui/nautilus-toolbar-view-menu.ui</file>
     <file>ui/nautilus-create-folder-dialog.ui</file>
+    <file>ui/nautilus-compress-dialog.ui</file>
     <file>ui/nautilus-rename-file-popover.ui</file>
     <file>ui/nautilus-files-view-context-menus.ui</file>
     <file>ui/nautilus-progress-info-widget.ui</file>
diff --git a/src/resources/ui/nautilus-compress-dialog.ui b/src/resources/ui/nautilus-compress-dialog.ui
new file mode 100644
index 0000000..b034270
--- /dev/null
+++ b/src/resources/ui/nautilus-compress-dialog.ui
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="3.14"/>
+  <object class="GtkDialog" id="compress_dialog">
+    <property name="title" translatable="true">Create Archive</property>
+    <property name="resizable">False</property>
+    <property name="modal">True</property>
+    <property name="window_position">center-on-parent</property>
+    <property name="destroy_with_parent">True</property>
+    <property name="type_hint">dialog</property>
+    <property name="use-header-bar">1</property>
+    <property name="width_request">450</property>
+    <child internal-child="vbox">
+      <object class="GtkBox" id="vbox">
+        <property name="orientation">vertical</property>
+        <property name="margin_top">18</property>
+        <property name="margin_bottom">12</property>
+        <property name="margin_start">18</property>
+        <property name="margin_end">18</property>
+        <property name="spacing">6</property>
+        <child>
+          <object class="GtkLabel" id="name_label">
+            <property name="label" translatable="yes">Archive name</property>
+            <property name="visible">True</property>
+            <property name="xalign">0</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkEntry" id="name_entry">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="error_label">
+            <property name="visible">True</property>
+            <property name="xalign">0</property>
+            <style>
+              <class name="dim-label"/>
+            </style>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">3</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox" id="hbox">
+            <property name="orientation">horizontal</property>
+            <property name="spacing">0</property>
+            <child>
+              <object class="GtkRadioButton" id="zip_radio_button">
+                <property name="label" translatable="no">.zip</property>
+                <property name="draw_indicator">True</property>
+                <signal name="toggled" handler="zip_radio_button_on_toggled"/>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkRadioButton" id="tar_xz_radio_button">
+                <property name="label" translatable="no">.tar.xz</property>
+                <property name="group">zip_radio_button</property>
+                <property name="draw_indicator">True</property>
+                <signal name="toggled" handler="tar_xz_radio_button_on_toggled"/>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkRadioButton" id="seven_zip_radio_button">
+                <property name="label" translatable="no">.7z</property>
+                <property name="group">zip_radio_button</property>
+                <property name="draw_indicator">True</property>
+                <signal name="toggled" handler="seven_zip_radio_button_on_toggled"/>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">4</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="description_label">
+            <property name="visible">True</property>
+            <property name="xalign">0</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">5</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <child type="action">
+      <object class="GtkButton" id="cancel_button">
+        <property name="label" translatable="yes">Cancel</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">True</property>
+      </object>
+    </child>
+    <child type="action">
+      <object class="GtkButton" id="activate_button">
+        <property name="label" translatable="yes">Create</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="can_default">True</property>
+        <property name="receives_default">True</property>
+        <property name="sensitive">False</property>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="ok" default="true">activate_button</action-widget>
+      <action-widget response="cancel">cancel_button</action-widget>
+    </action-widgets>
+  </object>
+</interface>
diff --git a/src/resources/ui/nautilus-files-view-context-menus.ui 
b/src/resources/ui/nautilus-files-view-context-menus.ui
index 564201f..f87a8a0 100644
--- a/src/resources/ui/nautilus-files-view-context-menus.ui
+++ b/src/resources/ui/nautilus-files-view-context-menus.ui
@@ -245,6 +245,11 @@
         <attribute name="action">view.extract-to</attribute>
         <attribute name="hidden-when">action-disabled</attribute>
       </item>
+      <item>
+        <attribute name="label" translatable="yes">C_ompress</attribute>
+        <attribute name="action">view.compress</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]