summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2007-11-21 13:26:45 +0000
committerAlexander Larsson <alexl@src.gnome.org>2007-11-21 13:26:45 +0000
commit6299375a05eca7d0fcdb6e4734434346eb3d923f (patch)
tree6396d174875eb3d1905a00eaf84f7b8ef85b7550
parent645e735a28d40943db666201f92fe19c889bfc62 (diff)
downloadnautilus-6299375a05eca7d0fcdb6e4734434346eb3d923f.tar.gz
Add progress updates to copy. Make some error dialogs more consistent (add
2007-11-21 Alexander Larsson <alexl@redhat.com> * libnautilus-private/nautilus-file-operations.c: Add progress updates to copy. Make some error dialogs more consistent (add skip all, reorder) * libnautilus-private/nautilus-progress-info.[ch]: Add nautilus_progress_info_set_status_printf svn path=/branches/gio-branch/; revision=13433
-rw-r--r--ChangeLog9
-rw-r--r--libnautilus-private/nautilus-file-operations.c257
-rw-r--r--libnautilus-private/nautilus-progress-info.c28
-rw-r--r--libnautilus-private/nautilus-progress-info.h3
4 files changed, 256 insertions, 41 deletions
diff --git a/ChangeLog b/ChangeLog
index cc4680a5b..3df21f503 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,15 @@
2007-11-21 Alexander Larsson <alexl@redhat.com>
* libnautilus-private/nautilus-file-operations.c:
+ Add progress updates to copy.
+ Make some error dialogs more consistent (add skip all, reorder)
+
+ * libnautilus-private/nautilus-progress-info.[ch]:
+ Add nautilus_progress_info_set_status_printf
+
+2007-11-21 Alexander Larsson <alexl@redhat.com>
+
+ * libnautilus-private/nautilus-file-operations.c:
Don't create dest dir on merges
2007-11-21 Alexander Larsson <alexl@redhat.com>
diff --git a/libnautilus-private/nautilus-file-operations.c b/libnautilus-private/nautilus-file-operations.c
index 80afbadcc..164171510 100644
--- a/libnautilus-private/nautilus-file-operations.c
+++ b/libnautilus-private/nautilus-file-operations.c
@@ -29,6 +29,7 @@
#include <stdio.h>
#include <stdarg.h>
#include <locale.h>
+#include <math.h>
#include "nautilus-file-operations.h"
#include "nautilus-debug-log.h"
@@ -74,18 +75,22 @@
static gboolean confirm_trash_auto_value;
typedef struct {
- GIOJob *io_job;
+ GIOJob *io_job;
+ GTimer *time;
GtkWidget *parent_window;
NautilusProgressInfo *progress;
GCancellable *cancellable;
gboolean aborted;
GHashTable *skip_files;
GHashTable *skip_readdir_error;
- gboolean skip_all;
+ gboolean skip_all_error;
+ gboolean skip_all_conflict;
gboolean merge_all;
gboolean replace_all;
} CommonJob;
+#define SECONDS_NEEDED_FOR_RELIABLE_TRANSFER_RATE 15
+
#ifdef GIO_CONVERSION_DONE
typedef enum TransferKind TransferKind;
@@ -3117,6 +3122,8 @@ run_simple_dialog (CommonJob *job,
const char *button_title;
GPtrArray *ptr_array;
+ g_timer_stop (job->time);
+
data = g_new0 (RunSimpleDialogData, 1);
data->parent_window = GTK_WINDOW (job->parent_window);
data->ignore_close_box = ignore_close_box;
@@ -3144,6 +3151,9 @@ run_simple_dialog (CommonJob *job,
g_free (data->button_titles);
g_free (data);
+
+ g_timer_continue (job->time);
+
return res;
}
@@ -4042,6 +4052,7 @@ init_common (gsize job_size,
common->parent_window = g_object_ref (parent_window);
common->progress = nautilus_progress_info_new ();
common->cancellable = nautilus_progress_info_get_cancellable (common->progress);
+ common->time = g_timer_new ();
return common;
}
@@ -4050,6 +4061,8 @@ static void
finalize_common (CommonJob *common)
{
nautilus_progress_info_finish (common->progress);
+
+ g_timer_destroy (common->time);
if (common->parent_window) {
g_object_unref (common->parent_window);
@@ -4120,6 +4133,14 @@ typedef struct {
OpKind op;
} SourceInfo;
+typedef struct {
+ int num_files;
+ goffset num_bytes;
+ OpKind op;
+ GFile *dest;
+ guint64 last_report_time;
+} TransferInfo;
+
static void
report_count_progress (CommonJob *job,
SourceInfo *source_info)
@@ -4135,7 +4156,7 @@ report_count_progress (CommonJob *job,
}
g_free (size);
}
-
+
static void
count_file (GFileInfo *info,
CommonJob *job,
@@ -4255,6 +4276,8 @@ scan_dir (GFile *dir,
}
}
+ } else if (job->skip_all_error) {
+ skip_file (job, dir);
} else {
primary = _("Error while copying.");
details = NULL;
@@ -4274,17 +4297,20 @@ scan_dir (GFile *dir,
primary,
secondary,
details,
- _("Skip"), GTK_STOCK_CANCEL, _("_Retry"),
+ GTK_STOCK_CANCEL, _("S_kip All"), _("Skip"), _("_Retry"),
NULL);
g_free (secondary);
g_error_free (error);
- if (response == 0) {
- skip_file (job, dir);
- } else if (response == 1 || response == GTK_RESPONSE_DELETE_EVENT) {
+ if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
job->aborted = TRUE;
- } else if (response == 2) {
+ } else if (response == 1 || response == 2) {
+ if (response == 1) {
+ job->skip_all_error = TRUE;
+ }
+ skip_file (job, dir);
+ } else if (response == 3) {
goto retry;
} else {
g_assert_not_reached ();
@@ -4325,6 +4351,8 @@ scan_file (GFile *file,
}
g_object_unref (info);
+ } else if (job->skip_all_error) {
+ skip_file (job, file);
} else {
primary = _("Error while copying.");
details = NULL;
@@ -4344,17 +4372,20 @@ scan_file (GFile *file,
primary,
secondary,
details,
- _("Skip"), GTK_STOCK_CANCEL, _("_Retry"),
+ GTK_STOCK_CANCEL, _("S_kip All"), _("Skip"), _("_Retry"),
NULL);
g_free (secondary);
-
+
g_error_free (error);
- if (response == 0) {
- skip_file (job, file);
- } else if (response == 1 || response == GTK_RESPONSE_DELETE_EVENT) {
+ if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
job->aborted = TRUE;
- } else if (response == 2) {
+ } else if (response == 1 || response == 2) {
+ if (response == 1) {
+ job->skip_all_error = TRUE;
+ }
+ skip_file (job, file);
+ } else if (response == 3) {
goto retry;
} else {
g_assert_not_reached ();
@@ -4558,6 +4589,110 @@ verify_destination (CommonJob *job,
g_object_unref (fsinfo);
}
+static char *
+format_time (double seconds)
+{
+ int minutes;
+ int hours;
+ char *res;
+
+ if (seconds < 0) {
+ /* Just to make sure... */
+ seconds = 0;
+ }
+
+ if (seconds < 60) {
+ return g_strdup_printf (ngettext ("%d second","%d seconds", (int) seconds), (int) seconds);
+ }
+
+ if (seconds < 60*60) {
+ minutes = (int) floor (seconds / 60 + 0.5);
+ return g_strdup_printf (ngettext (_("%d minute"), _("%d minutes"), minutes), minutes);
+ }
+
+ hours = floor (seconds / (60*60));
+
+ if (seconds < 60*60*4) {
+ char *h, *m;
+
+ minutes = (int) floor ((seconds - hours * 60 * 60) / 60 + 0.5);
+
+ h = g_strdup_printf (ngettext (_("%d hour"), _("%d hours"), hours), hours);
+ m = g_strdup_printf (ngettext (_("%d minute"), _("%d minutes"), minutes), minutes);
+ res = g_strconcat (h, ", ", m, NULL);
+ g_free (h);
+ g_free (m);
+ return res;
+ }
+
+ return g_strdup_printf (_("about %d hours"), hours);
+}
+
+#define NSEC_PER_SEC 1000000000
+
+static void
+report_copy_progress (CommonJob *job,
+ SourceInfo *source_info,
+ TransferInfo *transfer_info)
+{
+ char *dest_basename;
+ int files_left;
+ goffset total_size;
+ char *size, *total_size_str, *rate_str, *time_str;
+ double elapsed, transfer_rate, remaining_time;
+ guint64 now;
+
+ now = g_thread_gettime ();
+
+ if (transfer_info->last_report_time != 0 &&
+ ABS (transfer_info->last_report_time - now) < 1 * NSEC_PER_SEC) {
+ return;
+ }
+ transfer_info->last_report_time = now;
+
+ dest_basename = get_display_name (transfer_info->dest, job->cancellable);
+
+ files_left = source_info->num_files - transfer_info->num_files;
+
+ /* Races and whatnot could cause this to be negative... */
+ if (files_left < 0) {
+ files_left = 1;
+ }
+
+ nautilus_progress_info_set_status_printf (job->progress,
+ _("Copying %d files to %s"),
+ files_left, dest_basename);
+ g_free (dest_basename);
+
+ total_size = MAX (source_info->num_bytes, transfer_info->num_bytes);
+
+ size = g_format_file_size_for_display (transfer_info->num_bytes);
+ total_size_str = g_format_file_size_for_display (total_size);
+
+ elapsed = g_timer_elapsed (job->time, NULL);
+ if (elapsed < SECONDS_NEEDED_FOR_RELIABLE_TRANSFER_RATE) {
+ nautilus_progress_info_set_details_printf (job->progress,
+ _("Copied %s of %s."),
+ size, total_size_str);
+ } else {
+ transfer_rate = transfer_info->num_bytes / elapsed;
+ rate_str = g_format_file_size_for_display ((goffset) floor (transfer_rate + 0.5));
+ remaining_time = (total_size - transfer_info->num_bytes) / transfer_rate;
+
+ time_str = format_time (remaining_time);
+
+ nautilus_progress_info_set_details_printf (job->progress,
+ _("Copied %s of %s, at %s/sec. Estimated time left: %s."),
+ size, total_size_str, rate_str,
+ time_str);
+ g_free (rate_str);
+ g_free (time_str);
+ }
+
+ g_free (size);
+ g_free (total_size_str);
+}
+
static GFile *
get_target_file (GFile *src,
GFile *dest_dir,
@@ -4644,7 +4779,7 @@ static void copy_file (CommonJob *job,
GFile *dest_dir,
gboolean same_fs,
SourceInfo *source_info,
- SourceInfo *done_info);
+ TransferInfo *transfer_info);
static void
create_dest_dir (CommonJob *job,
@@ -4679,16 +4814,16 @@ create_dest_dir (CommonJob *job,
primary,
secondary,
details,
- _("Skip"), GTK_STOCK_CANCEL, _("_Retry"),
+ GTK_STOCK_CANCEL, ("Skip"), _("_Retry"),
NULL);
g_free (secondary);
g_error_free (error);
- if (response == 0) {
- /* Skip: Do Nothing */
- } else if (response == 1 || response == GTK_RESPONSE_DELETE_EVENT) {
+ if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
job->aborted = TRUE;
+ } else if (response == 1) {
+ /* Skip: Do Nothing */
} else if (response == 2) {
goto retry;
} else {
@@ -4704,7 +4839,7 @@ copy_directory (CommonJob *job,
gboolean same_fs,
gboolean create_dest,
SourceInfo *source_info,
- SourceInfo *done_info)
+ TransferInfo *transfer_info)
{
GFileInfo *info;
GError *error;
@@ -4736,7 +4871,7 @@ copy_directory (CommonJob *job,
(info = g_file_enumerator_next_file (enumerator, job->cancellable, skip_error?NULL:&error)) != NULL) {
src_file = g_file_get_child (src,
g_file_info_get_name (info));
- copy_file (job, src_file, dest, same_fs, source_info, done_info);
+ copy_file (job, src_file, dest, same_fs, source_info, transfer_info);
g_object_unref (info);
}
g_file_enumerator_close (enumerator, job->cancellable, NULL);
@@ -4775,7 +4910,9 @@ copy_directory (CommonJob *job,
}
}
- done_info->num_files ++;
+ /* Count the copied directory as a file */
+ transfer_info->num_files ++;
+ report_copy_progress (job, source_info, transfer_info);
} else {
primary = _("Error while copying.");
details = NULL;
@@ -4820,13 +4957,42 @@ copy_directory (CommonJob *job,
}
}
+
+typedef struct {
+ CommonJob *job;
+ goffset last_size;
+ SourceInfo *source_info;
+ TransferInfo *transfer_info;
+} ProgressData;
+
+static void
+copy_file_progress_callback (goffset current_num_bytes,
+ goffset total_num_bytes,
+ gpointer user_data)
+{
+ ProgressData *pdata;
+ goffset new_size;
+
+ pdata = user_data;
+
+ new_size = current_num_bytes - pdata->last_size;
+
+ if (new_size > 0) {
+ pdata->transfer_info->num_bytes += new_size;
+ pdata->last_size = current_num_bytes;
+ report_copy_progress (pdata->job,
+ pdata->source_info,
+ pdata->transfer_info);
+ }
+}
+
static void
copy_file (CommonJob *job,
GFile *src,
GFile *dest_dir,
gboolean same_fs,
SourceInfo *source_info,
- SourceInfo *done_info)
+ TransferInfo *transfer_info)
{
GFile *dest;
GError *error;
@@ -4834,6 +5000,7 @@ copy_file (CommonJob *job,
GFileCopyFlags flags;
char *primary, *secondary, *details;
int response;
+ ProgressData pdata;
if (should_skip_file (job, src)) {
return;
@@ -4850,15 +5017,19 @@ copy_file (CommonJob *job,
if (overwrite) {
flags |= G_FILE_COPY_OVERWRITE;
}
+ pdata.job = job;
+ pdata.last_size = 0;
+ pdata.source_info = source_info;
+ pdata.transfer_info = transfer_info;
if (g_file_copy (src, dest,
flags,
job->cancellable,
- NULL /* TODO: GFileProgressCallback progress_callback */,
- NULL /* gpointer progress_callback_data */,
+ copy_file_progress_callback,
+ &pdata,
&error)) {
- done_info->num_files ++;
+ transfer_info->num_files ++;
+ report_copy_progress (job, source_info, transfer_info);
- /* TODO: Update done_info->num_bytes */
g_object_unref (dest);
return;
}
@@ -4904,7 +5075,7 @@ copy_file (CommonJob *job,
goto retry;
}
- if (job->skip_all) {
+ if (job->skip_all_conflict) {
g_free (primary);
g_free (secondary);
g_error_free (error);
@@ -4933,7 +5104,7 @@ copy_file (CommonJob *job,
job->aborted = TRUE;
} else if (response == 1 || response == 3) { /* skip all / skip */
if (response == 1) {
- job->skip_all = TRUE;
+ job->skip_all_conflict = TRUE;
}
} else if (response == 2 || response == 4) { /* merge/replace all / merge/replace*/
if (response == 2) {
@@ -4974,12 +5145,12 @@ copy_file (CommonJob *job,
copy_directory (job, src, dest, same_fs,
error->code != G_IO_ERROR_WOULD_MERGE,
- source_info, done_info);
+ source_info, transfer_info);
}
/* Other error */
else {
- if (job->skip_all) {
+ if (job->skip_all_error) {
goto out;
}
primary = strdup_with_name (_("Error while copying \"%s\"."), src);
@@ -5002,7 +5173,7 @@ copy_file (CommonJob *job,
if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
job->aborted = TRUE;
} else if (response == 1) { /* skip all */
- job->skip_all = TRUE;
+ job->skip_all_error = TRUE;
} else if (response == 2) { /* skip */
/* do nothing */
} else {
@@ -5020,12 +5191,14 @@ copy_files (CommonJob *job,
GFile *dest_dir,
const char *dest_fs_id,
SourceInfo *source_info,
- SourceInfo *done_info)
+ TransferInfo *transfer_info)
{
GList *l;
GFile *src;
gboolean same_fs;
+ report_copy_progress (job, source_info, transfer_info);
+
for (l = files;
l != NULL && !job->aborted ;
l = l->next) {
@@ -5038,7 +5211,7 @@ copy_files (CommonJob *job,
copy_file (job, src, dest_dir,
same_fs,
- source_info, done_info);
+ source_info, transfer_info);
}
}
@@ -5067,7 +5240,6 @@ copy_job_done (gpointer user_data)
finalize_common ((CommonJob *)job);
}
-
static void
copy_job (GIOJob *io_job,
GCancellable *cancellable,
@@ -5076,7 +5248,7 @@ copy_job (GIOJob *io_job,
CopyJob *job;
CommonJob *common;
SourceInfo source_info;
- SourceInfo done_info;
+ TransferInfo transfer_info;
char *dest_fs_id;
job = user_data;
@@ -5088,8 +5260,8 @@ copy_job (GIOJob *io_job,
dest_fs_id = NULL;
nautilus_progress_info_start (job->common.progress);
-
- memset (&source_info, 0, sizeof (source_info));
+
+ memset (&source_info, 0, sizeof (SourceInfo));
scan_sources (job->files,
&source_info,
common);
@@ -5109,11 +5281,14 @@ copy_job (GIOJob *io_job,
goto aborted;
}
- memset (&source_info, 0, sizeof (source_info));
+ g_timer_start (job->common.time);
+
+ memset (&transfer_info, 0, sizeof (transfer_info));
+ transfer_info.dest = job->destination;
copy_files (common, job->files, job->destination,
dest_fs_id,
- &source_info, &done_info);
-
+ &source_info, &transfer_info);
+
aborted:
g_print ("copy job done\n");
diff --git a/libnautilus-private/nautilus-progress-info.c b/libnautilus-private/nautilus-progress-info.c
index 9a3f3c82d..3970c83e1 100644
--- a/libnautilus-private/nautilus-progress-info.c
+++ b/libnautilus-private/nautilus-progress-info.c
@@ -433,6 +433,34 @@ nautilus_progress_info_set_status (NautilusProgressInfo *info,
}
void
+nautilus_progress_info_set_status_printf (NautilusProgressInfo *info,
+ const char *format,
+ ...)
+{
+ gchar *status;
+ va_list args;
+
+ va_start (args, format);
+ status = g_strdup_vprintf (format, args);
+ va_end (args);
+
+ G_LOCK (progress_info);
+
+ if (eel_strcmp (info->status, status) != 0) {
+ g_free (info->status);
+ info->status = status;
+
+ info->changed_at_idle = TRUE;
+ queue_idle (info, FALSE);
+ } else {
+ g_free (status);
+ }
+
+ G_UNLOCK (progress_info);
+}
+
+
+void
nautilus_progress_info_set_details (NautilusProgressInfo *info,
const char *details)
{
diff --git a/libnautilus-private/nautilus-progress-info.h b/libnautilus-private/nautilus-progress-info.h
index 74b6c97a9..85d26b7fe 100644
--- a/libnautilus-private/nautilus-progress-info.h
+++ b/libnautilus-private/nautilus-progress-info.h
@@ -65,6 +65,9 @@ void nautilus_progress_info_start (NautilusProgressInfo *info
void nautilus_progress_info_finish (NautilusProgressInfo *info);
void nautilus_progress_info_set_status (NautilusProgressInfo *info,
const char *status);
+void nautilus_progress_info_set_status_printf (NautilusProgressInfo *info,
+ const char *format,
+ ...);
void nautilus_progress_info_set_details (NautilusProgressInfo *info,
const char *details);
void nautilus_progress_info_set_details_printf (NautilusProgressInfo *info,