From 483ebae5399d6aa7d63e471ea6000021a4be94fb Mon Sep 17 00:00:00 2001 From: Ettore Perazzoli Date: Thu, 3 May 2001 01:10:46 +0000 Subject: Add interfaces to the shell to handle off-line operation, as well as a first (unfinished/untested) implementation for them. svn path=/trunk/; revision=9653 --- shell/ChangeLog | 20 + shell/Evolution-Offline.idl | 48 +++ shell/Evolution.idl | 1 + shell/Makefile.am | 3 + shell/e-shell-offline-handler.c | 646 +++++++++++++++++++++++++++++++ shell/e-shell-offline-handler.h | 86 ++++ shell/e-shell.c | 105 +++++ shell/e-shell.h | 4 + shell/evolution-shell-component-client.c | 37 ++ shell/evolution-shell-component-client.h | 6 +- 10 files changed, 955 insertions(+), 1 deletion(-) create mode 100644 shell/Evolution-Offline.idl create mode 100644 shell/e-shell-offline-handler.c create mode 100644 shell/e-shell-offline-handler.h diff --git a/shell/ChangeLog b/shell/ChangeLog index 7caa04b1f4..b765ad249b 100644 --- a/shell/ChangeLog +++ b/shell/ChangeLog @@ -1,3 +1,23 @@ +2001-05-02 Ettore Perazzoli + + * e-shell.c: New members `is_offline' and `offline_handler' in + `EShellPrivate'. + (init): Init `is_offline' to %FALSE, `offline_handler' to %NULL. + (e_shell_is_offline): New. + (e_shell_go_online): New. + (e_shell_go_offline): New. + + * e-shell-offline-handler.c: New. + * e-shell-offline-handler.h: New. + + * evolution-shell-component-client.c: New member + `offline_interface' in `EvolutionShellComponentClientPrivate'. + (init): Init to `CORBA_OBJECT_NIL'. + (impl_destroy): Unref/release if not NIL. + (evolution_shell_component_client_get_offline_interface): New. + + * Evolution-Offline.idl: New. + 2001-05-02 Chris Toshok * evolution-shell-component-dnd.c: new file. diff --git a/shell/Evolution-Offline.idl b/shell/Evolution-Offline.idl new file mode 100644 index 0000000000..54bee91023 --- /dev/null +++ b/shell/Evolution-Offline.idl @@ -0,0 +1,48 @@ +/* -*- Mode: IDL; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Interface to allow components to switch between on-line and off-line mode. + * + * Authors: + * Ettore Perazzoli + * + * Copyright (C) 2001 Ximian, Inc. + */ + +#include + +module GNOME { +module Evolution { + +struct Connection { + string hostName; + short portNumber; +}; +typedef sequence ConnectionList; + +interface OfflineProgressListener : Bonobo::Unknown { + /* Update the shell about the progress of going off-line. The + operation is considered completed when the ConnectionList is empty. */ + void updateProgress (in ConnectionList current_active_connections); +}; + +interface Offline : Bonobo::Unknown { + /* Whether the component is currently off-line. */ + attribute boolean isOffline; + + /* 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). */ + void prepareForOffline (out ConnectionList active_connection_list); + + /* Ask the component to go into off-line mode. This always comes after + a `::prepareForOffline' only. */ + void goOffline (in OfflineProgressListener listener); + + /* Tell the component to go into on-line mode. */ + void goOnline (); +}; + +}; +}; diff --git a/shell/Evolution.idl b/shell/Evolution.idl index 3acd6dcca4..b7d0ccc67f 100644 --- a/shell/Evolution.idl +++ b/shell/Evolution.idl @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/shell/Makefile.am b/shell/Makefile.am index c5c55b6d62..efd90a8f8e 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -17,6 +17,7 @@ INCLUDES = \ IDLS = \ Evolution-LocalStorage.idl \ + Evolution-Offline.idl \ Evolution-Session.idl \ Evolution-Shell.idl \ Evolution-ShellComponent.idl \ @@ -102,6 +103,8 @@ evolution_SOURCES = \ e-shell-folder-selection-dialog.h \ e-shell-folder-title-bar.c \ e-shell-folder-title-bar.h \ + e-shell-offline-handler.c \ + e-shell-offline-handler.h \ e-shell-utils.c \ e-shell-utils.h \ e-shell-view-menu.c \ diff --git a/shell/e-shell-offline-handler.c b/shell/e-shell-offline-handler.c new file mode 100644 index 0000000000..1967041a7e --- /dev/null +++ b/shell/e-shell-offline-handler.c @@ -0,0 +1,646 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* e-shell-offline-handler.c + * + * Copyright (C) 2001 Ximian, 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Ettore Perazzoli + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include + +#include + +#include "e-shell-offline-handler.h" + + +#define PARENT_TYPE GTK_TYPE_OBJECT +static GtkObjectClass *parent_class = NULL; + + +/* Private part. */ + +struct _OfflineProgressListenerServant { + POA_GNOME_Evolution_OfflineProgressListener servant; + EShellOfflineHandler *offline_handler; + char *component_id; +}; +typedef struct _OfflineProgressListenerServant OfflineProgressListenerServant; + +struct _ComponentInfo { + /* Component ID. */ + char *id; + + /* The `Evolution::Offline' interface for this component (cached just + to avoid going through the EComponentRegistry all the time). */ + GNOME_Evolution_Offline offline_interface; + + /* The interface and servant for the + `Evolution::OfflineProgressListener' we have to implement to get + notifications about progress of the off-line process. */ + GNOME_Evolution_OfflineProgressListener progress_listener_interface; + OfflineProgressListenerServant *progress_listener_servant; + + /* The current active connections for this component. This is updated + by the component itself through the `::ProgressListener' interface; + when the count reaches zero, the off-line process is considered to + be complete. */ + GNOME_Evolution_ConnectionList *active_connection_list; +}; +typedef struct _ComponentInfo ComponentInfo; + +struct _EShellOfflineHandlerPrivate { + EComponentRegistry *component_registry; + + EShellView *parent_shell_view; + + int num_total_connections; + GHashTable *id_to_component_info; + + gboolean procedure_in_progress : 1; +}; + + +/* Signals. */ + +enum { + OFFLINE_PROCEDURE_STARTED, + OFFLINE_PROCEDURE_FINISHED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + + +/* Implementation for the OfflineProgressListener interface. */ + +static PortableServer_ServantBase__epv OfflineProgressListener_base_epv; +static POA_GNOME_Evolution_OfflineProgressListener__epv OfflineProgressListener_epv; +static POA_GNOME_Evolution_OfflineProgressListener__vepv OfflineProgressListener_vepv; + +static OfflineProgressListenerServant * +progress_listener_servant_new (EShellOfflineHandler *offline_handler, + const char *id) +{ + OfflineProgressListenerServant *servant; + + servant = g_new0 (OfflineProgressListenerServant, 1); + + servant->servant.vepv = &OfflineProgressListener_vepv; + servant->offline_handler = offline_handler; + servant->component_id = g_strdup (id); + + return servant; +} + +static void +progress_listener_servant_free (OfflineProgressListenerServant *servant) +{ + g_free (servant->component_id); + g_free (servant); +} + +static GNOME_Evolution_ConnectionList * +duplicate_connection_list (const GNOME_Evolution_ConnectionList *source) +{ + GNOME_Evolution_ConnectionList *copy; + int i; + + copy = GNOME_Evolution_ConnectionList__alloc (); + + copy->_length = source->_length; + copy->_maximum = source->_length; + + copy->_buffer = CORBA_sequence_GNOME_Evolution_Connection_allocbuf (copy->_maximum); + + for (i = 0; i < source->_length; i++) { + copy->_buffer[i].hostName = CORBA_string_dup (source->_buffer[i].hostName); + copy->_buffer[i].portNumber = source->_buffer[i].portNumber; + } + + return copy; +} + +static void +impl_OfflineProgressListener_updateProgress (PortableServer_Servant servant, + const GNOME_Evolution_ConnectionList *current_active_connections, + CORBA_Environment *ev) +{ + EShellOfflineHandler *offline_handler; + EShellOfflineHandlerPrivate *priv; + ComponentInfo *component_info; + int connection_delta; + const char *component_id; + + component_id = ((OfflineProgressListenerServant *) servant)->component_id; + + offline_handler = ((OfflineProgressListenerServant *) servant)->offline_handler; + priv = offline_handler->priv; + + component_info = g_hash_table_lookup (priv->id_to_component_info, component_id); + g_assert (component_info != NULL); + + connection_delta = component_info->active_connection_list->_length - current_active_connections->_length; + if (connection_delta < 0) { + /* FIXME: Should raise an exception or something? */ + g_warning ("Weird, buggy component increased number of connection when going off-line -- %s", + component_id); + } + + g_assert (priv->num_total_connections >= connection_delta); + priv->num_total_connections -= connection_delta; + + CORBA_free (component_info->active_connection_list); + component_info->active_connection_list = duplicate_connection_list (current_active_connections); + + if (priv->num_total_connections == 0) + gtk_signal_emit (GTK_OBJECT (offline_handler), signals[OFFLINE_PROCEDURE_FINISHED], TRUE); + + /* TODO: update the dialog. */ +} + +static gboolean +create_progress_listener (EShellOfflineHandler *offline_handler, + const char *component_id, + GNOME_Evolution_OfflineProgressListener *objref_return, + OfflineProgressListenerServant **servant_return) +{ + OfflineProgressListenerServant *servant; + CORBA_Environment ev; + + *servant_return = NULL; + *objref_return = CORBA_OBJECT_NIL; + + OfflineProgressListener_base_epv._private = NULL; + OfflineProgressListener_base_epv.finalize = NULL; + OfflineProgressListener_base_epv.default_POA = NULL; + + OfflineProgressListener_epv.updateProgress = impl_OfflineProgressListener_updateProgress; + + OfflineProgressListener_vepv._base_epv = &OfflineProgressListener_base_epv; + OfflineProgressListener_vepv.GNOME_Evolution_OfflineProgressListener_epv = &OfflineProgressListener_epv; + + servant = progress_listener_servant_new (offline_handler, component_id); + + CORBA_exception_init (&ev); + + POA_GNOME_Evolution_OfflineProgressListener__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; + } + + *servant_return = servant; + *objref_return = PortableServer_POA_servant_to_reference (bonobo_poa (), servant, &ev); + + CORBA_exception_free (&ev); + + return TRUE; +} + + +/* ComponentInfo handling. */ + +static ComponentInfo * +component_info_new (const char *id, + const GNOME_Evolution_Offline offline_interface, + GNOME_Evolution_OfflineProgressListener progress_listener_interface, + OfflineProgressListenerServant *progress_listener_servant, + GNOME_Evolution_ConnectionList *active_connection_list) +{ + ComponentInfo *new; + CORBA_Environment ev; + + CORBA_exception_init (&ev); + + new = g_new (ComponentInfo, 1); + new->id = g_strdup (id); + new->offline_interface = CORBA_Object_duplicate (offline_interface, &ev); + new->progress_listener_interface = progress_listener_interface; + new->progress_listener_servant = progress_listener_servant; + new->active_connection_list = active_connection_list; + + CORBA_exception_free (&ev); + + return new; +} + +static void +component_info_free (ComponentInfo *component_info) +{ + CORBA_Environment ev; + + CORBA_exception_init (&ev); + + g_free (component_info->id); + + CORBA_Object_release (component_info->offline_interface, &ev); + + POA_GNOME_Evolution_OfflineProgressListener__fini + ((POA_GNOME_Evolution_OfflineProgressListener *) component_info->progress_listener_servant, &ev); + progress_listener_servant_free (component_info->progress_listener_servant); + + CORBA_Object_release (component_info->progress_listener_interface, &ev); + + CORBA_free (component_info->active_connection_list); + + g_free (component_info); + + CORBA_exception_free (&ev); +} + + +/* Utility functions. */ + +static void +hash_foreach_free_component_info (void *key, + void *value, + void *user_data) +{ + ComponentInfo *component_info; + + component_info = (ComponentInfo *) value; + component_info_free (component_info); +} + + +/* Cancelling the off-line procedure. */ + +static void +cancel_offline (EShellOfflineHandler *offline_handler) +{ + EShellOfflineHandlerPrivate *priv; + GList *component_ids; + GList *p; + + priv = offline_handler->priv; + + component_ids = e_component_registry_get_id_list (priv->component_registry); + + for (p = component_ids; p != NULL; p = p->next) { + EvolutionShellComponentClient *shell_component_client; + GNOME_Evolution_Offline offline_interface; + CORBA_Environment ev; + const char *id; + + id = (const char *) p->data; + shell_component_client = e_component_registry_get_component_by_id (priv->component_registry, id); + + offline_interface = evolution_shell_component_client_get_offline_interface (shell_component_client); + if (offline_interface == CORBA_OBJECT_NIL) + continue; + + CORBA_exception_init (&ev); + + GNOME_Evolution_Offline_goOnline (offline_interface, &ev); + if (ev._major != CORBA_NO_EXCEPTION) + g_warning ("Error putting component `%s' on-line.", id); + + CORBA_exception_free (&ev); + } + + e_free_string_list (component_ids); + + priv->num_total_connections = 0; +} + + +/* Preparing the off-line procedure. */ + +static gboolean +prepare_for_offline (EShellOfflineHandler *offline_handler) +{ + EShellOfflineHandlerPrivate *priv; + GList *component_ids; + GList *p; + gboolean error; + + priv = offline_handler->priv; + + component_ids = e_component_registry_get_id_list (priv->component_registry); + + error = FALSE; + for (p = component_ids; p != NULL; p = p->next) { + EvolutionShellComponentClient *shell_component_client; + GNOME_Evolution_Offline offline_interface; + GNOME_Evolution_OfflineProgressListener progress_listener_interface; + GNOME_Evolution_ConnectionList *active_connection_list; + OfflineProgressListenerServant *progress_listener_servant; + ComponentInfo *component_info; + CORBA_Environment ev; + const char *id; + + id = (const char *) p->data; + shell_component_client = e_component_registry_get_component_by_id (priv->component_registry, id); + offline_interface = evolution_shell_component_client_get_offline_interface (shell_component_client); + if (offline_interface == CORBA_OBJECT_NIL) + continue; + + if (! create_progress_listener (offline_handler, id, + &progress_listener_interface, + &progress_listener_servant)) { + g_warning ("Cannot create the Evolution::OfflineProgressListener interface for `%s'", id); + continue; + } + + CORBA_exception_init (&ev); + + GNOME_Evolution_Offline_prepareForOffline (offline_interface, &active_connection_list, &ev); + if (ev._major != CORBA_NO_EXCEPTION) { + g_warning ("Cannot prepare component component to go offline -- %s", id); + + POA_GNOME_Evolution_OfflineProgressListener__fini + ((POA_GNOME_Evolution_OfflineProgressListener *) progress_listener_servant, &ev); + progress_listener_servant_free (progress_listener_servant); + + CORBA_Object_release (progress_listener_interface, &ev); + + CORBA_exception_free (&ev); + + error = TRUE; + break; + } + + CORBA_exception_free (&ev); + + priv->num_total_connections += active_connection_list->_length; + + component_info = component_info_new (id, + offline_interface, + progress_listener_interface, + progress_listener_servant, + active_connection_list); + + g_assert (g_hash_table_lookup (priv->id_to_component_info, component_info->id) == NULL); + g_hash_table_insert (priv->id_to_component_info, component_info->id, component_info); + } + + /* If an error occurred while preparing, just put all the components + on-line again. */ + if (error) + cancel_offline (offline_handler); + + e_free_string_list (component_ids); + + return ! error; +} + + +/* Finalizing the off-line procedure. */ + +static void +finalize_offline_hash_foreach (void *key, + void *value, + void *user_data) +{ + EShellOfflineHandler *offline_handler; + EShellOfflineHandlerPrivate *priv; + ComponentInfo *component_info; + CORBA_Environment ev; + + offline_handler = E_SHELL_OFFLINE_HANDLER (user_data); + priv = offline_handler->priv; + + component_info = (ComponentInfo *) value; + + CORBA_exception_init (&ev); + + g_print ("Putting component off-line -- %s", component_info->id); + + GNOME_Evolution_Offline_goOffline (component_info->offline_interface, + component_info->progress_listener_interface, + &ev); + + if (ev._major != CORBA_NO_EXCEPTION) { + /* FIXME: Should detect an error and put all the components + on-line again. */ + g_warning ("Error putting component off-line -- %s", component_info->id); + } + + CORBA_exception_free (&ev); +} + +static void +finalize_offline (EShellOfflineHandler *offline_handler) +{ + EShellOfflineHandlerPrivate *priv; + + priv = offline_handler->priv; + + g_hash_table_foreach (priv->id_to_component_info, finalize_offline_hash_foreach, offline_handler); + + if (priv->num_total_connections == 0) { + /* Nothing else to do, we are all set. */ + gtk_signal_emit (GTK_OBJECT (offline_handler), signals[OFFLINE_PROCEDURE_FINISHED], TRUE); + } +} + + +/* The confirmation dialog. */ + +static void +pop_up_confirmation_dialog (EShellOfflineHandler *offline_handler) +{ + EShellOfflineHandlerPrivate *priv; + + priv = offline_handler->priv; + + g_warning ("Should pop up dialog here"); + + finalize_offline (offline_handler); +} + + +/* GtkObject methods. */ + +static void +impl_destroy (GtkObject *object) +{ + EShellOfflineHandler *offline_handler; + EShellOfflineHandlerPrivate *priv; + + offline_handler = E_SHELL_OFFLINE_HANDLER (object); + priv = offline_handler->priv; + + if (priv->component_registry != NULL) + gtk_object_unref (GTK_OBJECT (priv->component_registry)); + + g_hash_table_foreach (priv->id_to_component_info, hash_foreach_free_component_info, NULL); + g_hash_table_destroy (priv->id_to_component_info); + + if (GTK_OBJECT_CLASS (parent_class)->destroy != NULL) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + + +/* GTK type handling. */ + +static void +class_init (EShellOfflineHandlerClass *klass) +{ + GtkObjectClass *object_class; + + object_class = GTK_OBJECT_CLASS (klass); + object_class->destroy = impl_destroy; + + parent_class = gtk_type_class (gtk_object_get_type ()); + + signals[OFFLINE_PROCEDURE_STARTED] + = gtk_signal_new ("offline_procedure_started", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (EShellOfflineHandlerClass, offline_procedure_started), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + + signals[OFFLINE_PROCEDURE_FINISHED] + = gtk_signal_new ("offline_procedure_finished", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (EShellOfflineHandlerClass, offline_procedure_finished), + gtk_marshal_NONE__BOOL, + GTK_TYPE_NONE, 1, + GTK_TYPE_BOOL); + + gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL); +} + + +static void +init (EShellOfflineHandler *shell_offline_handler) +{ + EShellOfflineHandlerPrivate *priv; + + priv = g_new (EShellOfflineHandlerPrivate, 1); + + priv->component_registry = NULL; + priv->parent_shell_view = NULL; + priv->procedure_in_progress = TRUE; + + priv->num_total_connections = 0; + priv->id_to_component_info = g_hash_table_new (g_str_hash, g_str_equal); + + shell_offline_handler->priv = priv; +} + + +/** + * e_shell_offline_handler_construct: + * @offline_handler: A pointer to an EShellOfflineHandler to construct. + * @component_registry: The registry for the components that we want to put + * off-line. + * + * Construct the @offline_handler. + **/ +void +e_shell_offline_handler_construct (EShellOfflineHandler *offline_handler, + EComponentRegistry *component_registry) +{ + EShellOfflineHandlerPrivate *priv; + + g_return_if_fail (offline_handler != NULL); + g_return_if_fail (E_IS_SHELL_OFFLINE_HANDLER (offline_handler)); + g_return_if_fail (component_registry != NULL); + g_return_if_fail (E_IS_COMPONENT_REGISTRY (component_registry)); + + g_assert (priv->component_registry == NULL); + + gtk_object_ref (GTK_OBJECT (component_registry)); + priv->component_registry = component_registry; +} + +/** + * e_shell_offline_handler_new: + * @component_registry: The registry for the components that we want to put + * off-line. + * + * Create a new offline handler. + * + * Return value: A pointer to the newly created EShellOfflineHandler object. + **/ +EShellOfflineHandler * +e_shell_offline_handler_new (EComponentRegistry *component_registry) +{ + EShellOfflineHandler *offline_handler; + + g_return_val_if_fail (component_registry != NULL, NULL); + g_return_val_if_fail (E_IS_COMPONENT_REGISTRY (component_registry), NULL); + + offline_handler = (EShellOfflineHandler *) gtk_type_new (e_shell_offline_handler_get_type ()); + e_shell_offline_handler_construct (offline_handler, component_registry); + + return offline_handler; +} + + +/** + * e_shell_offline_handler_put_components_offline: + * @offline_handler: A pointer to an EShellOfflineHandler object. + * + * Put the components offline. + **/ +void +e_shell_offline_handler_put_components_offline (EShellOfflineHandler *offline_handler, + EShellView *parent_shell_view) +{ + EShellOfflineHandlerPrivate *priv; + + g_return_if_fail (offline_handler != NULL); + g_return_if_fail (E_IS_SHELL_OFFLINE_HANDLER (offline_handler)); + g_return_if_fail (parent_shell_view == NULL || E_IS_SHELL_VIEW (parent_shell_view)); + + priv = offline_handler->priv; + + priv->procedure_in_progress = TRUE; + priv->parent_shell_view = parent_shell_view; + + gtk_signal_emit (GTK_OBJECT (offline_handler), signals[OFFLINE_PROCEDURE_STARTED]); + + if (! prepare_for_offline (offline_handler)) { + /* FIXME: Maybe do something smarter here. */ + g_warning ("Couldn't put components off-line for some internal error"); + gtk_signal_emit (GTK_OBJECT (offline_handler), signals[OFFLINE_PROCEDURE_FINISHED], FALSE); + return; + } + + if (priv->num_total_connections == 0 && priv->parent_shell_view != NULL) + pop_up_confirmation_dialog (offline_handler); + else + finalize_offline (offline_handler); +} + + +E_MAKE_TYPE (e_shell_offline_handler, "EShellOfflineHandler", EShellOfflineHandler, class_init, init, PARENT_TYPE) diff --git a/shell/e-shell-offline-handler.h b/shell/e-shell-offline-handler.h new file mode 100644 index 0000000000..cbb726a057 --- /dev/null +++ b/shell/e-shell-offline-handler.h @@ -0,0 +1,86 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* e-shell-offline-handler.h + * + * Copyright (C) 2001 Ximian, 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Ettore Perazzoli + */ + +#ifndef _E_SHELL_OFFLINE_HANDLER_H_ +#define _E_SHELL_OFFLINE_HANDLER_H_ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "e-component-registry.h" +#include "e-shell-view.h" + +#ifdef __cplusplus +extern "C" { +#pragma } +#endif /* __cplusplus */ + +#define E_TYPE_SHELL_OFFLINE_HANDLER (e_shell_offline_handler_get_type ()) +#define E_SHELL_OFFLINE_HANDLER(obj) (GTK_CHECK_CAST ((obj), E_TYPE_SHELL_OFFLINE_HANDLER, EShellOfflineHandler)) +#define E_SHELL_OFFLINE_HANDLER_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_TYPE_SHELL_OFFLINE_HANDLER, EShellOfflineHandlerClass)) +#define E_IS_SHELL_OFFLINE_HANDLER(obj) (GTK_CHECK_TYPE ((obj), E_TYPE_SHELL_OFFLINE_HANDLER)) +#define E_IS_SHELL_OFFLINE_HANDLER_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), E_TYPE_SHELL_OFFLINE_HANDLER)) + + +typedef struct _EShellOfflineHandler EShellOfflineHandler; +typedef struct _EShellOfflineHandlerPrivate EShellOfflineHandlerPrivate; +typedef struct _EShellOfflineHandlerClass EShellOfflineHandlerClass; + +struct _EShellOfflineHandler { + GtkObject parent; + + EShellOfflineHandlerPrivate *priv; +}; + +struct _EShellOfflineHandlerClass { + GtkObjectClass parent_class; + + /* This signal is emitted when the offline procedure starts, i.e. the + EShellOfflineHanlder starts contacting the components one-by-one + telling them to be prepared to go off-line. */ + void (* offline_procedure_started) (EShellOfflineHandler *offline_handler); + + /* This is emitted when the procedure is finished, and all the + components are all either off-line (@now_offline is %TRUE) or + on-line (@now_offline is %FALSE). */ + void (* offline_procedure_finished) (EShellOfflineHandler *offline_hanlder, + gboolean now_offline); +}; + + +GtkType e_shell_offline_handler_get_type (void); +void e_shell_offline_handler_construct (EShellOfflineHandler *offline_handler, + EComponentRegistry *component_registry); +EShellOfflineHandler *e_shell_offline_handler_new (EComponentRegistry *component_registry); + +void e_shell_offline_handler_put_components_offline (EShellOfflineHandler *offline_handler, + EShellView *parent_shell_view); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _E_SHELL_OFFLINE_HANDLER_H_ */ diff --git a/shell/e-shell.c b/shell/e-shell.c index f9b38e666a..c2c5f39893 100644 --- a/shell/e-shell.c +++ b/shell/e-shell.c @@ -44,6 +44,7 @@ #include "e-local-storage.h" #include "e-shell-constants.h" #include "e-shell-folder-selection-dialog.h" +#include "e-shell-offline-handler.h" #include "e-shell-view.h" #include "e-shortcuts.h" #include "e-storage-set.h" @@ -74,8 +75,15 @@ struct _EShellPrivate { ECorbaStorageRegistry *corba_storage_registry; + /* This object handles going off-line. If the pointer is not NULL, it + means we have a going-off-line process in progress. */ + EShellOfflineHandler *offline_handler; + /* Names for the types of the folders that have maybe crashed. */ GList *crash_type_names; /* char * */ + + /* Whether the shell is off-line or not. */ + guint is_offline : 1; }; @@ -606,6 +614,10 @@ destroy (GtkObject *object) if (priv->corba_storage_registry != NULL) bonobo_object_unref (BONOBO_OBJECT (priv->corba_storage_registry)); + /* FIXME. Maybe we should do something special here. */ + if (priv->offline_handler != NULL) + gtk_object_unref (GTK_OBJECT (priv->offline_handler)); + e_free_string_list (priv->crash_type_names); g_free (priv); @@ -680,7 +692,9 @@ init (EShell *shell) priv->component_registry = NULL; priv->folder_type_registry = NULL; priv->corba_storage_registry = NULL; + priv->offline_handler = NULL; priv->crash_type_names = NULL; + priv->is_offline = FALSE; shell->priv = priv; } @@ -1256,5 +1270,96 @@ e_shell_component_maybe_crashed (EShell *shell, /* FIXME: we should probably re-start the component here */ } + +/** + * e_shell_is_offline: + * @shell: A pointer to an EShell object. + * + * Return whether @shell is working in off-line mode. + * + * Return value: %TRUE if the @shell is working in off-line mode, %FALSE + * otherwise. + **/ +gboolean +e_shell_is_offline (EShell *shell) +{ + g_return_val_if_fail (shell != NULL, FALSE); + g_return_val_if_fail (E_IS_SHELL (shell), FALSE); + + return shell->priv->is_offline; +} + +/** + * e_shell_go_offline: + * @shell: + * @action_view: + * + * Make the shell go into off-line mode. + **/ +void +e_shell_go_offline (EShell *shell, + EShellView *action_view) +{ + EShellPrivate *priv; + + g_return_if_fail (shell != NULL); + g_return_if_fail (E_IS_SHELL (shell)); + g_return_if_fail (action_view != NULL); + g_return_if_fail (action_view == NULL || E_IS_SHELL_VIEW (action_view)); + + priv = shell->priv; +} + +/** + * e_shell_go_online: + * @shell: + * @action_view: + * + * Make the shell go into on-line mode. + **/ +void +e_shell_go_online (EShell *shell, + EShellView *action_view) +{ + EShellPrivate *priv; + GList *component_ids; + GList *p; + + g_return_if_fail (shell != NULL); + g_return_if_fail (E_IS_SHELL (shell)); + g_return_if_fail (action_view == NULL || E_IS_SHELL_VIEW (action_view)); + + priv = shell->priv; + + component_ids = e_component_registry_get_id_list (priv->component_registry); + + for (p = component_ids; p != NULL; p = p->next) { + CORBA_Environment ev; + EvolutionShellComponentClient *client; + GNOME_Evolution_Offline offline_interface; + const char *id; + + id = (const char *) p->data; + client = e_component_registry_get_component_by_id (priv->component_registry, id); + + CORBA_exception_init (&ev); + + offline_interface = evolution_shell_component_client_get_offline_interface (client); + + if (CORBA_Object_is_nil (offline_interface, &ev) || ev._major != CORBA_NO_EXCEPTION) { + CORBA_exception_free (&ev); + continue; + } + + GNOME_Evolution_Offline_goOnline (offline_interface, &ev); + if (ev._major != CORBA_NO_EXCEPTION) + g_warning ("Error putting component `%s' online.", id); + + CORBA_exception_free (&ev); + } + + e_free_string_list (component_ids); +} + E_MAKE_TYPE (e_shell, "EShell", EShell, class_init, init, PARENT_TYPE) diff --git a/shell/e-shell.h b/shell/e-shell.h index f4342988ce..b3226b50d6 100644 --- a/shell/e-shell.h +++ b/shell/e-shell.h @@ -94,6 +94,10 @@ void e_shell_component_maybe_crashed (EShell *shell, const char *type_name, EShellView *shell_view); +gboolean e_shell_is_offline (EShell *shell); +void e_shell_go_offline (EShell *shell, EShellView *action_view); +void e_shell_go_online (EShell *shell, EShellView *action_view); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/shell/evolution-shell-component-client.c b/shell/evolution-shell-component-client.c index 759e4f6ac4..db92d0efaf 100644 --- a/shell/evolution-shell-component-client.c +++ b/shell/evolution-shell-component-client.c @@ -53,6 +53,7 @@ struct _EvolutionShellComponentClientPrivate { GNOME_Evolution_ShellComponentDnd_SourceFolder dnd_source_folder_interface; GNOME_Evolution_ShellComponentDnd_DestinationFolder dnd_destination_folder_interface; + GNOME_Evolution_Offline offline_interface; }; @@ -295,6 +296,11 @@ impl_destroy (GtkObject *object) CORBA_Object_release (priv->dnd_destination_folder_interface, &ev); } + if (priv->offline_interface != CORBA_OBJECT_NIL) { + Bonobo_Unknown_unref (priv->offline_interface, &ev); + CORBA_Object_release (priv->offline_interface, &ev); + } + CORBA_exception_free (&ev); g_free (priv); @@ -329,6 +335,7 @@ init (EvolutionShellComponentClient *shell_component_client) priv->dnd_source_folder_interface = CORBA_OBJECT_NIL; priv->dnd_destination_folder_interface = CORBA_OBJECT_NIL; + priv->offline_interface = CORBA_OBJECT_NIL; shell_component_client->priv = priv; } @@ -452,6 +459,36 @@ evolution_shell_component_client_get_dnd_destination_interface (EvolutionShellCo return interface; } + +/* Querying the offline interface. */ + +GNOME_Evolution_Offline +evolution_shell_component_client_get_offline_interface (EvolutionShellComponentClient *shell_component_client) +{ + EvolutionShellComponentClientPrivate *priv; + GNOME_Evolution_Offline interface; + CORBA_Environment ev; + + priv = shell_component_client->priv; + + if (priv->offline_interface != CORBA_OBJECT_NIL) + return priv->offline_interface; + + CORBA_exception_init (&ev); + + interface = Bonobo_Unknown_queryInterface (bonobo_object_corba_objref (BONOBO_OBJECT (shell_component_client)), + "IDL:GNOME/Evolution/ShellComponent/Offline:1.0", + &ev); + + if (ev._major != CORBA_NO_EXCEPTION) + interface = CORBA_OBJECT_NIL; + + CORBA_exception_free (&ev); + + priv->offline_interface = interface; + return interface; +} + /* Synchronous operations. */ diff --git a/shell/evolution-shell-component-client.h b/shell/evolution-shell-component-client.h index 579d830184..e781a0c74c 100644 --- a/shell/evolution-shell-component-client.h +++ b/shell/evolution-shell-component-client.h @@ -73,9 +73,13 @@ evolution_shell_component_client_get_dnd_source_interface (EvolutionShellCompone GNOME_Evolution_ShellComponentDnd_DestinationFolder evolution_shell_component_client_get_dnd_destination_interface (EvolutionShellComponentClient *shell_component_client); +/* Querying the offline interface. */ +GNOME_Evolution_Offline +evolution_shell_component_client_get_offline_interface (EvolutionShellComponentClient *shell_component_client); + /* Synchronous operations. */ EvolutionShellComponentResult evolution_shell_component_client_set_owner (EvolutionShellComponentClient *shell_component_client, - GNOME_Evolution_Shell shell, + GNOME_Evolution_Shell shell, const char *evolution_homedir); EvolutionShellComponentResult evolution_shell_component_client_unset_owner (EvolutionShellComponentClient *shell_component_client, GNOME_Evolution_Shell shell); -- cgit v1.2.3