[nautilus/wip/csoriano/operations: 13/13] operations: implement new design



commit 037278b2e34b29a18ff8fcf4725eaf937b81bde7
Author: Carlos Soriano <csoriano gnome org>
Date:   Wed Jul 1 15:53:43 2015 +0200

    operations: implement new design
    
    Now operations reside in the toolbar, in form of a button with
    a popover. In this way we avoid to have a nautilus window hanging
    around for it.
    When no nautilus window is open, the persistence handlers of nautilus
    are enough. This use a notification if the server supports it or
    a systray icon in case it doesn't.

 libnautilus-private/nautilus-file-operations.c     |   26 ++-
 libnautilus-private/nautilus-file-operations.h     |    2 +
 .../nautilus-progress-info-manager.c               |    2 +-
 .../nautilus-progress-info-manager.h               |    2 +-
 libnautilus-private/nautilus-progress-info.c       |   25 ++-
 libnautilus-private/nautilus-progress-info.h       |    4 +
 src/Makefile.am                                    |    4 +-
 src/nautilus-application-actions.c                 |   13 -
 src/nautilus-application.c                         |   13 +-
 src/nautilus-application.h                         |    4 -
 src/nautilus-progress-info-widget.c                |    6 +-
 src/nautilus-progress-info-widget.xml              |    4 +-
 ...r.c => nautilus-progress-persistence-handler.c} |  252 +++++++++-----------
 src/nautilus-progress-persistence-handler.h        |   65 +++++
 src/nautilus-progress-ui-handler.h                 |   64 -----
 src/nautilus-toolbar-ui.xml                        |   49 ++++
 src/nautilus-toolbar.c                             |  123 ++++++++++
 src/nautilus-toolbar.h                             |    3 +
 test/test-copy.c                                   |    2 +-
 19 files changed, 421 insertions(+), 242 deletions(-)
