aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEttore Perazzoli <ettore@src.gnome.org>2001-06-23 14:46:13 +0800
committerEttore Perazzoli <ettore@src.gnome.org>2001-06-23 14:46:13 +0800
commitb106b13525048195d99bcbde31e0e535972cbab4 (patch)
tree87b999777762c5bcea16a9430fbb94cc560de8c0
parent72ca61d74b9942040638b628a6f1358e02d23d42 (diff)
downloadgsoc2013-evolution-b106b13525048195d99bcbde31e0e535972cbab4.tar.gz
gsoc2013-evolution-b106b13525048195d99bcbde31e0e535972cbab4.tar.zst
gsoc2013-evolution-b106b13525048195d99bcbde31e0e535972cbab4.zip
Implemented an Evolution::Activity interface for keeping track of
background tasks. The Activity interface is added to the shell, and the status of the various tasks is now displayed in a task bar widget at the bottom of the EShellView. I also implemented a simple test component to test all this stuff. svn path=/trunk/; revision=10434
-rw-r--r--shell/ChangeLog58
-rw-r--r--shell/Evolution-Activity.idl108
-rw-r--r--shell/Evolution-Icon.idl23
-rw-r--r--shell/Evolution.idl2
-rw-r--r--shell/GNOME_Evolution_TestComponent.oafinfo27
-rw-r--r--shell/Makefile.am58
-rw-r--r--shell/e-activity-handler.c459
-rw-r--r--shell/e-activity-handler.h73
-rw-r--r--shell/e-local-folder.c304
-rw-r--r--shell/e-local-folder.h31
-rw-r--r--shell/e-shell-view.c148
-rw-r--r--shell/e-shell-view.h14
-rw-r--r--shell/e-shell.c44
-rw-r--r--shell/e-shell.h1
-rw-r--r--shell/e-task-bar.c154
-rw-r--r--shell/e-task-bar.h72
-rw-r--r--shell/e-task-widget.c190
-rw-r--r--shell/e-task-widget.h75
-rw-r--r--shell/evolution-test-component.c375
19 files changed, 2131 insertions, 85 deletions
diff --git a/shell/ChangeLog b/shell/ChangeLog
index 201c814670..431b87ba5e 100644
--- a/shell/ChangeLog
+++ b/shell/ChangeLog
@@ -1,3 +1,61 @@
+2001-06-23 Ettore Perazzoli <ettore@ximian.com>
+
+ * Makefile.am: Add rules to build the test component and an
+ `install-test-component' target to install it.
+
+ * GNOME_Evolution_TestComponent.oafinfo: New OAF file for the test
+ component.
+
+ * evolution-test-component.c: New component, currently to test the
+ activity interfaces. We will be able use it for testing more
+ things in the future.
+
+ * e-shell.c: New member `activity_handler' in `EShellViewPrivate'.
+ (init): Init here.
+ (class_init): Unref.
+ (setup_activity_interface): New helper function to create an
+ `EActivityHandler' object and aggregate it to the `EShell'.
+ (e_shell_construct): Call here.
+ (e_shell_new_view): Attach the task bar of the newly created view
+ to the activity handler by using
+ `e_activity_handler_attach_task_bar()'.
+
+ * e-shell-view.c: Removed old progress bar code. New members
+ `status_bar' and `task_bar' in EShellViewPrivagte; removed member
+ `progress_bar'.
+ (init): Initialize the new fields; remove initialization for
+ `progress_bar'.
+ (impl_destroy): Handle the new fields here too.
+ (setup_task_bar): New helper function to set up an ETaskBar.
+ (create_status_bar): New helper function to create the status bar
+ with an ETaskBar in it.
+ (ui_engine_add_hint_callback): New callback for the "add_int"
+ BonoboUIEngine signal.
+ (setup_statusbar_hints): New helper function to set up the menu
+ hints for the status bar; connect `ui_engine_add_hint_callback()'
+ here.
+ (setup_widgets): Call `create_status_bar()' and
+ `setup_statusbar_hints()'; pack the status bar in a vbox instead
+ of using the Bonobo status bar stuff, which is kinda broken.
+ (e_shell_view_get_task_bar): New.
+ (get_type_for_folder): No use to get the EFolderTypeRegistry here.
+
+ * Evolution.idl: #include <Evolution-Activity.idl> and
+ <Evolution-Icon.idl>.
+
+ * Evolution-Activity.idl: New.
+
+ * Evolution-Icon.idl: New.
+
+ * e-activity-handler.c: New.
+ * e-activity-handler.h: New.
+
+ * e-task-bar.c: New.
+ * e-task-bar.h: New.
+
+ * e-task-widget.c: New.
+ * e-task-widget.h: New.
+
2001-06-21 Jason Leach <jleach@ximian.com>
* evolution-storage.c (evolution_storage_deregister_on_shell): New
diff --git a/shell/Evolution-Activity.idl b/shell/Evolution-Activity.idl
new file mode 100644
index 0000000000..a2296d568b
--- /dev/null
+++ b/shell/Evolution-Activity.idl
@@ -0,0 +1,108 @@
+/* -*- Mode: IDL; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Activity management for Evolution.
+ *
+ * Authors:
+ * Ettore Perazzoli <ettore@ximian.com>
+ *
+ * Copyright (C) 2000, 2001 Ximian, Inc.
+ */
+
+module GNOME {
+module Evolution {
+
+interface Activity : Bonobo::Unknown {
+ typedef long ActivityID;
+
+ enum DialogType {
+ DIALOG_TYPE_NONE,
+ DIALOG_TYPE_MESSAGE,
+ DIALOG_TYPE_WARNING,
+ DIALOG_TYPE_INPUT,
+ DIALOG_TYPE_ERROR
+ };
+
+ enum DialogAction {
+ DIALOG_ACTION_DISPLAY,
+ DIALOG_ACTION_POSTPONE
+ };
+
+ exception InvalidIcon {};
+ exception IdNotFound {};
+
+ /* Events propagated through the listener:
+
+ - "Clicked": The status widget has been clicked on.
+
+ - "DisplayProgress": Display a nice progress dialog for this
+ operation.
+
+ - "DisplayDialog": The dialog that the component has requested
+ through ::requestDialog() can now be safely displayed.
+
+ - "Cancelled": The user wants the operation to be cancelled.
+ */
+
+ /**
+ * operationStarted:
+ * @component_id: ID of the component starting the operation.
+ * @information: Informative string about the operation being performed.
+ * @cancellable: Whether this operation should be cancellable by
+ * the user from the shell view.
+ * @event_listener: Listener which the events for the activity
+ * widget will be passed to.
+ * @activity_id: A unique ID for the activity, to be used to update the
+ * status of the operation.
+ * @suggest_display: Whether displaying the dialog might be a nice idea.
+ */
+ void operationStarted (in string component_id,
+ in AnimatedIcon icon,
+ in string information,
+ in boolean cancellable,
+ in Bonobo::Listener event_listener,
+ out ActivityID activity_id,
+ out boolean suggest_display)
+ raises (InvalidIcon);
+
+ /**
+ * operationProgressing:
+ * @activity: The unique ID for the activity whose status we want to update.
+ * @information: New informative string. If empty, the informative string
+ * isn't changed.
+ * @progress: A float from 0.0 to 1.0 indicating the status of completion.
+ *
+ * Update the status of the specified @activity.
+ */
+ void operationProgressing (in ActivityID activity,
+ in string information,
+ in float progress)
+ raises (IdNotFound);
+
+ /**
+ * operationFinished:
+ * @activity: The unique ID for the activity that has been completed.
+ *
+ * Report that the specified @activity has been completed. After this
+ * method is invoked, @activity is not considered to be a valid ID
+ * anymore.
+ */
+ void operationFinished (in ActivityID activity);
+
+ /**
+ * requestDialog:
+ *
+ * Inform the shell that the specified @activity requires user input
+ * from a dialog. The returned value specifies whether the shell wants
+ * the dialog to be shown now (%DIALOG_ACTION_DISPLAY) or postponed
+ * (%DIALOG_ACTION_POSTPONE). If the return value is
+ * %DIALOG_ACTION_POSTPONE, the component should wait for the
+ * "DisplayDialog" event before proceeding further. In that case, the
+ * shell will flash the label related to this activity, and emit
+ * "DisplayDialog" through the event source when the user clicks on it.
+ */
+ DialogAction requestDialog (in ActivityID activity,
+ in DialogType dialog_type);
+};
+
+};
+};
diff --git a/shell/Evolution-Icon.idl b/shell/Evolution-Icon.idl
new file mode 100644
index 0000000000..f8a3d66817
--- /dev/null
+++ b/shell/Evolution-Icon.idl
@@ -0,0 +1,23 @@
+/* -*- Mode: IDL; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Icon definition.
+ *
+ * Authors:
+ * Ettore Perazzoli <ettore@ximian.com>
+ *
+ * Copyright (C) 2000, 2001 Ximian, Inc.
+ */
+
+module GNOME {
+module Evolution {
+
+struct Icon {
+ short width, height;
+ boolean hasAlpha;
+ sequence <octet> rgba_data; // Row-by-row, left-to-right, top-to-bottom RGBA bytes
+};
+typedef sequence <Icon> AnimatedIcon;
+
+};
+};
+
diff --git a/shell/Evolution.idl b/shell/Evolution.idl
index b7d0ccc67f..1408699c6b 100644
--- a/shell/Evolution.idl
+++ b/shell/Evolution.idl
@@ -10,6 +10,8 @@
#include <Bonobo.idl>
+#include <Evolution-Icon.idl>
+#include <Evolution-Activity.idl>
#include <Evolution-Session.idl>
#include <Evolution-ShellComponent.idl>
#include <Evolution-ShellComponentDnd.idl>
diff --git a/shell/GNOME_Evolution_TestComponent.oafinfo b/shell/GNOME_Evolution_TestComponent.oafinfo
new file mode 100644
index 0000000000..5a203b51b4
--- /dev/null
+++ b/shell/GNOME_Evolution_TestComponent.oafinfo
@@ -0,0 +1,27 @@
+<oaf_info>
+
+<oaf_server iid="OAFIID:GNOME_Evolution_TestComponent_ShellComponentFactory"
+ type="exe"
+ location="evolution-test-component">
+
+ <oaf_attribute name="repo_ids" type="stringv">
+ <item value="IDL:GNOME/ObjectFactory:1.0"/>
+ </oaf_attribute>
+
+ <oaf_attribute name="description" type="string"
+ value="Factory for the Evolution test component."/>
+</oaf_server>
+
+<oaf_server iid="OAFIID:GNOME_Evolution_TestComponent_ShellComponent"
+ type="factory"
+ location="OAFIID:GNOME_Evolution_TestComponent_ShellComponentFactory">
+
+ <oaf_attribute name="repo_ids" type="stringv">
+ <item value="IDL:GNOME/Evolution/ShellComponent:1.0"/>
+ </oaf_attribute>
+
+ <oaf_attribute name="description" type="string"
+ value="Evolution test component."/>
+</oaf_server>
+
+</oaf_info>
diff --git a/shell/Makefile.am b/shell/Makefile.am
index 2dcbcb2496..08c24b5268 100644
--- a/shell/Makefile.am
+++ b/shell/Makefile.am
@@ -1,6 +1,6 @@
SUBDIRS = glade importer
-INCLUDES = \
+INCLUDES = -O \
-I$(top_srcdir)/widgets \
-I$(top_srcdir)/widgets/misc \
-I$(top_srcdir) \
@@ -16,15 +16,17 @@ INCLUDES = \
# CORBA stuff
IDLS = \
- Evolution-LocalStorage.idl \
- Evolution-Offline.idl \
- Evolution-Session.idl \
- Evolution-Shell.idl \
- Evolution-ShellComponent.idl \
- Evolution-ShellComponentDnd.idl \
- Evolution-ShellView.idl \
- Evolution-Storage.idl \
- Evolution-StorageSetView.idl \
+ Evolution-Activity.idl \
+ Evolution-Icon.idl \
+ Evolution-LocalStorage.idl \
+ Evolution-Offline.idl \
+ Evolution-Session.idl \
+ Evolution-Shell.idl \
+ Evolution-ShellComponent.idl \
+ Evolution-ShellComponentDnd.idl \
+ Evolution-ShellView.idl \
+ Evolution-Storage.idl \
+ Evolution-StorageSetView.idl \
Evolution.idl
IDL_GENERATED = \
@@ -88,6 +90,8 @@ libeshell_la_SOURCES = \
bin_PROGRAMS = evolution
evolution_SOURCES = \
+ e-activity-handler.c \
+ e-activity-handler.h \
e-component-registry.c \
e-component-registry.h \
e-corba-storage-registry.c \
@@ -139,6 +143,10 @@ evolution_SOURCES = \
e-storage-set.h \
e-storage.c \
e-storage.h \
+ e-task-bar.c \
+ e-task-bar.h \
+ e-task-widget.c \
+ e-task-widget.h \
evolution-storage-set-view.c \
evolution-storage-set-view.h \
evolution-storage-set-view-factory.c \
@@ -155,6 +163,29 @@ evolution_LDADD = \
$(GTKHTML_LIBS) \
$(BONOBO_GNOME_LIBS)
+# Test component
+
+noinst_PROGRAMS = \
+ evolution-test-component
+
+evolution_test_component_SOURCES = \
+ evolution-test-component.c
+
+evolution_test_component_LDADD = \
+ libeshell.la \
+ $(EXTRA_GNOME_LIBS) \
+ $(GNOME_PRINT_LIBS) \
+ $(GTKHTML_LIBS) \
+ $(BONOBO_GNOME_LIBS)
+
+install-test-component: evolution-test-component
+ $(mkinstalldirs) $(DESTDIR)$(bindir)
+ $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) evolution-test-component $(DESTDIR)$(bindir)/evolution-test-component
+ $(mkinstalldirs) $(DESTDIR)$(oafdir)
+ $(INSTALL_DATA) $(srcdir)/GNOME_Evolution_TestComponent.oafinfo $(DESTDIR)$(oafdir)/GNOME_Evolution_TestComponent.oafinfo
+
+# Misc stuff
+
oafdir = $(datadir)/oaf
oaf_in_files = GNOME_Evolution_Shell.oaf.in
oaf_DATA = $(oaf_in_files:.oaf.in=.oaf)
@@ -164,7 +195,12 @@ etspec_DATA = e-storage-set-view.etspec
@XML_I18N_MERGE_OAF_RULE@
-EXTRA_DIST = $(IDLS) $(oaf_in_files) $(oaf_DATA) $(etspec_DATA)
+EXTRA_DIST = \
+ $(IDLS) \
+ $(oaf_in_files) \
+ $(oaf_DATA) \
+ $(etspec_DATA) \
+ GNOME_Evolution_TestComponent.oafinfo
# Purify support
diff --git a/shell/e-activity-handler.c b/shell/e-activity-handler.c
new file mode 100644
index 0000000000..4ae3e0ccde
--- /dev/null
+++ b/shell/e-activity-handler.c
@@ -0,0 +1,459 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-activity-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 <ettore@ximian.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-activity-handler.h"
+
+#include <gtk/gtksignal.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include <gal/util/e-util.h>
+
+
+#define PARENT_TYPE bonobo_x_object_get_type ()
+static BonoboXObjectClass *parent_class = NULL;
+
+
+#define ICON_SIZE 16
+
+
+struct _ActivityInfo {
+ GdkPixbuf *icon_pixbuf;
+ GNOME_Evolution_Activity_ActivityID id;
+ CORBA_char *information;
+ CORBA_boolean cancellable;
+ Bonobo_Listener event_listener;
+ CORBA_float progress;
+};
+typedef struct _ActivityInfo ActivityInfo;
+
+struct _EActivityHandlerPrivate {
+ GNOME_Evolution_Activity_ActivityID next_activity_id;
+ GList *activity_infos;
+ GSList *task_bars;
+};
+
+
+/* Utility functions. */
+
+static GdkPixbuf *
+create_gdk_pixbuf_from_corba_icon (const GNOME_Evolution_Icon *icon)
+{
+ GdkPixbuf *pixbuf;
+ GdkPixbuf *scaled_pixbuf;
+ unsigned char *p;
+ int src_offset;
+ int i, j;
+ int rowstride;
+ int total_width;
+
+ pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, icon->hasAlpha, 8, icon->width, icon->height);
+
+ if (icon->hasAlpha)
+ total_width = 4 * icon->width;
+ else
+ total_width = 3 * icon->width;
+
+ rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+ src_offset = 0;
+ p = gdk_pixbuf_get_pixels (pixbuf);
+
+ for (i = 0; i < icon->height; i++) {
+ for (j = 0; j < total_width; j++)
+ p[j] = icon->rgba_data._buffer[src_offset ++];
+ p += rowstride;
+ }
+
+ if (icon->width == ICON_SIZE && icon->height == ICON_SIZE)
+ return pixbuf;
+
+ scaled_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, icon->hasAlpha, 8, ICON_SIZE, ICON_SIZE);
+ gdk_pixbuf_scale (pixbuf, scaled_pixbuf,
+ 0, 0, ICON_SIZE, ICON_SIZE,
+ 0, 0, (double) ICON_SIZE / icon->width, (double) ICON_SIZE / icon->height,
+ GDK_INTERP_HYPER);
+
+ gdk_pixbuf_unref (pixbuf);
+
+ return scaled_pixbuf;
+}
+
+static unsigned int
+get_new_activity_id (EActivityHandler *activity_handler)
+{
+ EActivityHandlerPrivate *priv;
+
+ priv = activity_handler->priv;
+
+ return priv->next_activity_id ++;
+}
+
+static GList *
+lookup_activity (GList *list,
+ GNOME_Evolution_Activity_ActivityID activity_id,
+ int *order_number_return)
+{
+ GList *p;
+ int i;
+
+ for (p = list, i = 0; p != NULL; p = p->next, i ++) {
+ ActivityInfo *activity_info;
+
+ activity_info = (ActivityInfo *) p->data;
+ if (activity_info->id == activity_id) {
+ *order_number_return = i;
+ return p;
+ }
+ }
+
+ *order_number_return = -1;
+ return NULL;
+}
+
+
+/* Creating and destroying ActivityInfos. */
+
+static ActivityInfo *
+activity_info_new (GNOME_Evolution_Activity_ActivityID id,
+ GdkPixbuf *icon,
+ const CORBA_char *information,
+ CORBA_boolean cancellable,
+ const Bonobo_Listener event_listener)
+{
+ ActivityInfo *info;
+ CORBA_Environment ev;
+
+ CORBA_exception_init (&ev);
+
+ info = g_new (ActivityInfo, 1);
+ info->id = id;
+ info->icon_pixbuf = gdk_pixbuf_ref (icon);
+ info->information = CORBA_string_dup (information);
+ info->cancellable = cancellable;
+ info->event_listener = CORBA_Object_duplicate (event_listener, &ev);
+ info->progress = -1.0; /* (Unknown) */
+
+ CORBA_exception_free (&ev);
+
+ return info;
+}
+
+static void
+activity_info_free (ActivityInfo *info)
+{
+ CORBA_Environment ev;
+
+ CORBA_exception_init (&ev);
+
+ CORBA_free (info->information);
+ CORBA_Object_release (info->event_listener, &ev);
+
+ g_free (info);
+
+ CORBA_exception_free (&ev);
+}
+
+static ETaskWidget *
+task_widget_new_from_activity_info (ActivityInfo *activity_info)
+{
+ GtkWidget *widget;
+
+ widget = e_task_widget_new (activity_info->icon_pixbuf, activity_info->information);
+ gtk_widget_show (widget);
+
+ return E_TASK_WIDGET (widget);
+}
+
+
+/* Task Bar handling. */
+
+static void
+setup_task_bar (EActivityHandler *activity_handler,
+ ETaskBar *task_bar)
+{
+ EActivityHandlerPrivate *priv;
+ GList *p;
+
+ priv = activity_handler->priv;
+
+ for (p = g_list_last (priv->activity_infos); p != NULL; p = p->prev) {
+ e_task_bar_prepend_task (task_bar,
+ task_widget_new_from_activity_info ((ActivityInfo *) p->data));
+ }
+}
+
+static void
+task_bar_destroy_callback (GtkObject *task_bar_object,
+ void *data)
+{
+ ETaskBar *task_bar;
+ EActivityHandler *activity_handler;
+ EActivityHandlerPrivate *priv;
+
+ task_bar = E_TASK_BAR (task_bar_object);
+
+ activity_handler = E_ACTIVITY_HANDLER (data);
+ priv = activity_handler->priv;
+
+ priv->task_bars = g_slist_remove (priv->task_bars, task_bar);
+}
+
+
+/* GtkObject methods. */
+
+static void
+impl_destroy (GtkObject *object)
+{
+ EActivityHandler *handler;
+ EActivityHandlerPrivate *priv;
+ GList *p;
+
+ handler = E_ACTIVITY_HANDLER (object);
+ priv = handler->priv;
+
+ for (p = priv->activity_infos; p != NULL; p = p->next) {
+ ActivityInfo *info;
+
+ info = (ActivityInfo *) p->data;
+ activity_info_free (info);
+ }
+
+ g_free (priv);
+
+ (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
+
+
+/* CORBA methods. */
+
+static void
+impl_operationStarted (PortableServer_Servant servant,
+ const CORBA_char *component_id,
+ const GNOME_Evolution_AnimatedIcon *icon,
+ const CORBA_char *information,
+ const CORBA_boolean cancellable,
+ const Bonobo_Listener event_listener,
+ GNOME_Evolution_Activity_ActivityID *activity_id_return,
+ CORBA_boolean *suggest_display_return,
+ CORBA_Environment *ev)
+{
+ EActivityHandler *activity_handler;
+ EActivityHandlerPrivate *priv;
+ ActivityInfo *activity_info;
+ GdkPixbuf *icon_pixbuf;
+ unsigned int activity_id;
+ GSList *p;
+
+ activity_handler = E_ACTIVITY_HANDLER (bonobo_object_from_servant (servant));
+ priv = activity_handler->priv;
+
+ if (icon->_length == 0) {
+ CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+ ex_GNOME_Evolution_Activity_InvalidIcon, NULL);
+ return;
+ }
+
+ if (icon->_length > 1)
+ g_warning ("Animated icons are not supported for activities (yet).");
+
+ icon_pixbuf = create_gdk_pixbuf_from_corba_icon (icon->_buffer);
+
+ activity_id = get_new_activity_id (activity_handler);
+
+ activity_info = activity_info_new (activity_id, icon_pixbuf, information, cancellable, event_listener);
+
+ for (p = priv->task_bars; p != NULL; p = p->next)
+ e_task_bar_prepend_task (E_TASK_BAR (p->data),
+ task_widget_new_from_activity_info (activity_info));
+
+ priv->activity_infos = g_list_prepend (priv->activity_infos, activity_info);
+
+ *activity_id_return = activity_id;
+}
+
+static void
+impl_operationProgressing (PortableServer_Servant servant,
+ const GNOME_Evolution_Activity_ActivityID activity_id,
+ const CORBA_char *information,
+ const CORBA_float progress,
+ CORBA_Environment *ev)
+{
+ EActivityHandler *activity_handler;
+ EActivityHandlerPrivate *priv;
+ ActivityInfo *activity_info;
+ GList *p;
+ GSList *sp;
+ int order_number;
+
+ /* FIXME? The complexity in this function sucks. */
+
+ activity_handler = E_ACTIVITY_HANDLER (bonobo_object_from_servant (servant));
+ priv = activity_handler->priv;
+
+ p = lookup_activity (priv->activity_infos, activity_id, &order_number);
+ if (p == NULL) {
+ CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+ ex_GNOME_Evolution_Activity_IdNotFound, NULL);
+ return;
+ }
+
+ activity_info = (ActivityInfo *) p->data;
+
+ CORBA_free (activity_info->information);
+ activity_info->information = CORBA_string_dup (information);
+
+ activity_info->progress = progress;
+
+ for (sp = priv->task_bars; sp != NULL; sp = sp->next) {
+ ETaskBar *task_bar;
+ ETaskWidget *task_widget;
+
+ task_bar = E_TASK_BAR (sp->data);
+ task_widget = e_task_bar_get_task_widget (task_bar, order_number);
+
+ e_task_widget_update (task_widget, information, progress);
+ }
+}
+
+static void
+impl_operationFinished (PortableServer_Servant servant,
+ const GNOME_Evolution_Activity_ActivityID activity_id,
+ CORBA_Environment *ev)
+{
+ EActivityHandler *activity_handler;
+ EActivityHandlerPrivate *priv;
+ GList *p;
+ GSList *sp;
+ int order_number;
+
+ activity_handler = E_ACTIVITY_HANDLER (bonobo_object_from_servant (servant));
+ priv = activity_handler->priv;
+
+ p = lookup_activity (priv->activity_infos, activity_id, &order_number);
+
+ activity_info_free ((ActivityInfo *) p->data);
+ priv->activity_infos = g_list_remove_link (priv->activity_infos, p);
+
+ for (sp = priv->task_bars; sp != NULL; sp = sp->next) {
+ ETaskBar *task_bar;
+
+ task_bar = E_TASK_BAR (sp->data);
+ e_task_bar_remove_task (task_bar, order_number);
+ }
+}
+
+static GNOME_Evolution_Activity_DialogAction
+impl_requestDialog (PortableServer_Servant servant,
+ const GNOME_Evolution_Activity_ActivityID activity_id,
+ const GNOME_Evolution_Activity_DialogType dialog_type,
+ CORBA_Environment *ev)
+{
+ /* FIXME implement. */
+ g_warning ("Evolution::Activity::requestDialog not implemented");
+
+ return GNOME_Evolution_Activity_DIALOG_ACTION_DISPLAY;
+}
+
+
+/* GTK+ type stuff. */
+
+static void
+class_init (GtkObjectClass *object_class)
+{
+ EActivityHandlerClass *handler_class;
+
+ parent_class = gtk_type_class (PARENT_TYPE);
+
+ object_class->destroy = impl_destroy;
+
+ handler_class = E_ACTIVITY_HANDLER_CLASS (object_class);
+ handler_class->epv.operationStarted = impl_operationStarted;
+ handler_class->epv.operationProgressing = impl_operationProgressing;
+ handler_class->epv.operationFinished = impl_operationFinished;
+ handler_class->epv.requestDialog = impl_requestDialog;
+}
+
+static void
+init (EActivityHandler *activity_handler)
+{
+ EActivityHandlerPrivate *priv;
+
+ priv = g_new (EActivityHandlerPrivate, 1);
+ priv->next_activity_id = 0;
+ priv->activity_infos = NULL;
+ priv->task_bars = NULL;
+
+ activity_handler->priv = priv;
+}
+
+
+void
+e_activity_handler_construct (EActivityHandler *activity_handler)
+{
+ g_return_if_fail (activity_handler != NULL);
+ g_return_if_fail (E_IS_ACTIVITY_HANDLER (activity_handler));
+
+ /* Nothing to do here. */
+}
+
+EActivityHandler *
+e_activity_handler_new (void)
+{
+ EActivityHandler *activity_handler;
+
+ activity_handler = gtk_type_new (e_activity_handler_get_type ());
+ e_activity_handler_construct (activity_handler);
+
+ return activity_handler;
+}
+
+
+void
+e_activity_handler_attach_task_bar (EActivityHandler *activity_handler,
+ ETaskBar *task_bar)
+{
+ EActivityHandlerPrivate *priv;
+
+ g_return_if_fail (activity_handler != NULL);
+ g_return_if_fail (E_IS_ACTIVITY_HANDLER (activity_handler));
+ g_return_if_fail (task_bar != NULL);
+ g_return_if_fail (E_IS_TASK_BAR (task_bar));
+
+ priv = activity_handler->priv;
+
+ gtk_signal_connect_while_alive (GTK_OBJECT (task_bar), "destroy",
+ GTK_SIGNAL_FUNC (task_bar_destroy_callback), activity_handler,
+ GTK_OBJECT (activity_handler));
+
+ priv->task_bars = g_slist_prepend (priv->task_bars, task_bar);
+
+ setup_task_bar (activity_handler, task_bar);
+}
+
+
+E_MAKE_X_TYPE (e_activity_handler, "EActivityHandler", EActivityHandler, class_init, init, PARENT_TYPE,
+ POA_GNOME_Evolution_Activity__init,
+ GTK_STRUCT_OFFSET (EActivityHandlerClass, epv))
diff --git a/shell/e-activity-handler.h b/shell/e-activity-handler.h
new file mode 100644
index 0000000000..0a131bc5e9
--- /dev/null
+++ b/shell/e-activity-handler.h
@@ -0,0 +1,73 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-activity-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 <ettore@ximian.com>
+ */
+
+#ifndef _E_ACTIVITY_HANDLER_H_
+#define _E_ACTIVITY_HANDLER_H_
+
+#include "Evolution.h"
+
+#include "e-task-bar.h"
+
+#include <bonobo/bonobo-xobject.h>
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+#define E_TYPE_ACTIVITY_HANDLER (e_activity_handler_get_type ())
+#define E_ACTIVITY_HANDLER(obj) (GTK_CHECK_CAST ((obj), E_TYPE_ACTIVITY_HANDLER, EActivityHandler))
+#define E_ACTIVITY_HANDLER_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_TYPE_ACTIVITY_HANDLER, EActivityHandlerClass))
+#define E_IS_ACTIVITY_HANDLER(obj) (GTK_CHECK_TYPE ((obj), E_TYPE_ACTIVITY_HANDLER))
+#define E_IS_ACTIVITY_HANDLER_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), E_TYPE_ACTIVITY_HANDLER))
+
+
+typedef struct _EActivityHandler EActivityHandler;
+typedef struct _EActivityHandlerPrivate EActivityHandlerPrivate;
+typedef struct _EActivityHandlerClass EActivityHandlerClass;
+
+struct _EActivityHandler {
+ BonoboXObject parent;
+
+ EActivityHandlerPrivate *priv;
+};
+
+struct _EActivityHandlerClass {
+ BonoboXObjectClass parent_class;
+
+ POA_GNOME_Evolution_Activity__epv epv;
+};
+
+
+GtkType e_activity_handler_get_type (void);
+void e_activity_handler_construct (EActivityHandler *activity_hanlder);
+EActivityHandler *e_activity_handler_new (void);
+
+void e_activity_handler_attach_task_bar (EActivityHandler *activity_hanlder,
+ ETaskBar *task_bar);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _E_ACTIVITY_HANDLER_H_ */
diff --git a/shell/e-local-folder.c b/shell/e-local-folder.c
index 73ae6734da..21f6e6e1d8 100644
--- a/shell/e-local-folder.c
+++ b/shell/e-local-folder.c
@@ -60,11 +60,142 @@ static EFolderClass *parent_class = NULL;
#define URI_PREFIX "file://"
#define URI_PREFIX_LEN 7
+/* This provides the name and the description for a specific locale. */
+struct _I18nInfo {
+ char *language_id;
+ char *name;
+ char *description;
+};
+typedef struct _I18nInfo I18nInfo;
+
struct _ELocalFolderPrivate {
- int dummy;
+ GHashTable *language_id_to_i18n_info;
};
+/* Locale information. */
+
+static char *global_language_id = NULL;
+
+
+/* I18nInfo handling. */
+
+static I18nInfo *
+i18n_info_new (const char *language_id,
+ const char *name,
+ const char *description)
+{
+ I18nInfo *info;
+
+ info = g_new (I18nInfo, 1);
+ info->language_id = g_strdup (language_id);
+ info->name = g_strdup (name);
+ info->description = g_strdup (description);
+
+ return info;
+}
+
+static void
+i18n_info_free (I18nInfo *info)
+{
+ g_free (info->language_id);
+ g_free (info->name);
+ g_free (info->description);
+
+ g_free (info);
+}
+
+
+/* Language ID -> I18nInfo hash table handling. */
+
+static void
+add_i18n_info_to_hash (GHashTable *language_id_to_i18n_info_hash,
+ I18nInfo *i18n_info)
+{
+ I18nInfo *existing_i18n_info;
+
+ existing_i18n_info = (I18nInfo *) g_hash_table_lookup (language_id_to_i18n_info_hash,
+ i18n_info->language_id);
+ if (existing_i18n_info != NULL) {
+ g_hash_table_remove (language_id_to_i18n_info_hash,
+ i18n_info->language_id);
+ i18n_info_free (existing_i18n_info);
+ }
+
+ g_hash_table_insert (language_id_to_i18n_info_hash, i18n_info->language_id, i18n_info);
+}
+
+static void
+language_id_to_i18n_info_hash_foreach_free (void *key,
+ void *value,
+ void *data)
+{
+ i18n_info_free ((I18nInfo *) value);
+}
+
+static I18nInfo *
+get_i18n_info_for_language (ELocalFolder *local_folder,
+ const char *language_id)
+{
+ ELocalFolderPrivate *priv;
+ I18nInfo *i18n_info;
+
+ priv = local_folder->priv;
+
+ if (language_id == NULL)
+ language_id = global_language_id;
+
+ i18n_info = g_hash_table_lookup (priv->language_id_to_i18n_info, language_id);
+
+ /* For locale info like `en_UK@yadda', we try to use `en' as a backup. */
+ /* Note: this is exactly the same thing that gnome-config does with the
+ I18N value handling. I hope it works. */
+ if (i18n_info == NULL) {
+ size_t n;
+
+ n = strcspn (language_id, "@_");
+ if (language_id[n] != '\0') {
+ char *simplified_language_id;
+
+ simplified_language_id = g_strndup (language_id, n);
+ i18n_info = g_hash_table_lookup (priv->language_id_to_i18n_info,
+ simplified_language_id);
+ }
+ }
+
+ return i18n_info;
+}
+
+
+/* Locale handling. */
+
+static void
+setup_global_language_id (void)
+{
+ /* FIXME: Implement. */
+ global_language_id = "C";
+}
+
+/* Update the EFolder attributes according to the current locale. */
+static void
+update_for_global_locale (ELocalFolder *local_folder)
+{
+ I18nInfo *i18n_info;
+
+ i18n_info = get_i18n_info_for_language (local_folder, NULL);
+
+ if (i18n_info == NULL)
+ i18n_info = get_i18n_info_for_language (local_folder, "C");
+
+ g_assert (i18n_info != NULL);
+
+ e_folder_set_name (E_FOLDER (local_folder), i18n_info->name);
+ e_folder_set_description (E_FOLDER (local_folder), i18n_info->description);
+}
+
+
+/* XML tree handling. */
+
static char *
get_string_value (xmlNode *node,
const char *name)
@@ -81,13 +212,51 @@ get_string_value (xmlNode *node,
if (p == NULL)
return NULL;
- xml_string = xmlNodeListGetString (node->doc, p, 1);
+ xml_string = xmlNodeListGetString (node->doc, p, TRUE);
retval = g_strdup ((char *) xml_string);
xmlFree (xml_string);
return retval;
}
+static void
+retrieve_info_item (ELocalFolder *local_folder,
+ xmlNode *node)
+{
+ xmlChar *lang;
+ char *name;
+ char *description;
+
+ lang = xmlGetProp (node, "lang");
+ name = get_string_value (node, "name");
+ description = get_string_value (node, "description");
+
+ if (lang == NULL) {
+ e_local_folder_add_i18n_info (local_folder, "C", name, description);
+ } else {
+ e_local_folder_add_i18n_info (local_folder, lang, name, description);
+ xmlFree (lang);
+ }
+
+ g_free (name);
+ g_free (description);
+}
+
+static void
+retrieve_info (ELocalFolder *local_folder,
+ xmlNode *root_xml_node)
+{
+ ELocalFolderPrivate *priv;
+ xmlNode *p;
+
+ priv = local_folder->priv;
+
+ for (p = root_xml_node->childs; p != NULL; p = p->next) {
+ if (xmlStrcmp (p->name, "info") == 0)
+ retrieve_info_item (local_folder, p);
+ }
+}
+
static gboolean
construct_loading_metadata (ELocalFolder *local_folder,
const char *path)
@@ -96,7 +265,6 @@ construct_loading_metadata (ELocalFolder *local_folder,
xmlDoc *doc;
xmlNode *root;
char *type;
- char *description;
char *metadata_path;
char *physical_uri;
@@ -118,12 +286,16 @@ construct_loading_metadata (ELocalFolder *local_folder,
}
type = get_string_value (root, "type");
- description = get_string_value (root, "description");
-
- e_folder_construct (folder, g_basename (path), type, description);
+ if (type == NULL) {
+ g_free (metadata_path);
+ xmlFreeDoc (doc);
+ return FALSE;
+ }
+ e_local_folder_construct (local_folder, g_basename (path), type, NULL);
g_free (type);
- g_free (description);
+
+ retrieve_info (local_folder, root);
xmlFreeDoc (doc);
@@ -180,7 +352,18 @@ save_metadata (ELocalFolder *local_folder)
static void
destroy (GtkObject *object)
{
- /* No ELocalFolder-specific data to free. */
+ ELocalFolder *local_folder;
+ ELocalFolderPrivate *priv;
+
+ local_folder = E_LOCAL_FOLDER (object);
+ priv = local_folder->priv;
+
+ g_hash_table_foreach (priv->language_id_to_i18n_info,
+ language_id_to_i18n_info_hash_foreach_free,
+ NULL);
+ g_hash_table_destroy (priv->language_id_to_i18n_info);
+
+ g_free (priv);
(* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
}
@@ -195,11 +378,19 @@ class_init (ELocalFolderClass *klass)
object_class = GTK_OBJECT_CLASS (klass);
object_class->destroy = destroy;
+
+ setup_global_language_id ();
}
static void
init (ELocalFolder *local_folder)
{
+ ELocalFolderPrivate *priv;
+
+ priv = g_new (ELocalFolderPrivate, 1);
+ priv->language_id_to_i18n_info = g_hash_table_new (g_str_hash, g_str_equal);
+
+ local_folder->priv = priv;
}
@@ -209,12 +400,20 @@ e_local_folder_construct (ELocalFolder *local_folder,
const char *type,
const char *description)
{
+ ELocalFolderPrivate *priv;
+ I18nInfo *i18n_info;
+
g_return_if_fail (local_folder != NULL);
g_return_if_fail (E_IS_LOCAL_FOLDER (local_folder));
g_return_if_fail (name != NULL);
g_return_if_fail (type != NULL);
+ priv = local_folder->priv;
+
e_folder_construct (E_FOLDER (local_folder), name, type, description);
+
+ i18n_info = i18n_info_new ("C", name, description);
+ add_i18n_info_to_hash (priv->language_id_to_i18n_info, i18n_info);
}
EFolder *
@@ -262,4 +461,93 @@ e_local_folder_save (ELocalFolder *local_folder)
}
+/**
+ * e_local_folder_add_i18n_info:
+ * @local_folder: A pointer to an ELocalFolder object
+ * @language_id: An I1I8N locale ID
+ * @name: Name for @local_folder in the specified @language_id
+ * @description: Description for @local_folder in the specified @language_id
+ *
+ * Set the @name and @description for the specified @language_id locale.
+ **/
+void
+e_local_folder_add_i18n_info (ELocalFolder *local_folder,
+ const char *language_id,
+ const char *name,
+ const char *description)
+{
+ ELocalFolderPrivate *priv;
+ I18nInfo *info;
+
+ g_return_if_fail (local_folder != NULL);
+ g_return_if_fail (E_IS_LOCAL_FOLDER (local_folder));
+ g_return_if_fail (language_id != NULL);
+ g_return_if_fail (name != NULL || description != NULL);
+
+ priv = local_folder->priv;
+
+ info = i18n_info_new (language_id, name, description);
+ add_i18n_info_to_hash (priv->language_id_to_i18n_info, info);
+
+ update_for_global_locale (local_folder);
+}
+
+/**
+ * e_local_folder_get_i18n_info:
+ * @local_folder: A pointer to an ELocalFolder object
+ * @language_id: The ID of the language whose locale we want to retrieve name
+ * and description for
+ * @language_id_return: The actual locale ID that the name and description are
+ * saved under (e.g. if you ask for an "en_UK@yadda", we might give you the
+ * info for just "en")
+ * @name_return: A pointer to a pointer that will point to the i18nized name on
+ * return. Can be NULL.
+ * @description_return: A pointer to a pointer that will point to the i18n
+ * description on return. Can be NULL.
+ *
+ * Retrieve the name and description for @local_folder in the specified locale.
+ *
+ * Return value: %TRUE if some info is found for that @language_id, %FALSE
+ * otherwise.
+ **/
+gboolean
+e_local_folder_get_i18n_info (ELocalFolder *local_folder,
+ const char *language_id,
+ const char **language_id_return,
+ const char **name_return,
+ const char **description_return)
+{
+ ELocalFolderPrivate *priv;
+ I18nInfo *i18n_info;
+
+ g_return_val_if_fail (local_folder != NULL, FALSE);
+ g_return_val_if_fail (E_IS_LOCAL_FOLDER (local_folder), FALSE);
+ g_return_val_if_fail (language_id != NULL, FALSE);
+
+ priv = local_folder->priv;
+
+ i18n_info = get_i18n_info_for_language (local_folder, language_id);
+
+ if (i18n_info == NULL) {
+ if (language_id_return != NULL)
+ *language_id_return = NULL;
+ if (name_return != NULL)
+ *name_return = NULL;
+ if (description_return != NULL)
+ *description_return = NULL;
+
+ return FALSE;
+ }
+
+ if (language_id_return != NULL)
+ *language_id_return = i18n_info->language_id;
+ if (name_return != NULL)
+ *name_return = i18n_info->name;
+ if (description_return != NULL)
+ *description_return = i18n_info->description;
+
+ return TRUE;
+}
+
+
E_MAKE_TYPE (e_local_folder, "ELocalFolder", ELocalFolder, class_init, init, PARENT_TYPE)
diff --git a/shell/e-local-folder.h b/shell/e-local-folder.h
index b57abe8d6f..b41e0608ab 100644
--- a/shell/e-local-folder.h
+++ b/shell/e-local-folder.h
@@ -44,9 +44,12 @@ extern "C" {
typedef struct _ELocalFolder ELocalFolder;
typedef struct _ELocalFolderClass ELocalFolderClass;
+typedef struct _ELocalFolderPrivate ELocalFolderPrivate;
struct _ELocalFolder {
EFolder parent;
+
+ ELocalFolderPrivate *priv;
};
struct _ELocalFolderClass {
@@ -55,15 +58,25 @@ struct _ELocalFolderClass {
GtkType e_local_folder_get_type (void);
-void e_local_folder_construct (ELocalFolder *local_folder,
- const char *name,
- const char *type,
- const char *description);
-EFolder *e_local_folder_new (const char *name,
- const char *type,
- const char *description);
-EFolder *e_local_folder_new_from_path (const char *physical_path);
-gboolean e_local_folder_save (ELocalFolder *local_folder);
+void e_local_folder_construct (ELocalFolder *local_folder,
+ const char *name,
+ const char *type,
+ const char *description);
+EFolder *e_local_folder_new (const char *name,
+ const char *type,
+ const char *description);
+EFolder *e_local_folder_new_from_path (const char *physical_path);
+gboolean e_local_folder_save (ELocalFolder *local_folder);
+
+void e_local_folder_add_i18n_info (ELocalFolder *local_folder,
+ const char *language_id,
+ const char *name,
+ const char *description);
+gboolean e_local_folder_get_i18n_info (ELocalFolder *local_folder,
+ const char *language_id,
+ const char **language_id_return,
+ const char **name_return,
+ const char **description_return);
#ifdef __cplusplus
}
diff --git a/shell/e-shell-view.c b/shell/e-shell-view.c
index 9ca860ff5f..d2d29c26dc 100644
--- a/shell/e-shell-view.c
+++ b/shell/e-shell-view.c
@@ -34,6 +34,7 @@
#include <libgnome/gnome-i18n.h>
#include <libgnomeui/gnome-window.h>
#include <libgnomeui/gnome-window-icon.h>
+#include <libgnomeui/gnome-app.h>
#include <bonobo/bonobo-socket.h>
#include <bonobo/bonobo-ui-util.h>
#include <bonobo/bonobo-widget.h>
@@ -100,9 +101,10 @@ struct _EShellViewPrivate {
GtkWidget *storage_set_view_box;
/* The status bar widgetry. */
+ GtkWidget *status_bar;
GtkWidget *offline_toggle;
GtkWidget *offline_toggle_pixmap;
- GtkWidget *progress_bar;
+ GtkWidget *task_bar;
/* The view we have already open. */
GHashTable *uri_to_control;
@@ -116,12 +118,6 @@ struct _EShellViewPrivate {
EShellViewSubwindowMode shortcut_bar_mode;
EShellViewSubwindowMode folder_bar_mode;
- /* Timeout ID for the progress bar. */
- int progress_bar_timeout_id;
-
- /* Status of the progress bar. */
- int progress_bar_value;
-
/* List of sockets we created. */
GList *sockets;
};
@@ -617,7 +613,6 @@ static void
setup_offline_toggle (EShellView *shell_view)
{
EShellViewPrivate *priv;
- BonoboControl *control;
GtkWidget *toggle;
GtkWidget *pixmap;
@@ -637,46 +632,78 @@ setup_offline_toggle (EShellView *shell_view)
gtk_widget_show (toggle);
gtk_widget_show (pixmap);
- control = bonobo_control_new (toggle);
- g_return_if_fail (control != NULL);
-
- bonobo_ui_component_object_set (priv->ui_component, "/status/OfflineToggle",
- BONOBO_OBJREF (control),
- NULL);
- bonobo_object_unref (BONOBO_OBJECT (control));
-
priv->offline_toggle = toggle;
priv->offline_toggle_pixmap = pixmap;
update_offline_toggle_status (shell_view);
+
+ g_assert (priv->status_bar != NULL);
+
+ gtk_box_pack_start (GTK_BOX (priv->status_bar), priv->offline_toggle, FALSE, TRUE, 0);
+}
+
+static void
+setup_task_bar (EShellView *task_bar)
+{
+ EShellViewPrivate *priv;
+
+ priv = task_bar->priv;
+
+ priv->task_bar = e_task_bar_new ();
+
+ g_assert (priv->status_bar != NULL);
+
+ gtk_box_pack_start (GTK_BOX (priv->status_bar), priv->task_bar, TRUE, TRUE, 0);
+ gtk_widget_show (priv->task_bar);
}
static void
-setup_progress_bar (EShellView *shell_view)
+create_status_bar (EShellView *shell_view)
{
EShellViewPrivate *priv;
- GtkProgressBar *progress_bar;
- BonoboControl *control;
priv = shell_view->priv;
- progress_bar = (GTK_PROGRESS_BAR (gtk_progress_bar_new ()));
+ priv->status_bar = gtk_hbox_new (FALSE, 2);
+ gtk_widget_show (priv->status_bar);
- gtk_progress_bar_set_orientation (progress_bar, GTK_PROGRESS_LEFT_TO_RIGHT);
- gtk_progress_bar_set_bar_style (progress_bar, GTK_PROGRESS_CONTINUOUS);
-
- priv->progress_bar = GTK_WIDGET (progress_bar);
- gtk_widget_show (priv->progress_bar);
+ setup_offline_toggle (shell_view);
+ setup_task_bar (shell_view);
+}
- control = bonobo_control_new (priv->progress_bar);
- g_return_if_fail (control != NULL);
+
+/* Menu hints for the status bar. */
+
+static void
+ui_engine_add_hint_callback (BonoboUIEngine *engine,
+ const char *str,
+ void *data)
+{
+ EShellView *shell_view;
+ EShellViewPrivate *priv;
+
+ shell_view = E_SHELL_VIEW (data);
+ priv = shell_view->priv;
+
+ g_print ("Hint -- %s\n", str);
+
+ /* FIXME: Implement me. */
+}
- bonobo_ui_component_object_set (priv->ui_component, "/status/Progress",
- BONOBO_OBJREF (control),
- NULL);
- bonobo_object_unref (BONOBO_OBJECT (control));
+static void
+setup_statusbar_hints (EShellView *shell_view)
+{
+ EShellViewPrivate *priv;
+
+ priv = shell_view->priv;
+
+ g_assert (priv->status_bar != NULL);
+
+ gtk_signal_connect (GTK_OBJECT (bonobo_window_get_ui_engine (BONOBO_WINDOW (shell_view))), "add_hint",
+ GTK_SIGNAL_FUNC (ui_engine_add_hint_callback), shell_view);
}
+
void
e_shell_view_set_current_shortcuts_group_num (EShellView *shell_view, int group_num)
{
@@ -711,17 +738,10 @@ static void
setup_widgets (EShellView *shell_view)
{
EShellViewPrivate *priv;
+ GtkWidget *contents_vbox;
priv = shell_view->priv;
- /* The offline/online button toggle. */
-
- setup_offline_toggle (shell_view);
-
- /* The progress bar. */
-
- setup_progress_bar (shell_view);
-
/* The shortcut bar. */
priv->shortcut_bar = e_shortcuts_new_view (e_shell_get_shortcuts (priv->shell));
@@ -773,7 +793,19 @@ setup_widgets (EShellView *shell_view)
e_paned_pack2 (E_PANED (priv->hpaned), priv->view_vbox, TRUE, FALSE);
e_paned_set_position (E_PANED (priv->hpaned), DEFAULT_SHORTCUT_BAR_WIDTH);
- bonobo_window_set_contents (BONOBO_WINDOW (shell_view), priv->hpaned);
+ /* The status bar. */
+
+ create_status_bar (shell_view);
+ setup_statusbar_hints (shell_view);
+
+ /* The contents. */
+
+ contents_vbox = gtk_vbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (contents_vbox), priv->hpaned, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (contents_vbox), priv->status_bar, FALSE, TRUE, 0);
+ gtk_widget_show (contents_vbox);
+
+ bonobo_window_set_contents (BONOBO_WINDOW (shell_view), contents_vbox);
/* Show stuff. */
@@ -786,6 +818,7 @@ setup_widgets (EShellView *shell_view)
gtk_widget_show (priv->view_hpaned);
gtk_widget_show (priv->view_vbox);
gtk_widget_show (priv->view_title_bar);
+ gtk_widget_show (priv->status_bar);
/* By default, both the folder bar and shortcut bar are visible. */
priv->shortcut_bar_mode = E_SHELL_VIEW_SUBWINDOW_STICKY;
@@ -839,16 +872,10 @@ destroy (GtkObject *object)
g_hash_table_foreach (priv->uri_to_control, hash_forall_destroy_control, NULL);
g_hash_table_destroy (priv->uri_to_control);
- gtk_widget_destroy (priv->offline_toggle);
- gtk_widget_destroy (priv->progress_bar);
-
bonobo_object_unref (BONOBO_OBJECT (priv->ui_component));
g_free (priv->uri);
- if (priv->progress_bar_timeout_id != 0)
- gtk_timeout_remove (priv->progress_bar_timeout_id);
-
g_free (priv);
(* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
@@ -929,9 +956,10 @@ init (EShellView *shell_view)
priv->storage_set_view_box = NULL;
priv->shortcut_bar = NULL;
- priv->progress_bar = NULL;
+ priv->status_bar = NULL;
priv->offline_toggle = NULL;
priv->offline_toggle_pixmap = NULL;
+ priv->task_bar = NULL;
priv->shortcut_bar_mode = E_SHELL_VIEW_SUBWINDOW_HIDDEN;
priv->folder_bar_mode = E_SHELL_VIEW_SUBWINDOW_HIDDEN;
@@ -941,14 +969,13 @@ init (EShellView *shell_view)
priv->uri_to_control = g_hash_table_new (g_str_hash, g_str_equal);
- priv->progress_bar_timeout_id = 0;
- priv->progress_bar_value = 0;
priv->sockets = NULL;
shell_view->priv = priv;
}
+#if 0
/* Progress bar handling. */
#define PROGRESS_BAR_TIMEOUT 80
@@ -1013,6 +1040,8 @@ stop_progress_bar (EShellView *shell_view)
gtk_progress_set_value (GTK_PROGRESS (progress_bar), 0);
}
+#endif
+
/* EvolutionShellView interface callbacks. */
@@ -1045,10 +1074,12 @@ corba_interface_set_message_cb (EvolutionShellView *shell_view,
g_free (status);
+#if 0
if (busy)
start_progress_bar (E_SHELL_VIEW (data));
else
stop_progress_bar (E_SHELL_VIEW (data));
+#endif
}
static void
@@ -1063,7 +1094,9 @@ corba_interface_unset_message_cb (EvolutionShellView *shell_view,
bonobo_ui_component_set_status (view->priv->ui_component, "", NULL);
+#if 0
stop_progress_bar (E_SHELL_VIEW (data));
+#endif
}
static void
@@ -1222,6 +1255,11 @@ e_shell_view_construct (EShellView *shell_view,
return view;
}
+/* WARNING: Don't use `e_shell_view_new()' to create new views for the shell
+ unless you know what you are doing; this is just the standard GTK+
+ constructor thing and it won't allow the shell to do the required
+ bookkeeping for the created views. Instead, the right way to create a new
+ view is calling `e_shell_new_view()'. */
EShellView *
e_shell_view_new (EShell *shell)
{
@@ -1644,7 +1682,6 @@ get_type_for_folder (EShellView *shell_view,
{
EShellViewPrivate *priv;
EStorageSet *storage_set;
- EFolderTypeRegistry *folder_type_registry;
EFolder *folder;
priv = shell_view->priv;
@@ -1656,8 +1693,6 @@ get_type_for_folder (EShellView *shell_view,
*physical_uri_return = e_folder_get_physical_uri (folder);
- folder_type_registry = e_shell_get_folder_type_registry (e_shell_view_get_shell (shell_view));
-
return e_folder_get_type_string (folder);
}
@@ -1989,6 +2024,15 @@ e_shell_view_get_folder_bar_mode (EShellView *shell_view)
}
+ETaskBar *
+e_shell_view_get_task_bar (EShellView *shell_view)
+{
+ g_return_val_if_fail (shell_view != NULL, NULL);
+ g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
+
+ return E_TASK_BAR (shell_view->priv->task_bar);
+}
+
EShell *
e_shell_view_get_shell (EShellView *shell_view)
{
diff --git a/shell/e-shell-view.h b/shell/e-shell-view.h
index c7ee7fa4af..d22e875b0d 100644
--- a/shell/e-shell-view.h
+++ b/shell/e-shell-view.h
@@ -24,9 +24,9 @@
#ifndef _E_SHELL_VIEW_H_
#define _E_SHELL_VIEW_H_
-#include <bonobo/bonobo-win.h>
+#include "e-task-bar.h"
-#include "e-shell.h"
+#include <bonobo/bonobo-win.h>
#ifdef __cplusplus
extern "C" {
@@ -44,6 +44,8 @@ typedef struct _EShellView EShellView;
typedef struct _EShellViewPrivate EShellViewPrivate;
typedef struct _EShellViewClass EShellViewClass;
+#include "e-shell.h"
+
enum _EShellViewSubwindowMode {
E_SHELL_VIEW_SUBWINDOW_HIDDEN,
E_SHELL_VIEW_SUBWINDOW_TRANSIENT,
@@ -66,6 +68,12 @@ struct _EShellViewClass {
};
+/* WARNING: Don't use `e_shell_view_new()' to create new views for the shell
+ unless you know what you are doing; this is just the standard GTK+
+ constructor thing and it won't allow the shell to do the required
+ bookkeeping for the created views. Instead, the right way to create a new
+ view is calling `e_shell_new_view()'. */
+
GtkType e_shell_view_get_type (void);
EShellView *e_shell_view_construct (EShellView *shell_view,
EShell *shell);
@@ -84,7 +92,7 @@ void e_shell_view_set_folder_bar_mode (EShellView
EShellViewSubwindowMode mode);
EShellViewSubwindowMode e_shell_view_get_folder_bar_mode (EShellView *shell_view);
-
+ETaskBar *e_shell_view_get_task_bar (EShellView *shell_view);
EShell *e_shell_view_get_shell (EShellView *shell_view);
BonoboUIComponent *e_shell_view_get_bonobo_ui_component (EShellView *shell_view);
BonoboUIContainer *e_shell_view_get_bonobo_ui_container (EShellView *shell_view);
diff --git a/shell/e-shell.c b/shell/e-shell.c
index 405770aeb1..01392b0025 100644
--- a/shell/e-shell.c
+++ b/shell/e-shell.c
@@ -38,6 +38,7 @@
#include "Evolution.h"
+#include "e-activity-handler.h"
#include "e-component-registry.h"
#include "e-corba-storage-registry.h"
#include "e-folder-type-registry.h"
@@ -75,6 +76,9 @@ struct _EShellPrivate {
ECorbaStorageRegistry *corba_storage_registry;
+ /* ::Activity interface handler. */
+ EActivityHandler *activity_handler;
+
/* 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;
@@ -345,6 +349,26 @@ register_shell (EShell *shell,
}
+/* Set up the ::Activity interface. */
+
+static void
+setup_activity_interface (EShell *shell)
+{
+ EActivityHandler *activity_handler;
+ EShellPrivate *priv;
+
+ priv = shell->priv;
+
+ activity_handler = e_activity_handler_new ();
+
+ bonobo_object_add_interface (BONOBO_OBJECT (shell),
+ BONOBO_OBJECT (activity_handler));
+
+ bonobo_object_ref (BONOBO_OBJECT (activity_handler));
+ priv->activity_handler = activity_handler;
+}
+
+
/* Initialization of the storages. */
static gboolean
@@ -618,6 +642,9 @@ destroy (GtkObject *object)
if (priv->corba_storage_registry != NULL)
bonobo_object_unref (BONOBO_OBJECT (priv->corba_storage_registry));
+ if (priv->activity_handler != NULL)
+ bonobo_object_unref (BONOBO_OBJECT (priv->activity_handler));
+
/* FIXME. Maybe we should do something special here. */
if (priv->offline_handler != NULL)
gtk_object_unref (GTK_OBJECT (priv->offline_handler));
@@ -705,6 +732,7 @@ init (EShell *shell)
priv->component_registry = NULL;
priv->folder_type_registry = NULL;
priv->corba_storage_registry = NULL;
+ priv->activity_handler = NULL;
priv->offline_handler = NULL;
priv->crash_type_names = NULL;
priv->line_status = E_SHELL_LINE_STATUS_ONLINE;
@@ -775,7 +803,12 @@ e_shell_construct (EShell *shell,
/* The local storage depends on the component registry. */
setup_local_storage (shell);
- /* Now that we have a local storage, we can tell the components we are here. */
+ /* Set up the ::Activity interface. This must be done before we notify
+ the components, as they might want to use it. */
+ setup_activity_interface (shell);
+
+ /* Now that we have a local storage and an ::Activity interface, we can
+ tell the components we are here. */
set_owner_on_components (shell);
/* Run the intelligent importers to find see if any data needs
@@ -858,10 +891,14 @@ e_shell_new_view (EShell *shell,
const char *uri)
{
EShellView *view;
+ EShellPrivate *priv;
+ ETaskBar *task_bar;
g_return_val_if_fail (shell != NULL, NULL);
g_return_val_if_fail (E_IS_SHELL (shell), NULL);
+ priv = shell->priv;
+
view = e_shell_view_new (shell);
gtk_widget_show (GTK_WIDGET (view));
@@ -875,6 +912,9 @@ e_shell_new_view (EShell *shell,
shell->priv->views = g_list_prepend (shell->priv->views, view);
+ task_bar = e_shell_view_get_task_bar (view);
+ e_activity_handler_attach_task_bar (priv->activity_handler, task_bar);
+
return view;
}
@@ -1130,7 +1170,7 @@ e_shell_restore_from_settings (EShell *shell)
EShellView *view;
/* FIXME: restore the URI here. There should be an
- e_shell_view_new_from_configuration() thingie. */
+ e_shell_new_view_from_configuration() thingie. */
view = e_shell_new_view (shell, NULL);
if (! e_shell_view_load_settings (view, i))
diff --git a/shell/e-shell.h b/shell/e-shell.h
index 674ce24148..4786c49767 100644
--- a/shell/e-shell.h
+++ b/shell/e-shell.h
@@ -37,6 +37,7 @@ typedef struct _EShellPrivate EShellPrivate;
typedef struct _EShellClass EShellClass;
#include "Evolution.h"
+
#include "e-shortcuts.h"
#include "e-shell-view.h"
#include "e-local-storage.h"
diff --git a/shell/e-task-bar.c b/shell/e-task-bar.c
new file mode 100644
index 0000000000..efc552f661
--- /dev/null
+++ b/shell/e-task-bar.c
@@ -0,0 +1,154 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-task-bar.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 <ettore@ximian.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-task-bar.h"
+
+#include <gal/util/e-util.h>
+
+
+#define PARENT_TYPE gtk_hbox_get_type ()
+static GtkHBoxClass *parent_class = NULL;
+
+
+/* GtkObject methods. */
+
+static void
+impl_destroy (GtkObject *object)
+{
+ ETaskBar *task_bar;
+
+ task_bar = E_TASK_BAR (object);
+
+ /* Nothing to do here. */
+
+ (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
+
+
+static void
+class_init (GtkObjectClass *object_class)
+{
+ parent_class = gtk_type_class (PARENT_TYPE);
+
+ object_class->destroy = impl_destroy;
+}
+
+static void
+init (ETaskBar *task_bar)
+{
+ /* Nothing to do here. */
+}
+
+
+void
+e_task_bar_construct (ETaskBar *task_bar)
+{
+ g_return_if_fail (task_bar != NULL);
+ g_return_if_fail (E_IS_TASK_BAR (task_bar));
+
+ /* Nothing to do here. */
+}
+
+GtkWidget *
+e_task_bar_new (void)
+{
+ ETaskBar *task_bar;
+
+ task_bar = gtk_type_new (e_task_bar_get_type ());
+ e_task_bar_construct (task_bar);
+
+ return GTK_WIDGET (task_bar);
+}
+
+void
+e_task_bar_prepend_task (ETaskBar *task_bar,
+ ETaskWidget *task_widget)
+{
+ GtkBoxChild *child_info;
+ GtkBox *box;
+
+ g_return_if_fail (task_bar != NULL);
+ g_return_if_fail (E_IS_TASK_BAR (task_bar));
+ g_return_if_fail (task_widget != NULL);
+ g_return_if_fail (E_IS_TASK_WIDGET (task_widget));
+
+ /* Hah hah. GTK+ sucks. This is adapted from `gtkhbox.c'. */
+
+ child_info = g_new (GtkBoxChild, 1);
+ child_info->widget = GTK_WIDGET (task_widget);
+ child_info->padding = 0;
+ child_info->expand = TRUE;
+ child_info->fill = TRUE;
+ child_info->pack = GTK_PACK_START;
+
+ box = GTK_BOX (task_bar);
+
+ box->children = g_list_append (box->children, child_info);
+
+ gtk_widget_set_parent (GTK_WIDGET (task_widget), GTK_WIDGET (task_bar));
+
+ if (GTK_WIDGET_REALIZED (task_bar))
+ gtk_widget_realize (GTK_WIDGET (task_widget));
+
+ if (GTK_WIDGET_VISIBLE (task_bar) && GTK_WIDGET_VISIBLE (task_widget)) {
+ if (GTK_WIDGET_MAPPED (task_bar))
+ gtk_widget_map (GTK_WIDGET (task_widget));
+ gtk_widget_queue_resize (GTK_WIDGET (task_widget));
+ }
+}
+
+void
+e_task_bar_remove_task (ETaskBar *task_bar,
+ int n)
+{
+ ETaskWidget *task_widget;
+
+ g_return_if_fail (task_bar != NULL);
+ g_return_if_fail (E_IS_TASK_BAR (task_bar));
+ g_return_if_fail (n >= 0);
+
+ task_widget = e_task_bar_get_task_widget (task_bar, n);
+
+ gtk_container_remove (GTK_CONTAINER (task_bar), GTK_WIDGET (task_widget));
+}
+
+ETaskWidget *
+e_task_bar_get_task_widget (ETaskBar *task_bar,
+ int n)
+{
+ GtkBoxChild *child_info;
+
+ g_return_val_if_fail (task_bar != NULL, NULL);
+ g_return_val_if_fail (E_IS_TASK_BAR (task_bar), NULL);
+
+ child_info = (GtkBoxChild *) g_list_nth (GTK_BOX (task_bar)->children, n)->data;
+
+ return E_TASK_WIDGET (child_info->widget);
+}
+
+
+E_MAKE_TYPE (e_task_bar, "ETaskBar", ETaskBar, class_init, init, PARENT_TYPE)
diff --git a/shell/e-task-bar.h b/shell/e-task-bar.h
new file mode 100644
index 0000000000..14e4c961d7
--- /dev/null
+++ b/shell/e-task-bar.h
@@ -0,0 +1,72 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-task-bar.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 <ettore@ximian.com>
+ */
+
+#ifndef _E_TASK_BAR_H_
+#define _E_TASK_BAR_H_
+
+#include "e-task-widget.h"
+
+#include <gtk/gtkhbox.h>
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+#define E_TYPE_TASK_BAR (e_task_bar_get_type ())
+#define E_TASK_BAR(obj) (GTK_CHECK_CAST ((obj), E_TYPE_TASK_BAR, ETaskBar))
+#define E_TASK_BAR_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_TYPE_TASK_BAR, ETaskBarClass))
+#define E_IS_TASK_BAR(obj) (GTK_CHECK_TYPE ((obj), E_TYPE_TASK_BAR))
+#define E_IS_TASK_BAR_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), E_TYPE_TASK_BAR))
+
+
+typedef struct _ETaskBar ETaskBar;
+typedef struct _ETaskBarPrivate ETaskBarPrivate;
+typedef struct _ETaskBarClass ETaskBarClass;
+
+struct _ETaskBar {
+ GtkHBox parent;
+};
+
+struct _ETaskBarClass {
+ GtkHBoxClass parent_class;
+};
+
+
+GtkType e_task_bar_get_type (void);
+void e_task_bar_construct (ETaskBar *task_bar);
+GtkWidget *e_task_bar_new (void);
+
+void e_task_bar_prepend_task (ETaskBar *task_bar,
+ ETaskWidget *task_widget);
+void e_task_bar_remove_task (ETaskBar *task_bar,
+ int n);
+
+ETaskWidget *e_task_bar_get_task_widget (ETaskBar *task_bar,
+ int n);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _E_TASK_BAR_H_ */
diff --git a/shell/e-task-widget.c b/shell/e-task-widget.c
new file mode 100644
index 0000000000..e67baaf0e7
--- /dev/null
+++ b/shell/e-task-widget.c
@@ -0,0 +1,190 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-task-widget.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 <ettore@ximian.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-task-widget.h"
+
+#include <gtk/gtkhbox.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkpixmap.h>
+
+/* HA HA. Just #including <libgnome/gnome-i18n.h> doesn't seem to work, so
+ I'll have to include the full thing. */
+#include <libgnome/libgnome.h>
+
+#include <gal/util/e-util.h>
+
+
+#define SPACING 2
+
+#define PARENT_TYPE (gtk_frame_get_type ())
+static GtkFrameClass *parent_class = NULL;
+
+struct _ETaskWidgetPrivate {
+ GdkPixbuf *icon_pixbuf;
+ GtkWidget *label;
+ GtkWidget *pixmap;
+};
+
+
+/* GtkObject methods. */
+
+static void
+impl_destroy (GtkObject *object)
+{
+ ETaskWidget *task_widget;
+ ETaskWidgetPrivate *priv;
+
+ task_widget = E_TASK_WIDGET (object);
+ priv = task_widget->priv;
+
+ gdk_pixbuf_unref (priv->icon_pixbuf);
+
+ (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
+
+
+static void
+class_init (GtkObjectClass *object_class)
+{
+ parent_class = gtk_type_class (PARENT_TYPE);
+
+ object_class->destroy = impl_destroy;
+}
+
+static void
+init (ETaskWidget *task_widget)
+{
+ ETaskWidgetPrivate *priv;
+
+ priv = g_new (ETaskWidgetPrivate, 1);
+
+ task_widget->priv = priv;
+}
+
+
+void
+e_task_widget_construct (ETaskWidget *task_widget,
+ GdkPixbuf *icon_pixbuf,
+ const char *information)
+{
+ ETaskWidgetPrivate *priv;
+ GdkPixmap *pixmap;
+ GdkBitmap *mask;
+ GtkWidget *box;
+
+ g_return_if_fail (task_widget != NULL);
+ g_return_if_fail (E_IS_TASK_WIDGET (task_widget));
+ g_return_if_fail (icon_pixbuf != NULL);
+ g_return_if_fail (information != NULL);
+
+ priv = task_widget->priv;
+
+ gtk_frame_set_shadow_type (GTK_FRAME (task_widget), GTK_SHADOW_IN);
+
+ box = gtk_hbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (task_widget), box);
+ gtk_widget_show (box);
+
+ priv->icon_pixbuf = gdk_pixbuf_ref (icon_pixbuf);
+
+ gdk_pixbuf_render_pixmap_and_mask (icon_pixbuf, &pixmap, &mask, 128);
+
+ priv->pixmap = gtk_pixmap_new (pixmap, mask);
+ gtk_widget_show (priv->pixmap);
+ gtk_box_pack_start (GTK_BOX (box), priv->pixmap, FALSE, TRUE, 0);
+
+ priv->label = gtk_label_new ("");
+ gtk_misc_set_alignment (GTK_MISC (priv->label), 0.0, 0.5);
+ gtk_widget_show (priv->label);
+ gtk_box_pack_start (GTK_BOX (box), priv->label, TRUE, TRUE, 0);
+
+ gdk_pixmap_unref (pixmap);
+ gdk_bitmap_unref (mask);
+
+ e_task_widget_update (task_widget, information, -1.0);
+}
+
+GtkWidget *
+e_task_widget_new (GdkPixbuf *icon_pixbuf,
+ const char *information)
+{
+ ETaskWidget *task_widget;
+
+ g_return_val_if_fail (icon_pixbuf != NULL, NULL);
+ g_return_val_if_fail (information != NULL, NULL);
+
+ task_widget = gtk_type_new (e_task_widget_get_type ());
+ e_task_widget_construct (task_widget, icon_pixbuf, information);
+
+ return GTK_WIDGET (task_widget);
+}
+
+
+void
+e_task_widget_update (ETaskWidget *task_widget,
+ const char *information,
+ double completion)
+{
+ ETaskWidgetPrivate *priv;
+ char *text;
+
+ g_return_if_fail (task_widget != NULL);
+ g_return_if_fail (E_IS_TASK_WIDGET (task_widget));
+ g_return_if_fail (information != NULL);
+
+ priv = task_widget->priv;
+
+ if (completion < 0.0) {
+ text = g_strdup_printf (_("%s (...)"), information);
+ } else {
+ int percent_complete;
+
+ percent_complete = (int) (completion * 100.0 + .5);
+ text = g_strdup_printf (_("%s (%d%% complete)"), information, percent_complete);
+ }
+
+ gtk_label_set_text (GTK_LABEL (priv->label), text);
+
+ g_free (text);
+}
+
+void
+e_task_wiget_alert (ETaskWidget *task_widget)
+{
+ g_return_if_fail (task_widget != NULL);
+ g_return_if_fail (E_IS_TASK_WIDGET (task_widget));
+}
+
+void
+e_task_wiget_unalert (ETaskWidget *task_widget)
+{
+ g_return_if_fail (task_widget != NULL);
+ g_return_if_fail (E_IS_TASK_WIDGET (task_widget));
+}
+
+
+E_MAKE_TYPE (e_task_widget, "ETaskWidget", ETaskWidget, class_init, init, PARENT_TYPE)
diff --git a/shell/e-task-widget.h b/shell/e-task-widget.h
new file mode 100644
index 0000000000..cc177252ce
--- /dev/null
+++ b/shell/e-task-widget.h
@@ -0,0 +1,75 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-task-widget.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 <ettore@ximian.com>
+ */
+
+#ifndef _E_TASK_WIDGET_H_
+#define _E_TASK_WIDGET_H_
+
+#include <gtk/gtkframe.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+#define E_TYPE_TASK_WIDGET (e_task_widget_get_type ())
+#define E_TASK_WIDGET(obj) (GTK_CHECK_CAST ((obj), E_TYPE_TASK_WIDGET, ETaskWidget))
+#define E_TASK_WIDGET_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_TYPE_TASK_WIDGET, ETaskWidgetClass))
+#define E_IS_TASK_WIDGET(obj) (GTK_CHECK_TYPE ((obj), E_TYPE_TASK_WIDGET))
+#define E_IS_TASK_WIDGET_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), E_TYPE_TASK_WIDGET))
+
+
+typedef struct _ETaskWidget ETaskWidget;
+typedef struct _ETaskWidgetPrivate ETaskWidgetPrivate;
+typedef struct _ETaskWidgetClass ETaskWidgetClass;
+
+struct _ETaskWidget {
+ GtkFrame parent;
+
+ ETaskWidgetPrivate *priv;
+};
+
+struct _ETaskWidgetClass {
+ GtkFrameClass parent_class;
+};
+
+
+GtkType e_task_widget_get_type (void);
+void e_task_widget_construct (ETaskWidget *task_widget,
+ GdkPixbuf *icon_pixbuf,
+ const char *information);
+GtkWidget *e_task_widget_new (GdkPixbuf *icon_pixbuf,
+ const char *information);
+
+void e_task_widget_update (ETaskWidget *task_widget,
+ const char *information,
+ double completion);
+
+void e_task_wiget_alert (ETaskWidget *task_widget);
+void e_task_wiget_unalert (ETaskWidget *task_widget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _E_TASK_WIDGET_H_ */
diff --git a/shell/evolution-test-component.c b/shell/evolution-test-component.c
new file mode 100644
index 0000000000..1b5b428059
--- /dev/null
+++ b/shell/evolution-test-component.c
@@ -0,0 +1,375 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* evolution-test-component.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
+ */
+
+/* Simple test component for the Evolution shell. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "evolution-shell-component.h"
+
+#include <bonobo/bonobo-generic-factory.h>
+#include <bonobo/bonobo-main.h>
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+
+#define COMPONENT_FACTORY_ID "OAFIID:GNOME_Evolution_TestComponent_ShellComponentFactory"
+#define COMPONENT_ID "OAFIID:GNOME_Evolution_TestComponent_ShellComponent"
+
+static const EvolutionShellComponentFolderType folder_types[] = {
+ { "test", "/usr/share/pixmaps/gnome-money.png", NULL, NULL },
+ { NULL }
+};
+
+
+static EvolutionShellClient *parent_shell = NULL;
+static GNOME_Evolution_Activity activity_interface = CORBA_OBJECT_NIL;
+
+static CORBA_long activity_id = 0;
+
+static BonoboListener *task_bar_event_listener;
+
+static int timeout_id = 0;
+static int progress = -1;
+
+
+static void
+create_icon_from_pixbuf (GdkPixbuf *pixbuf,
+ GNOME_Evolution_Icon *frame_return)
+{
+ const char *sp;
+ CORBA_octet *dp;
+ int width, height, total_width, rowstride;
+ int i, j;
+ gboolean has_alpha;
+
+ width = gdk_pixbuf_get_width (pixbuf);
+ height = gdk_pixbuf_get_height (pixbuf);
+ rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+ has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
+
+ if (has_alpha)
+ total_width = 4 * width;
+ else
+ total_width = 3 * width;
+
+ frame_return->width = width;
+ frame_return->height = height;
+ frame_return->hasAlpha = has_alpha;
+
+ frame_return->rgba_data._length = frame_return->height * total_width;
+ frame_return->rgba_data._maximum = frame_return->rgba_data._length;
+ frame_return->rgba_data._buffer = CORBA_sequence_CORBA_octet_allocbuf (frame_return->rgba_data._maximum);
+
+ sp = gdk_pixbuf_get_pixels (pixbuf);
+ dp = frame_return->rgba_data._buffer;
+ for (i = 0; i < height; i ++) {
+ for (j = 0; j < total_width; j++) {
+ *(dp ++) = sp[j];
+ }
+ sp += rowstride;
+ }
+}
+
+static GNOME_Evolution_AnimatedIcon *
+create_animated_icon (void)
+{
+ GNOME_Evolution_AnimatedIcon *animated_icon;
+ GdkPixbuf *pixbuf;
+
+ animated_icon = GNOME_Evolution_AnimatedIcon__alloc ();
+
+ animated_icon->_length = 1;
+ animated_icon->_maximum = 1;
+ animated_icon->_buffer = CORBA_sequence_GNOME_Evolution_Icon_allocbuf (animated_icon->_maximum);
+
+ pixbuf = gdk_pixbuf_new_from_file (gnome_pixmap_file ("gnome-money.png"));
+ create_icon_from_pixbuf (pixbuf, &animated_icon->_buffer[0]);
+ gdk_pixbuf_unref (pixbuf);
+
+ CORBA_sequence_set_release (animated_icon, TRUE);
+
+ return animated_icon;
+}
+
+
+static void
+task_bar_event_listener_callback (BonoboListener *listener,
+ char *event_name,
+ CORBA_any *any,
+ CORBA_Environment *ev,
+ void *data)
+{
+ g_print ("Taskbar event -- %s\n", event_name);
+}
+
+/* Timeout #3: We are done. */
+static int
+timeout_callback_3 (void *data)
+{
+ CORBA_Environment ev;
+
+ CORBA_exception_init (&ev);
+
+ GNOME_Evolution_Activity_operationFinished (activity_interface,
+ activity_id,
+ &ev);
+
+ if (ev._major != CORBA_NO_EXCEPTION) {
+ g_warning ("Cannot report operation as finished; exception returned -- %s\n",
+ ev._repo_id);
+ CORBA_exception_free (&ev);
+ return FALSE;
+ }
+
+ CORBA_exception_free (&ev);
+
+ return FALSE;
+}
+
+/* Timeout #2: Update the progress until it reaches 100%. */
+static int
+timeout_callback_2 (void *data)
+{
+ CORBA_Environment ev;
+
+ if (progress < 0)
+ progress = 0;
+
+ CORBA_exception_init (&ev);
+
+ GNOME_Evolution_Activity_operationProgressing (activity_interface,
+ activity_id,
+ "Operation Foo in progress",
+ (CORBA_float) progress / 100.0,
+ &ev);
+
+ if (ev._major != CORBA_NO_EXCEPTION) {
+ g_warning ("Cannot update operation; exception returned -- %s\n",
+ ev._repo_id);
+ CORBA_exception_free (&ev);
+ return FALSE;
+ }
+
+ CORBA_exception_free (&ev);
+
+ progress += 10;
+ if (progress > 100) {
+ gtk_timeout_add (1000, timeout_callback_3, NULL);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Timeout #1: Set busy. */
+static int
+timeout_callback_1 (void *data)
+{
+ CORBA_boolean suggest_display;
+ CORBA_Environment ev;
+ GNOME_Evolution_AnimatedIcon *animated_icon;
+
+ CORBA_exception_init (&ev);
+
+ if (CORBA_Object_is_nil (activity_interface, &ev)) {
+ CORBA_exception_free (&ev);
+ return FALSE;
+ }
+
+ g_print ("Component becoming busy -- %s\n", COMPONENT_ID);
+
+ task_bar_event_listener = bonobo_listener_new (task_bar_event_listener_callback, NULL);
+
+ animated_icon = create_animated_icon ();
+
+ GNOME_Evolution_Activity_operationStarted (activity_interface,
+ COMPONENT_ID,
+ animated_icon,
+ "Operation Foo started!",
+ FALSE,
+ bonobo_object_corba_objref (BONOBO_OBJECT (task_bar_event_listener)),
+ &activity_id,
+ &suggest_display,
+ &ev);
+
+ CORBA_free (animated_icon);
+
+ if (ev._major != CORBA_NO_EXCEPTION) {
+ g_warning ("Cannot start an operation; exception returned -- %s\n",
+ ev._repo_id);
+ CORBA_exception_free (&ev);
+ return FALSE;
+ }
+
+ g_print (" --> Activity ID: %ld\n", (long) activity_id);
+
+ if (suggest_display)
+ g_print (" --> Could display dialog box.\n");
+
+ CORBA_exception_free (&ev);
+
+ gtk_timeout_add (3000, timeout_callback_2, NULL);
+
+ return FALSE;
+}
+
+
+static EvolutionShellComponentResult
+create_view_fn (EvolutionShellComponent *shell_component,
+ const char *physical_uri,
+ const char *folder_type,
+ BonoboControl **control_return,
+ void *closure)
+{
+ GtkWidget *vbox;
+ GtkWidget *label_1, *label_2;
+ GtkWidget *event_box_1, *event_box_2;
+
+ label_1 = gtk_label_new ("This is just a test component, displaying the following URI:");
+ label_2 = gtk_label_new (physical_uri);
+
+ event_box_1 = gtk_event_box_new ();
+ event_box_2 = gtk_event_box_new ();
+
+ vbox = gtk_vbox_new (FALSE, 5);
+
+ gtk_box_pack_start (GTK_BOX (vbox), event_box_1, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), label_1, FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), label_2, FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), event_box_2, TRUE, TRUE, 0);
+
+ gtk_widget_show (label_1);
+ gtk_widget_show (label_2);
+ gtk_widget_show (event_box_1);
+ gtk_widget_show (event_box_2);
+
+ gtk_widget_show (vbox);
+
+ *control_return = bonobo_control_new (vbox);
+
+ g_assert (timeout_id == 0);
+ timeout_id = gtk_timeout_add (2000, timeout_callback_1, NULL);
+
+ return EVOLUTION_SHELL_COMPONENT_OK;
+}
+
+
+/* Callbacks. */
+
+static void
+owner_set_callback (EvolutionShellComponent *shell_component,
+ EvolutionShellClient *shell_client,
+ const char *evolution_homedir)
+{
+ CORBA_Environment ev;
+
+ g_assert (parent_shell == NULL);
+
+ g_print ("We have an owner -- home directory is `%s'\n", evolution_homedir);
+
+ parent_shell = shell_client;
+
+ CORBA_exception_init (&ev);
+
+ activity_interface = Bonobo_Unknown_queryInterface (bonobo_object_corba_objref (BONOBO_OBJECT (shell_client)),
+ "IDL:GNOME/Evolution/Activity:1.0",
+ &ev);
+ if (ev._major != CORBA_NO_EXCEPTION)
+ activity_interface = CORBA_OBJECT_NIL;
+
+ if (CORBA_Object_is_nil (activity_interface, &ev))
+ g_warning ("Shell doesn't have a ::Activity interface -- weird!");
+
+ CORBA_exception_free (&ev);
+}
+
+static int
+owner_unset_idle_callback (void *data)
+{
+ gtk_main_quit ();
+ return FALSE;
+}
+
+static void
+owner_unset_callback (EvolutionShellComponent *shell_component,
+ void *data)
+{
+ g_idle_add_full (G_PRIORITY_LOW, owner_unset_idle_callback, NULL, NULL);
+}
+
+
+static BonoboObject *
+factory_fn (BonoboGenericFactory *factory,
+ void *closure)
+{
+ EvolutionShellComponent *shell_component;
+
+ shell_component = evolution_shell_component_new (folder_types,
+ create_view_fn,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+
+ gtk_signal_connect (GTK_OBJECT (shell_component), "owner_set",
+ GTK_SIGNAL_FUNC (owner_set_callback), NULL);
+ gtk_signal_connect (GTK_OBJECT (shell_component), "owner_unset",
+ GTK_SIGNAL_FUNC (owner_unset_callback), NULL);
+
+ return BONOBO_OBJECT (shell_component);
+}
+
+static void
+component_factory_init (void)
+{
+ BonoboGenericFactory *factory;
+
+ factory = bonobo_generic_factory_new (COMPONENT_FACTORY_ID, factory_fn, NULL);
+
+ if (factory == NULL)
+ g_error ("Cannot initialize test component.");
+}
+
+
+int
+main (int argc, char **argv)
+{
+ CORBA_ORB orb;
+
+ bindtextdomain (PACKAGE, EVOLUTION_LOCALEDIR);
+ textdomain (PACKAGE);
+
+ gnome_init_with_popt_table ("evolution-test-component", VERSION,
+ argc, argv, oaf_popt_options, 0, NULL);
+
+ orb = oaf_init (argc, argv);
+
+ if (bonobo_init (orb, CORBA_OBJECT_NIL, CORBA_OBJECT_NIL) == FALSE)
+ g_error ("Cannot initialize the test component.");
+
+ component_factory_init ();
+
+ bonobo_main ();
+
+ return 0;
+}