diff options
author | Razvan Chitu <razvan.ch95@gmail.com> | 2016-08-21 12:22:29 +0300 |
---|---|---|
committer | Razvan Chitu <razvan.ch95@gmail.com> | 2016-08-23 00:37:17 +0300 |
commit | 918f2b6163bb61cb53612496c2c381b85900dbda (patch) | |
tree | b9bf637ffbe63c385f87eeec90e1f7a114ff3343 /src/nautilus-file-operations.c | |
parent | 51dbfc977808b996aedf96b819766b8c982adc59 (diff) | |
download | nautilus-918f2b6163bb61cb53612496c2c381b85900dbda.tar.gz |
file-operations: implement compression operation
Add an operation for compressing files using gnome-autoar. The operation is
similar in functionality to the one offered by file roller but comes with
integrated progress feedback and support for undoing and redoing.
https://bugzilla.gnome.org/show_bug.cgi?id=770199
Diffstat (limited to 'src/nautilus-file-operations.c')
-rw-r--r-- | src/nautilus-file-operations.c | 319 |
1 files changed, 315 insertions, 4 deletions
diff --git a/src/nautilus-file-operations.c b/src/nautilus-file-operations.c index 58c825e99..e8a2c4da6 100644 --- a/src/nautilus-file-operations.c +++ b/src/nautilus-file-operations.c @@ -51,7 +51,6 @@ #include <gtk/gtk.h> #include <gio/gio.h> #include <glib.h> -#include <gnome-autoar/gnome-autoar.h> #include "nautilus-operations-ui-manager.h" #include "nautilus-file-changes-queue.h" @@ -153,7 +152,8 @@ typedef enum { OP_KIND_COPY, OP_KIND_MOVE, OP_KIND_DELETE, - OP_KIND_TRASH + OP_KIND_TRASH, + OP_KIND_COMPRESS } OpKind; typedef struct { @@ -186,6 +186,23 @@ typedef struct { gpointer done_callback_data; } ExtractJob; +typedef struct { + CommonJob common; + GList *source_files; + GFile *output_file; + + AutoarFormat format; + AutoarFilter filter; + + guint64 total_size; + guint total_files; + + gboolean success; + + NautilusCreateCallback done_callback; + gpointer done_callback_data; +} CompressJob; + #define SECONDS_NEEDED_FOR_RELIABLE_TRANSFER_RATE 8 #define NSEC_PER_MICROSEC 1000 #define PROGRESS_NOTIFY_INTERVAL 100 * NSEC_PER_MICROSEC @@ -2710,7 +2727,12 @@ report_preparing_count_progress (CommonJob *job, source_info->num_files), source_info->num_files); break; - } + case OP_KIND_COMPRESS: + s = f (ngettext("Preparing to compress %'d file", + "Preparing to compress %'d files", + source_info->num_files), + source_info->num_files); + } nautilus_progress_info_take_details (job->progress, s); nautilus_progress_info_pulse_progress (job->progress); @@ -2743,7 +2765,9 @@ get_scan_primary (OpKind kind) return f (_("Error while deleting.")); case OP_KIND_TRASH: return f (_("Error while moving files to trash.")); - } + case OP_KIND_COMPRESS: + return f (_("Error while compressing files.")); + } } static void @@ -7403,6 +7427,293 @@ nautilus_file_operations_extract_files (GList *files, g_task_run_in_thread (task, extract_task_thread_func); } +static void +compress_task_done (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + CompressJob *compress_job = user_data; + + if (compress_job->done_callback) { + compress_job->done_callback (compress_job->output_file, + compress_job->success, + compress_job->done_callback_data); + } + + g_object_unref (compress_job->output_file); + g_list_free_full (compress_job->source_files, g_object_unref); + + finalize_common ((CommonJob *)compress_job); + + nautilus_file_changes_consume_changes (TRUE); +} + +static void +compress_job_on_progress (AutoarCompressor *compressor, + guint64 completed_size, + guint completed_files, + gpointer user_data) +{ + CompressJob *compress_job = user_data; + CommonJob *common = user_data; + char *status; + char *details; + int files_left; + double elapsed; + double transfer_rate; + int remaining_time; + + files_left = compress_job->total_files - completed_files; + + if (compress_job->total_files == 1) { + status = f (_("Compressing “%B” into “%B”"), + G_FILE (compress_job->source_files->data), + compress_job->output_file); + } else { + status = f (ngettext ("Compressing %'d file into “%B”", + "Compressing %'d files into “%B”", + compress_job->total_files), + compress_job->total_files, + compress_job->output_file); + + } + + nautilus_progress_info_take_status (common->progress, status); + + elapsed = g_timer_elapsed (common->time, NULL); + + transfer_rate = 0; + remaining_time = -1; + + if (elapsed > 0) { + if (completed_size > 0) { + transfer_rate = completed_size / elapsed; + remaining_time = (compress_job->total_size - completed_size) / transfer_rate; + } else if (completed_files > 0) { + transfer_rate = completed_files / elapsed; + remaining_time = (compress_job->total_files - completed_files) / transfer_rate; + } + } + + if (elapsed < SECONDS_NEEDED_FOR_RELIABLE_TRANSFER_RATE || + transfer_rate == 0) { + if (compress_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, compress_job->total_size); + } else { + details = f (_("%'d / %'d"), + files_left > 0 ? completed_files + 1 : completed_files, + compress_job->total_files); + } + } else { + if (compress_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, compress_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, + compress_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, compress_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, + compress_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, + compress_job->total_size); +} + +static void +compress_job_on_error (AutoarCompressor *compressor, + GError *error, + gpointer user_data) +{ + CompressJob *compress_job = user_data; + char *status; + + if (compress_job->total_files == 1) { + status = f (_("Error compressing “%B” into “%B”"), + G_FILE (compress_job->source_files->data), + compress_job->output_file); + } else { + status = f (ngettext ("Error compressing %'d file into “%B”", + "Error compressing %'d files into “%B”", + compress_job->total_files), + compress_job->total_files, + compress_job->output_file); + } + + nautilus_progress_info_take_status (compress_job->common.progress, + status); + + run_error ((CommonJob *)compress_job, + _("There was an error while compressing files."), + g_strdup (error->message), + NULL, + FALSE, + CANCEL, + NULL); + + abort_job ((CommonJob *)compress_job); +} + +static void +compress_job_on_completed (AutoarCompressor *compressor, + gpointer user_data) +{ + CompressJob *compress_job = user_data; + g_autoptr (GFile) destination_directory; + char *status; + + if (compress_job->total_files == 1) { + status = f (_("Compressed “%B” into “%B”"), + G_FILE (compress_job->source_files->data), + compress_job->output_file); + } else { + status = f (ngettext ("Compressed %'d file into “%B”", + "Compressed %'d files into “%B”", + compress_job->total_files), + compress_job->total_files, + compress_job->output_file); + } + + nautilus_progress_info_take_status (compress_job->common.progress, + status); + + nautilus_file_changes_queue_file_added (compress_job->output_file); + + destination_directory = g_file_get_parent (compress_job->output_file); + nautilus_progress_info_set_destination (compress_job->common.progress, + destination_directory); +} + +static void +compress_task_thread_func (GTask *task, + gpointer source_object, + gpointer task_data, + GCancellable *cancellable) +{ + CompressJob *compress_job = task_data; + SourceInfo source_info; + g_autoptr (AutoarCompressor) compressor; + + g_timer_start (compress_job->common.time); + + nautilus_progress_info_start (compress_job->common.progress); + + scan_sources (compress_job->source_files, + &source_info, + (CommonJob *)compress_job, + OP_KIND_COMPRESS); + + compress_job->total_files = source_info.num_files; + compress_job->total_size = source_info.num_bytes; + + compressor = autoar_compressor_new (compress_job->source_files, + compress_job->output_file, + compress_job->format, + compress_job->filter, + FALSE); + + autoar_compressor_set_output_is_dest (compressor, TRUE); + + autoar_compressor_set_notify_interval (compressor, + PROGRESS_NOTIFY_INTERVAL); + + g_signal_connect (compressor, "progress", + G_CALLBACK (compress_job_on_progress), compress_job); + g_signal_connect (compressor, "error", + G_CALLBACK (compress_job_on_error), compress_job); + g_signal_connect (compressor, "completed", + G_CALLBACK (compress_job_on_completed), compress_job); + autoar_compressor_start (compressor, + compress_job->common.cancellable); + + compress_job->success = g_file_query_exists (compress_job->output_file, + NULL); + + /* There is nothing to undo if the output was not created */ + if (compress_job->common.undo_info != NULL && !compress_job->success) { + g_clear_object (&compress_job->common.undo_info); + } +} + +void +nautilus_file_operations_compress (GList *files, + GFile *output, + AutoarFormat format, + AutoarFilter filter, + GtkWindow *parent_window, + NautilusCreateCallback done_callback, + gpointer done_callback_data) +{ + g_autoptr (GTask) task; + CompressJob *compress_job; + + compress_job = op_job_new (CompressJob, parent_window); + compress_job->source_files = g_list_copy_deep (files, + (GCopyFunc)g_object_ref, + NULL); + compress_job->output_file = g_object_ref (output); + compress_job->format = format; + compress_job->filter = filter; + compress_job->done_callback = done_callback; + compress_job->done_callback_data = done_callback_data; + + inhibit_power_manager ((CommonJob *)compress_job, _("Compressing Files")); + + if (!nautilus_file_undo_manager_is_operating ()) { + compress_job->common.undo_info = nautilus_file_undo_info_compress_new (files, + output, + format, + filter); + } + + task = g_task_new (NULL, compress_job->common.cancellable, + compress_task_done, compress_job); + g_task_set_task_data (task, compress_job, NULL); + g_task_run_in_thread (task, compress_task_thread_func); +} + #if !defined (NAUTILUS_OMIT_SELF_CHECK) void |