---
diff --git a/libnautilus-private/nautilus-file-operations.c b/libnautilus-private/nautilus-file-operations.c
index acb4c7c..f0deba8 100644
--- a/libnautilus-private/nautilus-file-operations.c
+++ b/libnautilus-private/nautilus-file-operations.c
@@ -1454,6 +1454,7 @@ report_delete_progress (CommonJob *job,
        int remaining_time;
        gint64 now;
        char *files_left_s;
+        double total_size;
 
        now = g_get_monotonic_time ();
        if (transfer_info->last_report_time != 0 &&
@@ -1477,14 +1478,21 @@ report_delete_progress (CommonJob *job,
        nautilus_progress_info_take_status (job->progress,
                                            f (_("Deleting files")));
 
+       total_size = MAX (source_info->num_bytes, transfer_info->num_bytes);
+
        elapsed = g_timer_elapsed (job->time, NULL);
-       if (elapsed < SECONDS_NEEDED_FOR_RELIABLE_TRANSFER_RATE) {
+        transfer_rate = 0;
+        remaining_time = INT_MAX;
+       if (elapsed > 0) {
+               transfer_rate = transfer_info->num_bytes / elapsed;
+                if (transfer_rate > 0)
+                       remaining_time = (total_size - transfer_info->num_bytes) / transfer_rate;
+       }
 
+       if (elapsed < SECONDS_NEEDED_FOR_RELIABLE_TRANSFER_RATE) {
                nautilus_progress_info_set_details (job->progress, files_left_s);
        } else {
                char *details, *time_left_s;
-               transfer_rate = transfer_info->num_files / elapsed;
-               remaining_time = files_left / transfer_rate;
 
                /* To translators: %T will expand to a time like "2 minutes".
                 * The singular/plural form will be used depending on the remaining time (i.e. the %T 
argument).
@@ -1500,6 +1508,10 @@ report_delete_progress (CommonJob *job,
                g_free (time_left_s);
        }
 
+        if (elapsed > SECONDS_NEEDED_FOR_APROXIMATE_TRANSFER_RATE)
+                nautilus_progress_info_set_stimated_total_time (job->progress,
+                                                                remaining_time + elapsed);
+
        g_free (files_left_s);
 
        if (source_info->num_files != 0) {
@@ -3039,8 +3051,11 @@ report_copy_progress (CopyMoveJob *copy_job,
        
        elapsed = g_timer_elapsed (job->time, NULL);
        transfer_rate = 0;
+        remaining_time = INT_MAX;
        if (elapsed > 0) {
                transfer_rate = transfer_info->num_bytes / elapsed;
+                if (transfer_rate > 0)
+                       remaining_time = (total_size - transfer_info->num_bytes) / transfer_rate;
        }
 
        if (elapsed < SECONDS_NEEDED_FOR_RELIABLE_TRANSFER_RATE &&
@@ -3051,7 +3066,6 @@ report_copy_progress (CopyMoveJob *copy_job,
                nautilus_progress_info_take_details (job->progress, s);
        } else {
                char *s;
-               remaining_time = (total_size - transfer_info->num_bytes) / transfer_rate;
 
                /* 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 of 4 MB -- 2 hours left 
(4kb/sec)"
@@ -3067,6 +3081,10 @@ report_copy_progress (CopyMoveJob *copy_job,
                nautilus_progress_info_take_details (job->progress, s);
        }
 
+        if (elapsed > SECONDS_NEEDED_FOR_APROXIMATE_TRANSFER_RATE)
+                nautilus_progress_info_set_stimated_total_time (job->progress,
+                                                                remaining_time + elapsed);
+
        nautilus_progress_info_set_progress (job->progress, transfer_info->num_bytes, total_size);
 }
 
diff --git a/libnautilus-private/nautilus-file-operations.h b/libnautilus-private/nautilus-file-operations.h
index e65ba7d..38b714f 100644
--- a/libnautilus-private/nautilus-file-operations.h
+++ b/libnautilus-private/nautilus-file-operations.h
@@ -28,6 +28,8 @@
 #include <gtk/gtk.h>
 #include <gio/gio.h>
 
+#define SECONDS_NEEDED_FOR_APROXIMATE_TRANSFER_RATE 1
+
 typedef void (* NautilusCopyCallback)      (GHashTable *debuting_uris,
                                            gboolean    success,
                                            gpointer    callback_data);
diff --git a/libnautilus-private/nautilus-progress-info-manager.c 
b/libnautilus-private/nautilus-progress-info-manager.c
index 97343ee..661f5da 100644
--- a/libnautilus-private/nautilus-progress-info-manager.c
+++ b/libnautilus-private/nautilus-progress-info-manager.c
@@ -111,7 +111,7 @@ progress_info_finished_cb (NautilusProgressInfo *info,
 }
 
 NautilusProgressInfoManager *
-nautilus_progress_info_manager_new (void)
+nautilus_progress_info_manager_dup_singleton (void)
 {
        return g_object_new (NAUTILUS_TYPE_PROGRESS_INFO_MANAGER, NULL);
 }
diff --git a/libnautilus-private/nautilus-progress-info-manager.h 
b/libnautilus-private/nautilus-progress-info-manager.h
index 21c22f0..7198bd3 100644
--- a/libnautilus-private/nautilus-progress-info-manager.h
+++ b/libnautilus-private/nautilus-progress-info-manager.h
@@ -57,7 +57,7 @@ struct _NautilusProgressInfoManagerClass {
 
 GType nautilus_progress_info_manager_get_type (void);
 
-NautilusProgressInfoManager* nautilus_progress_info_manager_new (void);
+NautilusProgressInfoManager* nautilus_progress_info_manager_dup_singleton (void);
 
 void nautilus_progress_info_manager_add_new_info (NautilusProgressInfoManager *self,
                                                   NautilusProgressInfo *info);
diff --git a/libnautilus-private/nautilus-progress-info.c b/libnautilus-private/nautilus-progress-info.c
index 16b2cb2..609fcb2 100644
--- a/libnautilus-private/nautilus-progress-info.c
+++ b/libnautilus-private/nautilus-progress-info.c
@@ -50,6 +50,7 @@ struct _NautilusProgressInfo
        char *status;
        char *details;
        double progress;
+        gint stimated_total_time;
        gboolean activity_mode;
        gboolean started;
        gboolean finished;
@@ -162,7 +163,7 @@ nautilus_progress_info_init (NautilusProgressInfo *info)
 
        info->cancellable = g_cancellable_new ();
 
-       manager = nautilus_progress_info_manager_new ();
+       manager = nautilus_progress_info_manager_dup_singleton ();
        nautilus_progress_info_manager_add_new_info (manager, info);
        g_object_unref (manager);
 }
@@ -305,6 +306,7 @@ idle_callback (gpointer data)
        gboolean finish_at_idle;
        gboolean changed_at_idle;
        gboolean progress_at_idle;
+       gboolean time_remaining_at_idle;
        GSource *source;
 
        source = g_main_current_source ();
@@ -570,3 +572,24 @@ nautilus_progress_info_set_progress (NautilusProgressInfo *info,
        
        G_UNLOCK (progress_info);
 }
+
+void
+nautilus_progress_info_set_stimated_total_time (NautilusProgressInfo *info,
+                                                gint                  time)
+{
+        G_LOCK (progress_info);
+        info->stimated_total_time = time;
+        G_UNLOCK (progress_info);
+}
+
+gint
+nautilus_progress_info_get_stimated_total_time (NautilusProgressInfo *info)
+{
+        gint stimated_total_time;
+
+        G_LOCK (progress_info);
+        stimated_total_time = info->stimated_total_time;
+        G_UNLOCK (progress_info);
+
+        return stimated_total_time;
+}
diff --git a/libnautilus-private/nautilus-progress-info.h b/libnautilus-private/nautilus-progress-info.h
index edca861..9dd9267 100644
--- a/libnautilus-private/nautilus-progress-info.h
+++ b/libnautilus-private/nautilus-progress-info.h
@@ -78,6 +78,10 @@ void          nautilus_progress_info_set_progress    (NautilusProgressInfo *info
                                                      double                total);
 void          nautilus_progress_info_pulse_progress  (NautilusProgressInfo *info);
 
+void          nautilus_progress_info_set_stimated_total_time  (NautilusProgressInfo *info,
+                                                               gint                  time);
+gint          nautilus_progress_info_get_stimated_total_time (NautilusProgressInfo *info);
+
 
 
 #endif /* NAUTILUS_PROGRESS_INFO_H */
diff --git a/src/Makefile.am b/src/Makefile.am
index 72a07c3..7de649b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -189,8 +189,8 @@ nautilus_SOURCES = \
        nautilus-previewer.h                    \
        nautilus-progress-info-widget.c         \
        nautilus-progress-info-widget.h         \
-       nautilus-progress-ui-handler.c          \
-       nautilus-progress-ui-handler.h          \
+       nautilus-progress-persistence-handler.c \
+       nautilus-progress-persistence-handler.h \
        nautilus-properties-window.c            \
        nautilus-properties-window.h            \
        nautilus-query-editor.c                 \
diff --git a/src/nautilus-application-actions.c b/src/nautilus-application-actions.c
index 3caa09e..17c4b68 100644
--- a/src/nautilus-application-actions.c
+++ b/src/nautilus-application-actions.c
@@ -217,18 +217,6 @@ action_search (GSimpleAction *action,
 }
 
 static void
-action_show_file_transfers (GSimpleAction *action,
-                           GVariant *parameter,
-                           gpointer user_data)
-{
-       NautilusApplication *application = user_data;
-       NautilusProgressUIHandler *progress_handler;
-
-       progress_handler = nautilus_application_get_progress_ui_handler (application);
-       nautilus_progress_ui_handler_ensure_window (progress_handler);
-}
-
-static void
 action_show_hide_sidebar (GSimpleAction *action,
                          GVariant      *state,
                          gpointer       user_data)
@@ -261,7 +249,6 @@ static GActionEntry app_entries[] = {
        { "kill", action_kill, NULL, NULL, NULL },
        { "open-desktop", action_open_desktop, NULL, NULL, NULL },
        { "close-desktop", action_close_desktop, NULL, NULL, NULL },
-       { "show-file-transfers", action_show_file_transfers, NULL, NULL, NULL }
 };
 
 void
diff --git a/src/nautilus-application.c b/src/nautilus-application.c
index bde2330..19ce99a 100644
--- a/src/nautilus-application.c
+++ b/src/nautilus-application.c
@@ -37,6 +37,7 @@
 #include "nautilus-freedesktop-dbus.h"
 #include "nautilus-image-properties-page.h"
 #include "nautilus-previewer.h"
+#include "nautilus-progress-persistence-handler.h"
 #include "nautilus-self-check-functions.h"
 #include "nautilus-shell-search-provider.h"
 #include "nautilus-window.h"
@@ -70,7 +71,7 @@
 G_DEFINE_TYPE (NautilusApplication, nautilus_application, GTK_TYPE_APPLICATION);
 
 struct _NautilusApplicationPriv {
-       NautilusProgressUIHandler *progress_handler;
+       NautilusProgressPersistenceHandler *progress_handler;
        NautilusDBusManager *dbus_manager;
        NautilusFreedesktopDBus *fdb_manager;
 
@@ -104,13 +105,6 @@ nautilus_application_get_windows (NautilusApplication *application)
        return application->priv->windows;
 }
 
-
-NautilusProgressUIHandler *
-nautilus_application_get_progress_ui_handler (NautilusApplication *application)
-{
-       return application->priv->progress_handler;
-}
-
 NautilusBookmarkList *
 nautilus_application_get_bookmarks (NautilusApplication *application)
 {
@@ -996,7 +990,7 @@ nautilus_application_startup (GApplication *app)
        menu_provider_init_callback ();
        
        /* Initialize the UI handler singleton for file operations */
-       self->priv->progress_handler = nautilus_progress_ui_handler_new ();
+       self->priv->progress_handler = nautilus_progress_persistence_handler_new (G_OBJECT (self));
 
        /* Check the user's .nautilus directories and post warnings
         * if there are problems.
@@ -1169,6 +1163,7 @@ nautilus_application_window_removed (GtkApplication *app,
        /* if this was the last window, close the previewer */
        if (g_list_length (self->priv->windows) == 0) {
                nautilus_previewer_call_close ();
+                nautilus_progress_persistence_handler_make_persistent (self->priv->progress_handler);
        }
 }
 
diff --git a/src/nautilus-application.h b/src/nautilus-application.h
index 3dd4af5..8b6ef79 100644
--- a/src/nautilus-application.h
+++ b/src/nautilus-application.h
@@ -27,7 +27,6 @@
 #include <gtk/gtk.h>
 
 #include "nautilus-bookmark-list.h"
-#include "nautilus-progress-ui-handler.h"
 #include "nautilus-window.h"
 
 #define NAUTILUS_DESKTOP_ICON_VIEW_IID "OAFIID:Nautilus_File_Manager_Desktop_Canvas_View"
@@ -81,7 +80,4 @@ void nautilus_application_edit_bookmarks (NautilusApplication *application,
 
 GtkWidget * nautilus_application_connect_server (NautilusApplication *application,
                                                 NautilusWindow      *window);
-
-NautilusProgressUIHandler * nautilus_application_get_progress_ui_handler (NautilusApplication *application);
-
 #endif /* __NAUTILUS_APPLICATION_H__ */
diff --git a/src/nautilus-progress-info-widget.c b/src/nautilus-progress-info-widget.c
index 86b34fd..8ee730f 100644
--- a/src/nautilus-progress-info-widget.c
+++ b/src/nautilus-progress-info-widget.c
@@ -93,6 +93,9 @@ nautilus_progress_info_widget_dispose (GObject *obj)
 {
        NautilusProgressInfoWidget *self = NAUTILUS_PROGRESS_INFO_WIDGET (obj);
 
+        if (self->priv->info != NULL) {
+                g_signal_handlers_disconnect_by_data (self->priv->info, self);
+        }
        g_clear_object (&self->priv->info);
 
        G_OBJECT_CLASS (nautilus_progress_info_widget_parent_class)->dispose (obj);
@@ -185,8 +188,5 @@ nautilus_progress_info_widget_new (NautilusProgressInfo *info)
 {
        return g_object_new (NAUTILUS_TYPE_PROGRESS_INFO_WIDGET,
                             "info", info,
-                            "orientation", GTK_ORIENTATION_VERTICAL,
-                            "homogeneous", FALSE,
-                            "spacing", 5,
                             NULL);
 }
diff --git a/src/nautilus-progress-info-widget.xml b/src/nautilus-progress-info-widget.xml
index e4a9802..9845480 100644
--- a/src/nautilus-progress-info-widget.xml
+++ b/src/nautilus-progress-info-widget.xml
@@ -2,7 +2,9 @@
 <interface>
   <template class="NautilusProgressInfoWidget" parent="GtkBox">
     <property name="visible">True</property>
-    <property name="margin">5</property>
+    <property name="margin-start">5</property>
+    <property name="margin-end">5</property>
+    <property name="spacing">0</property>
     <property name="orientation">vertical</property>
     <child>
       <object class="GtkLabel" id="status">
diff --git a/src/nautilus-progress-ui-handler.c b/src/nautilus-progress-persistence-handler.c
similarity index 60%
rename from src/nautilus-progress-ui-handler.c
rename to src/nautilus-progress-persistence-handler.c
index 21722df..dd8d2eb 100644
--- a/src/nautilus-progress-ui-handler.c
+++ b/src/nautilus-progress-persistence-handler.c
@@ -1,8 +1,8 @@
 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
 /*
- * nautilus-progress-ui-handler.c: file operation progress user interface.
+ * nautilus-progress-persistence-handler.c: file operation progress systray icon or notification handler.
  *
- * Copyright (C) 2007, 2011 Red Hat, Inc.
+ * Copyright (C) 2007, 2011, 2015 Red Hat, Inc.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -19,12 +19,13 @@
  *
  * Authors: Alexander Larsson <alexl redhat com>
  *          Cosimo Cecchi <cosimoc redhat com>
+ *          Carlos Soriano <csoriano gnome com>
  *
  */
 
 #include <config.h>
 
-#include "nautilus-progress-ui-handler.h"
+#include "nautilus-progress-persistence-handler.h"
 
 #include "nautilus-application.h"
 #include "nautilus-progress-info-widget.h"
@@ -34,17 +35,16 @@
 #include <libnautilus-private/nautilus-progress-info.h>
 #include <libnautilus-private/nautilus-progress-info-manager.h>
 
-struct _NautilusProgressUIHandlerPriv {
+struct _NautilusProgressPersistenceHandlerPriv {
        NautilusProgressInfoManager *manager;
 
-       GtkWidget *progress_dialog;
-       GtkWidget *content_area;
+        NautilusApplication *app;
        guint active_infos;
 
        GtkStatusIcon *status_icon;
 };
 
-G_DEFINE_TYPE (NautilusProgressUIHandler, nautilus_progress_ui_handler, G_TYPE_OBJECT);
+G_DEFINE_TYPE (NautilusProgressPersistenceHandler, nautilus_progress_persistence_handler, G_TYPE_OBJECT);
 
 /* Our policy for showing progress notification is the following:
  * - file operations that end within two seconds do not get notified in any way
@@ -65,16 +65,44 @@ G_DEFINE_TYPE (NautilusProgressUIHandler, nautilus_progress_ui_handler, G_TYPE_O
 
 static gboolean server_has_persistence (void);
 
+
 static void
-status_icon_activate_cb (GtkStatusIcon *icon,
-                        NautilusProgressUIHandler *self)
-{      
+show_file_transfers (NautilusProgressPersistenceHandler *self)
+{
+        GFile *home;
+
+        home = g_file_new_for_path (g_get_home_dir ());
+        nautilus_application_open_location (self->priv->app, home, NULL, NULL);
+
+        g_object_unref (home);
+
+}
+
+static void
+action_show_file_transfers (GSimpleAction *action,
+                           GVariant *parameter,
+                           gpointer user_data)
+{
+        NautilusProgressPersistenceHandler *self;
+
+        self = NAUTILUS_PROGRESS_PERSISTENCE_HANDLER (user_data);
+        show_file_transfers (self);
+}
+
+static GActionEntry progress_persistence_entries[] = {
+       { "show-file-transfers", action_show_file_transfers, NULL, NULL, NULL }
+};
+
+static void
+status_icon_activate_cb (GtkStatusIcon                      *icon,
+                         NautilusProgressPersistenceHandler *self)
+{
        gtk_status_icon_set_visible (icon, FALSE);
-       gtk_window_present (GTK_WINDOW (self->priv->progress_dialog));
+        show_file_transfers (self);
 }
 
 static void
-progress_ui_handler_ensure_status_icon (NautilusProgressUIHandler *self)
+progress_persistence_handler_ensure_status_icon (NautilusProgressPersistenceHandler *self)
 {
        GIcon *icon;
        GtkStatusIcon *status_icon;
@@ -96,7 +124,7 @@ progress_ui_handler_ensure_status_icon (NautilusProgressUIHandler *self)
 }
 
 static void
-progress_ui_handler_update_notification (NautilusProgressUIHandler *self)
+progress_persistence_handler_update_notification (NautilusProgressPersistenceHandler *self)
 {
         GNotification *notification;
        gchar *body;
@@ -120,11 +148,11 @@ progress_ui_handler_update_notification (NautilusProgressUIHandler *self)
 }
 
 static void
-progress_ui_handler_update_status_icon (NautilusProgressUIHandler *self)
+progress_persistence_handler_update_status_icon (NautilusProgressPersistenceHandler *self)
 {
        gchar *tooltip;
 
-       progress_ui_handler_ensure_status_icon (self);
+       progress_persistence_handler_ensure_status_icon (self);
 
        tooltip = g_strdup_printf (ngettext ("%'d file operation active",
                                             "%'d file operations active",
@@ -136,81 +164,34 @@ progress_ui_handler_update_status_icon (NautilusProgressUIHandler *self)
        gtk_status_icon_set_visible (self->priv->status_icon, TRUE);
 }
 
-static gboolean
-progress_window_delete_event (GtkWidget *widget,
-                             GdkEvent *event,
-                             NautilusProgressUIHandler *self)
-{
-       gtk_widget_hide (widget);
-
-       if (server_has_persistence ()) {
-               progress_ui_handler_update_notification (self);
-       } else {
-               progress_ui_handler_update_status_icon (self);
-       }
-
-       return TRUE;
-}
-
-static void
-progress_ui_handler_ensure_window (NautilusProgressUIHandler *self)
+void
+nautilus_progress_persistence_handler_make_persistent (NautilusProgressPersistenceHandler *self)
 {
-       GtkWidget *progress_dialog;
-       
-       if (self->priv->progress_dialog != NULL) {
-               return;
-       }
-       
-       progress_dialog = g_object_new (GTK_TYPE_DIALOG, "use-header-bar", TRUE, NULL);
-       self->priv->progress_dialog = progress_dialog;
-       gtk_window_set_resizable (GTK_WINDOW (progress_dialog),
-                                 FALSE);
-       gtk_container_set_border_width (GTK_CONTAINER (progress_dialog), 10);
- 
-       gtk_window_set_title (GTK_WINDOW (progress_dialog),
-                             _("File Operations"));
-       gtk_window_set_wmclass (GTK_WINDOW (progress_dialog),
-                               "file_progress", "Nautilus");
-       gtk_window_set_position (GTK_WINDOW (progress_dialog),
-                                GTK_WIN_POS_CENTER);
-       gtk_window_set_icon_name (GTK_WINDOW (progress_dialog),
-                               "system-file-manager");
-
-       self->priv->content_area = gtk_dialog_get_content_area (GTK_DIALOG (self->priv->progress_dialog));
-
-       g_signal_connect (progress_dialog,
-                         "delete-event",
-                         (GCallback) progress_window_delete_event, self);
+        GList *windows;
+
+        windows = nautilus_application_get_windows (self->priv->app);
+        if (self->priv->active_infos > 0 &&
+            g_list_length (windows) == 0) {
+               if (server_has_persistence ()) {
+                       progress_persistence_handler_update_notification (self);
+               } else {
+                       progress_persistence_handler_update_status_icon (self);
+               }
+        }
 }
 
 static void
-progress_ui_handler_update_notification_or_status (NautilusProgressUIHandler *self)
+progress_persistence_handler_update_notification_or_status (NautilusProgressPersistenceHandler *self)
 {
        if (server_has_persistence ()) {
-               progress_ui_handler_update_notification (self);
+               progress_persistence_handler_update_notification (self);
        } else {
-               progress_ui_handler_update_status_icon (self);
+               progress_persistence_handler_update_status_icon (self);
        }
 }
 
 static void
-progress_ui_handler_add_to_window (NautilusProgressUIHandler *self,
-                                  NautilusProgressInfo *info)
-{
-       GtkWidget *progress;
-
-       progress = nautilus_progress_info_widget_new (info);
-       progress_ui_handler_ensure_window (self);
-
-       gtk_box_pack_start (GTK_BOX (self->priv->content_area),
-                           progress,
-                           FALSE, FALSE, 6);
-
-       gtk_widget_show (progress);
-}
-
-static void
-progress_ui_handler_show_complete_notification (NautilusProgressUIHandler *self)
+progress_persistence_handler_show_complete_notification (NautilusProgressPersistenceHandler *self)
 {
        GNotification *complete_notification;
 
@@ -230,7 +211,7 @@ progress_ui_handler_show_complete_notification (NautilusProgressUIHandler *self)
 }
 
 static void
-progress_ui_handler_hide_notification_or_status (NautilusProgressUIHandler *self)
+progress_persistence_handler_hide_notification_or_status (NautilusProgressPersistenceHandler *self)
 {
        if (self->priv->status_icon != NULL) {
                gtk_status_icon_set_visible (self->priv->status_icon, FALSE);
@@ -241,50 +222,44 @@ progress_ui_handler_hide_notification_or_status (NautilusProgressUIHandler *self
 }
 
 static void
-progress_info_finished_cb (NautilusProgressInfo *info,
-                          NautilusProgressUIHandler *self)
+progress_info_finished_cb (NautilusProgressInfo               *info,
+                           NautilusProgressPersistenceHandler *self)
 {
+        GList *windows;
+
        self->priv->active_infos--;
 
-       if (self->priv->active_infos > 0) {
-               if (!gtk_widget_get_visible (self->priv->progress_dialog)) {
-                       progress_ui_handler_update_notification_or_status (self);
-               }
-       } else {
-               if (gtk_widget_get_visible (self->priv->progress_dialog)) {
-                       gtk_widget_hide (self->priv->progress_dialog);
-               } else {
-                       progress_ui_handler_hide_notification_or_status (self);
-                       progress_ui_handler_show_complete_notification (self);
-               }
-       }
+        windows = nautilus_application_get_windows (self->priv->app);
+        if (self->priv->active_infos > 0) {
+               if (g_list_length (windows) == 0) {
+                       progress_persistence_handler_update_notification_or_status (self);
+               }
+        } else if (g_list_length (windows)  == 0) {
+               progress_persistence_handler_hide_notification_or_status (self);
+               progress_persistence_handler_show_complete_notification (self);
+        }
+
 }
 
 static void
-handle_new_progress_info (NautilusProgressUIHandler *self,
-                         NautilusProgressInfo *info)
+handle_new_progress_info (NautilusProgressPersistenceHandler *self,
+                          NautilusProgressInfo               *info)
 {
+        GList *windows;
        g_signal_connect (info, "finished",
                          G_CALLBACK (progress_info_finished_cb), self);
 
        self->priv->active_infos++;
+        windows = nautilus_application_get_windows (self->priv->app);
 
-       if (self->priv->active_infos == 1) {
-               /* this is the only active operation, present the window */
-               progress_ui_handler_add_to_window (self, info);
-               gtk_window_present (GTK_WINDOW (self->priv->progress_dialog));
-       } else {
-               if (gtk_widget_get_visible (self->priv->progress_dialog)) {
-                       progress_ui_handler_add_to_window (self, info);
-               } else {
-                       progress_ui_handler_update_notification_or_status (self);
-               }
-       }
+       if (g_list_length (windows) == 0) {
+               progress_persistence_handler_update_notification_or_status (self);
+        }
 }
 
 typedef struct {
        NautilusProgressInfo *info;
-       NautilusProgressUIHandler *self;
+       NautilusProgressPersistenceHandler *self;
 } TimeoutData;
 
 static void
@@ -297,8 +272,8 @@ timeout_data_free (TimeoutData *data)
 }
 
 static TimeoutData *
-timeout_data_new (NautilusProgressUIHandler *self,
-                 NautilusProgressInfo *info)
+timeout_data_new (NautilusProgressPersistenceHandler *self,
+                  NautilusProgressInfo               *info)
 {
        TimeoutData *retval;
 
@@ -313,7 +288,7 @@ static gboolean
 new_op_started_timeout (TimeoutData *data)
 {
        NautilusProgressInfo *info = data->info;
-       NautilusProgressUIHandler *self = data->self;
+       NautilusProgressPersistenceHandler *self = data->self;
 
        if (nautilus_progress_info_get_is_paused (info)) {
                return TRUE;
@@ -329,16 +304,16 @@ new_op_started_timeout (TimeoutData *data)
 }
 
 static void
-release_application (NautilusProgressInfo *info,
-                    NautilusProgressUIHandler *self)
+release_application (NautilusProgressInfo               *info,
+                     NautilusProgressPersistenceHandler *self)
 {
        /* release the GApplication hold we acquired */
        g_application_release (g_application_get_default ());
 }
 
 static void
-progress_info_started_cb (NautilusProgressInfo *info,
-                         NautilusProgressUIHandler *self)
+progress_info_started_cb (NautilusProgressInfo               *info,
+                          NautilusProgressPersistenceHandler *self)
 {
        TimeoutData *data;
 
@@ -357,22 +332,22 @@ progress_info_started_cb (NautilusProgressInfo *info,
 }
 
 static void
-new_progress_info_cb (NautilusProgressInfoManager *manager,
-                     NautilusProgressInfo *info,
-                     NautilusProgressUIHandler *self)
+new_progress_info_cb (NautilusProgressInfoManager        *manager,
+                      NautilusProgressInfo               *info,
+                      NautilusProgressPersistenceHandler *self)
 {
        g_signal_connect (info, "started",
                          G_CALLBACK (progress_info_started_cb), self);
 }
 
 static void
-nautilus_progress_ui_handler_dispose (GObject *obj)
+nautilus_progress_persistence_handler_dispose (GObject *obj)
 {
-       NautilusProgressUIHandler *self = NAUTILUS_PROGRESS_UI_HANDLER (obj);
+       NautilusProgressPersistenceHandler *self = NAUTILUS_PROGRESS_PERSISTENCE_HANDLER (obj);
 
        g_clear_object (&self->priv->manager);
 
-       G_OBJECT_CLASS (nautilus_progress_ui_handler_parent_class)->dispose (obj);
+       G_OBJECT_CLASS (nautilus_progress_persistence_handler_parent_class)->dispose (obj);
 }
 
 static gboolean
@@ -416,36 +391,37 @@ server_has_persistence (void)
 }
 
 static void
-nautilus_progress_ui_handler_init (NautilusProgressUIHandler *self)
+nautilus_progress_persistence_handler_init (NautilusProgressPersistenceHandler *self)
 {
-       self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NAUTILUS_TYPE_PROGRESS_UI_HANDLER,
-                                                 NautilusProgressUIHandlerPriv);
+       self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NAUTILUS_TYPE_PROGRESS_PERSISTENCE_HANDLER,
+                                                 NautilusProgressPersistenceHandlerPriv);
 
-       self->priv->manager = nautilus_progress_info_manager_new ();
+       self->priv->manager = nautilus_progress_info_manager_dup_singleton ();
        g_signal_connect (self->priv->manager, "new-progress-info",
                          G_CALLBACK (new_progress_info_cb), self);
 }
 
 static void
-nautilus_progress_ui_handler_class_init (NautilusProgressUIHandlerClass *klass)
+nautilus_progress_persistence_handler_class_init (NautilusProgressPersistenceHandlerClass *klass)
 {
        GObjectClass *oclass;
 
        oclass = G_OBJECT_CLASS (klass);
-       oclass->dispose = nautilus_progress_ui_handler_dispose;
-       
-       g_type_class_add_private (klass, sizeof (NautilusProgressUIHandlerPriv));
-}
+       oclass->dispose = nautilus_progress_persistence_handler_dispose;
 
-NautilusProgressUIHandler *
-nautilus_progress_ui_handler_new (void)
-{
-       return g_object_new (NAUTILUS_TYPE_PROGRESS_UI_HANDLER, NULL);
+       g_type_class_add_private (klass, sizeof (NautilusProgressPersistenceHandlerPriv));
 }
 
-void
-nautilus_progress_ui_handler_ensure_window (NautilusProgressUIHandler *self)
+NautilusProgressPersistenceHandler *
+nautilus_progress_persistence_handler_new (GObject *app)
 {
-       if (self->priv->active_infos > 0)
-               gtk_window_present (GTK_WINDOW (self->priv->progress_dialog));
+        NautilusProgressPersistenceHandler *self;
+
+        self = g_object_new (NAUTILUS_TYPE_PROGRESS_PERSISTENCE_HANDLER, NULL);
+        self->priv->app = NAUTILUS_APPLICATION (app);
+
+        g_action_map_add_action_entries (G_ACTION_MAP (self->priv->app),
+                                         progress_persistence_entries, G_N_ELEMENTS 
(progress_persistence_entries),
+                                         self);
+       return self;
 }
diff --git a/src/nautilus-progress-persistence-handler.h b/src/nautilus-progress-persistence-handler.h
new file mode 100644
index 0000000..33718a3
--- /dev/null
+++ b/src/nautilus-progress-persistence-handler.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * nautilus-progress-persistence-handler.h: file operation progress systray icon or notification handler.
+ *
+ * Copyright (C) 2007, 2011 Red Hat, Inc.
+ *
+ * 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/>.
+ *
+ * Authors: Alexander Larsson <alexl redhat com>
+ *          Cosimo Cecchi <cosimoc redhat com>
+ *
+ */
+
+#ifndef __NAUTILUS_PROGRESS_PERSISTENCE_HANDLER_H__
+#define __NAUTILUS_PROGRESS_PERSISTENCE_HANDLER_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define NAUTILUS_TYPE_PROGRESS_PERSISTENCE_HANDLER nautilus_progress_persistence_handler_get_type()
+#define NAUTILUS_PROGRESS_PERSISTENCE_HANDLER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_PROGRESS_PERSISTENCE_HANDLER, 
NautilusProgressPersistenceHandler))
+#define NAUTILUS_PROGRESS_PERSISTENCE_HANDLER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_PROGRESS_PERSISTENCE_HANDLER, 
NautilusProgressPersistenceHandlerClass))
+#define NAUTILUS_IS_PROGRESS_PERSISTENCE_HANDLER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NAUTILUS_TYPE_PROGRESS_PERSISTENCE_HANDLER))
+#define NAUTILUS_IS_PROGRESS_PERSISTENCE_HANDLER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_PROGRESS_PERSISTENCE_HANDLER))
+#define NAUTILUS_PROGRESS_PERSISTENCE_HANDLER_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), NAUTILUS_TYPE_PROGRESS_PERSISTENCE_HANDLER, 
NautilusProgressPersistenceHandlerClass))
+
+typedef struct _NautilusProgressPersistenceHandlerPriv NautilusProgressPersistenceHandlerPriv;
+
+typedef struct {
+  GObject parent;
+
+  /* private */
+  NautilusProgressPersistenceHandlerPriv *priv;
+} NautilusProgressPersistenceHandler;
+
+typedef struct {
+  GObjectClass parent_class;
+} NautilusProgressPersistenceHandlerClass;
+
+GType nautilus_progress_persistence_handler_get_type (void);
+
+/* @app is actually a NautilusApplication, butwe have to avoid circular dependencies */
+NautilusProgressPersistenceHandler * nautilus_progress_persistence_handler_new (GObject *app);
+void nautilus_progress_persistence_handler_make_persistent (NautilusProgressPersistenceHandler *self);
+
+G_END_DECLS
+
+#endif /* __NAUTILUS_PROGRESS_PERSISTENCE_HANDLER_H__ */
diff --git a/src/nautilus-toolbar-ui.xml b/src/nautilus-toolbar-ui.xml
index bf371b0..2171a76 100644
--- a/src/nautilus-toolbar-ui.xml
+++ b/src/nautilus-toolbar-ui.xml
@@ -141,5 +141,54 @@
         <property name="pack-type">end</property>
       </packing>
     </child>
