diff options
-rw-r--r-- | shell/ChangeLog | 16 | ||||
-rw-r--r-- | shell/Evolution-Offline.idl | 28 | ||||
-rw-r--r-- | shell/Makefile.am | 2 | ||||
-rw-r--r-- | shell/e-shell-offline-handler.c | 15 | ||||
-rw-r--r-- | shell/e-shell-offline-sync.c | 447 | ||||
-rw-r--r-- | shell/e-shell-offline-sync.h | 33 |
6 files changed, 527 insertions, 14 deletions
diff --git a/shell/ChangeLog b/shell/ChangeLog index 14b151ac1e..db0b341117 100644 --- a/shell/ChangeLog +++ b/shell/ChangeLog @@ -1,3 +1,19 @@ +2002-05-14 Ettore Perazzoli <ettore@ximian.com> + + * e-shell-offline-handler.c + (e_shell_offline_handler_put_components_offline): Call + e_shell_offline_sync_all_folders() if no connection is reported + here. + (dialog_handle_ok): Sync all the folders here through + e_shell_offline_sync_all_folders(). + + * e-shell-offline-sync.c: New. + * e-shell-offline-sync.h: New. + + * Evolution-Offline.idl (syncFolder): Make oneway. + (cancelSyncFolder): Likewise. + (SyncFolderProgressListener::reportSuccess): New method. + 2002-05-14 Christopher James Lahey <clahey@ximian.com> * Makefile.am: Added check-empty.xpm, check-filled.xpm, and diff --git a/shell/Evolution-Offline.idl b/shell/Evolution-Offline.idl index 24973df174..97bfd0cc84 100644 --- a/shell/Evolution-Offline.idl +++ b/shell/Evolution-Offline.idl @@ -26,8 +26,12 @@ interface OfflineProgressListener { }; interface SyncFolderProgressListener { - /* Report that syncing is progressed @percent %. */ - void updateProgress (in float percent); + /* Report that syncing has progressed. @progress has to be between 0.0 + and 1.0. */ + void updateProgress (in float progress); + + /* Report that the operation has finished. */ + void reportSuccess (); /* Report an error. */ void reportFailure (in string message); @@ -42,25 +46,29 @@ interface Offline : Bonobo::Unknown { /* Ask the component to prepare to go into off-line mode. The component must return a list of the current active connections. - After this call, the shell is expected to either invoke - `::goOffline()' (actually complete the operation and go off-line) or - `::goOnline()' (operation cancelled). */ + After this call, the shell is expected to: (in order) + + 1. Invoke ::syncFolder for each of the component's folders that + need to be synchronized to disk for offline usage. + + 2. Either invoke ::goOffline (actually complete the operation + and go off-line) or ::goOnline (operation cancelled). + */ void prepareForOffline (out ConnectionList active_connection_list); /* Request the component to sync the specified folder. This has to happen after ::prepareForOffline. */ - void syncFolder (in Folder folder, - in SyncFolderProgressListener listener) + oneway void syncFolder (in Folder folder, + in SyncFolderProgressListener listener) raises (notPrepared); /* Request the component to stop syncing the specified folder. This has to happen after ::syncFolder. */ - void cancelSyncFolder (in string evolution_uri, - in string physical_uri) + oneway void cancelSyncFolder (in Folder folder) raises (notSyncing); /* Ask the component to go into off-line mode. This always comes after - a `::prepareForOffline'. */ + a ::prepareForOffline. */ void goOffline (in OfflineProgressListener listener) raises (notPrepared); diff --git a/shell/Makefile.am b/shell/Makefile.am index 8bbdb5eff8..275d9a54c1 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -169,6 +169,8 @@ evolution_SOURCES = \ e-shell-importer.h \ e-shell-offline-handler.c \ e-shell-offline-handler.h \ + e-shell-offline-sync.c \ + e-shell-offline-sync.h \ e-shell-settings-dialog.c \ e-shell-settings-dialog.h \ e-shell-shared-folder-picker-dialog.c \ diff --git a/shell/e-shell-offline-handler.c b/shell/e-shell-offline-handler.c index 4e77bd1eb9..fc26e71a38 100644 --- a/shell/e-shell-offline-handler.c +++ b/shell/e-shell-offline-handler.c @@ -24,6 +24,10 @@ #include <config.h> #endif +#include "e-shell-offline-handler.h" + +#include "e-shell-offline-sync.h" + #include <gtk/gtktypeutils.h> #include <gtk/gtksignal.h> #include <gtk/gtkwidget.h> @@ -38,8 +42,6 @@ #include <bonobo/bonobo-main.h> -#include "e-shell-offline-handler.h" - #define GLADE_DIALOG_FILE_NAME EVOLUTION_GLADEDIR "/e-active-connection-dialog.glade" @@ -573,6 +575,8 @@ dialog_handle_ok (GnomeDialog *dialog, g_assert (instruction_label != NULL); g_assert (GTK_IS_LABEL (instruction_label)); + e_shell_offline_sync_all_folders (priv->shell, GTK_WINDOW (dialog)); + gtk_label_set_text (GTK_LABEL (instruction_label), _("Closing connections...")); finalize_offline (offline_handler); @@ -826,10 +830,13 @@ e_shell_offline_handler_put_components_offline (EShellOfflineHandler *offline_ha return; } - if (priv->num_total_connections > 0 && priv->parent_shell_view != NULL) + if (priv->num_total_connections > 0 && priv->parent_shell_view != NULL) { pop_up_confirmation_dialog (offline_handler); - else + } else { + e_shell_offline_sync_all_folders (priv->shell, + parent_shell_view ? GTK_WINDOW (parent_shell_view) : NULL); finalize_offline (offline_handler); + } gtk_object_unref (GTK_OBJECT (offline_handler)); } diff --git a/shell/e-shell-offline-sync.c b/shell/e-shell-offline-sync.c new file mode 100644 index 0000000000..b574dcf322 --- /dev/null +++ b/shell/e-shell-offline-sync.c @@ -0,0 +1,447 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* e-shell-offline-sync.c - Sync folders before going into Offline mode. + * + * Copyright (C) 2002 Ximian, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Ettore Perazzoli <ettore@ximian.com> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "e-shell-offline-sync.h" + +#include "e-shell.h" +#include "e-shell-constants.h" + +#include "Evolution.h" + +#include <gal/widgets/e-gui-utils.h> + +#include <gtk/gtklabel.h> +#include <gtk/gtkmain.h> +#include <gtk/gtkprogressbar.h> +#include <gtk/gtksignal.h> + +#include <libgnomeui/gnome-dialog.h> +#include <libgnomeui/gnome-stock.h> +#include <libgnome/gnome-i18n.h> + +#include <bonobo/bonobo-main.h> +#include <bonobo/bonobo-exception.h> + + +typedef struct _SyncData SyncData; +typedef struct _SyncFolderProgressListenerServant SyncFolderProgressListenerServant; + +struct _SyncFolderProgressListenerServant { + POA_GNOME_Evolution_SyncFolderProgressListener servant; + SyncData *sync_data; +}; + +struct _SyncData { + /* The shell. */ + EShell *shell; + + /* The progress dialog. */ + GtkWidget *dialog; + + /* Label in the progress dialog. */ + GtkWidget *label; + + /* Progress bar in the progress dialog. */ + GtkWidget *progress_bar; + + /* Path of the folder currently being synced. */ + char *current_folder_path; + + /* Whether to cancel the current folder's syncing. */ + gboolean cancel; + + /* Whether the current folder is finished syncing; used for async + notification of completion. */ + gboolean current_folder_finished; + + /* CORBA cruft. */ + SyncFolderProgressListenerServant *progress_listener_servant; + GNOME_Evolution_SyncFolderProgressListener progress_listener_objref; +}; + + +/* The progress listener interface. */ + +static PortableServer_ServantBase__epv SyncFolderProgressListener_base_epv; +static POA_GNOME_Evolution_SyncFolderProgressListener__epv SyncFolderProgressListener_epv; +static POA_GNOME_Evolution_SyncFolderProgressListener__vepv SyncFolderProgressListener_vepv; + +static SyncFolderProgressListenerServant * +progress_listener_servant_new (SyncData *sync_data) +{ + SyncFolderProgressListenerServant *servant; + + servant = g_new0 (SyncFolderProgressListenerServant, 1); + + servant->servant.vepv = &SyncFolderProgressListener_vepv; + servant->sync_data = sync_data; + + return servant; +} + +static void +progress_listener_servant_free (SyncFolderProgressListenerServant *servant) +{ + CORBA_Environment ev; + PortableServer_ObjectId *oid; + + CORBA_exception_init (&ev); + + oid = PortableServer_POA_servant_to_id (bonobo_poa (), servant, &ev); + PortableServer_POA_deactivate_object (bonobo_poa (), oid, &ev); + CORBA_free (oid); + + POA_GNOME_Evolution_SyncFolderProgressListener__fini ((POA_GNOME_Evolution_SyncFolderProgressListener *) servant, &ev); + + CORBA_exception_free (&ev); + + g_free (servant); +} + +static void +impl_SyncFolderProgressListener_updateProgress (PortableServer_Servant servant, + const CORBA_float percent, + CORBA_Environment *ev) +{ + SyncData *sync_data; + + sync_data = ((SyncFolderProgressListenerServant *) servant)->sync_data; + gtk_progress_set_percentage (GTK_PROGRESS (sync_data->progress_bar), percent); +} + +static void +impl_SyncFolderProgressListener_reportSuccess (PortableServer_Servant servant, + CORBA_Environment *ev) +{ + SyncData *sync_data; + + sync_data = ((SyncFolderProgressListenerServant *) servant)->sync_data; + sync_data->current_folder_finished = TRUE; +} + +static void +impl_SyncFolderProgressListener_reportFailure (PortableServer_Servant servant, + const CORBA_char *message, + CORBA_Environment *ev) +{ + EFolder *folder; + SyncData *sync_data; + + sync_data = ((SyncFolderProgressListenerServant *) servant)->sync_data; + + folder = e_storage_set_get_folder (e_shell_get_storage_set (sync_data->shell), + sync_data->current_folder_path); + + /* FIXME -- We probably should give the user more of a chance to do + something about it. */ + e_notice (GTK_WINDOW (sync_data->dialog), + _("Error synchronizing \"%s\":\n%s"), e_folder_get_name (folder), message); + + sync_data->current_folder_finished = TRUE; +} + +static gboolean +setup_progress_listener (SyncData *sync_data) +{ + SyncFolderProgressListenerServant *servant; + CORBA_Environment ev; + + SyncFolderProgressListener_base_epv._private = NULL; + SyncFolderProgressListener_base_epv.finalize = NULL; + SyncFolderProgressListener_base_epv.default_POA = NULL; + + SyncFolderProgressListener_epv.updateProgress = impl_SyncFolderProgressListener_updateProgress; + SyncFolderProgressListener_epv.reportSuccess = impl_SyncFolderProgressListener_reportSuccess; + SyncFolderProgressListener_epv.reportFailure = impl_SyncFolderProgressListener_reportFailure; + + SyncFolderProgressListener_vepv._base_epv = &SyncFolderProgressListener_base_epv; + SyncFolderProgressListener_vepv.GNOME_Evolution_SyncFolderProgressListener_epv = &SyncFolderProgressListener_epv; + + servant = progress_listener_servant_new (sync_data); + + CORBA_exception_init (&ev); + + POA_GNOME_Evolution_SyncFolderProgressListener__init ((PortableServer_Servant) servant, &ev); + if (ev._major != CORBA_NO_EXCEPTION) { + g_warning ("Cannot initialize GNOME::Evolution::Offline::ProgressListener"); + progress_listener_servant_free (servant); + CORBA_exception_free (&ev); + return FALSE; + } + + CORBA_free (PortableServer_POA_activate_object (bonobo_poa (), servant, &ev)); + + if (ev._major != CORBA_NO_EXCEPTION) { + g_warning ("Cannot activate GNOME::Evolution::Offline::ProgressListener"); + progress_listener_servant_free (servant); + CORBA_exception_free (&ev); + return FALSE; + } + + sync_data->progress_listener_servant = servant; + sync_data->progress_listener_objref = PortableServer_POA_servant_to_reference (bonobo_poa (), + servant, &ev); + + CORBA_exception_free (&ev); + + return TRUE; +} + + +/* Setting up the progress dialog. */ + +static int +progress_dialog_close_callback (GnomeDialog *dialog, + void *data) +{ + /* Don't allow the dialog to be closed through the window manager close + command. */ + return TRUE; +} + +static void +progress_dialog_clicked_callback (GnomeDialog *dialog, + int button_num, + void *data) +{ + SyncData *sync_data; + + sync_data = (SyncData *) data; + sync_data->cancel = TRUE; +} + +static void +setup_dialog (SyncData *sync_data) +{ + sync_data->dialog = gnome_dialog_new (_("Syncing Folder"), GNOME_STOCK_BUTTON_CANCEL, NULL); + gtk_widget_set_usize (sync_data->dialog, 300, -1); + gtk_window_set_policy (GTK_WINDOW (sync_data->dialog), FALSE, FALSE, FALSE); + + gtk_signal_connect (GTK_OBJECT (sync_data->dialog), "close", + GTK_SIGNAL_FUNC (progress_dialog_close_callback), sync_data); + gtk_signal_connect (GTK_OBJECT (sync_data->dialog), "clicked", + GTK_SIGNAL_FUNC (progress_dialog_clicked_callback), sync_data); + + sync_data->label = gtk_label_new (""); + gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (sync_data->dialog)->vbox), + sync_data->label, FALSE, TRUE, 0); + + sync_data->progress_bar = gtk_progress_bar_new (); + gtk_progress_set_activity_mode (GTK_PROGRESS (sync_data->progress_bar), FALSE); + gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (sync_data->dialog)->vbox), + sync_data->progress_bar, FALSE, TRUE, 0); + + gtk_widget_show_all (sync_data->dialog); +} + + +/* Sync the folder at the specified @folder_path. */ +static void +sync_folder (SyncData *sync_data, + const char *folder_path, + int num, + int total) +{ + EvolutionShellComponentClient *component_client; + EStorageSet *storage_set; + GNOME_Evolution_Folder *corba_folder; + GNOME_Evolution_Offline offline_interface; + CORBA_Environment ev; + EFolder *folder; + char *evolution_uri; + char *msg; + + CORBA_exception_init (&ev); + + /* Retrieve the folder that needs to be synced from the storage set, as + well as the component that should perform the syncing. */ + + storage_set = e_shell_get_storage_set (sync_data->shell); + + folder = e_storage_set_get_folder (storage_set, folder_path); + if (folder == NULL) { + /* This might be a remote folder that is not visible right now, + or is otherwise hidden from the tree somehow. So we just + ignore it, and keep going without signalling any error. */ + return; + } + + component_client = e_folder_type_registry_get_handler_for_type (e_shell_get_folder_type_registry (sync_data->shell), + e_folder_get_type_string (folder)); + + offline_interface = evolution_shell_component_client_get_offline_interface (component_client); + if (offline_interface == CORBA_OBJECT_NIL) { + /* The component doesn't support going off-line, just ignore + this as it's probably a programming error in the + implementation of the component. */ + return; + } + + /* Prepare the CORBA folder to be passed to the component. */ + + corba_folder = GNOME_Evolution_Folder__alloc (); + evolution_uri = g_strconcat (E_SHELL_URI_PREFIX, "/", folder_path, NULL); + e_folder_to_corba (folder, evolution_uri, corba_folder); + g_free (evolution_uri); + + /* Prepare the dialog. */ + + msg = g_strdup_printf (_("Synchronizing \"%s\" (%d of %d) ..."), + e_folder_get_name (folder), num, total); + gtk_label_set (GTK_LABEL (sync_data->label), msg); + g_free (msg); + + gtk_progress_set_value (GTK_PROGRESS (sync_data->progress_bar), 0.0); + + /* Get the data ready. */ + + g_free (sync_data->current_folder_path); + sync_data->current_folder_path = g_strdup (folder_path); + sync_data->current_folder_finished = FALSE; + sync_data->cancel = FALSE; + + /* Tell the component to start syncing. */ + + GNOME_Evolution_Offline_syncFolder (offline_interface, + corba_folder, + sync_data->progress_listener_objref, + &ev); + if (BONOBO_EX (&ev)) { + g_warning ("Error invoking ::syncFolder -- %s", BONOBO_EX_ID (&ev)); + CORBA_free (corba_folder); + CORBA_exception_free (&ev); + return; + } + + /* Wait for the component to signal completion... */ + + while (! sync_data->current_folder_finished && ! sync_data->cancel) { + gtk_main_iteration (); + + /* Check if the user clicked the Cancel button. */ + if (sync_data->cancel) { + gnome_dialog_set_sensitive (GNOME_DIALOG (sync_data->dialog), 0, FALSE); + + GNOME_Evolution_Offline_cancelSyncFolder (offline_interface, corba_folder, &ev); + + while (! sync_data->current_folder_finished) + gtk_main_iteration (); + + break; + } + } + + /* All done. */ + + CORBA_free (corba_folder); + CORBA_exception_free (&ev); +} + +/* Free up the data needed for syncing. */ +static void +cleanup (SyncData *sync_data) +{ + CORBA_Environment ev; + + CORBA_exception_init (&ev); + + if (sync_data->dialog != NULL) + gtk_widget_destroy (sync_data->dialog); + + if (sync_data->progress_listener_servant != NULL) + progress_listener_servant_free (sync_data->progress_listener_servant); + + if (sync_data->progress_listener_objref != CORBA_OBJECT_NIL) + CORBA_Object_release (sync_data->progress_listener_objref, &ev); + + g_free (sync_data); + + CORBA_exception_free (&ev); +} + + +void +e_shell_offline_sync_all_folders (EShell *shell, + GtkWindow *parent_window) +{ + Bonobo_ConfigDatabase config_db; + CORBA_sequence_CORBA_string *folder_path_sequence; + CORBA_any *any; + CORBA_Environment ev; + SyncData *sync_data; + int i; + + config_db = e_shell_get_config_db (shell); + + CORBA_exception_init (&ev); + + /* Get the paths for the folders to sync up. */ + + any = Bonobo_ConfigDatabase_getValue (config_db, "/OfflineFolders/paths", "", &ev); + if (BONOBO_EX (&ev)) { + g_warning ("Cannot get /OfflineFolders/paths from ConfigDatabase -- %s", BONOBO_EX_ID (&ev)); + CORBA_exception_free (&ev); + return; + } + if (! CORBA_TypeCode_equal (any->_type, TC_CORBA_sequence_CORBA_string, &ev) || BONOBO_EX (&ev)) { + g_warning ("/OfflineFolders/Paths in ConfigDatabase is not the expected type"); + CORBA_free (any); + CORBA_exception_free (&ev); + return; + } + + folder_path_sequence = (CORBA_sequence_CORBA_string *) any->_value; + + sync_data = g_new0 (SyncData, 1); + sync_data->shell = shell; + + /* Initialize everything, then go ahead and sync. */ + + if (! setup_progress_listener (sync_data)) + goto done; + + setup_dialog (sync_data); + + for (i = 0; i < folder_path_sequence->_length; i ++) { + sync_folder (sync_data, + folder_path_sequence->_buffer[i], + i + 1, folder_path_sequence->_length); + + /* If the operation has been cancelled, stop syncing and + return. */ + if (sync_data->cancel) { + /* FIXME: Do we want to pop up a dialog asking for + confirmation? */ + break; + } + } + + done: + cleanup (sync_data); + + CORBA_free (folder_path_sequence); + CORBA_exception_free (&ev); +} diff --git a/shell/e-shell-offline-sync.h b/shell/e-shell-offline-sync.h new file mode 100644 index 0000000000..f214938585 --- /dev/null +++ b/shell/e-shell-offline-sync.h @@ -0,0 +1,33 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* e-shell-offline-sync.h - Sync folders before going into Offline mode. + * + * Copyright (C) 2002 Ximian, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Ettore Perazzoli <ettore@ximian.com> + */ + +#ifndef E_SHELL_OFFLINE_SYNC_H +#define E_SHELL_OFFLINE_SYNC_H + +#include "e-shell.h" + +#include <gtk/gtkwidget.h> + +void e_shell_offline_sync_all_folders (EShell *shell, + GtkWindow *widget); + +#endif /* E_SHELL_OFFLINE_SYNC_H */ |