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.
parent 17eee1de
......@@ -1478,13 +1478,18 @@ report_delete_progress (CommonJob *job,
f (_("Deleting files")));
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_files / elapsed;
if (transfer_rate > 0)
remaining_time = (source_info->num_files - transfer_info->num_files) / 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 +1505,12 @@ report_delete_progress (CommonJob *job,
g_free (time_left_s);
}
if (elapsed > SECONDS_NEEDED_FOR_APROXIMATE_TRANSFER_RATE) {
nautilus_progress_info_set_remaining_time (job->progress,
remaining_time);
nautilus_progress_info_set_elapsed_time (job->progress,
elapsed);
}
g_free (files_left_s);
if (source_info->num_files != 0) {
......@@ -3039,8 +3050,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 +3065,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 +3080,13 @@ 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_remaining_time (job->progress,
remaining_time);
nautilus_progress_info_set_elapsed_time (job->progress,
elapsed);
}
nautilus_progress_info_set_progress (job->progress, transfer_info->num_bytes, total_size);
}
......
......@@ -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);
......
......@@ -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);
}
......@@ -139,3 +139,17 @@ nautilus_progress_info_manager_get_all_infos (NautilusProgressInfoManager *self)
{
return self->priv->progress_infos;
}
gboolean
nautilus_progress_manager_are_all_infos_finished (NautilusProgressInfoManager *self)
{
GList *l;
for (l = self->priv->progress_infos; l != NULL; l = l->next) {
if (!nautilus_progress_info_get_is_finished (l->data)) {
return FALSE;
}
}
return TRUE;
}
......@@ -57,11 +57,12 @@ 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);
GList *nautilus_progress_info_manager_get_all_infos (NautilusProgressInfoManager *self);
gboolean nautilus_progress_manager_are_all_infos_finished (NautilusProgressInfoManager *self);
G_END_DECLS
......
......@@ -50,6 +50,8 @@ struct _NautilusProgressInfo
char *status;
char *details;
double progress;
gdouble remaining_time;
gdouble elapsed_time;
gboolean activity_mode;
gboolean started;
gboolean finished;
......@@ -162,7 +164,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);
}
......@@ -570,3 +572,45 @@ nautilus_progress_info_set_progress (NautilusProgressInfo *info,
G_UNLOCK (progress_info);
}
void
nautilus_progress_info_set_remaining_time (NautilusProgressInfo *info,
gdouble time)
{
G_LOCK (progress_info);
info->remaining_time = time;
G_UNLOCK (progress_info);
}
gdouble
nautilus_progress_info_get_remaining_time (NautilusProgressInfo *info)
{
gint remaining_time;
G_LOCK (progress_info);
remaining_time = info->remaining_time;
G_UNLOCK (progress_info);
return remaining_time;
}
void
nautilus_progress_info_set_elapsed_time (NautilusProgressInfo *info,
gdouble time)
{
G_LOCK (progress_info);
info->elapsed_time = time;
G_UNLOCK (progress_info);
}
gdouble
nautilus_progress_info_get_elapsed_time (NautilusProgressInfo *info)
{
gint elapsed_time;
G_LOCK (progress_info);
elapsed_time = info->elapsed_time;
G_UNLOCK (progress_info);
return elapsed_time;
}
......@@ -78,6 +78,13 @@ void nautilus_progress_info_set_progress (NautilusProgressInfo *info
double total);
void nautilus_progress_info_pulse_progress (NautilusProgressInfo *info);
void nautilus_progress_info_set_remaining_time (NautilusProgressInfo *info,
gdouble time);
gdouble nautilus_progress_info_get_remaining_time (NautilusProgressInfo *info);
void nautilus_progress_info_set_elapsed_time (NautilusProgressInfo *info,
gdouble time);
gdouble nautilus_progress_info_get_elapsed_time (NautilusProgressInfo *info);
#endif /* NAUTILUS_PROGRESS_INFO_H */
......@@ -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 \
......
......@@ -216,18 +216,6 @@ action_search (GSimpleAction *action,
g_object_unref (location);
}
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,
......@@ -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
......
......@@ -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);
}
}
......
......@@ -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__ */
......@@ -42,7 +42,7 @@ enum {
static GParamSpec *properties[NUM_PROPERTIES] = { NULL };
G_DEFINE_TYPE_WITH_PRIVATE (NautilusProgressInfoWidget, nautilus_progress_info_widget,
GTK_TYPE_BOX);
GTK_TYPE_GRID);
static void
info_finished (NautilusProgressInfoWidget *self)
......@@ -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);
}
......@@ -44,14 +44,14 @@
typedef struct _NautilusProgressInfoWidgetPrivate NautilusProgressInfoWidgetPrivate;
typedef struct {
GtkBox parent;
GtkGrid parent;
/* private */
NautilusProgressInfoWidgetPrivate *priv;
} NautilusProgressInfoWidget;
typedef struct {
GtkBoxClass parent_class;
GtkGridClass parent_class;
} NautilusProgressInfoWidgetClass;
GType nautilus_progress_info_widget_get_type (void);
......
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="NautilusProgressInfoWidget" parent="GtkBox">
<template class="NautilusProgressInfoWidget" parent="GtkGrid">
<property name="visible">True</property>
<property name="margin">5</property>
<property name="orientation">vertical</property>
<property name="margin-start">5</property>
<property name="margin-end">5</property>
<child>
<object class="GtkLabel" id="status">
<property name="label">status</property>
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="width-request">400</property>
<property name="wrap">True</property>
<property name="wrap-mode">word-char</property>
<property name="width-request">300</property>
<property name="max-width-chars">30</property>
<property name="ellipsize">middle</property>
<property name="margin-bottom">6</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
<property name="top-attach">0</property>
<property name="left-attach">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box2">
<object class="GtkProgressBar" id="progress_bar">
<property name="visible">True</property>
<property name="valign">center</property>
<property name="pulse-step">0.05</property>
<property name="margin_start">2</property>
<property name="margin-bottom">4</property>
</object>
<packing>
<property name="top-attach">1</property>
<property name="left-attach">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="cancel">
<property name="visible">True</property>
<property name="receives_default">True</property>
<property name="margin_start">20</property>
<property name="valign">center</property>
<style>
<class name="image-button"/>
<class name="nautilus-circular-button"/>
</style>
<child>
<object class="GtkProgressBar" id="progress_bar">
<property name="visible">True</property>
<property name="valign">center</property>
<property name="pulse-step">0.05</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="cancel">
<object class="GtkImage" id="cancel_icon">
<property name="visible">True</property>
<property name="receives_default">True</property>
<property name="margin_start">20</property>
<style>
<class name="image-button"/>
<class name="nautilus-circular-button"/>
</style>
<child>
<object class="GtkImage" id="cancel_icon">
<property name="visible">True</property>
<property name="icon-name">window-close-symbolic</property>
<property name="icon-size">1</property>
</object>
</child>
<property name="icon-name">window-close-symbolic</property>
<property name="icon-size">1</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
<property name="height">3</property>
<property name="top-attach">0</property>
<property name="left-attach">1</property>
</packing>
</child>
<child>
......@@ -78,9 +70,8 @@
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
<property name="top-attach">2</property>
<property name="left-attach">0</property>
</packing>
</child>
</template>
......
/* -*- 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 and 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
......@@ -66,15 +66,41 @@ 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 +122,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 +146,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 +162,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 +209,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 +220,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);