+    <child>
+      <object class="GtkRevealer" id="operations_revealer">
+        <property name="visible">True</property>
+        <property name="transition-type">GTK_REVEALER_TRANSITION_TYPE_CROSSFADE</property>
+        <child>
+          <object class="GtkMenuButton" id="operations_button">
+            <property name="visible">False</property>
+            <property name="popover">operations_popover</property>
+            <style>
+              <class name="button"/>
+            </style>
+            <child>
+              <object class="GtkImage" id="operations_icon">
+                <property name="visible">True</property>
+                <property name="icon-name">appointment-missed-symbolic</property>
+                <property name="icon-size">1</property>
+              </object>
+            </child>
+            <child internal-child="accessible">
+              <object class="AtkObject">
+                <property name="accessible-name" translatable="yes">Operations in progress</property>
+                <property name="accessible-description" translatable="yes">Open operations in 
progress</property>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+      <packing>
+        <property name="pack-type">end</property>
+      </packing>
+    </child>
   </template>
+  <object class="GtkPopover" id="operations_popover">
+    <property name="modal">false</property>
+    <property name="relative-to">operations_button</property>
+    <child>
+      <object class="GtkScrolledWindow">
+        <property name="visible">True</property>
+        <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+        <property name="min-content-height">270</property>
+        <child>
+          <object class="GtkBox" id="operations_container">
+            <property name="orientation">vertical</property>
+            <property name="visible">True</property>
+            <property name="margin">12</property>
+          </object>
+        </child>
+      </object>
+    </child>
+  </object>
 </interface>
