summaryrefslogtreecommitdiffstats
path: root/src/nautilus-compress-dialog-controller.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nautilus-compress-dialog-controller.c')
-rw-r--r--src/nautilus-compress-dialog-controller.c612
1 files changed, 612 insertions, 0 deletions
diff --git a/src/nautilus-compress-dialog-controller.c b/src/nautilus-compress-dialog-controller.c
new file mode 100644
index 0000000..9937beb
--- /dev/null
+++ b/src/nautilus-compress-dialog-controller.c
@@ -0,0 +1,612 @@
+/* nautilus-compress-dialog-controller.h
+ *
+ * Copyright (C) 2016 the Nautilus developers
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <glib/gi18n.h>
+#include <gnome-autoar/gnome-autoar.h>
+#include <libadwaita-1/adwaita.h>
+
+#include <eel/eel-vfs-extensions.h>
+
+#include "nautilus-compress-dialog-controller.h"
+
+#include "nautilus-global-preferences.h"
+
+struct _NautilusCompressDialogController
+{
+ NautilusFileNameWidgetController parent_instance;
+
+ GtkWidget *compress_dialog;
+ GtkWidget *activate_button;
+ GtkWidget *error_label;
+ GtkWidget *name_entry;
+ GtkWidget *extension_dropdown;
+ GtkSizeGroup *extension_sizegroup;
+ GtkWidget *passphrase_label;
+ GtkWidget *passphrase_entry;
+
+ const char *extension;
+ gchar *passphrase;
+
+ gulong response_handler_id;
+};
+
+G_DEFINE_TYPE (NautilusCompressDialogController, nautilus_compress_dialog_controller, NAUTILUS_TYPE_FILE_NAME_WIDGET_CONTROLLER);
+
+#define NAUTILUS_TYPE_COMPRESS_ITEM (nautilus_compress_item_get_type ())
+G_DECLARE_FINAL_TYPE (NautilusCompressItem, nautilus_compress_item, NAUTILUS, COMPRESS_ITEM, GObject)
+
+struct _NautilusCompressItem
+{
+ GObject parent_instance;
+ NautilusCompressionFormat format;
+ char *extension;
+ char *description;
+};
+
+G_DEFINE_TYPE (NautilusCompressItem, nautilus_compress_item, G_TYPE_OBJECT);
+
+static void
+nautilus_compress_item_init (NautilusCompressItem *item)
+{
+}
+
+static void
+nautilus_compress_item_finalize (GObject *object)
+{
+ NautilusCompressItem *item = NAUTILUS_COMPRESS_ITEM (object);
+
+ g_free (item->extension);
+ g_free (item->description);
+
+ G_OBJECT_CLASS (nautilus_compress_item_parent_class)->finalize (object);
+}
+
+static void
+nautilus_compress_item_class_init (NautilusCompressItemClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->finalize = nautilus_compress_item_finalize;
+}
+
+static NautilusCompressItem *
+nautilus_compress_item_new (NautilusCompressionFormat format,
+ const char *extension,
+ const char *description)
+{
+ NautilusCompressItem *item = g_object_new (NAUTILUS_TYPE_COMPRESS_ITEM, NULL);
+
+ item->format = format;
+ item->extension = g_strdup (extension);
+ item->description = g_strdup (description);
+
+ return item;
+}
+
+static gboolean
+nautilus_compress_dialog_controller_name_is_valid (NautilusFileNameWidgetController *self,
+ gchar *name,
+ gchar **error_message)
+{
+ gboolean is_valid;
+
+ is_valid = TRUE;
+ if (strlen (name) == 0)
+ {
+ is_valid = FALSE;
+ }
+ else if (strstr (name, "/") != NULL)
+ {
+ is_valid = FALSE;
+ *error_message = _("Archive names cannot contain “/”.");
+ }
+ else if (strcmp (name, ".") == 0)
+ {
+ is_valid = FALSE;
+ *error_message = _("An archive cannot be called “.”.");
+ }
+ else if (strcmp (name, "..") == 0)
+ {
+ is_valid = FALSE;
+ *error_message = _("An archive cannot be called “..”.");
+ }
+ else if (nautilus_file_name_widget_controller_is_name_too_long (self, name))
+ {
+ is_valid = FALSE;
+ *error_message = _("Archive name is too long.");
+ }
+
+ if (is_valid && g_str_has_prefix (name, "."))
+ {
+ /* We must warn about the side effect */
+ *error_message = _("Archives with “.” at the beginning of their name are hidden.");
+ }
+
+ return is_valid;
+}
+
+static gchar *
+nautilus_compress_dialog_controller_get_new_name (NautilusFileNameWidgetController *controller)
+{
+ NautilusCompressDialogController *self;
+ g_autofree gchar *basename = NULL;
+ 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)
+{
+ gboolean show_passphrase = FALSE;
+ guint selected;
+ GListModel *model;
+ NautilusCompressItem *item;
+
+ selected = gtk_drop_down_get_selected (GTK_DROP_DOWN (self->extension_dropdown));
+ if (selected == GTK_INVALID_LIST_POSITION)
+ {
+ return;
+ }
+
+ model = gtk_drop_down_get_model (GTK_DROP_DOWN (self->extension_dropdown));
+ item = g_list_model_get_item (model, selected);
+ if (item == NULL)
+ {
+ return;
+ }
+
+ if (item->format == NAUTILUS_COMPRESSION_ENCRYPTED_ZIP)
+ {
+ show_passphrase = TRUE;
+ }
+
+ self->extension = item->extension;
+
+ gtk_widget_set_visible (self->passphrase_label, show_passphrase);
+ gtk_widget_set_visible (self->passphrase_entry, show_passphrase);
+ if (!show_passphrase)
+ {
+ gtk_editable_set_text (GTK_EDITABLE (self->passphrase_entry), "");
+ gtk_entry_set_visibility (GTK_ENTRY (self->passphrase_entry), FALSE);
+ gtk_entry_set_icon_from_icon_name (GTK_ENTRY (self->passphrase_entry),
+ GTK_ENTRY_ICON_SECONDARY,
+ "view-conceal");
+ }
+
+ g_settings_set_enum (nautilus_compression_preferences,
+ NAUTILUS_PREFERENCES_DEFAULT_COMPRESSION_FORMAT,
+ item->format);
+
+ /* Since the extension changes when the button is toggled, force a
+ * verification of the new file name by simulating an entry change
+ */
+ gtk_widget_set_sensitive (self->activate_button, FALSE);
+ g_signal_emit_by_name (self->name_entry, "changed");
+}
+
+static void
+extension_dropdown_setup_item (GtkSignalListItemFactory *factory,
+ GtkListItem *item,
+ gpointer user_data)
+{
+ GtkWidget *title;
+
+ title = gtk_label_new ("");
+ gtk_label_set_xalign (GTK_LABEL (title), 0.0);
+
+ g_object_set_data (G_OBJECT (item), "title", title);
+ gtk_list_item_set_child (item, title);
+}
+
+
+static void
+extension_dropdown_setup_item_full (GtkSignalListItemFactory *factory,
+ GtkListItem *item,
+ gpointer user_data)
+{
+ GtkWidget *hbox, *vbox, *title, *subtitle, *checkmark;
+
+ title = gtk_label_new ("");
+ gtk_label_set_xalign (GTK_LABEL (title), 0.0);
+ gtk_widget_set_halign (title, GTK_ALIGN_START);
+
+ subtitle = gtk_label_new ("");
+ gtk_label_set_xalign (GTK_LABEL (subtitle), 0.0);
+ gtk_widget_add_css_class (subtitle, "dim-label");
+ gtk_widget_add_css_class (subtitle, "caption");
+
+ checkmark = gtk_image_new_from_icon_name ("object-select-symbolic");
+
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 3);
+ gtk_widget_set_hexpand (vbox, TRUE);
+
+ gtk_box_append (GTK_BOX (hbox), vbox);
+ gtk_box_append (GTK_BOX (vbox), title);
+ gtk_box_append (GTK_BOX (vbox), subtitle);
+ gtk_box_append (GTK_BOX (hbox), checkmark);
+
+ g_object_set_data (G_OBJECT (item), "title", title);
+ g_object_set_data (G_OBJECT (item), "subtitle", subtitle);
+ g_object_set_data (G_OBJECT (item), "checkmark", checkmark);
+
+ gtk_list_item_set_child (item, hbox);
+}
+
+static void
+extension_dropdown_on_selected_item_notify (GtkDropDown *dropdown,
+ GParamSpec *pspec,
+ GtkListItem *item)
+{
+ GtkWidget *checkmark;
+
+ checkmark = g_object_get_data (G_OBJECT (item), "checkmark");
+
+ if (gtk_drop_down_get_selected_item (dropdown) == gtk_list_item_get_item (item))
+ {
+ gtk_widget_set_opacity (checkmark, 1.0);
+ }
+ else
+ {
+ gtk_widget_set_opacity (checkmark, 0.0);
+ }
+}
+
+static void
+extension_dropdown_bind (GtkSignalListItemFactory *factory,
+ GtkListItem *list_item,
+ gpointer user_data)
+{
+ NautilusCompressDialogController *self;
+ GtkWidget *title, *subtitle, *checkmark;
+ NautilusCompressItem *item;
+
+ self = NAUTILUS_COMPRESS_DIALOG_CONTROLLER (user_data);
+ item = gtk_list_item_get_item (list_item);
+
+ title = g_object_get_data (G_OBJECT (list_item), "title");
+ subtitle = g_object_get_data (G_OBJECT (list_item), "subtitle");
+ checkmark = g_object_get_data (G_OBJECT (list_item), "checkmark");
+
+ gtk_label_set_label (GTK_LABEL (title), item->extension);
+ gtk_size_group_add_widget (self->extension_sizegroup, title);
+
+ if (item->format == NAUTILUS_COMPRESSION_ENCRYPTED_ZIP)
+ {
+ gtk_widget_add_css_class (title, "encrypted_zip");
+ }
+
+ if (subtitle)
+ {
+ gtk_label_set_label (GTK_LABEL (subtitle), item->description);
+ }
+
+ if (checkmark)
+ {
+ g_signal_connect (self->extension_dropdown,
+ "notify::selected-item",
+ G_CALLBACK (extension_dropdown_on_selected_item_notify),
+ list_item);
+ extension_dropdown_on_selected_item_notify (GTK_DROP_DOWN (self->extension_dropdown),
+ NULL,
+ list_item);
+ }
+}
+
+static void
+extension_dropdown_unbind (GtkSignalListItemFactory *factory,
+ GtkListItem *item,
+ gpointer user_data)
+{
+ NautilusCompressDialogController *self;
+ GtkWidget *title;
+
+ self = NAUTILUS_COMPRESS_DIALOG_CONTROLLER (user_data);
+ g_signal_handlers_disconnect_by_func (self->extension_dropdown,
+ extension_dropdown_on_selected_item_notify,
+ item);
+
+ title = g_object_get_data (G_OBJECT (item), "title");
+ if (title)
+ {
+ gtk_widget_remove_css_class (title, "encrypted_zip");
+ }
+}
+
+static void
+passphrase_entry_on_changed (GtkEditable *editable,
+ gpointer user_data)
+{
+ NautilusCompressDialogController *self;
+ const gchar *error_message;
+
+ self = NAUTILUS_COMPRESS_DIALOG_CONTROLLER (user_data);
+
+ g_free (self->passphrase);
+ self->passphrase = g_strdup (gtk_editable_get_text (GTK_EDITABLE (self->passphrase_entry)));
+
+ /* Simulate a change of the name_entry to ensure the correct sensitivity of
+ * the activate_button, but only if the name_entry is valid in order to
+ * avoid changes of the error_revealer.
+ */
+ error_message = gtk_label_get_text (GTK_LABEL (self->error_label));
+ if (error_message[0] == '\0')
+ {
+ gtk_widget_set_sensitive (self->activate_button, FALSE);
+ g_signal_emit_by_name (self->name_entry, "changed");
+ }
+}
+
+static void
+passphrase_entry_on_icon_press (GtkEntry *entry,
+ GtkEntryIconPosition icon_pos,
+ gpointer user_data)
+{
+ NautilusCompressDialogController *self;
+ gboolean visibility;
+
+ self = NAUTILUS_COMPRESS_DIALOG_CONTROLLER (user_data);
+ visibility = gtk_entry_get_visibility (GTK_ENTRY (self->passphrase_entry));
+
+ gtk_entry_set_icon_from_icon_name (GTK_ENTRY (self->passphrase_entry),
+ GTK_ENTRY_ICON_SECONDARY,
+ visibility ? "view-conceal" : "view-reveal");
+ gtk_entry_set_visibility (GTK_ENTRY (self->passphrase_entry), !visibility);
+}
+
+static void
+activate_button_on_sensitive_notify (GObject *gobject,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ NautilusCompressDialogController *self;
+ NautilusCompressionFormat format;
+
+ self = NAUTILUS_COMPRESS_DIALOG_CONTROLLER (user_data);
+ format = g_settings_get_enum (nautilus_compression_preferences,
+ NAUTILUS_PREFERENCES_DEFAULT_COMPRESSION_FORMAT);
+ if (format == NAUTILUS_COMPRESSION_ENCRYPTED_ZIP &&
+ (self->passphrase == NULL || self->passphrase[0] == '\0'))
+ {
+ /* Reset sensitivity of the activate_button if password is not set. */
+ gtk_widget_set_sensitive (self->activate_button, FALSE);
+ }
+}
+
+static void
+extension_dropdown_setup (NautilusCompressDialogController *self)
+{
+ GtkListItemFactory *factory, *list_factory;
+ GListStore *store;
+ NautilusCompressItem *item;
+ NautilusCompressionFormat format;
+ gint i;
+
+ store = g_list_store_new (NAUTILUS_TYPE_COMPRESS_ITEM);
+ item = nautilus_compress_item_new (NAUTILUS_COMPRESSION_ZIP,
+ ".zip",
+ _("Compatible with all operating systems."));
+ g_list_store_append (store, item);
+ g_object_unref (item);
+ item = nautilus_compress_item_new (NAUTILUS_COMPRESSION_ENCRYPTED_ZIP,
+ ".zip",
+ _("Password protected .zip, must be installed on Windows and Mac."));
+ g_list_store_append (store, item);
+ g_object_unref (item);
+ item = nautilus_compress_item_new (NAUTILUS_COMPRESSION_TAR_XZ,
+ ".tar.xz",
+ _("Smaller archives but Linux and Mac only."));
+ g_list_store_append (store, item);
+ g_object_unref (item);
+ item = nautilus_compress_item_new (NAUTILUS_COMPRESSION_7ZIP,
+ ".7z",
+ _("Smaller archives but must be installed on Windows and Mac."));
+ g_list_store_append (store, item);
+ g_object_unref (item);
+
+ factory = gtk_signal_list_item_factory_new ();
+ g_signal_connect_object (factory, "setup",
+ G_CALLBACK (extension_dropdown_setup_item), self, 0);
+ g_signal_connect_object (factory, "bind",
+ G_CALLBACK (extension_dropdown_bind), self, 0);
+ g_signal_connect_object (factory, "unbind",
+ G_CALLBACK (extension_dropdown_unbind), self, 0);
+
+ list_factory = gtk_signal_list_item_factory_new ();
+ g_signal_connect_object (list_factory, "setup",
+ G_CALLBACK (extension_dropdown_setup_item_full), self, 0);
+ g_signal_connect_object (list_factory, "bind",
+ G_CALLBACK (extension_dropdown_bind), self, 0);
+ g_signal_connect_object (list_factory, "unbind",
+ G_CALLBACK (extension_dropdown_unbind), self, 0);
+
+ gtk_drop_down_set_factory (GTK_DROP_DOWN (self->extension_dropdown), factory);
+ gtk_drop_down_set_list_factory (GTK_DROP_DOWN (self->extension_dropdown), list_factory);
+ gtk_drop_down_set_model (GTK_DROP_DOWN (self->extension_dropdown), G_LIST_MODEL (store));
+
+ format = g_settings_get_enum (nautilus_compression_preferences,
+ NAUTILUS_PREFERENCES_DEFAULT_COMPRESSION_FORMAT);
+ for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (store)); i++)
+ {
+ item = g_list_model_get_item (G_LIST_MODEL (store), i);
+ if (item->format == format)
+ {
+ gtk_drop_down_set_selected (GTK_DROP_DOWN (self->extension_dropdown), i);
+ update_selected_format (self);
+ g_object_unref (item);
+ break;
+ }
+
+ g_object_unref (item);
+ }
+
+ g_object_unref (store);
+ g_object_unref (factory);
+ g_object_unref (list_factory);
+}
+
+NautilusCompressDialogController *
+nautilus_compress_dialog_controller_new (GtkWindow *parent_window,
+ NautilusDirectory *destination_directory,
+ gchar *initial_name)
+{
+ NautilusCompressDialogController *self;
+ g_autoptr (GtkBuilder) builder = NULL;
+ GtkWidget *compress_dialog;
+ GtkWidget *error_revealer;
+ GtkWidget *error_label;
+ GtkWidget *name_entry;
+ GtkWidget *activate_button;
+ GtkWidget *extension_dropdown;
+ GtkSizeGroup *extension_sizegroup;
+ GtkWidget *passphrase_label;
+ GtkWidget *passphrase_entry;
+
+ 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_revealer = GTK_WIDGET (gtk_builder_get_object (builder, "error_revealer"));
+ 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"));
+ extension_dropdown = GTK_WIDGET (gtk_builder_get_object (builder, "extension_dropdown"));
+ extension_sizegroup = GTK_SIZE_GROUP (gtk_builder_get_object (builder, "extension_sizegroup"));
+ passphrase_label = GTK_WIDGET (gtk_builder_get_object (builder, "passphrase_label"));
+ passphrase_entry = GTK_WIDGET (gtk_builder_get_object (builder, "passphrase_entry"));
+
+ gtk_window_set_transient_for (GTK_WINDOW (compress_dialog),
+ parent_window);
+
+ self = g_object_new (NAUTILUS_TYPE_COMPRESS_DIALOG_CONTROLLER,
+ "error-revealer", error_revealer,
+ "error-label", error_label,
+ "name-entry", name_entry,
+ "activate-button", activate_button,
+ "containing-directory", destination_directory, NULL);
+
+ self->compress_dialog = compress_dialog;
+ self->activate_button = activate_button;
+ self->error_label = error_label;
+ self->name_entry = name_entry;
+ self->extension_dropdown = extension_dropdown;
+ self->extension_sizegroup = extension_sizegroup;
+ self->passphrase_label = passphrase_label;
+ self->passphrase_entry = passphrase_entry;
+
+ extension_dropdown_setup (self);
+
+ self->response_handler_id = g_signal_connect (compress_dialog,
+ "response",
+ (GCallback) compress_dialog_controller_on_response,
+ self);
+
+ g_signal_connect (self->passphrase_entry, "changed",
+ G_CALLBACK (passphrase_entry_on_changed), self);
+ g_signal_connect (self->passphrase_entry, "icon-press",
+ G_CALLBACK (passphrase_entry_on_icon_press), self);
+ g_signal_connect (self->activate_button, "notify::sensitive",
+ G_CALLBACK (activate_button_on_sensitive_notify), self);
+ g_signal_connect_swapped (self->extension_dropdown, "notify::selected-item",
+ G_CALLBACK (update_selected_format), self);
+
+ if (initial_name != NULL)
+ {
+ gtk_editable_set_text (GTK_EDITABLE (name_entry), initial_name);
+ }
+
+ gtk_widget_show (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)
+ {
+ g_clear_signal_handler (&self->response_handler_id, self->compress_dialog);
+ gtk_window_destroy (GTK_WINDOW (self->compress_dialog));
+ self->compress_dialog = NULL;
+ }
+
+ g_free (self->passphrase);
+
+ 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;
+}
+
+const gchar *
+nautilus_compress_dialog_controller_get_passphrase (NautilusCompressDialogController *self)
+{
+ return self->passphrase;
+}