[nautilus/wip/razvan/automatic-decompression: 2/2] Add extract operation
- From: Răzvan-Mihai Chițu <razvanchitu src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [nautilus/wip/razvan/automatic-decompression: 2/2] Add extract operation
- Date: Tue, 28 Jun 2016 09:50:26 +0000 (UTC)
commit ad0d96d59fbbfb937a5eb14bff01dfe0fd0e3c08
Author: Razvan Chitu <razvan ch95 gmail com>
Date: Mon Jun 27 11:43:22 2016 +0300
Add extract operation
configure.ac | 2 +
src/nautilus-application.c | 19 ++
src/nautilus-application.h | 2 +
src/nautilus-file-operations.c | 447 ++++++++++++++++++++++++++++++++++++-
src/nautilus-file-operations.h | 9 +
src/nautilus-files-view.c | 10 +-
src/nautilus-mime-actions.c | 42 ++++
src/nautilus-mime-actions.h | 1 +
src/nautilus-operations-manager.c | 157 +++++++++++++
src/nautilus-operations-manager.h | 12 +
10 files changed, 697 insertions(+), 4 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 493c5de..3d6b0a2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -11,6 +11,7 @@ m4_define(exif_minver, 0.6.20)
m4_define(exempi_minver, 2.1.0)
m4_define(notify_minver, 0.7.0)
m4_define(schemas_minver, 3.8.0)
+m4_define(autoar_minver, 0.1)
dnl 1. If the library code has changed at all since last release, then increment revision.
dnl 2. If any interfaces have been added, then increment current and set revision to 0.
@@ -270,6 +271,7 @@ dnl base libs
PKG_CHECK_MODULES(BASE, [
gtk+-3.0 >= gtk_minver
glib-2.0 >= glib_minver
+ gnome-autoar >= autoar_minver
])
dnl common libs (eel, nautilus)
diff --git a/src/nautilus-application.c b/src/nautilus-application.c
index 989f31d..2e2b474 100644
--- a/src/nautilus-application.c
+++ b/src/nautilus-application.c
@@ -76,6 +76,8 @@ typedef struct {
GList *windows;
GHashTable *notifications;
+
+ AutoarPref *arpref;
} NautilusApplicationPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (NautilusApplication, nautilus_application, GTK_TYPE_APPLICATION);
@@ -547,6 +549,8 @@ nautilus_application_finalize (GObject *object)
g_clear_object (&priv->fdb_manager);
g_clear_object (&priv->search_provider);
+ g_clear_object (&priv->arpref);
+
g_list_free (priv->windows);
g_hash_table_destroy (priv->notifications);
@@ -948,6 +952,7 @@ static void
nautilus_application_init (NautilusApplication *self)
{
NautilusApplicationPrivate *priv;
+ g_autoptr (GSettings) archive_settings;
priv = nautilus_application_get_instance_private (self);
@@ -960,6 +965,10 @@ nautilus_application_init (NautilusApplication *self)
nautilus_ensure_extension_points ();
nautilus_ensure_extension_builtins ();
+
+
+ archive_settings = g_settings_new (AUTOAR_PREF_DEFAULT_GSCHEMA_ID);
+ priv->arpref = autoar_pref_new_with_gsettings (archive_settings);
}
static void
@@ -1038,6 +1047,16 @@ nautilus_application_get_default (void)
return self;
}
+AutoarPref *
+nautilus_application_get_arpref (NautilusApplication *self)
+{
+ NautilusApplicationPrivate *priv;
+
+ priv = nautilus_application_get_instance_private (self);
+
+ return priv->arpref;
+}
+
void
nautilus_application_send_notification (NautilusApplication *self,
const gchar *notification_id,
diff --git a/src/nautilus-application.h b/src/nautilus-application.h
index 197a276..6498816 100644
--- a/src/nautilus-application.h
+++ b/src/nautilus-application.h
@@ -24,6 +24,7 @@
#include <gdk/gdk.h>
#include <gio/gio.h>
#include <gtk/gtk.h>
+#include <gnome-autoar/autoar.h>
#include "nautilus-bookmark-list.h"
#include "nautilus-window.h"
@@ -71,6 +72,7 @@ void nautilus_application_open_location_full (NautilusApplication *applicati
NautilusWindowSlot *target_slot);
NautilusApplication *nautilus_application_get_default (void);
+AutoarPref * nautilus_application_get_arpref (NautilusApplication *self);
void nautilus_application_send_notification (NautilusApplication *self,
const gchar *notification_id,
GNotification *notification);
diff --git a/src/nautilus-file-operations.c b/src/nautilus-file-operations.c
index 7ea2ada..032384d 100644
--- a/src/nautilus-file-operations.c
+++ b/src/nautilus-file-operations.c
@@ -51,6 +51,8 @@
#include <gtk/gtk.h>
#include <gio/gio.h>
#include <glib.h>
+#include <gnome-autoar/autoar.h>
+
#include "nautilus-operations-manager.h"
#include "nautilus-file-changes-queue.h"
#include "nautilus-file-private.h"
@@ -61,6 +63,7 @@
#include "nautilus-file-conflict-dialog.h"
#include "nautilus-file-undo-operations.h"
#include "nautilus-file-undo-manager.h"
+#include "nautilus-application.h"
/* TODO: TESTING!!! */
@@ -170,6 +173,23 @@ typedef struct {
int last_reported_files_left;
} TransferInfo;
+typedef struct {
+ CommonJob common;
+ GFile *source;
+ GFile *output;
+
+ NautilusExtractCallback done_callback;
+ gpointer done_callback_data;
+
+ AutoarExtract *arextract;
+
+ GFile *confirmed_destination;
+ gboolean success;
+
+ guint64 total_size;
+ guint total_files;
+} ExtractJob;
+
#define SECONDS_NEEDED_FOR_RELIABLE_TRANSFER_RATE 8
#define NSEC_PER_MICROSEC 1000
@@ -1838,7 +1858,7 @@ delete_files (CommonJob *job, GList *files, int *files_skipped)
SourceInfo source_info;
TransferInfo transfer_info;
gboolean skipped_file;
-
+
if (job_aborted (job)) {
return;
}
@@ -5780,7 +5800,7 @@ link_file (CopyMoveJob *job,
g_object_unref (new_dest);
}
}
- /* Conflict */
+ /* FileConflict */
if (error != NULL && IS_IO_ERROR (error, EXISTS)) {
g_object_unref (dest);
dest = get_target_file_for_link (src, dest_dir, *dest_fs_type, count++);
@@ -7108,6 +7128,429 @@ nautilus_file_mark_desktop_file_trusted (GFile *file,
g_object_unref (task);
}
+static FileConflictResponse *
+signal_extract_conflict (CommonJob *job,
+ GFile *src,
+ GFile *dest,
+ GFile *dest_dir)
+{
+ FileConflictResponse *response;
+
+ g_timer_stop (job->time);
+ nautilus_progress_info_pause (job->progress);
+
+ response = get_extract_file_conflict_response (job->parent_window,
+ src,
+ dest,
+ dest_dir);
+
+ nautilus_progress_info_resume (job->progress);
+ g_timer_continue (job->time);
+
+ return response;
+}
+
+static gboolean
+remove_file (GFile *file,
+ GError **error)
+{
+ gboolean success = TRUE;
+ g_autoptr (GFileEnumerator) enumerator = NULL;
+
+ if (g_file_delete (file, NULL, error)) {
+ return TRUE;
+ }
+
+ if (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_NOT_EMPTY)) {
+ g_clear_error (error);
+ } else {
+ return FALSE;
+ }
+
+ enumerator = g_file_enumerate_children (file,
+ G_FILE_ATTRIBUTE_STANDARD_NAME,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, error);
+
+ if (enumerator) {
+ GFileInfo *info;
+
+ while ((info = g_file_enumerator_next_file (enumerator, NULL, error)) != NULL) {
+ g_autoptr(GFile) child;
+
+ child = g_file_get_child (file, g_file_info_get_name (info));
+
+ success = remove_file (child, error);
+
+ g_object_unref (info);
+
+ if (!success) {
+ return FALSE;
+ }
+ }
+ } else {
+ return FALSE;
+ }
+
+ g_file_delete (file, NULL, error);
+
+ return success && *error == NULL;
+}
+
+static gboolean
+extract_check_archive (ExtractJob *extract_job,
+ GError **error)
+{
+ g_autoptr (GFile) destination_directory = NULL;
+ g_autoptr (GFileInfo) info;
+ guint64 free_space;
+ double free_space_percentage;
+
+ g_clear_error (error);
+
+ destination_directory = g_file_get_parent (extract_job->confirmed_destination);
+
+ info = g_file_query_filesystem_info (destination_directory,
+ G_FILE_ATTRIBUTE_FILESYSTEM_FREE,
+ extract_job->common.cancellable,
+ error);
+
+ if (info == NULL) {
+ return FALSE;
+ }
+
+ free_space = g_file_info_get_attribute_uint64 (info,
+ G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
+
+ free_space_percentage = ((double) extract_job->total_size) / ((double) free_space);
+
+ return TRUE;
+}
+
+static void
+extract_task_done (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ ExtractJob *extract_job = user_data;
+
+ if (extract_job->done_callback) {
+ extract_job->done_callback (extract_job->source,
+ extract_job->confirmed_destination,
+ extract_job->success,
+ extract_job->done_callback_data);
+ }
+
+ g_clear_object (&extract_job->source);
+ g_clear_object (&extract_job->output);
+ g_clear_object (&extract_job->arextract);
+ g_clear_object (&extract_job->confirmed_destination);
+
+ finalize_common ((CommonJob *)extract_job);
+}
+
+static void
+extract_scanned_handler (AutoarExtract *arextract,
+ guint files_count,
+ gpointer user_data)
+{
+ ExtractJob *extract_job = user_data;
+
+ extract_job->total_files = autoar_extract_get_files (arextract);
+ extract_job->total_size = autoar_extract_get_size (arextract);
+}
+
+static GFile*
+extract_confirm_dest_handler (AutoarExtract *arextract,
+ GFile *destination,
+ GList *files,
+ gpointer user_data)
+{
+ ExtractJob *extract_job = user_data;
+ GFileType file_type;
+ g_autoptr (GFile) destination_directory;
+ GFile *confirmed_destination = NULL;
+
+ nautilus_progress_info_set_details (extract_job->common.progress,
+ _("Checking destination"));
+
+ destination_directory = g_file_get_parent (destination);
+
+ confirmed_destination = g_object_ref (destination);
+ file_type = g_file_query_file_type (confirmed_destination,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ NULL);
+
+ while (file_type != G_FILE_TYPE_UNKNOWN) {
+ FileConflictResponse *response;
+ GError *error = NULL;
+
+ response = signal_extract_conflict ((CommonJob *)extract_job,
+ extract_job->source,
+ confirmed_destination,
+ destination_directory);
+
+ switch (response->id) {
+ case GTK_RESPONSE_CANCEL:
+ case GTK_RESPONSE_DELETE_EVENT:
+ g_cancellable_cancel (extract_job->common.cancellable);
+
+ g_clear_object (&confirmed_destination);
+ conflict_response_data_free (response);
+
+ goto out;
+ case CONFLICT_RESPONSE_REPLACE:
+ nautilus_progress_info_set_details (extract_job->common.progress,
+ _("Replacing existing destination"));
+
+ if (!remove_file (confirmed_destination, &error)) {
+ run_error ((CommonJob *)extract_job,
+ f (_("Error while extracting “%B”."),
+ extract_job->source),
+ f (_("The existing destination “%B” could not be
replaced."),
+ confirmed_destination),
+ error->message,
+ FALSE,
+ CANCEL,
+ NULL);
+
+ g_cancellable_cancel (extract_job->common.cancellable);
+
+ g_error_free (error);
+ }
+
+ conflict_response_data_free (response);
+
+ goto out;
+ case CONFLICT_RESPONSE_RENAME:
+ g_clear_object (&confirmed_destination);
+
+ confirmed_destination = get_target_file_for_display_name
(destination_directory,
+
response->new_name);
+
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ file_type = g_file_query_file_type (confirmed_destination,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ NULL);
+
+ conflict_response_data_free (response);
+
+ }
+out:
+ extract_job->confirmed_destination = confirmed_destination;
+
+ // extract_check_archive (extract_job, NULL);
+
+ return g_object_ref (confirmed_destination);
+}
+
+static void
+extract_progress_handler (AutoarExtract *arextract,
+ guint64 completed_size,
+ guint completed_files,
+ gpointer user_data)
+{
+ ExtractJob *extract_job = user_data;
+ CommonJob *common = user_data;
+ char *details;
+ int files_left;
+ double elapsed, transfer_rate;
+ int remaining_time;
+
+ files_left = extract_job->total_files - completed_files;
+
+ nautilus_progress_info_take_status (common->progress,
+ f (_("Extracting “%B”"), extract_job->source));
+
+ elapsed = g_timer_elapsed (common->time, NULL);
+ transfer_rate = 0;
+ remaining_time = INT_MAX;
+ if (elapsed > 0) {
+ transfer_rate = completed_size / elapsed;
+ if (transfer_rate > 0) {
+ remaining_time = (extract_job->total_size - completed_size) / transfer_rate;
+ }
+ }
+
+ if (transfer_rate == 0) {
+ transfer_rate = completed_files / elapsed;
+ if (transfer_rate > 0) {
+ remaining_time = (extract_job->total_files - completed_files) / transfer_rate;
+ }
+ }
+
+ if (elapsed < SECONDS_NEEDED_FOR_RELIABLE_TRANSFER_RATE &&
+ transfer_rate > 0) {
+ if (extract_job->total_files == 1) {
+ /* To translators: %S will expand to a size like "2 bytes" or "3 MB", so something
like "4 kb / 4 MB" */
+ details = f (_("%S / %S"), completed_size, extract_job->total_size);
+ } else {
+ details = f (_("%'d / %'d"),
+ files_left > 0 ? completed_files + 1 : completed_files,
+ extract_job->total_files);
+ }
+ } else {
+ if (extract_job->total_files == 1) {
+ if (files_left > 0) {
+ /* To translators: %S will expand to a size like "2 bytes" or "3 MB", %T to
a time duration like
+ * "2 minutes". So the whole thing will be something like "2 kb / 4 MB -- 2
hours left (4kb/sec)"
+ *
+ * The singular/plural form will be used depending on the remaining time
(i.e. the %T argument).
+ */
+ details = f (ngettext ("%S / %S \xE2\x80\x94 %T left (%S/sec)",
+ "%S / %S \xE2\x80\x94 %T left (%S/sec)",
+ seconds_count_format_time_units (remaining_time)),
+ completed_size, extract_job->total_size,
+ remaining_time,
+ (goffset)transfer_rate);
+ } else {
+ /* To translators: %S will expand to a size like "2 bytes" or "3 MB". */
+ details = f (_("%S / %S"),
+ completed_size,
+ extract_job->total_size);
+ }
+ } else {
+ if (files_left > 0) {
+ /* To translators: %T will expand to a time duration like "2 minutes".
+ * So the whole thing will be something like "1 / 5 -- 2 hours left
(4kb/sec)"
+ *
+ * The singular/plural form will be used depending on the remaining time
(i.e. the %T argument).
+ */
+ details = f (ngettext ("%'d / %'d \xE2\x80\x94 %T left (%S/sec)",
+ "%'d / %'d \xE2\x80\x94 %T left (%S/sec)",
+ seconds_count_format_time_units (remaining_time)),
+ completed_files + 1, extract_job->total_files,
+ remaining_time,
+ (goffset)transfer_rate);
+ } else {
+ /* To translators: %'d is the number of files completed for the operation,
+ * so it will be something like 2/14. */
+ details = f (_("%'d / %'d"),
+ completed_files,
+ extract_job->total_files);
+ }
+ }
+ }
+
+ nautilus_progress_info_take_details (common->progress, details);
+
+ if (elapsed > SECONDS_NEEDED_FOR_APROXIMATE_TRANSFER_RATE) {
+ nautilus_progress_info_set_remaining_time (common->progress,
+ remaining_time);
+ nautilus_progress_info_set_elapsed_time (common->progress,
+ elapsed);
+ }
+
+ nautilus_progress_info_set_progress (common->progress,
+ completed_size,
+ extract_job->total_size);
+}
+
+static void
+extract_error_handler (AutoarExtract *arextract,
+ GError *error,
+ gpointer user_data)
+{
+ ExtractJob *extract_job = user_data;
+
+ nautilus_progress_info_take_status (extract_job->common.progress,
+ f (_("Error extracting “%B””"),
+ extract_job->source));
+
+ run_error ((CommonJob *)extract_job,
+ f (_("There was an error while extracting “%B”."),
+ extract_job->source),
+ g_strdup (error->message),
+ NULL,
+ FALSE,
+ CANCEL,
+ NULL);
+}
+
+static void
+extract_completed_handler (AutoarExtract *arextract,
+ gpointer user_data)
+{
+ ExtractJob *extract_job = user_data;
+
+ extract_job->success = TRUE;
+
+ nautilus_progress_info_take_status (extract_job->common.progress,
+ f (_("Finished extracting “%B” to “%B”"),
+ extract_job->source,
+ extract_job->confirmed_destination));
+
+ nautilus_progress_info_set_destination (extract_job->common.progress,
+ extract_job->confirmed_destination);
+}
+
+static void
+extract_task_thread_func (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ ExtractJob *extract_job = task_data;
+ AutoarPref *arpref;
+
+ arpref = nautilus_application_get_arpref (nautilus_application_get_default ());
+
+ extract_job->arextract = autoar_extract_new_file (extract_job->source,
+ extract_job->output,
+ arpref);
+
+ autoar_extract_set_notify_interval (extract_job->arextract, 100000);
+
+ g_signal_connect (extract_job->arextract, "scanned",
+ G_CALLBACK (extract_scanned_handler), extract_job);
+ g_signal_connect (extract_job->arextract, "error",
+ G_CALLBACK (extract_error_handler), extract_job);
+ g_signal_connect (extract_job->arextract, "confirm-dest",
+ G_CALLBACK (extract_confirm_dest_handler), extract_job);
+ g_signal_connect (extract_job->arextract, "progress",
+ G_CALLBACK (extract_progress_handler), extract_job);
+ g_signal_connect (extract_job->arextract, "completed",
+ G_CALLBACK (extract_completed_handler), extract_job);
+
+ g_timer_start (extract_job->common.time);
+
+ nautilus_progress_info_start (extract_job->common.progress);
+
+ nautilus_progress_info_set_details (extract_job->common.progress,
+ _("Scanning archive contents"));
+
+ autoar_extract_start (extract_job->arextract, extract_job->common.cancellable);
+}
+
+void
+nautilus_file_operations_extract (GFile *source,
+ GFile *output,
+ GtkWindow *parent_window,
+ NautilusExtractCallback done_callback,
+ gpointer done_callback_data)
+{
+ GTask *task;
+ ExtractJob *job;
+
+ job = op_job_new (ExtractJob, parent_window);
+ job->source = g_object_ref (source);
+ job->output = g_object_ref (output);
+ job->done_callback = done_callback;
+ job->done_callback = done_callback_data;
+ job->success = FALSE;
+
+ inhibit_power_manager ((CommonJob *)job, _("Extracting Files"));
+
+ task = g_task_new (NULL, job->common.cancellable, extract_task_done, job);
+ g_task_set_task_data (task, job, NULL);
+ g_task_run_in_thread (task, extract_task_thread_func);
+ g_object_unref (task);
+}
+
#if !defined (NAUTILUS_OMIT_SELF_CHECK)
void
diff --git a/src/nautilus-file-operations.h b/src/nautilus-file-operations.h
index 08b11ca..50ae56c 100644
--- a/src/nautilus-file-operations.h
+++ b/src/nautilus-file-operations.h
@@ -44,6 +44,10 @@ typedef void (* NautilusMountCallback) (GVolume *volume,
gboolean success,
GObject *callback_data_object);
typedef void (* NautilusUnmountCallback) (gpointer callback_data);
+typedef void (* NautilusExtractCallback) (GFile *source,
+ GFile *destination,
+ gboolean success,
+ gpointer callback_data);
/* FIXME: int copy_action should be an enum */
@@ -147,6 +151,11 @@ void nautilus_file_mark_desktop_file_trusted (GFile *file,
gboolean interactive,
NautilusOpCallback done_callback,
gpointer done_callback_data);
+void nautilus_file_operations_extract (GFile *source,
+ GFile *output,
+ GtkWindow *parent_window,
+ NautilusExtractCallback done_callback,
+ gpointer done_callback_data);
#endif /* NAUTILUS_FILE_OPERATIONS_H */
diff --git a/src/nautilus-files-view.c b/src/nautilus-files-view.c
index 3c9a8ea..06ec752 100644
--- a/src/nautilus-files-view.c
+++ b/src/nautilus-files-view.c
@@ -6644,7 +6644,7 @@ update_selection_menu (NautilusFilesView *view)
GList *selection, *l;
NautilusFile *file;
gint selection_count;
- gboolean show_app, show_run;
+ gboolean show_extract, show_app, show_run;
gboolean item_opens_in_view;
gchar *item_label;
GAppInfo *app;
@@ -6682,12 +6682,16 @@ update_selection_menu (NautilusFilesView *view)
g_free (item_label);
/* Open With <App> menu item */
- show_app = show_run = item_opens_in_view = selection_count != 0;
+ show_extract = show_app = show_run = item_opens_in_view = selection_count != 0;
for (l = selection; l != NULL; l = l->next) {
NautilusFile *file;
file = NAUTILUS_FILE (selection->data);
+ if (!nautilus_mime_file_extracts (file)) {
+ show_extract = FALSE;
+ }
+
if (!nautilus_mime_file_opens_in_external_app (file)) {
show_app = FALSE;
}
@@ -6726,6 +6730,8 @@ update_selection_menu (NautilusFilesView *view)
g_object_unref (app);
} else if (show_run) {
item_label = g_strdup (_("Run"));
+ } else if (show_extract) {
+ item_label = g_strdup (_("Extract Here"));
} else {
item_label = g_strdup (_("Open"));
}
diff --git a/src/nautilus-mime-actions.c b/src/nautilus-mime-actions.c
index e196dce..db72235 100644
--- a/src/nautilus-mime-actions.c
+++ b/src/nautilus-mime-actions.c
@@ -35,6 +35,7 @@
#include <glib/gstdio.h>
#include <string.h>
#include <gdk/gdkx.h>
+#include <gnome-autoar/autoar.h>
#include "nautilus-file-attributes.h"
#include "nautilus-file.h"
@@ -43,6 +44,7 @@
#include "nautilus-program-choosing.h"
#include "nautilus-global-preferences.h"
#include "nautilus-signaller.h"
+#include "nautilus-application.h"
#define DEBUG_FLAG NAUTILUS_DEBUG_MIME
#include "nautilus-debug.h"
@@ -54,6 +56,7 @@ typedef enum {
ACTIVATION_ACTION_LAUNCH_IN_TERMINAL,
ACTIVATION_ACTION_OPEN_IN_VIEW,
ACTIVATION_ACTION_OPEN_IN_APPLICATION,
+ ACTIVATION_ACTION_EXTRACT,
ACTIVATION_ACTION_DO_NOTHING,
} ActivationAction;
@@ -677,6 +680,16 @@ get_activation_action (NautilusFile *file)
{
ActivationAction action;
char *activation_uri;
+ g_autofree char* mime_type;
+ AutoarPref *arpref;
+
+ arpref = nautilus_application_get_arpref (nautilus_application_get_default ());
+
+ mime_type = nautilus_file_get_mime_type (file);
+
+ if (autoar_pref_check_mime_type_d (arpref, mime_type)) {
+ return ACTIVATION_ACTION_EXTRACT;
+ }
if (nautilus_file_is_nautilus_link (file)) {
return ACTIVATION_ACTION_LAUNCH_DESKTOP_FILE;
@@ -715,6 +728,12 @@ get_activation_action (NautilusFile *file)
}
gboolean
+nautilus_mime_file_extracts (NautilusFile *file)
+{
+ return get_activation_action (file) == ACTIVATION_ACTION_EXTRACT;
+}
+
+gboolean
nautilus_mime_file_launches (NautilusFile *file)
{
ActivationAction activation_action;
@@ -1506,6 +1525,7 @@ activate_files (ActivateParameters *parameters)
GList *open_in_app_uris;
GList *open_in_app_parameters;
GList *unhandled_open_in_app_uris;
+ GList *extract_files;
ApplicationLaunchParameters *one_parameters;
GList *open_in_view_files;
GList *l;
@@ -1528,6 +1548,7 @@ activate_files (ActivateParameters *parameters)
launch_in_terminal_files = NULL;
open_in_app_uris = NULL;
open_in_view_files = NULL;
+ extract_files = NULL;
for (l = parameters->locations; l != NULL; l = l->next) {
location = l->data;
@@ -1560,6 +1581,9 @@ activate_files (ActivateParameters *parameters)
case ACTIVATION_ACTION_OPEN_IN_VIEW :
open_in_view_files = g_list_prepend (open_in_view_files, file);
break;
+ case ACTIVATION_ACTION_EXTRACT :
+ extract_files = g_list_prepend (extract_files, file);
+ break;
case ACTIVATION_ACTION_OPEN_IN_APPLICATION :
open_in_app_uris = g_list_prepend (open_in_app_uris, location->uri);
break;
@@ -1674,6 +1698,24 @@ activate_files (ActivateParameters *parameters)
}
}
+ extract_files = g_list_reverse (extract_files);
+ if (extract_files) {
+ for (l = extract_files; l != NULL; l = l->next) {
+ file = NAUTILUS_FILE (l->data);
+ g_autoptr (GFile) source;
+ g_autoptr (GFile) output;
+
+ source = nautilus_file_get_location (file);
+ output = nautilus_file_get_parent_location (file);
+
+ nautilus_file_operations_extract (source,
+ output,
+ parameters->parent_window,
+ NULL,
+ NULL);
+ }
+ }
+
open_in_app_parameters = NULL;
unhandled_open_in_app_uris = NULL;
diff --git a/src/nautilus-mime-actions.h b/src/nautilus-mime-actions.h
index f96ca66..c3f9f87 100644
--- a/src/nautilus-mime-actions.h
+++ b/src/nautilus-mime-actions.h
@@ -38,6 +38,7 @@ GList * nautilus_mime_get_applications_for_file (Nauti
GAppInfo * nautilus_mime_get_default_application_for_files (GList *files);
gboolean nautilus_mime_file_opens_in_external_app (NautilusFile *file);
+gboolean nautilus_mime_file_extracts (NautilusFile *file);
gboolean nautilus_mime_file_launches (NautilusFile *file);
void nautilus_mime_activate_files (GtkWindow
*parent_window,
NautilusWindowSlot *slot,
diff --git a/src/nautilus-operations-manager.c b/src/nautilus-operations-manager.c
index a26b2b0..8a39cc7 100644
--- a/src/nautilus-operations-manager.c
+++ b/src/nautilus-operations-manager.c
@@ -59,6 +59,13 @@ create_copy_move_dialog (FileConflictDialogData *data)
}
static void
+create_extract_dialog (FileConflictDialogData *data)
+{
+ data->dialog = nautilus_file_conflict_dialog_new (data->parent,
+ _("Extract conflict"));
+}
+
+static void
set_copy_move_dialog_text (FileConflictDialogData *data)
{
g_autofree gchar *primary_text = NULL;
@@ -141,6 +148,42 @@ set_copy_move_dialog_text (FileConflictDialogData *data)
}
static void
+set_extract_dialog_text (FileConflictDialogData *data)
+{
+
+ g_autofree gchar *primary_text = NULL;
+ g_autofree gchar *secondary_text = NULL;
+ const gchar *message_extra;
+ g_autofree gchar *message = NULL;
+ g_autofree gchar *dest_name;
+ g_autofree gchar *dest_dir_name;
+
+ dest_name = nautilus_file_get_display_name (data->destination);
+ dest_dir_name = nautilus_file_get_display_name (data->dest_dir);
+
+ if (nautilus_file_is_directory (data->destination)) {
+ primary_text = g_strdup_printf (_("Replace folder “%s”?"), dest_name);
+ message = g_strdup_printf
+ (_("A folder with the same name as the extract destination already exists in “%s”."),
+ dest_dir_name);
+ message_extra =
+ _("Replacing it will remove all files in the folder.");
+ } else {
+ primary_text = g_strdup_printf (_("Replace file “%s”?"), dest_name);
+ message = g_strdup_printf
+ (_("A file with the same name as the extract destination already exists in “%s”."),
+ dest_dir_name);
+ message_extra = _("Replacing it will overwrite its content.");
+ }
+
+ secondary_text = g_strdup_printf ("%s\n%s", message, message_extra);
+
+ nautilus_file_conflict_dialog_set_text (data->dialog,
+ primary_text,
+ secondary_text);
+}
+
+static void
set_images (FileConflictDialogData *data)
{
GdkPixbuf *source_pixbuf;
@@ -306,6 +349,34 @@ copy_move_file_list_ready_cb (GList *files,
}
static void
+extract_file_list_ready_cb (GList *files,
+ gpointer user_data)
+{
+ FileConflictDialogData *data = user_data;
+
+ data->handle = NULL;
+
+ set_extract_dialog_text (data);
+
+ set_images (data);
+
+ set_file_labels (data);
+
+ set_conflict_name (data);
+
+ nautilus_file_conflict_dialog_disable_skip (data->dialog);
+ nautilus_file_conflict_dialog_disable_apply_to_all (data->dialog);
+
+ nautilus_file_monitor_add (data->source, data, NAUTILUS_FILE_ATTRIBUTES_FOR_ICON);
+ nautilus_file_monitor_add (data->destination, data, NAUTILUS_FILE_ATTRIBUTES_FOR_ICON);
+
+ data->src_handler_id = g_signal_connect (data->source, "changed",
+ G_CALLBACK (file_icons_changed), data);
+ data->dest_handler_id = g_signal_connect (data->destination, "changed",
+ G_CALLBACK (file_icons_changed), data);
+}
+
+static void
build_dialog_appearance (FileConflictDialogData *data)
{
GList *files = NULL;
@@ -427,3 +498,89 @@ get_copy_move_file_conflict_response (GtkWindow *parent_window,
return get_file_conflict_response (data);
}
+
+FileConflictResponse *
+get_extract_file_conflict_response (GtkWindow *parent_window,
+ GFile *src_name,
+ GFile *dest_name,
+ GFile *dest_dir_name)
+{
+ FileConflictDialogData *data;
+
+ data = g_slice_new0 (FileConflictDialogData);
+ data->parent = parent_window;
+ data->src_name = src_name;
+ data->dest_name = dest_name;
+ data->dest_dir_name = dest_dir_name;
+
+ data->create_dialog = create_extract_dialog;
+ data->files_list_ready_cb = extract_file_list_ready_cb;
+
+ return get_file_conflict_response (data);
+}
+
+typedef struct {
+ GFile *source;
+
+ GtkWindow *parent;
+
+ NameConflictResponse *response;
+
+ GtkWidget *dialog;
+ /* Dialogs are ran from operation threads, which need to be blocked until
+ * the user gives a valid response
+ */
+ gboolean completed;
+ GMutex mutex;
+ GCond cond;
+} NameConflictData;
+
+static gboolean
+run_name_conflict_dialog (gpointer _data)
+{
+ NameConflictData *data = _data;
+
+
+
+
+ return FALSE;
+}
+
+
+NameConflictResponse *
+get_extract_name_conflict_response (GtkWindow *parent_window,
+ GFile *source)
+{
+ NameConflictData *data;
+ NameConflictResponse *response;
+
+ data = g_slice_new0 (NameConflictResponse);
+ data->parent = parent_window;
+ data->source = source;
+
+ response = g_slice_new0 (NameConflictResponse);
+ response->new_name = NULL;
+ data->response = response;
+
+ data->completed = FALSE;
+ g_mutex_init (&data->mutex);
+ g_cond_init (&data->cond);
+
+ g_mutex_lock (&data->mutex);
+
+ g_main_context_invoke (NULL,
+ run_name_conflict_dialog,
+ data);
+
+ while (!data->completed) {
+ g_cond_wait (&data->cond, &data->mutex);
+ }
+
+ g_mutex_unlock (&data->mutex);
+ g_mutex_clear (&data->mutex);
+ g_cond_clear (&data->cond);
+
+ g_slice_free (FileConflictDialogData, data);
+
+ return response;
+}
diff --git a/src/nautilus-operations-manager.h b/src/nautilus-operations-manager.h
index 84d15d0..c91bafd 100644
--- a/src/nautilus-operations-manager.h
+++ b/src/nautilus-operations-manager.h
@@ -13,5 +13,17 @@ FileConflictResponse * get_copy_move_file_conflict_response (GtkWindow *parent_w
GFile *src,
GFile *dest,
GFile *dest_dir);
+FileConflictResponse * get_extract_file_conflict_response (GtkWindow *parent_window,
+ GFile *src,
+ GFile *dest,
+ GFile *dest_dir);
+
+typedef struct {
+ int id;
+ char *new_name;
+} NameConflictResponse;
+
+NameConflictResponse * get_extract_name_conflict_response (GtkWindow *parent_window,
+ GFile *source);
#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]