diff --git a/src/nautilus-toolbar.c b/src/nautilus-toolbar.c
index 79697a7..67f9cd1 100644
--- a/src/nautilus-toolbar.c
+++ b/src/nautilus-toolbar.c
@@ -29,13 +29,18 @@
 #include "nautilus-location-entry.h"
 #include "nautilus-pathbar.h"
 #include "nautilus-window.h"
+#include "nautilus-progress-info-widget.h"
 
 #include <libnautilus-private/nautilus-global-preferences.h>
 #include <libnautilus-private/nautilus-ui-utilities.h>
+#include <libnautilus-private/nautilus-progress-info-manager.h>
+#include <libnautilus-private/nautilus-file-operations.h>
 
 #include <glib/gi18n.h>
 #include <math.h>
 
+#define OPERATION_MINIMUM_TIME 5 //s
+
 typedef enum {
        NAUTILUS_NAVIGATION_DIRECTION_NONE,
        NAUTILUS_NAVIGATION_DIRECTION_BACK,
@@ -53,10 +58,15 @@ struct _NautilusToolbarPrivate {
        gboolean show_location_entry;
 
        guint popup_timeout_id;
+        guint operations_timeout_id;
 
+       GtkWidget *operations_button;
        GtkWidget *view_button;
        GtkWidget *action_button;
 
+        GtkWidget *operations_popover;
+        GtkWidget *operations_container;
+        GtkWidget *operations_revealer;
        GtkWidget *view_menu_widget;
        GtkWidget *sort_menu;
        GtkWidget *sort_modification_date;
@@ -72,6 +82,8 @@ struct _NautilusToolbarPrivate {
 
        GtkWidget *forward_button;
        GtkWidget *back_button;
+
+        NautilusProgressInfoManager *progress_manager;
 };
 
 enum {
@@ -421,6 +433,93 @@ view_menu_popover_closed (GtkPopover *popover,
 }
 
 static void
+on_progress_info_finished (NautilusProgressInfo *info,
+                           NautilusToolbar      *self)
+{
+        GList *progress_infos;
+
+        progress_infos = nautilus_progress_info_manager_get_all_infos (self->priv->progress_manager);
+        if (g_list_length (progress_infos) == 0) {
+                gtk_revealer_set_reveal_child (GTK_REVEALER (self->priv->operations_revealer),
+                                               FALSE);
+        }
+}
+
+static gboolean
+update_operations (NautilusToolbar *self)
+{
+        GList *progress_infos;
+        GList *l;
+        GtkWidget *progress;
+        gboolean show_operations_button;
+
+        g_print ("update operations\n");
+        show_operations_button = FALSE;
+        gtk_container_foreach (GTK_CONTAINER (self->priv->operations_container),
+                               (GtkCallback) gtk_widget_destroy,
+                               NULL);
+
+        progress_infos = nautilus_progress_info_manager_get_all_infos (self->priv->progress_manager);
+
+        for (l = progress_infos; l != NULL; l = l->next) {
+                g_print ("update operation %d\n", nautilus_progress_info_get_stimated_total_time (l->data));
+                if (nautilus_progress_info_get_stimated_total_time (l->data) > OPERATION_MINIMUM_TIME) {
+                        show_operations_button = TRUE;
+
+                       g_signal_connect (l->data, "finished",
+                                         G_CALLBACK (on_progress_info_finished), self);
+                        progress = nautilus_progress_info_widget_new (l->data);
+                        gtk_box_pack_start (GTK_BOX (self->priv->operations_container),
+                                            progress,
+                                            FALSE, FALSE, 0);
+                }
+        }
+
+        if (show_operations_button) {
+                gtk_revealer_set_reveal_child (GTK_REVEALER (self->priv->operations_revealer),
+                                               TRUE);
+        } else {
+                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->priv->operations_button),
+                                              FALSE);
+                gtk_revealer_set_reveal_child (GTK_REVEALER (self->priv->operations_revealer),
+                                               FALSE);
+        }
+
+        self->priv->operations_timeout_id = 0;
+
+        /* In case we didn't show the operations button because the operation total
+         * time stimation is not good enough, update again to make sure we don't miss
+         * a long time operation because of that */
+        if (g_list_length (progress_infos) == 0)
+                return G_SOURCE_REMOVE;
+        else
+                return G_SOURCE_CONTINUE;
+}
+
+static void
+on_progress_info_started (NautilusProgressInfo *info,
+                          NautilusToolbar      *self)
+{
+        g_print ("disconnecting %p\n", self);
+        g_signal_handlers_disconnect_by_data (info, self);
+        /* Timeout is a little more than what we require for a stimated operation
+         * total time, to make sure the stimated total time is correct */
+        self->priv->operations_timeout_id = g_timeout_add (SECONDS_NEEDED_FOR_APROXIMATE_TRANSFER_RATE * 
1000 + 500,
+                                                           (GSourceFunc) update_operations,
+                                                           self);
+}
+
+static void
+on_new_progress_info (NautilusProgressInfoManager *manager,
+                      NautilusProgressInfo        *info,
+                      NautilusToolbar             *self)
+{
+        g_print ("connecting %p\n", self);
+        g_signal_connect (info, "started",
+                          G_CALLBACK (on_progress_info_started), self);
+}
+
+static void
 nautilus_toolbar_init (NautilusToolbar *self)
 {
        GtkBuilder *builder;
@@ -462,6 +561,11 @@ nautilus_toolbar_init (NautilusToolbar *self)
                                        G_MENU_MODEL (self->priv->action_menu));
        g_object_unref (builder);
 
+        self->priv->progress_manager = nautilus_progress_info_manager_dup_singleton ();
+       g_signal_connect (self->priv->progress_manager, "new-progress-info",
+                         G_CALLBACK (on_new_progress_info), self);
+        update_operations (self);
+
        g_object_set_data (G_OBJECT (self->priv->back_button), "nav-direction",
                           GUINT_TO_POINTER (NAUTILUS_NAVIGATION_DIRECTION_BACK));
        g_object_set_data (G_OBJECT (self->priv->forward_button), "nav-direction",
@@ -524,11 +628,27 @@ static void
 nautilus_toolbar_dispose (GObject *obj)
 {
        NautilusToolbar *self = NAUTILUS_TOOLBAR (obj);
+        GList *progress_infos;
+        GList *l;
 
+        g_print ("dispose toolbar\n");
        g_signal_handlers_disconnect_by_func (nautilus_preferences,
                                              toolbar_update_appearance, self);
        unschedule_menu_popup_timeout (self);
 
+        progress_infos = nautilus_progress_info_manager_get_all_infos (self->priv->progress_manager);
+        for (l = progress_infos; l != NULL; l = l->next) {
+                g_signal_handlers_disconnect_by_data (l->data, self);
+        }
+
+        if (self->priv->operations_timeout_id != 0) {
+                g_source_remove (self->priv->operations_timeout_id);
+                self->priv->operations_timeout_id = 0;
+        }
+
+        g_signal_handlers_disconnect_by_data (self->priv->progress_manager, self);
+        g_clear_object (&self->priv->progress_manager);
+
        G_OBJECT_CLASS (nautilus_toolbar_parent_class)->dispose (obj);
 }
 
@@ -563,6 +683,9 @@ nautilus_toolbar_class_init (NautilusToolbarClass *klass)
        gtk_widget_class_set_template_from_resource (widget_class,
                                                     "/org/gnome/nautilus/nautilus-toolbar-ui.xml");
 
+       gtk_widget_class_bind_template_child_private (widget_class, NautilusToolbar, operations_button);
+       gtk_widget_class_bind_template_child_private (widget_class, NautilusToolbar, operations_container);
+       gtk_widget_class_bind_template_child_private (widget_class, NautilusToolbar, operations_revealer);
        gtk_widget_class_bind_template_child_private (widget_class, NautilusToolbar, view_button);
        gtk_widget_class_bind_template_child_private (widget_class, NautilusToolbar, action_button);
        gtk_widget_class_bind_template_child_private (widget_class, NautilusToolbar, path_bar_container);
diff --git a/src/nautilus-toolbar.h b/src/nautilus-toolbar.h
index f281b95..18d1765 100644
--- a/src/nautilus-toolbar.h
+++ b/src/nautilus-toolbar.h
@@ -67,9 +67,12 @@ GtkWidget *nautilus_toolbar_new (void);
 GtkWidget *nautilus_toolbar_get_path_bar (NautilusToolbar *self);
 GtkWidget *nautilus_toolbar_get_location_entry (NautilusToolbar *self);
 GMenu     *nautilus_toolbar_get_action_menu (NautilusToolbar *self);
+GtkWidget *nautilus_toolbar_get_operations_container (NautilusToolbar *self);
 
 void nautilus_toolbar_set_show_location_entry (NautilusToolbar *self,
                                               gboolean show_location_entry);
 void nautilus_toolbar_reset_menus (NautilusToolbar *self);
+void nautilus_toolbar_hide_operations (NautilusToolbar *self);
+void nautilus_toolbar_show_operations (NautilusToolbar *self);
 
 #endif /* __NAUTILUS_TOOLBAR_H__ */
diff --git a/test/test-copy.c b/test/test-copy.c
index be8e7c4..d9c491e 100644
--- a/test/test-copy.c
+++ b/test/test-copy.c
@@ -69,7 +69,7 @@ main (int argc, char* argv[])
        
        gtk_widget_show (window);
 
-        manager = nautilus_progress_info_manager_new ();
+        manager = nautilus_progress_info_manager_dup_singleton ();
 
        nautilus_file_operations_copy (sources,
                                       NULL /* GArray *relative_item_points */,



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]