aboutsummaryrefslogtreecommitdiffstats
path: root/modules/calendar
diff options
context:
space:
mode:
Diffstat (limited to 'modules/calendar')
-rw-r--r--modules/calendar/Makefile.am89
-rw-r--r--modules/calendar/e-cal-attachment-handler.c577
-rw-r--r--modules/calendar/e-cal-attachment-handler.h67
-rw-r--r--modules/calendar/e-cal-config-hook.c75
-rw-r--r--modules/calendar/e-cal-config-hook.h33
-rw-r--r--modules/calendar/e-cal-event-hook.c75
-rw-r--r--modules/calendar/e-cal-event-hook.h33
-rw-r--r--modules/calendar/e-cal-shell-backend.c858
-rw-r--r--modules/calendar/e-cal-shell-backend.h71
-rw-r--r--modules/calendar/e-cal-shell-content.c945
-rw-r--r--modules/calendar/e-cal-shell-content.h98
-rw-r--r--modules/calendar/e-cal-shell-migrate.c37
-rw-r--r--modules/calendar/e-cal-shell-migrate.h37
-rw-r--r--modules/calendar/e-cal-shell-sidebar.c889
-rw-r--r--modules/calendar/e-cal-shell-sidebar.h104
-rw-r--r--modules/calendar/e-cal-shell-view-actions.c2021
-rw-r--r--modules/calendar/e-cal-shell-view-actions.h163
-rw-r--r--modules/calendar/e-cal-shell-view-memopad.c482
-rw-r--r--modules/calendar/e-cal-shell-view-private.c1787
-rw-r--r--modules/calendar/e-cal-shell-view-private.h223
-rw-r--r--modules/calendar/e-cal-shell-view-taskpad.c609
-rw-r--r--modules/calendar/e-cal-shell-view.c632
-rw-r--r--modules/calendar/e-cal-shell-view.h66
-rw-r--r--modules/calendar/e-calendar-preferences.c972
-rw-r--r--modules/calendar/e-calendar-preferences.h83
-rw-r--r--modules/calendar/e-calendar-preferences.ui1508
-rw-r--r--modules/calendar/e-memo-shell-backend.c488
-rw-r--r--modules/calendar/e-memo-shell-backend.h67
-rw-r--r--modules/calendar/e-memo-shell-content.c766
-rw-r--r--modules/calendar/e-memo-shell-content.h94
-rw-r--r--modules/calendar/e-memo-shell-migrate.c38
-rw-r--r--modules/calendar/e-memo-shell-migrate.h37
-rw-r--r--modules/calendar/e-memo-shell-sidebar.c816
-rw-r--r--modules/calendar/e-memo-shell-sidebar.h103
-rw-r--r--modules/calendar/e-memo-shell-view-actions.c1049
-rw-r--r--modules/calendar/e-memo-shell-view-actions.h91
-rw-r--r--modules/calendar/e-memo-shell-view-private.c551
-rw-r--r--modules/calendar/e-memo-shell-view-private.h135
-rw-r--r--modules/calendar/e-memo-shell-view.c344
-rw-r--r--modules/calendar/e-memo-shell-view.h66
-rw-r--r--modules/calendar/e-task-shell-backend.c488
-rw-r--r--modules/calendar/e-task-shell-backend.h67
-rw-r--r--modules/calendar/e-task-shell-content.c790
-rw-r--r--modules/calendar/e-task-shell-content.h98
-rw-r--r--modules/calendar/e-task-shell-migrate.c38
-rw-r--r--modules/calendar/e-task-shell-migrate.h37
-rw-r--r--modules/calendar/e-task-shell-sidebar.c816
-rw-r--r--modules/calendar/e-task-shell-sidebar.h103
-rw-r--r--modules/calendar/e-task-shell-view-actions.c1251
-rw-r--r--modules/calendar/e-task-shell-view-actions.h109
-rw-r--r--modules/calendar/e-task-shell-view-private.c755
-rw-r--r--modules/calendar/e-task-shell-view-private.h155
-rw-r--r--modules/calendar/e-task-shell-view.c530
-rw-r--r--modules/calendar/e-task-shell-view.h71
-rw-r--r--modules/calendar/evolution-module-calendar.c83
55 files changed, 22570 insertions, 0 deletions
diff --git a/modules/calendar/Makefile.am b/modules/calendar/Makefile.am
new file mode 100644
index 0000000000..8422fb1e7f
--- /dev/null
+++ b/modules/calendar/Makefile.am
@@ -0,0 +1,89 @@
+module_LTLIBRARIES = module-calendar.la
+
+module_calendar_la_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ -DG_LOG_DOMAIN=\"calendar-modules\" \
+ -DEVOLUTION_BINDIR=\""$(bindir)"\" \
+ -DEVOLUTION_PRIVLIBEXECDIR=\""$(PRIVLIBEXECDIR)"\" \
+ -I$(top_srcdir) \
+ -DEVOLUTION_ETSPECDIR=\""$(etspecdir)"\" \
+ $(EVOLUTION_DATA_SERVER_CFLAGS) \
+ $(GNOME_PLATFORM_CFLAGS) \
+ $(GTKHTML_CFLAGS)
+
+module_calendar_la_SOURCES = \
+ evolution-module-calendar.c \
+ e-calendar-preferences.c \
+ e-calendar-preferences.h \
+ e-cal-attachment-handler.c \
+ e-cal-attachment-handler.h \
+ e-cal-config-hook.c \
+ e-cal-config-hook.h \
+ e-cal-event-hook.c \
+ e-cal-event-hook.h \
+ e-cal-shell-backend.c \
+ e-cal-shell-backend.h \
+ e-cal-shell-content.c \
+ e-cal-shell-content.h \
+ e-cal-shell-migrate.c \
+ e-cal-shell-migrate.h \
+ e-cal-shell-sidebar.c \
+ e-cal-shell-sidebar.h \
+ e-cal-shell-view.c \
+ e-cal-shell-view.h \
+ e-cal-shell-view-actions.c \
+ e-cal-shell-view-actions.h \
+ e-cal-shell-view-memopad.c \
+ e-cal-shell-view-private.c \
+ e-cal-shell-view-private.h \
+ e-cal-shell-view-taskpad.c \
+ e-memo-shell-backend.c \
+ e-memo-shell-backend.h \
+ e-memo-shell-content.c \
+ e-memo-shell-content.h \
+ e-memo-shell-migrate.c \
+ e-memo-shell-migrate.h \
+ e-memo-shell-sidebar.c \
+ e-memo-shell-sidebar.h \
+ e-memo-shell-view.c \
+ e-memo-shell-view.h \
+ e-memo-shell-view-actions.c \
+ e-memo-shell-view-actions.h \
+ e-memo-shell-view-private.c \
+ e-memo-shell-view-private.h \
+ e-task-shell-backend.c \
+ e-task-shell-backend.h \
+ e-task-shell-content.c \
+ e-task-shell-content.h \
+ e-task-shell-migrate.c \
+ e-task-shell-migrate.h \
+ e-task-shell-sidebar.c \
+ e-task-shell-sidebar.h \
+ e-task-shell-view.c \
+ e-task-shell-view.h \
+ e-task-shell-view-actions.c \
+ e-task-shell-view-actions.h \
+ e-task-shell-view-private.c \
+ e-task-shell-view-private.h
+
+module_calendar_la_LIBADD = \
+ $(top_builddir)/shell/libevolution-shell.la \
+ $(top_builddir)/calendar/gui/libevolution-calendar.la \
+ $(top_builddir)/calendar/importers/libevolution-calendar-importers.la \
+ $(top_builddir)/mail/libevolution-mail.la \
+ $(top_builddir)/addressbook/gui/contact-editor/libecontacteditor.la \
+ $(top_builddir)/addressbook/gui/contact-list-editor/libecontactlisteditor.la \
+ $(top_builddir)/e-util/libevolution-util.la \
+ $(EVOLUTION_DATA_SERVER_LIBS) \
+ $(GNOME_PLATFORM_LIBS) \
+ $(GTKHTML_LIBS)
+
+module_calendar_la_LDFLAGS = \
+ -module -avoid-version $(NO_UNDEFINED)
+
+ui_DATA = e-calendar-preferences.ui
+
+EXTRA_DIST = \
+ $(ui_DATA)
+
+-include $(top_srcdir)/git.mk
diff --git a/modules/calendar/e-cal-attachment-handler.c b/modules/calendar/e-cal-attachment-handler.c
new file mode 100644
index 0000000000..8613fbf169
--- /dev/null
+++ b/modules/calendar/e-cal-attachment-handler.c
@@ -0,0 +1,577 @@
+/*
+ * e-cal-attachment-handler.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-cal-attachment-handler.h"
+
+#include <glib/gi18n.h>
+#include <libical/ical.h>
+#include <camel/camel.h>
+#include <libecal/libecal.h>
+
+#include <shell/e-shell.h>
+
+#define E_CAL_ATTACHMENT_HANDLER_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_CAL_ATTACHMENT_HANDLER, ECalAttachmentHandlerPrivate))
+
+typedef struct _ImportContext ImportContext;
+
+struct _ECalAttachmentHandlerPrivate {
+ gint placeholder;
+};
+
+struct _ImportContext {
+ ECalClient *client;
+ icalcomponent *component;
+ ECalClientSourceType source_type;
+};
+
+static gpointer parent_class;
+static GType cal_attachment_handler_type;
+
+static const gchar *ui =
+"<ui>"
+" <popup name='context'>"
+" <placeholder name='custom-actions'>"
+" <menuitem action='import-to-calendar'/>"
+" <menuitem action='import-to-tasks'/>"
+" </placeholder>"
+" </popup>"
+"</ui>";
+
+static icalcomponent *
+attachment_handler_get_component (EAttachment *attachment)
+{
+ CamelDataWrapper *wrapper;
+ CamelMimePart *mime_part;
+ CamelStream *stream;
+ GByteArray *buffer;
+ icalcomponent *component;
+ const gchar *key = "__icalcomponent__";
+
+ component = g_object_get_data (G_OBJECT (attachment), key);
+ if (component != NULL)
+ return component;
+
+ if (e_attachment_get_loading (attachment) ||
+ e_attachment_get_saving (attachment))
+ return NULL;
+
+ mime_part = e_attachment_ref_mime_part (attachment);
+ if (mime_part == NULL)
+ return NULL;
+
+ buffer = g_byte_array_new ();
+ stream = camel_stream_mem_new ();
+ camel_stream_mem_set_byte_array (CAMEL_STREAM_MEM (stream), buffer);
+ wrapper = camel_medium_get_content (CAMEL_MEDIUM (mime_part));
+ camel_data_wrapper_decode_to_stream_sync (wrapper, stream, NULL, NULL);
+ g_object_unref (stream);
+
+ g_object_unref (mime_part);
+
+ if (buffer->len > 0) {
+ const gchar *str;
+
+ /* ensure string being null-terminated */
+ g_byte_array_append (buffer, (const guint8 *) "", 1);
+
+ str = (const gchar *) buffer->data;
+ while (*str && g_ascii_isspace (*str))
+ str++;
+
+ if (g_ascii_strncasecmp (str, "BEGIN:", 6) == 0)
+ component = e_cal_util_parse_ics_string (str);
+ }
+
+ g_byte_array_free (buffer, TRUE);
+
+ if (component == NULL)
+ return NULL;
+
+ g_object_set_data_full (
+ G_OBJECT (attachment), key, component,
+ (GDestroyNotify) icalcomponent_free);
+
+ return component;
+}
+
+static gboolean
+attachment_handler_update_objects (ECalClient *client,
+ icalcomponent *component)
+{
+ icalcomponent_kind kind;
+ icalcomponent *vcalendar;
+ gboolean success;
+ GError *error = NULL;
+
+ kind = icalcomponent_isa (component);
+
+ switch (kind) {
+ case ICAL_VTODO_COMPONENT:
+ case ICAL_VEVENT_COMPONENT:
+ vcalendar = e_cal_util_new_top_level ();
+ if (icalcomponent_get_method (component) == ICAL_METHOD_CANCEL)
+ icalcomponent_set_method (vcalendar, ICAL_METHOD_CANCEL);
+ else
+ icalcomponent_set_method (vcalendar, ICAL_METHOD_PUBLISH);
+ icalcomponent_add_component (
+ vcalendar, icalcomponent_new_clone (component));
+ break;
+
+ case ICAL_VCALENDAR_COMPONENT:
+ vcalendar = icalcomponent_new_clone (component);
+ if (!icalcomponent_get_first_property (vcalendar, ICAL_METHOD_PROPERTY))
+ icalcomponent_set_method (vcalendar, ICAL_METHOD_PUBLISH);
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ success = e_cal_client_receive_objects_sync (
+ client, vcalendar, NULL, &error);
+
+ if (error != NULL) {
+ g_warning (
+ "%s: Failed to receive objects: %s",
+ G_STRFUNC, error->message);
+ g_error_free (error);
+ }
+
+ icalcomponent_free (vcalendar);
+
+ return success;
+}
+
+static void
+attachment_handler_import_event (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EAttachment *attachment = user_data;
+ EClient *client;
+ icalcomponent *component;
+ icalcomponent *subcomponent;
+ icalcompiter iter;
+ GError *error = NULL;
+
+ client = e_cal_client_connect_finish (result, &error);
+
+ /* Sanity check. */
+ g_return_if_fail (
+ ((client != NULL) && (error == NULL)) ||
+ ((client == NULL) && (error != NULL)));
+
+ if (error != NULL) {
+ g_warning ("%s: %s", G_STRFUNC, error->message);
+ g_object_unref (attachment);
+ g_error_free (error);
+ return;
+ }
+
+ component = attachment_handler_get_component (attachment);
+ g_return_if_fail (component != NULL);
+
+ iter = icalcomponent_begin_component (component, ICAL_ANY_COMPONENT);
+
+ while ((subcomponent = icalcompiter_deref (&iter)) != NULL) {
+ icalcomponent_kind kind;
+
+ kind = icalcomponent_isa (subcomponent);
+ icalcompiter_next (&iter);
+
+ if (kind == ICAL_VEVENT_COMPONENT)
+ continue;
+
+ if (kind == ICAL_VTIMEZONE_COMPONENT)
+ continue;
+
+ icalcomponent_remove_component (component, subcomponent);
+ icalcomponent_free (subcomponent);
+ }
+
+ /* XXX Do something with the return value. */
+ attachment_handler_update_objects (E_CAL_CLIENT (client), component);
+
+ g_object_unref (attachment);
+ g_object_unref (client);
+}
+
+static void
+attachment_handler_import_todo (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EAttachment *attachment = user_data;
+ EClient *client;
+ icalcomponent *component;
+ icalcomponent *subcomponent;
+ icalcompiter iter;
+ GError *error = NULL;
+
+ client = e_cal_client_connect_finish (result, &error);
+
+ /* Sanity check. */
+ g_return_if_fail (
+ ((client != NULL) && (error == NULL)) ||
+ ((client == NULL) && (error != NULL)));
+
+ if (error != NULL) {
+ g_warning ("%s: %s", G_STRFUNC, error->message);
+ g_object_unref (attachment);
+ g_error_free (error);
+ return;
+ }
+
+ component = attachment_handler_get_component (attachment);
+ g_return_if_fail (component != NULL);
+
+ iter = icalcomponent_begin_component (component, ICAL_ANY_COMPONENT);
+
+ while ((subcomponent = icalcompiter_deref (&iter)) != NULL) {
+ icalcomponent_kind kind;
+
+ kind = icalcomponent_isa (subcomponent);
+ icalcompiter_next (&iter);
+
+ if (kind == ICAL_VTODO_COMPONENT)
+ continue;
+
+ if (kind == ICAL_VTIMEZONE_COMPONENT)
+ continue;
+
+ icalcomponent_remove_component (component, subcomponent);
+ icalcomponent_free (subcomponent);
+ }
+
+ /* XXX Do something with the return value. */
+ attachment_handler_update_objects (E_CAL_CLIENT (client), component);
+
+ g_object_unref (attachment);
+ g_object_unref (client);
+}
+
+static void
+attachment_handler_row_activated_cb (GtkDialog *dialog)
+{
+ gtk_dialog_response (dialog, GTK_RESPONSE_OK);
+}
+
+static void
+attachment_handler_run_dialog (GtkWindow *parent,
+ EAttachment *attachment,
+ ECalClientSourceType source_type,
+ const gchar *title)
+{
+ EShell *shell;
+ GtkWidget *dialog;
+ GtkWidget *container;
+ GtkWidget *widget;
+ ESourceRegistry *registry;
+ ESourceSelector *selector;
+ ESource *source;
+ const gchar *extension_name;
+ icalcomponent *component;
+
+ switch (source_type) {
+ case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+ extension_name = E_SOURCE_EXTENSION_CALENDAR;
+ break;
+ case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+ extension_name = E_SOURCE_EXTENSION_TASK_LIST;
+ break;
+ case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+ extension_name = E_SOURCE_EXTENSION_MEMO_LIST;
+ break;
+ default:
+ g_return_if_reached ();
+ }
+
+ component = attachment_handler_get_component (attachment);
+ g_return_if_fail (component != NULL);
+
+ dialog = gtk_dialog_new_with_buttons (
+ title, parent, GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL);
+
+ widget = gtk_button_new_with_mnemonic (_("I_mport"));
+ gtk_button_set_image (
+ GTK_BUTTON (widget), gtk_image_new_from_icon_name (
+ "stock_mail-import", GTK_ICON_SIZE_MENU));
+ gtk_dialog_add_action_widget (
+ GTK_DIALOG (dialog), widget, GTK_RESPONSE_OK);
+ gtk_widget_show (widget);
+
+ gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 400);
+
+ container = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (
+ GTK_SCROLLED_WINDOW (widget),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (
+ GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ shell = e_shell_get_default ();
+ registry = e_shell_get_registry (shell);
+ widget = e_source_selector_new (registry, extension_name);
+ selector = E_SOURCE_SELECTOR (widget);
+ e_source_selector_set_show_toggles (selector, FALSE);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ gtk_widget_show (widget);
+
+ g_signal_connect_swapped (
+ widget, "row-activated",
+ G_CALLBACK (attachment_handler_row_activated_cb), dialog);
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK)
+ goto exit;
+
+ source = e_source_selector_ref_primary_selection (selector);
+ if (source == NULL)
+ goto exit;
+
+ switch (source_type) {
+ case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+ e_cal_client_connect (
+ source, source_type, NULL,
+ attachment_handler_import_event,
+ g_object_ref (attachment));
+ break;
+ case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+ e_cal_client_connect (
+ source, source_type, NULL,
+ attachment_handler_import_todo,
+ g_object_ref (attachment));
+ break;
+ default:
+ break;
+ }
+
+ g_object_unref (source);
+
+ exit:
+ gtk_widget_destroy (dialog);
+}
+
+static void
+attachment_handler_import_to_calendar (GtkAction *action,
+ EAttachmentHandler *handler)
+{
+ EAttachment *attachment;
+ EAttachmentView *view;
+ GList *selected;
+ gpointer parent;
+
+ view = e_attachment_handler_get_view (handler);
+
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
+ parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
+
+ selected = e_attachment_view_get_selected_attachments (view);
+ g_return_if_fail (g_list_length (selected) == 1);
+ attachment = E_ATTACHMENT (selected->data);
+
+ attachment_handler_run_dialog (
+ parent, attachment,
+ E_CAL_CLIENT_SOURCE_TYPE_EVENTS,
+ _("Select a Calendar"));
+
+ g_object_unref (attachment);
+ g_list_free (selected);
+}
+
+static void
+attachment_handler_import_to_tasks (GtkAction *action,
+ EAttachmentHandler *handler)
+{
+ EAttachment *attachment;
+ EAttachmentView *view;
+ GList *selected;
+ gpointer parent;
+
+ view = e_attachment_handler_get_view (handler);
+
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
+ parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
+
+ selected = e_attachment_view_get_selected_attachments (view);
+ g_return_if_fail (g_list_length (selected) == 1);
+ attachment = E_ATTACHMENT (selected->data);
+
+ attachment_handler_run_dialog (
+ parent, attachment,
+ E_CAL_CLIENT_SOURCE_TYPE_TASKS,
+ _("Select a Task List"));
+
+ g_object_unref (attachment);
+ g_list_free (selected);
+}
+
+static GtkActionEntry standard_entries[] = {
+
+ { "import-to-calendar",
+ "stock_mail-import",
+ N_("I_mport to Calendar"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (attachment_handler_import_to_calendar) },
+
+ { "import-to-tasks",
+ "stock_mail-import",
+ N_("I_mport to Tasks"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (attachment_handler_import_to_tasks) }
+};
+
+static void
+cal_attachment_handler_update_actions (EAttachmentView *view)
+{
+ EAttachment *attachment;
+ GtkAction *action;
+ GList *selected;
+ icalcomponent *component;
+ icalcomponent *subcomponent;
+ icalcomponent_kind kind;
+ gboolean is_vevent = FALSE;
+ gboolean is_vtodo = FALSE;
+
+ selected = e_attachment_view_get_selected_attachments (view);
+
+ if (g_list_length (selected) != 1)
+ goto exit;
+
+ attachment = E_ATTACHMENT (selected->data);
+ component = attachment_handler_get_component (attachment);
+
+ if (component == NULL)
+ goto exit;
+
+ subcomponent = icalcomponent_get_inner (component);
+
+ if (subcomponent == NULL)
+ goto exit;
+
+ kind = icalcomponent_isa (subcomponent);
+ is_vevent = (kind == ICAL_VEVENT_COMPONENT);
+ is_vtodo = (kind == ICAL_VTODO_COMPONENT);
+
+exit:
+ action = e_attachment_view_get_action (view, "import-to-calendar");
+ gtk_action_set_visible (action, is_vevent);
+
+ action = e_attachment_view_get_action (view, "import-to-tasks");
+ gtk_action_set_visible (action, is_vtodo);
+
+ g_list_foreach (selected, (GFunc) g_object_unref, NULL);
+ g_list_free (selected);
+}
+
+static void
+cal_attachment_handler_constructed (GObject *object)
+{
+ EAttachmentHandler *handler;
+ EAttachmentView *view;
+ GtkActionGroup *action_group;
+ GtkUIManager *ui_manager;
+ GError *error = NULL;
+
+ handler = E_ATTACHMENT_HANDLER (object);
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (parent_class)->constructed (object);
+
+ view = e_attachment_handler_get_view (handler);
+
+ action_group = e_attachment_view_add_action_group (view, "calendar");
+ gtk_action_group_add_actions (
+ action_group, standard_entries,
+ G_N_ELEMENTS (standard_entries), handler);
+
+ ui_manager = e_attachment_view_get_ui_manager (view);
+ gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error);
+
+ if (error != NULL) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+
+ g_signal_connect (
+ view, "update_actions",
+ G_CALLBACK (cal_attachment_handler_update_actions),
+ NULL);
+}
+
+static void
+cal_attachment_handler_class_init (ECalAttachmentHandlerClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (ECalAttachmentHandlerPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->constructed = cal_attachment_handler_constructed;
+}
+
+static void
+cal_attachment_handler_init (ECalAttachmentHandler *handler)
+{
+ handler->priv = E_CAL_ATTACHMENT_HANDLER_GET_PRIVATE (handler);
+}
+
+GType
+e_cal_attachment_handler_get_type (void)
+{
+ return cal_attachment_handler_type;
+}
+
+void
+e_cal_attachment_handler_register_type (GTypeModule *type_module)
+{
+ static const GTypeInfo type_info = {
+ sizeof (ECalAttachmentHandlerClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) cal_attachment_handler_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (ECalAttachmentHandler),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) cal_attachment_handler_init,
+ NULL /* value_table */
+ };
+
+ cal_attachment_handler_type = g_type_module_register_type (
+ type_module, E_TYPE_ATTACHMENT_HANDLER,
+ "ECalAttachmentHandler", &type_info, 0);
+}
diff --git a/modules/calendar/e-cal-attachment-handler.h b/modules/calendar/e-cal-attachment-handler.h
new file mode 100644
index 0000000000..549199ec35
--- /dev/null
+++ b/modules/calendar/e-cal-attachment-handler.h
@@ -0,0 +1,67 @@
+/*
+ * e-cal-attachment-handler.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_CAL_ATTACHMENT_HANDLER_H
+#define E_CAL_ATTACHMENT_HANDLER_H
+
+#include <e-util/e-util.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CAL_ATTACHMENT_HANDLER \
+ (e_cal_attachment_handler_get_type ())
+#define E_CAL_ATTACHMENT_HANDLER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_CAL_ATTACHMENT_HANDLER, ECalAttachmentHandler))
+#define E_CAL_ATTACHMENT_HANDLER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_CAL_ATTACHMENT_HANDLER, ECalAttachmentHandlerClass))
+#define E_IS_CAL_ATTACHMENT_HANDLER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_CAL_ATTACHMENT_HANDLER))
+#define E_IS_CAL_ATTACHMENT_HANDLER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_CAL_ATTACHMENT_HANDLER))
+#define E_CAL_ATTACHMENT_HANDLER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_CAL_ATTACHMENT_HANDLER, ECalAttachmentHandlerClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ECalAttachmentHandler ECalAttachmentHandler;
+typedef struct _ECalAttachmentHandlerClass ECalAttachmentHandlerClass;
+typedef struct _ECalAttachmentHandlerPrivate ECalAttachmentHandlerPrivate;
+
+struct _ECalAttachmentHandler {
+ EAttachmentHandler parent;
+ ECalAttachmentHandlerPrivate *priv;
+};
+
+struct _ECalAttachmentHandlerClass {
+ EAttachmentHandlerClass parent_class;
+};
+
+GType e_cal_attachment_handler_get_type (void);
+void e_cal_attachment_handler_register_type
+ (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* E_CAL_ATTACHMENT_HANDLER_H */
diff --git a/modules/calendar/e-cal-config-hook.c b/modules/calendar/e-cal-config-hook.c
new file mode 100644
index 0000000000..57fb8b8cc5
--- /dev/null
+++ b/modules/calendar/e-cal-config-hook.c
@@ -0,0 +1,75 @@
+/*
+ * e-cal-config-hook.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-cal-config-hook.h"
+
+#include "calendar/gui/e-cal-config.h"
+
+static const EConfigHookTargetMask no_masks[] = {
+ { NULL }
+};
+
+static const EConfigHookTargetMap targets[] = {
+ { "source", EC_CONFIG_TARGET_SOURCE, no_masks },
+ { "prefs", EC_CONFIG_TARGET_PREFS, no_masks },
+ { NULL }
+};
+
+static void
+cal_config_hook_class_init (EConfigHookClass *class)
+{
+ EPluginHookClass *plugin_hook_class;
+ gint ii;
+
+ plugin_hook_class = E_PLUGIN_HOOK_CLASS (class);
+ plugin_hook_class->id = "org.gnome.evolution.calendar.config:1.0";
+
+ class->config_class = g_type_class_ref (e_cal_config_get_type ());
+
+ for (ii = 0; targets[ii].type != NULL; ii++)
+ e_config_hook_class_add_target_map (
+ (EConfigHookClass *) class, &targets[ii]);
+}
+
+void
+e_cal_config_hook_register_type (GTypeModule *type_module)
+{
+ const GTypeInfo type_info = {
+ sizeof (EConfigHookClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) cal_config_hook_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EConfigHook),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) NULL,
+ NULL /* value_table */
+ };
+
+ g_type_module_register_type (
+ type_module, e_config_hook_get_type (),
+ "ECalConfigHook", &type_info, 0);
+}
diff --git a/modules/calendar/e-cal-config-hook.h b/modules/calendar/e-cal-config-hook.h
new file mode 100644
index 0000000000..a22ec56bbc
--- /dev/null
+++ b/modules/calendar/e-cal-config-hook.h
@@ -0,0 +1,33 @@
+/*
+ * e-cal-config-hook.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_CAL_CONFIG_HOOK_H
+#define E_CAL_CONFIG_HOOK_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+void e_cal_config_hook_register_type (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* E_CAL_CONFIG_HOOK_H */
diff --git a/modules/calendar/e-cal-event-hook.c b/modules/calendar/e-cal-event-hook.c
new file mode 100644
index 0000000000..9f38e7005b
--- /dev/null
+++ b/modules/calendar/e-cal-event-hook.c
@@ -0,0 +1,75 @@
+/*
+ * e-cal-event-hook.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-cal-event-hook.h"
+
+#include "calendar/gui/e-cal-event.h"
+
+static const EEventHookTargetMask masks[] = {
+ { "migration", E_CAL_EVENT_MODULE_MIGRATION },
+ { NULL }
+};
+
+static const EEventHookTargetMap targets[] = {
+ { "module", E_CAL_EVENT_TARGET_BACKEND, masks },
+ { NULL }
+};
+
+static void
+cal_event_hook_class_init (EEventHookClass *class)
+{
+ EPluginHookClass *plugin_hook_class;
+ gint ii;
+
+ plugin_hook_class = E_PLUGIN_HOOK_CLASS (class);
+ plugin_hook_class->id = "org.gnome.evolution.calendar.events:1.0";
+
+ class->event = (EEvent *) e_cal_event_peek ();
+
+ for (ii = 0; targets[ii].type != NULL; ii++)
+ e_event_hook_class_add_target_map (
+ (EEventHookClass *) class, &targets[ii]);
+}
+
+void
+e_cal_event_hook_register_type (GTypeModule *type_module)
+{
+ const GTypeInfo type_info = {
+ sizeof (EEventHookClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) cal_event_hook_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EEventHook),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) NULL,
+ NULL /* value_table */
+ };
+
+ g_type_module_register_type (
+ type_module, e_event_hook_get_type (),
+ "ECalEventHook", &type_info, 0);
+}
diff --git a/modules/calendar/e-cal-event-hook.h b/modules/calendar/e-cal-event-hook.h
new file mode 100644
index 0000000000..9dde31f900
--- /dev/null
+++ b/modules/calendar/e-cal-event-hook.h
@@ -0,0 +1,33 @@
+/*
+ * e-cal-event-hook.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_CAL_EVENT_HOOK_H
+#define E_CAL_EVENT_HOOK_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+void e_cal_event_hook_register_type (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* E_CAL_EVENT_HOOK_H */
diff --git a/modules/calendar/e-cal-shell-backend.c b/modules/calendar/e-cal-shell-backend.c
new file mode 100644
index 0000000000..6a9bc1aac8
--- /dev/null
+++ b/modules/calendar/e-cal-shell-backend.c
@@ -0,0 +1,858 @@
+/*
+ * e-cal-shell-backend.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-cal-shell-backend.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <libecal/libecal.h>
+
+#include "shell/e-shell.h"
+#include "shell/e-shell-backend.h"
+#include "shell/e-shell-window.h"
+
+#include "calendar/gui/comp-util.h"
+#include "calendar/gui/dialogs/event-editor.h"
+#include "calendar/gui/e-calendar-view.h"
+#include "calendar/gui/gnome-cal.h"
+#include "calendar/importers/evolution-calendar-importer.h"
+
+#include "e-cal-shell-content.h"
+#include "e-cal-shell-migrate.h"
+#include "e-cal-shell-sidebar.h"
+#include "e-cal-shell-view.h"
+
+#include "e-calendar-preferences.h"
+
+#define E_CAL_SHELL_BACKEND_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_CAL_SHELL_BACKEND, ECalShellBackendPrivate))
+
+struct _ECalShellBackendPrivate {
+ gint placeholder;
+};
+
+G_DEFINE_DYNAMIC_TYPE (
+ ECalShellBackend,
+ e_cal_shell_backend,
+ E_TYPE_SHELL_BACKEND)
+
+static void
+cal_shell_backend_new_event (ECalClient *cal_client,
+ EShell *shell,
+ CompEditorFlags flags,
+ gboolean all_day)
+{
+ ECalComponent *comp;
+ GSettings *settings;
+ CompEditor *editor;
+
+ settings = g_settings_new ("org.gnome.evolution.calendar");
+
+ editor = event_editor_new (cal_client, shell, flags);
+ comp = cal_comp_event_new_with_current_time (
+ cal_client, all_day,
+ g_settings_get_boolean (settings, "use-default-reminder"),
+ g_settings_get_int (settings, "default-reminder-interval"),
+ g_settings_get_enum (settings, "default-reminder-units"));
+ e_cal_component_commit_sequence (comp);
+ comp_editor_edit_comp (editor, comp);
+
+ gtk_window_present (GTK_WINDOW (editor));
+
+ g_object_unref (comp);
+
+ g_object_unref (settings);
+}
+
+static void
+cal_shell_backend_event_new_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EShell *shell = E_SHELL (user_data);
+ EClient *client;
+ CompEditorFlags flags = 0;
+ gboolean all_day = FALSE;
+ GError *error = NULL;
+
+ flags |= COMP_EDITOR_NEW_ITEM;
+ flags |= COMP_EDITOR_USER_ORG;
+
+ client = e_client_cache_get_client_finish (
+ E_CLIENT_CACHE (source_object), result, &error);
+
+ /* Sanity check. */
+ g_return_if_fail (
+ ((client != NULL) && (error == NULL)) ||
+ ((client == NULL) && (error != NULL)));
+
+ if (client != NULL) {
+ cal_shell_backend_new_event (
+ E_CAL_CLIENT (client), shell, flags, all_day);
+ g_object_unref (client);
+ } else {
+ /* XXX Handle errors better. */
+ g_warning ("%s: %s", G_STRFUNC, error->message);
+ g_error_free (error);
+ }
+
+ g_object_unref (shell);
+}
+
+static void
+cal_shell_backend_event_all_day_new_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EShell *shell = E_SHELL (user_data);
+ EClient *client;
+ CompEditorFlags flags = 0;
+ gboolean all_day = TRUE;
+ GError *error = NULL;
+
+ flags |= COMP_EDITOR_NEW_ITEM;
+ flags |= COMP_EDITOR_USER_ORG;
+
+ client = e_client_cache_get_client_finish (
+ E_CLIENT_CACHE (source_object), result, &error);
+
+ /* Sanity check. */
+ g_return_if_fail (
+ ((client != NULL) && (error == NULL)) ||
+ ((client == NULL) && (error != NULL)));
+
+ if (client != NULL) {
+ cal_shell_backend_new_event (
+ E_CAL_CLIENT (client), shell, flags, all_day);
+ g_object_unref (client);
+ } else {
+ /* XXX Handle errors better. */
+ g_warning ("%s: %s", G_STRFUNC, error->message);
+ g_error_free (error);
+ }
+
+ g_object_unref (shell);
+}
+
+static void
+cal_shell_backend_event_meeting_new_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EShell *shell = E_SHELL (user_data);
+ EClient *client;
+ CompEditorFlags flags = 0;
+ gboolean all_day = FALSE;
+ GError *error = NULL;
+
+ flags |= COMP_EDITOR_NEW_ITEM;
+ flags |= COMP_EDITOR_USER_ORG;
+ flags |= COMP_EDITOR_MEETING;
+
+ client = e_client_cache_get_client_finish (
+ E_CLIENT_CACHE (source_object), result, &error);
+
+ /* Sanity check. */
+ g_return_if_fail (
+ ((client != NULL) && (error == NULL)) ||
+ ((client == NULL) && (error != NULL)));
+
+ if (client != NULL) {
+ cal_shell_backend_new_event (
+ E_CAL_CLIENT (client), shell, flags, all_day);
+ g_object_unref (client);
+ } else {
+ /* XXX Handle errors better. */
+ g_warning ("%s: %s", G_STRFUNC, error->message);
+ g_error_free (error);
+ }
+
+ g_object_unref (shell);
+}
+
+static void
+action_event_new_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellBackend *shell_backend;
+ ESource *source;
+ ESourceRegistry *registry;
+ EClientCache *client_cache;
+ const gchar *action_name;
+
+ shell = e_shell_window_get_shell (shell_window);
+ client_cache = e_shell_get_client_cache (shell);
+
+ action_name = gtk_action_get_name (action);
+
+ /* With a 'calendar' active shell view pass the new appointment
+ * request to it, thus the event will inherit selected time from
+ * the view. */
+ shell_view = e_shell_window_peek_shell_view (shell_window, "calendar");
+ if (shell_view != NULL) {
+ EShellWindow *shell_window;
+ EShellContent *shell_content;
+ GnomeCalendar *gcal;
+ GnomeCalendarViewType view_type;
+ ECalendarView *view;
+
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+ shell_content = e_shell_view_get_shell_content (shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ e_shell_backend_set_prefer_new_item (
+ shell_backend, action_name);
+
+ /* This forces the shell window to update the "New" toolbar
+ * button menu, and the toolbar button will then update its
+ * button image to reflect the "preferred new item" we just
+ * set on the shell backend. */
+ g_object_notify (G_OBJECT (shell_window), "active-view");
+
+ gcal = e_cal_shell_content_get_calendar (
+ E_CAL_SHELL_CONTENT (shell_content));
+
+ view_type = gnome_calendar_get_view (gcal);
+ view = gnome_calendar_get_calendar_view (gcal, view_type);
+
+ if (view != NULL) {
+ e_calendar_view_new_appointment_full (
+ view,
+ g_str_equal (action_name, "event-all-day-new"),
+ g_str_equal (action_name, "event-meeting-new"),
+ TRUE);
+
+ return;
+ }
+ }
+
+ /* This callback is used for both appointments and meetings. */
+
+ registry = e_shell_get_registry (shell);
+ source = e_source_registry_ref_default_calendar (registry);
+
+ shell_backend = e_shell_get_backend_by_name (shell, "calendar");
+ e_shell_backend_set_prefer_new_item (shell_backend, action_name);
+
+ /* Use a callback function appropriate for the action. */
+ if (strcmp (action_name, "event-all-day-new") == 0)
+ e_client_cache_get_client (
+ client_cache, source,
+ E_SOURCE_EXTENSION_CALENDAR,
+ NULL,
+ cal_shell_backend_event_all_day_new_cb,
+ g_object_ref (shell));
+ else if (strcmp (action_name, "event-meeting-new") == 0)
+ e_client_cache_get_client (
+ client_cache, source,
+ E_SOURCE_EXTENSION_CALENDAR,
+ NULL,
+ cal_shell_backend_event_meeting_new_cb,
+ g_object_ref (shell));
+ else
+ e_client_cache_get_client (
+ client_cache, source,
+ E_SOURCE_EXTENSION_CALENDAR,
+ NULL,
+ cal_shell_backend_event_new_cb,
+ g_object_ref (shell));
+
+ g_object_unref (source);
+}
+
+static void
+action_calendar_new_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ EShell *shell;
+ ESourceRegistry *registry;
+ ECalClientSourceType source_type;
+ GtkWidget *config;
+ GtkWidget *dialog;
+ const gchar *icon_name;
+
+ shell = e_shell_window_get_shell (shell_window);
+
+ registry = e_shell_get_registry (shell);
+ source_type = E_CAL_CLIENT_SOURCE_TYPE_EVENTS;
+ config = e_cal_source_config_new (registry, NULL, source_type);
+
+ dialog = e_source_config_dialog_new (E_SOURCE_CONFIG (config));
+
+ gtk_window_set_transient_for (
+ GTK_WINDOW (dialog), GTK_WINDOW (shell_window));
+
+ icon_name = gtk_action_get_icon_name (action);
+ gtk_window_set_icon_name (GTK_WINDOW (dialog), icon_name);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), _("New Calendar"));
+
+ gtk_widget_show (dialog);
+}
+
+static GtkActionEntry item_entries[] = {
+
+ { "event-new",
+ "appointment-new",
+ NC_("New", "_Appointment"),
+ "<Shift><Control>a",
+ N_("Create a new appointment"),
+ G_CALLBACK (action_event_new_cb) },
+
+ { "event-all-day-new",
+ "stock_new-24h-appointment",
+ NC_("New", "All Day A_ppointment"),
+ NULL,
+ N_("Create a new all-day appointment"),
+ G_CALLBACK (action_event_new_cb) },
+
+ { "event-meeting-new",
+ "stock_new-meeting",
+ NC_("New", "M_eeting"),
+ "<Shift><Control>e",
+ N_("Create a new meeting request"),
+ G_CALLBACK (action_event_new_cb) }
+};
+
+static GtkActionEntry source_entries[] = {
+
+ { "calendar-new",
+ "x-office-calendar",
+ NC_("New", "Cale_ndar"),
+ NULL,
+ N_("Create a new calendar"),
+ G_CALLBACK (action_calendar_new_cb) }
+};
+
+static void
+cal_shell_backend_init_importers (void)
+{
+ EImportClass *import_class;
+ EImportImporter *importer;
+
+ import_class = g_type_class_ref (e_import_get_type ());
+
+ importer = gnome_calendar_importer_peek ();
+ e_import_class_add_importer (import_class, importer, NULL, NULL);
+
+ importer = ical_importer_peek ();
+ e_import_class_add_importer (import_class, importer, NULL, NULL);
+
+ importer = vcal_importer_peek ();
+ e_import_class_add_importer (import_class, importer, NULL, NULL);
+}
+
+static void
+populate_g_date (GDate *date,
+ time_t utc_time,
+ icaltimezone *zone)
+{
+ struct icaltimetype icaltm;
+
+ g_return_if_fail (date != NULL);
+
+ if ((gint) utc_time == -1)
+ return;
+
+ if (zone)
+ icaltm = icaltime_from_timet_with_zone (utc_time, FALSE, zone);
+ else
+ icaltm = icaltime_from_timet (utc_time, FALSE);
+
+ if (icaltime_is_null_time (icaltm) ||
+ !icaltime_is_valid_time (icaltm))
+ return;
+
+ g_date_set_dmy (date, icaltm.day, icaltm.month, icaltm.year);
+}
+
+static gboolean
+cal_shell_backend_handle_uri_cb (EShellBackend *shell_backend,
+ const gchar *uri)
+{
+ EShell *shell;
+ CompEditor *editor;
+ CompEditorFlags flags = 0;
+ EClient *client;
+ EClientCache *client_cache;
+ ECalComponent *comp;
+ ESource *source;
+ ESourceRegistry *registry;
+ GSettings *settings;
+ SoupURI *soup_uri;
+ icalcomponent *icalcomp;
+ icalproperty *icalprop;
+ const gchar *cp;
+ gchar *source_uid = NULL;
+ gchar *comp_uid = NULL;
+ gchar *comp_rid = NULL;
+ GDate start_date;
+ GDate end_date;
+ icaltimezone *zone;
+ gboolean handled = FALSE;
+ GError *error = NULL;
+
+ shell = e_shell_backend_get_shell (shell_backend);
+ client_cache = e_shell_get_client_cache (shell);
+
+ if (strncmp (uri, "calendar:", 9) != 0)
+ return FALSE;
+
+ soup_uri = soup_uri_new (uri);
+
+ if (soup_uri == NULL)
+ return FALSE;
+
+ cp = soup_uri_get_query (soup_uri);
+ if (cp == NULL)
+ goto exit;
+
+ g_date_clear (&start_date, 1);
+ g_date_clear (&end_date, 1);
+
+ settings = g_settings_new ("org.gnome.evolution.calendar");
+
+ if (g_settings_get_boolean (settings, "use-system-timezone"))
+ zone = e_cal_util_get_system_timezone ();
+ else {
+ gchar *location;
+
+ location = g_settings_get_string (settings, "timezone");
+
+ if (location != NULL) {
+ zone = icaltimezone_get_builtin_timezone (location);
+ g_free (location);
+ }
+ }
+
+ if (zone == NULL)
+ zone = icaltimezone_get_utc_timezone ();
+
+ g_object_unref (settings);
+
+ while (*cp != '\0') {
+ gchar *header;
+ gchar *content;
+ gsize header_len;
+ gsize content_len;
+
+ header_len = strcspn (cp, "=&");
+
+ /* It it's malformed, give up. */
+ if (cp[header_len] != '=')
+ break;
+
+ header = (gchar *) cp;
+ header[header_len] = '\0';
+ cp += header_len + 1;
+
+ content_len = strcspn (cp, "&");
+
+ content = g_strndup (cp, content_len);
+ if (g_ascii_strcasecmp (header, "startdate") == 0)
+ populate_g_date (&start_date, time_from_isodate (content), zone);
+ else if (g_ascii_strcasecmp (header, "enddate") == 0)
+ populate_g_date (&end_date, time_from_isodate (content), zone);
+ else if (g_ascii_strcasecmp (header, "source-uid") == 0)
+ source_uid = g_strdup (content);
+ else if (g_ascii_strcasecmp (header, "comp-uid") == 0)
+ comp_uid = g_strdup (content);
+ else if (g_ascii_strcasecmp (header, "comp-rid") == 0)
+ comp_rid = g_strdup (content);
+ g_free (content);
+
+ cp += content_len;
+ if (*cp == '&') {
+ cp++;
+ if (strncmp (cp, "amp;", 4) == 0)
+ cp += 4;
+ }
+ }
+
+ /* This is primarily for launching Evolution
+ * from the calendar in the clock applet. */
+ if (g_date_valid (&start_date)) {
+ if (g_date_valid (&end_date))
+ e_cal_shell_backend_open_date_range (
+ E_CAL_SHELL_BACKEND (shell_backend),
+ &start_date, &end_date);
+ else
+ e_cal_shell_backend_open_date_range (
+ E_CAL_SHELL_BACKEND (shell_backend),
+ &start_date, NULL);
+ handled = TRUE;
+ goto exit;
+ }
+
+ if (source_uid == NULL || comp_uid == NULL)
+ goto exit;
+
+ /* URI is valid, so consider it handled. Whether
+ * we successfully open it is another matter... */
+ handled = TRUE;
+
+ registry = e_shell_get_registry (shell);
+ source = e_source_registry_ref_source (registry, source_uid);
+ if (source == NULL) {
+ g_printerr ("No source for UID '%s'\n", source_uid);
+ goto exit;
+ }
+
+ client = e_client_cache_get_client_sync (
+ client_cache, source,
+ E_SOURCE_EXTENSION_CALENDAR,
+ NULL, &error);
+
+ /* Sanity check. */
+ g_return_val_if_fail (
+ ((client != NULL) && (error == NULL)) ||
+ ((client == NULL) && (error != NULL)), FALSE);
+
+ if (error != NULL) {
+ g_warning (
+ "%s: Failed to create/open client '%s': %s",
+ G_STRFUNC, e_source_get_display_name (source),
+ error->message);
+ g_object_unref (source);
+ g_error_free (error);
+ goto exit;
+ }
+
+ g_object_unref (source);
+ source = NULL;
+
+ /* XXX Copied from e_cal_shell_view_open_event().
+ * Clearly a new utility function is needed. */
+
+ editor = comp_editor_find_instance (comp_uid);
+
+ if (editor != NULL)
+ goto present;
+
+ e_cal_client_get_object_sync (
+ E_CAL_CLIENT (client),comp_uid,
+ comp_rid, &icalcomp, NULL, &error);
+
+ if (error != NULL) {
+ g_warning (
+ "%s: Failed to get object from client: %s",
+ G_STRFUNC, error->message);
+ g_object_unref (client);
+ g_error_free (error);
+ goto exit;
+ }
+
+ comp = e_cal_component_new ();
+ if (!e_cal_component_set_icalcomponent (comp, icalcomp)) {
+ g_warning ("%s: Failed to set icalcomp to comp\n", G_STRFUNC);
+ icalcomponent_free (icalcomp);
+ icalcomp = NULL;
+ }
+
+ icalprop = icalcomp ? icalcomponent_get_first_property (
+ icalcomp, ICAL_ATTENDEE_PROPERTY) : NULL;
+ if (icalprop != NULL)
+ flags |= COMP_EDITOR_MEETING;
+
+ if (itip_organizer_is_user (registry, comp, E_CAL_CLIENT (client)))
+ flags |= COMP_EDITOR_USER_ORG;
+
+ if (itip_sentby_is_user (registry, comp, E_CAL_CLIENT (client)))
+ flags |= COMP_EDITOR_USER_ORG;
+
+ if (!e_cal_component_has_attendees (comp))
+ flags |= COMP_EDITOR_USER_ORG;
+
+ editor = event_editor_new (E_CAL_CLIENT (client), shell, flags);
+ comp_editor_edit_comp (editor, comp);
+
+ g_object_unref (comp);
+
+present:
+ gtk_window_present (GTK_WINDOW (editor));
+
+ g_object_unref (client);
+
+exit:
+ g_free (source_uid);
+ g_free (comp_uid);
+ g_free (comp_rid);
+
+ soup_uri_free (soup_uri);
+
+ return handled;
+}
+
+static void
+cal_shell_backend_window_added_cb (EShellBackend *shell_backend,
+ GtkWindow *window)
+{
+ const gchar *backend_name;
+
+ if (!E_IS_SHELL_WINDOW (window))
+ return;
+
+ backend_name = E_SHELL_BACKEND_GET_CLASS (shell_backend)->name;
+
+ e_shell_window_register_new_item_actions (
+ E_SHELL_WINDOW (window), backend_name,
+ item_entries, G_N_ELEMENTS (item_entries));
+
+ e_shell_window_register_new_source_actions (
+ E_SHELL_WINDOW (window), backend_name,
+ source_entries, G_N_ELEMENTS (source_entries));
+}
+
+static void
+ensure_alarm_notify_is_running (void)
+{
+ const gchar *base_dir;
+ gchar *filename;
+
+ #ifdef G_OS_WIN32
+ base_dir = EVOLUTION_BINDIR;
+ #else
+ base_dir = EVOLUTION_PRIVLIBEXECDIR;
+ #endif
+
+ filename = g_build_filename (base_dir, "evolution-alarm-notify", NULL);
+
+ if (g_file_test (filename, G_FILE_TEST_IS_EXECUTABLE)) {
+ gchar *argv[2];
+ GError *error = NULL;
+
+ argv[0] = filename;
+ argv[1] = NULL;
+
+ g_spawn_async (
+ base_dir, argv, NULL, 0, NULL, NULL, NULL, &error);
+
+ if (error != NULL) {
+ g_message (
+ "Failed to start '%s': %s",
+ filename, error->message);
+ g_error_free (error);
+ }
+ }
+
+ g_free (filename);
+}
+
+static void
+cal_shell_backend_use_system_timezone_changed_cb (GSettings *settings,
+ const gchar *key)
+{
+ g_signal_emit_by_name (settings, "changed::timezone", timezone);
+}
+
+static void
+cal_shell_backend_constructed (GObject *object)
+{
+ EShell *shell;
+ EShellBackend *shell_backend;
+ GtkWidget *preferences_window;
+ GSettings *settings;
+
+ shell_backend = E_SHELL_BACKEND (object);
+ shell = e_shell_backend_get_shell (shell_backend);
+
+ g_signal_connect_swapped (
+ shell, "handle-uri",
+ G_CALLBACK (cal_shell_backend_handle_uri_cb),
+ shell_backend);
+
+ g_signal_connect_swapped (
+ shell, "window-added",
+ G_CALLBACK (cal_shell_backend_window_added_cb),
+ shell_backend);
+
+ cal_shell_backend_init_importers ();
+
+ /* Setup preference widget factories */
+ preferences_window = e_shell_get_preferences_window (shell);
+
+ e_preferences_window_add_page (
+ E_PREFERENCES_WINDOW (preferences_window),
+ "calendar-and-tasks",
+ "preferences-calendar-and-tasks",
+ _("Calendar and Tasks"),
+ "index#calendar",
+ e_calendar_preferences_new,
+ 600);
+
+ settings = g_settings_new ("org.gnome.evolution.calendar");
+
+ g_settings_bind (
+ settings, "prefer-new-item",
+ shell_backend, "prefer-new-item",
+ G_SETTINGS_BIND_DEFAULT);
+
+ /* Changing whether or not to use the system timezone may change
+ * Evolution's current timezone. Need to emit "changed" signals
+ * for both keys. */
+ g_signal_connect (
+ settings, "changed::use-system-timezone",
+ G_CALLBACK (cal_shell_backend_use_system_timezone_changed_cb),
+ NULL);
+
+ g_object_unref (settings);
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_cal_shell_backend_parent_class)->constructed (object);
+
+ ensure_alarm_notify_is_running ();
+}
+
+static void
+e_cal_shell_backend_class_init (ECalShellBackendClass *class)
+{
+ GObjectClass *object_class;
+ EShellBackendClass *shell_backend_class;
+
+ g_type_class_add_private (class, sizeof (ECalShellBackendPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->constructed = cal_shell_backend_constructed;
+
+ shell_backend_class = E_SHELL_BACKEND_CLASS (class);
+ shell_backend_class->shell_view_type = E_TYPE_CAL_SHELL_VIEW;
+ shell_backend_class->name = "calendar";
+ shell_backend_class->aliases = "";
+ shell_backend_class->schemes = "calendar";
+ shell_backend_class->sort_order = 400;
+ shell_backend_class->preferences_page = "calendar-and-tasks";
+ shell_backend_class->start = NULL;
+ shell_backend_class->migrate = e_cal_shell_backend_migrate;
+
+ /* Register relevant ESource extensions. */
+ E_TYPE_SOURCE_CALENDAR;
+}
+
+static void
+e_cal_shell_backend_class_finalize (ECalShellBackendClass *class)
+{
+}
+
+static void
+e_cal_shell_backend_init (ECalShellBackend *cal_shell_backend)
+{
+ icalarray *builtin_timezones;
+ gint ii;
+
+ cal_shell_backend->priv =
+ E_CAL_SHELL_BACKEND_GET_PRIVATE (cal_shell_backend);
+
+ /* XXX Pre-load all built-in timezones in libical.
+ *
+ * Built-in time zones in libical 0.43 are loaded on demand,
+ * but not in a thread-safe manner, resulting in a race when
+ * multiple threads call icaltimezone_load_builtin_timezone()
+ * on the same time zone. Until built-in time zone loading
+ * in libical is made thread-safe, work around the issue by
+ * loading all built-in time zones now, so libical's internal
+ * time zone array will be fully populated before any threads
+ * are spawned.
+ */
+ builtin_timezones = icaltimezone_get_builtin_timezones ();
+ for (ii = 0; ii < builtin_timezones->num_elements; ii++) {
+ icaltimezone *zone;
+
+ zone = icalarray_element_at (builtin_timezones, ii);
+
+ /* We don't care about the component right now,
+ * we just need some function that will trigger
+ * icaltimezone_load_builtin_timezone(). */
+ icaltimezone_get_component (zone);
+ }
+}
+
+void
+e_cal_shell_backend_type_register (GTypeModule *type_module)
+{
+ /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
+ * function, so we have to wrap it with a public function in
+ * order to register types from a separate compilation unit. */
+ e_cal_shell_backend_register_type (type_module);
+}
+
+void
+e_cal_shell_backend_open_date_range (ECalShellBackend *cal_shell_backend,
+ const GDate *start_date,
+ const GDate *end_date)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellBackend *shell_backend;
+ EShellSidebar *shell_sidebar;
+ GtkWidget *shell_window = NULL;
+ GtkApplication *application;
+ ECalendar *navigator;
+ GList *list;
+
+ g_return_if_fail (E_IS_CAL_SHELL_BACKEND (cal_shell_backend));
+
+ shell_backend = E_SHELL_BACKEND (cal_shell_backend);
+ shell = e_shell_backend_get_shell (shell_backend);
+
+ application = GTK_APPLICATION (shell);
+ list = gtk_application_get_windows (application);
+
+ /* Try to find an EShellWindow already in calendar view. */
+ while (list != NULL) {
+ GtkWidget *window = GTK_WIDGET (list->data);
+
+ if (E_IS_SHELL_WINDOW (window)) {
+ const gchar *active_view;
+
+ active_view = e_shell_window_get_active_view (
+ E_SHELL_WINDOW (window));
+ if (g_strcmp0 (active_view, "calendar") == 0) {
+ gtk_window_present (GTK_WINDOW (window));
+ shell_window = window;
+ break;
+ }
+ }
+
+ list = g_list_next (list);
+ }
+
+ /* Otherwise create a new EShellWindow in calendar view. */
+ if (shell_window == NULL)
+ shell_window = e_shell_create_shell_window (shell, "calendar");
+
+ /* Now dig up the date navigator and select the date range. */
+
+ shell_view = e_shell_window_get_shell_view (
+ E_SHELL_WINDOW (shell_window), "calendar");
+ shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+ navigator = e_cal_shell_sidebar_get_date_navigator (
+ E_CAL_SHELL_SIDEBAR (shell_sidebar));
+
+ e_calendar_item_set_selection (
+ navigator->calitem, start_date, end_date);
+}
diff --git a/modules/calendar/e-cal-shell-backend.h b/modules/calendar/e-cal-shell-backend.h
new file mode 100644
index 0000000000..c3058af53e
--- /dev/null
+++ b/modules/calendar/e-cal-shell-backend.h
@@ -0,0 +1,71 @@
+/*
+ * e-cal-shell-backend.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_CAL_SHELL_BACKEND_H
+#define E_CAL_SHELL_BACKEND_H
+
+#include <shell/e-shell-backend.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CAL_SHELL_BACKEND \
+ (e_cal_shell_backend_get_type ())
+#define E_CAL_SHELL_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_CAL_SHELL_BACKEND, ECalShellBackend))
+#define E_CAL_SHELL_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_CAL_SHELL_BACKEND, ECalShellBackendClass))
+#define E_IS_CAL_SHELL_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_CAL_SHELL_BACKEND))
+#define E_IS_CAL_SHELL_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_CAL_SHELL_BACKEND))
+#define E_CAL_SHELL_BACKEND_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_CAL_SHELL_BACKEND, ECalShellBackendClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ECalShellBackend ECalShellBackend;
+typedef struct _ECalShellBackendClass ECalShellBackendClass;
+typedef struct _ECalShellBackendPrivate ECalShellBackendPrivate;
+
+struct _ECalShellBackend {
+ EShellBackend parent;
+ ECalShellBackendPrivate *priv;
+};
+
+struct _ECalShellBackendClass {
+ EShellBackendClass parent_class;
+};
+
+GType e_cal_shell_backend_get_type (void);
+void e_cal_shell_backend_type_register
+ (GTypeModule *type_module);
+void e_cal_shell_backend_open_date_range
+ (ECalShellBackend *cal_shell_backend,
+ const GDate *start_date,
+ const GDate *end_date);
+
+G_END_DECLS
+
+#endif /* E_CAL_SHELL_BACKEND_H */
diff --git a/modules/calendar/e-cal-shell-content.c b/modules/calendar/e-cal-shell-content.c
new file mode 100644
index 0000000000..6e35a1fc66
--- /dev/null
+++ b/modules/calendar/e-cal-shell-content.c
@@ -0,0 +1,945 @@
+/*
+ * e-cal-shell-content.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-cal-shell-content.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+
+#include "calendar/gui/calendar-config.h"
+#include "calendar/gui/calendar-view.h"
+#include "calendar/gui/e-cal-list-view.h"
+#include "calendar/gui/e-cal-model-calendar.h"
+#include "calendar/gui/e-calendar-view.h"
+#include "calendar/gui/e-day-view.h"
+#include "calendar/gui/e-week-view.h"
+
+#include "e-cal-shell-view-private.h"
+
+#define E_CAL_SHELL_CONTENT_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_CAL_SHELL_CONTENT, ECalShellContentPrivate))
+
+struct _ECalShellContentPrivate {
+ GtkWidget *hpaned;
+ GtkWidget *notebook;
+ GtkWidget *vpaned;
+
+ GtkWidget *calendar;
+ GtkWidget *task_table;
+ GtkWidget *memo_table;
+};
+
+enum {
+ PROP_0,
+ PROP_CALENDAR,
+ PROP_MEMO_TABLE,
+ PROP_TASK_TABLE
+};
+
+/* Used to indicate who has the focus within the calendar view. */
+typedef enum {
+ FOCUS_CALENDAR,
+ FOCUS_MEMO_TABLE,
+ FOCUS_TASK_TABLE,
+ FOCUS_OTHER
+} FocusLocation;
+
+G_DEFINE_DYNAMIC_TYPE (
+ ECalShellContent,
+ e_cal_shell_content,
+ E_TYPE_SHELL_CONTENT)
+
+static void
+cal_shell_content_display_view_cb (ECalShellContent *cal_shell_content,
+ GalView *gal_view)
+{
+ GnomeCalendar *calendar;
+ GnomeCalendarViewType view_type;
+ GType gal_view_type;
+
+ gal_view_type = G_OBJECT_TYPE (gal_view);
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+
+ if (gal_view_type == GAL_TYPE_VIEW_ETABLE) {
+ ECalendarView *calendar_view;
+
+ view_type = GNOME_CAL_LIST_VIEW;
+ calendar_view = gnome_calendar_get_calendar_view (
+ calendar, view_type);
+ gal_view_etable_attach_table (
+ GAL_VIEW_ETABLE (gal_view),
+ E_CAL_LIST_VIEW (calendar_view)->table);
+
+ } else if (gal_view_type == GAL_TYPE_VIEW_CALENDAR_DAY) {
+ view_type = GNOME_CAL_DAY_VIEW;
+
+ } else if (gal_view_type == GAL_TYPE_VIEW_CALENDAR_WORK_WEEK) {
+ view_type = GNOME_CAL_WORK_WEEK_VIEW;
+
+ } else if (gal_view_type == GAL_TYPE_VIEW_CALENDAR_WEEK) {
+ view_type = GNOME_CAL_WEEK_VIEW;
+
+ } else if (gal_view_type == GAL_TYPE_VIEW_CALENDAR_MONTH) {
+ view_type = GNOME_CAL_MONTH_VIEW;
+
+ } else {
+ g_return_if_reached ();
+ }
+
+ gnome_calendar_display_view (calendar, view_type);
+}
+
+static void
+cal_shell_content_notify_view_id_cb (ECalShellContent *cal_shell_content)
+{
+ EShellContent *shell_content;
+ EShellView *shell_view;
+ GSettings *settings;
+ GtkWidget *paned;
+ const gchar *key;
+ const gchar *view_id;
+
+ settings = g_settings_new ("org.gnome.evolution.calendar");
+ paned = cal_shell_content->priv->hpaned;
+
+ shell_content = E_SHELL_CONTENT (cal_shell_content);
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ view_id = e_shell_view_get_view_id (shell_view);
+
+ if (view_id != NULL && strcmp (view_id, "Month_View") == 0)
+ key = "month-hpane-position";
+ else
+ key = "hpane-position";
+
+ g_settings_unbind (paned, "hposition");
+
+ g_settings_bind (
+ settings, key,
+ paned, "hposition",
+ G_SETTINGS_BIND_DEFAULT);
+
+ g_object_unref (settings);
+}
+
+static gchar *
+cal_shell_content_get_pad_state_filename (EShellContent *shell_content,
+ ETable *table)
+{
+ EShellBackend *shell_backend;
+ EShellView *shell_view;
+ const gchar *config_dir, *nick = NULL;
+
+ g_return_val_if_fail (shell_content != NULL, NULL);
+ g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
+ g_return_val_if_fail (table != NULL, NULL);
+ g_return_val_if_fail (E_IS_TABLE (table), NULL);
+
+ if (E_IS_TASK_TABLE (table))
+ nick = "TaskPad";
+ else if (E_IS_MEMO_TABLE (table))
+ nick = "MemoPad";
+
+ g_return_val_if_fail (nick != NULL, NULL);
+
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+ config_dir = e_shell_backend_get_config_dir (shell_backend);
+
+ return g_build_filename (config_dir, nick, NULL);
+}
+
+static void
+cal_shell_content_save_table_state (EShellContent *shell_content,
+ ETable *table)
+{
+ gchar *filename;
+
+ filename = cal_shell_content_get_pad_state_filename (
+ shell_content, table);
+ g_return_if_fail (filename != NULL);
+
+ e_table_save_state (table, filename);
+ g_free (filename);
+}
+
+static void
+cal_shell_content_load_table_state (EShellContent *shell_content,
+ ETable *table)
+{
+ gchar *filename;
+
+ filename = cal_shell_content_get_pad_state_filename (
+ shell_content, table);
+ g_return_if_fail (filename != NULL);
+
+ e_table_load_state (table, filename);
+ g_free (filename);
+}
+
+void
+e_cal_shell_content_save_state (ECalShellContent *cal_shell_content)
+{
+ ECalShellContentPrivate *priv;
+
+ g_return_if_fail (cal_shell_content != NULL);
+ g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
+
+ priv = cal_shell_content->priv;
+
+ if (priv->task_table != NULL)
+ cal_shell_content_save_table_state (
+ E_SHELL_CONTENT (cal_shell_content),
+ E_TABLE (priv->task_table));
+
+ if (priv->memo_table != NULL)
+ cal_shell_content_save_table_state (
+ E_SHELL_CONTENT (cal_shell_content),
+ E_TABLE (priv->memo_table));
+}
+
+static void
+cal_shell_content_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+cal_shell_content_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CALENDAR:
+ g_value_set_object (
+ value, e_cal_shell_content_get_calendar (
+ E_CAL_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_MEMO_TABLE:
+ g_value_set_object (
+ value, e_cal_shell_content_get_memo_table (
+ E_CAL_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_TASK_TABLE:
+ g_value_set_object (
+ value, e_cal_shell_content_get_task_table (
+ E_CAL_SHELL_CONTENT (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+cal_shell_content_dispose (GObject *object)
+{
+ ECalShellContentPrivate *priv;
+
+ priv = E_CAL_SHELL_CONTENT_GET_PRIVATE (object);
+
+ if (priv->hpaned != NULL) {
+ g_object_unref (priv->hpaned);
+ priv->hpaned = NULL;
+ }
+
+ if (priv->notebook != NULL) {
+ g_object_unref (priv->notebook);
+ priv->notebook = NULL;
+ }
+
+ if (priv->vpaned != NULL) {
+ g_object_unref (priv->vpaned);
+ priv->vpaned = NULL;
+ }
+
+ if (priv->calendar != NULL) {
+ g_object_unref (priv->calendar);
+ priv->calendar = NULL;
+ }
+
+ if (priv->task_table != NULL) {
+ g_object_unref (priv->task_table);
+ priv->task_table = NULL;
+ }
+
+ if (priv->memo_table != NULL) {
+ g_object_unref (priv->memo_table);
+ priv->memo_table = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_cal_shell_content_parent_class)->dispose (object);
+}
+
+static time_t
+gc_get_default_time (ECalModel *model,
+ gpointer user_data)
+{
+ GnomeCalendar *gcal = user_data;
+ time_t res = 0, end;
+
+ g_return_val_if_fail (model != NULL, 0);
+ g_return_val_if_fail (GNOME_IS_CALENDAR (user_data), 0);
+
+ gnome_calendar_get_current_time_range (gcal, &res, &end);
+
+ return res;
+}
+
+static void
+cal_shell_content_is_editing_changed_cb (gpointer cal_view_tasks_memos_table,
+ GParamSpec *param,
+ EShellView *shell_view)
+{
+ g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
+
+ e_shell_view_update_actions (shell_view);
+}
+
+static void
+cal_shell_content_constructed (GObject *object)
+{
+ ECalShellContentPrivate *priv;
+ ECalendarView *calendar_view;
+ ECalModel *memo_model = NULL;
+ ECalModel *task_model = NULL;
+ EShell *shell;
+ EShellContent *shell_content;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellContent *foreign_content;
+ EShellView *foreign_view;
+ GnomeCalendar *calendar;
+ ESourceRegistry *registry;
+ GalViewInstance *view_instance;
+ GSettings *settings;
+ GtkWidget *container;
+ GtkWidget *widget;
+ gchar *markup;
+ gint ii;
+
+ priv = E_CAL_SHELL_CONTENT_GET_PRIVATE (object);
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_cal_shell_content_parent_class)->constructed (object);
+
+ shell_content = E_SHELL_CONTENT (object);
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ shell = e_shell_window_get_shell (shell_window);
+
+ /* We borrow the memopad and taskpad models from the memo
+ * and task views, loading the views if necessary. */
+ foreign_view = e_shell_window_get_shell_view (shell_window, "memos");
+ foreign_content = e_shell_view_get_shell_content (foreign_view);
+ g_object_get (foreign_content, "model", &memo_model, NULL);
+
+ foreign_view = e_shell_window_get_shell_view (shell_window, "tasks");
+ foreign_content = e_shell_view_get_shell_content (foreign_view);
+ g_object_get (foreign_content, "model", &task_model, NULL);
+
+ /* Build content widgets. */
+
+ container = GTK_WIDGET (object);
+
+ widget = e_paned_new (GTK_ORIENTATION_HORIZONTAL);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ priv->hpaned = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ container = priv->hpaned;
+
+ widget = gtk_notebook_new ();
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE);
+ gtk_notebook_set_show_border (GTK_NOTEBOOK (widget), FALSE);
+ gtk_paned_pack1 (GTK_PANED (container), widget, TRUE, FALSE);
+ priv->notebook = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ /* FIXME Need to deal with saving and restoring the position.
+ * Month view has its own position. */
+ widget = e_paned_new (GTK_ORIENTATION_VERTICAL);
+ e_paned_set_fixed_resize (E_PANED (widget), FALSE);
+ gtk_paned_pack2 (GTK_PANED (container), widget, FALSE, TRUE);
+ priv->vpaned = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ container = priv->notebook;
+
+ /* Add views in the order defined by GnomeCalendarViewType, such
+ * that the notebook page number corresponds to the view type. */
+
+ registry = e_shell_get_registry (shell);
+ priv->calendar = gnome_calendar_new (registry);
+ calendar = GNOME_CALENDAR (priv->calendar);
+
+ for (ii = 0; ii < GNOME_CAL_LAST_VIEW; ii++) {
+ calendar_view = gnome_calendar_get_calendar_view (calendar, ii);
+
+ g_signal_connect (
+ calendar_view, "notify::is-editing",
+ G_CALLBACK (cal_shell_content_is_editing_changed_cb), shell_view);
+
+ gtk_notebook_append_page (
+ GTK_NOTEBOOK (container),
+ GTK_WIDGET (calendar_view), NULL);
+ gtk_widget_show (GTK_WIDGET (calendar_view));
+ }
+
+ g_object_bind_property (
+ priv->calendar, "view",
+ priv->notebook, "page",
+ G_BINDING_SYNC_CREATE);
+
+ container = priv->vpaned;
+
+ widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+ gtk_paned_pack1 (GTK_PANED (container), widget, TRUE, TRUE);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0);
+ gtk_widget_show (widget);
+
+ widget = gtk_label_new (NULL);
+ markup = g_strdup_printf ("<b>%s</b>", _("Tasks"));
+ gtk_label_set_markup (GTK_LABEL (widget), markup);
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0);
+ gtk_widget_show (widget);
+ g_free (markup);
+
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (
+ GTK_SCROLLED_WINDOW (widget),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (
+ GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = e_task_table_new (shell_view, task_model);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ priv->task_table = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ cal_shell_content_load_table_state (
+ shell_content, E_TABLE (widget));
+
+ g_signal_connect_swapped (
+ widget, "open-component",
+ G_CALLBACK (e_cal_shell_view_taskpad_open_task),
+ shell_view);
+
+ g_signal_connect (
+ widget, "notify::is-editing",
+ G_CALLBACK (cal_shell_content_is_editing_changed_cb), shell_view);
+
+ container = priv->vpaned;
+
+ widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+ gtk_paned_pack2 (GTK_PANED (container), widget, TRUE, TRUE);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = gtk_label_new (NULL);
+ markup = g_strdup_printf ("<b>%s</b>", _("Memos"));
+ gtk_label_set_markup (GTK_LABEL (widget), markup);
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0);
+ gtk_widget_show (widget);
+ g_free (markup);
+
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (
+ GTK_SCROLLED_WINDOW (widget),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (
+ GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = e_memo_table_new (shell_view, memo_model);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ priv->memo_table = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ cal_shell_content_load_table_state (
+ shell_content, E_TABLE (widget));
+
+ e_cal_model_set_default_time_func (
+ memo_model, gc_get_default_time, calendar);
+
+ g_signal_connect_swapped (
+ widget, "open-component",
+ G_CALLBACK (e_cal_shell_view_memopad_open_memo),
+ shell_view);
+
+ g_signal_connect (
+ widget, "notify::is-editing",
+ G_CALLBACK (cal_shell_content_is_editing_changed_cb), shell_view);
+
+ /* Load the view instance. */
+
+ view_instance = e_shell_view_new_view_instance (shell_view, NULL);
+ g_signal_connect_swapped (
+ view_instance, "display-view",
+ G_CALLBACK (cal_shell_content_display_view_cb),
+ object);
+ /* XXX Actually, don't load the view instance just yet.
+ * The GtkWidget::map() callback below explains why. */
+ e_shell_view_set_view_instance (shell_view, view_instance);
+ g_object_unref (view_instance);
+
+ g_signal_connect_swapped (
+ shell_view, "notify::view-id",
+ G_CALLBACK (cal_shell_content_notify_view_id_cb),
+ object);
+
+ settings = g_settings_new ("org.gnome.evolution.calendar");
+
+ g_settings_bind (
+ settings, "tag-vpane-position",
+ priv->vpaned, "proportion",
+ G_SETTINGS_BIND_DEFAULT);
+
+ g_object_unref (settings);
+
+ if (memo_model)
+ g_object_unref (memo_model);
+ if (task_model)
+ g_object_unref (task_model);
+}
+
+static void
+cal_shell_content_map (GtkWidget *widget)
+{
+ EShellView *shell_view;
+ EShellContent *shell_content;
+ GalViewInstance *view_instance;
+
+ shell_content = E_SHELL_CONTENT (widget);
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ view_instance = e_shell_view_get_view_instance (shell_view);
+
+ /* XXX Delay loading the GalViewInstance until after ECalShellView
+ * has a chance to install the sidebar's date navigator into
+ * GnomeCalendar, since loading the GalViewInstance triggers a
+ * callback in GnomeCalendar that requires the date navigator.
+ * Ordinarily we would do this at the end of constructed(), but
+ * that's too soon in this case. (This feels kind of kludgy.) */
+ gal_view_instance_load (view_instance);
+
+ /* Chain up to parent's map() method. */
+ GTK_WIDGET_CLASS (e_cal_shell_content_parent_class)->map (widget);
+}
+
+/* Helper for cal_shell_content_check_state() */
+static icalproperty *
+cal_shell_content_get_attendee_prop (icalcomponent *icalcomp,
+ const gchar *address)
+{
+ icalproperty *prop;
+
+ if (address == NULL || *address == '\0')
+ return NULL;
+
+ prop = icalcomponent_get_first_property (
+ icalcomp, ICAL_ATTENDEE_PROPERTY);
+
+ while (prop != NULL) {
+ const gchar *attendee;
+
+ attendee = icalproperty_get_attendee (prop);
+
+ if (g_str_equal (itip_strip_mailto (attendee), address))
+ return prop;
+
+ prop = icalcomponent_get_next_property (
+ icalcomp, ICAL_ATTENDEE_PROPERTY);
+ }
+
+ return NULL;
+}
+
+/* Helper for cal_shell_content_check_state() */
+static gboolean
+cal_shell_content_icalcomp_is_delegated (icalcomponent *icalcomp,
+ const gchar *user_email)
+{
+ icalproperty *prop;
+ icalparameter *param;
+ const gchar *delto = NULL;
+ gboolean is_delegated = FALSE;
+
+ prop = cal_shell_content_get_attendee_prop (icalcomp, user_email);
+
+ if (prop != NULL) {
+ param = icalproperty_get_first_parameter (
+ prop, ICAL_DELEGATEDTO_PARAMETER);
+ if (param != NULL) {
+ delto = icalparameter_get_delegatedto (param);
+ delto = itip_strip_mailto (delto);
+ }
+ } else
+ return FALSE;
+
+ prop = cal_shell_content_get_attendee_prop (icalcomp, delto);
+
+ if (prop != NULL) {
+ const gchar *delfrom = NULL;
+ icalparameter_partstat status = ICAL_PARTSTAT_NONE;
+
+ param = icalproperty_get_first_parameter (
+ prop, ICAL_DELEGATEDFROM_PARAMETER);
+ if (param != NULL) {
+ delfrom = icalparameter_get_delegatedfrom (param);
+ delfrom = itip_strip_mailto (delfrom);
+ }
+ param = icalproperty_get_first_parameter (
+ prop, ICAL_PARTSTAT_PARAMETER);
+ if (param != NULL)
+ status = icalparameter_get_partstat (param);
+ is_delegated =
+ (status != ICAL_PARTSTAT_DECLINED) &&
+ (g_strcmp0 (delfrom, user_email) == 0);
+ }
+
+ return is_delegated;
+}
+
+static guint32
+cal_shell_content_check_state (EShellContent *shell_content)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellBackend *shell_backend;
+ ESourceRegistry *registry;
+ ECalShellContent *cal_shell_content;
+ GnomeCalendar *calendar;
+ ECalendarView *calendar_view;
+ GnomeCalendarViewType view_type;
+ gboolean selection_is_editable = FALSE;
+ gboolean selection_is_instance = FALSE;
+ gboolean selection_is_meeting = FALSE;
+ gboolean selection_is_organizer = FALSE;
+ gboolean selection_is_recurring = FALSE;
+ gboolean selection_can_delegate = FALSE;
+ guint32 state = 0;
+ GList *selected;
+ GList *link;
+ guint n_selected;
+
+ cal_shell_content = E_CAL_SHELL_CONTENT (shell_content);
+
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+ shell = e_shell_backend_get_shell (shell_backend);
+ registry = e_shell_get_registry (shell);
+
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ view_type = gnome_calendar_get_view (calendar);
+ calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+
+ selected = e_calendar_view_get_selected_events (calendar_view);
+ n_selected = g_list_length (selected);
+
+ /* If we have a selection, assume it's
+ * editable until we learn otherwise. */
+ if (n_selected > 0)
+ selection_is_editable = TRUE;
+
+ for (link = selected; link != NULL; link = g_list_next (link)) {
+ ECalendarViewEvent *event = link->data;
+ ECalClient *client;
+ ECalComponent *comp;
+ gchar *user_email;
+ icalcomponent *icalcomp;
+ const gchar *capability;
+ gboolean cap_delegate_supported;
+ gboolean cap_delegate_to_many;
+ gboolean icalcomp_is_delegated;
+ gboolean read_only;
+
+ if (!is_comp_data_valid (event))
+ continue;
+
+ client = event->comp_data->client;
+ icalcomp = event->comp_data->icalcomp;
+
+ read_only = e_client_is_readonly (E_CLIENT (client));
+ selection_is_editable &= !read_only;
+
+ selection_is_instance |=
+ e_cal_util_component_is_instance (icalcomp);
+
+ selection_is_meeting =
+ (n_selected == 1) &&
+ e_cal_util_component_has_attendee (icalcomp);
+
+ selection_is_recurring |=
+ e_cal_util_component_is_instance (icalcomp) ||
+ e_cal_util_component_has_recurrences (icalcomp);
+
+ /* XXX The rest of this is rather expensive and
+ * only applies if a single event is selected,
+ * so continue with the loop iteration if the
+ * rest of this is not applicable. */
+ if (n_selected > 1)
+ continue;
+
+ /* XXX This probably belongs in comp-util.c. */
+
+ comp = e_cal_component_new ();
+ e_cal_component_set_icalcomponent (
+ comp, icalcomponent_new_clone (icalcomp));
+ user_email = itip_get_comp_attendee (
+ registry, comp, client);
+
+ selection_is_organizer =
+ e_cal_util_component_has_organizer (icalcomp) &&
+ itip_organizer_is_user (registry, comp, client);
+
+ capability = CAL_STATIC_CAPABILITY_DELEGATE_SUPPORTED;
+ cap_delegate_supported =
+ e_client_check_capability (
+ E_CLIENT (client), capability);
+
+ capability = CAL_STATIC_CAPABILITY_DELEGATE_TO_MANY;
+ cap_delegate_to_many =
+ e_client_check_capability (
+ E_CLIENT (client), capability);
+
+ icalcomp_is_delegated =
+ (user_email != NULL) &&
+ cal_shell_content_icalcomp_is_delegated (
+ icalcomp, user_email);
+
+ selection_can_delegate =
+ cap_delegate_supported &&
+ (cap_delegate_to_many ||
+ (!selection_is_organizer &&
+ !icalcomp_is_delegated));
+
+ g_free (user_email);
+ g_object_unref (comp);
+ }
+
+ g_list_free (selected);
+
+ if (n_selected == 1)
+ state |= E_CAL_SHELL_CONTENT_SELECTION_SINGLE;
+ if (n_selected > 1)
+ state |= E_CAL_SHELL_CONTENT_SELECTION_MULTIPLE;
+ if (selection_is_editable)
+ state |= E_CAL_SHELL_CONTENT_SELECTION_IS_EDITABLE;
+ if (selection_is_instance)
+ state |= E_CAL_SHELL_CONTENT_SELECTION_IS_INSTANCE;
+ if (selection_is_meeting)
+ state |= E_CAL_SHELL_CONTENT_SELECTION_IS_MEETING;
+ if (selection_is_organizer)
+ state |= E_CAL_SHELL_CONTENT_SELECTION_IS_ORGANIZER;
+ if (selection_is_recurring)
+ state |= E_CAL_SHELL_CONTENT_SELECTION_IS_RECURRING;
+ if (selection_can_delegate)
+ state |= E_CAL_SHELL_CONTENT_SELECTION_CAN_DELEGATE;
+
+ return state;
+}
+
+static void
+cal_shell_content_focus_search_results (EShellContent *shell_content)
+{
+ ECalShellContent *cal_shell_content;
+ GnomeCalendar *calendar;
+ GnomeCalendarViewType view_type;
+ ECalendarView *calendar_view;
+
+ cal_shell_content = E_CAL_SHELL_CONTENT (shell_content);
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ view_type = gnome_calendar_get_view (calendar);
+ calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+
+ gtk_widget_grab_focus (GTK_WIDGET (calendar_view));
+}
+
+static void
+e_cal_shell_content_class_init (ECalShellContentClass *class)
+{
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+ EShellContentClass *shell_content_class;
+
+ g_type_class_add_private (class, sizeof (ECalShellContentPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = cal_shell_content_set_property;
+ object_class->get_property = cal_shell_content_get_property;
+ object_class->dispose = cal_shell_content_dispose;
+ object_class->constructed = cal_shell_content_constructed;
+
+ widget_class = GTK_WIDGET_CLASS (class);
+ widget_class->map = cal_shell_content_map;
+
+ shell_content_class = E_SHELL_CONTENT_CLASS (class);
+ shell_content_class->check_state = cal_shell_content_check_state;
+ shell_content_class->focus_search_results = cal_shell_content_focus_search_results;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_CALENDAR,
+ g_param_spec_object (
+ "calendar",
+ NULL,
+ NULL,
+ GNOME_TYPE_CALENDAR,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_MEMO_TABLE,
+ g_param_spec_object (
+ "memo-table",
+ NULL,
+ NULL,
+ E_TYPE_MEMO_TABLE,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_TASK_TABLE,
+ g_param_spec_object (
+ "task-table",
+ NULL,
+ NULL,
+ E_TYPE_TASK_TABLE,
+ G_PARAM_READABLE));
+}
+
+static void
+e_cal_shell_content_class_finalize (ECalShellContentClass *class)
+{
+}
+
+static void
+e_cal_shell_content_init (ECalShellContent *cal_shell_content)
+{
+ cal_shell_content->priv =
+ E_CAL_SHELL_CONTENT_GET_PRIVATE (cal_shell_content);
+
+ /* Postpone widget construction until we have a shell view. */
+}
+
+void
+e_cal_shell_content_type_register (GTypeModule *type_module)
+{
+ /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
+ * function, so we have to wrap it with a public function in
+ * order to register types from a separate compilation unit. */
+ e_cal_shell_content_register_type (type_module);
+}
+
+GtkWidget *
+e_cal_shell_content_new (EShellView *shell_view)
+{
+ g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
+
+ return g_object_new (
+ E_TYPE_CAL_SHELL_CONTENT,
+ "shell-view", shell_view, NULL);
+}
+
+ECalModel *
+e_cal_shell_content_get_model (ECalShellContent *cal_shell_content)
+{
+ GnomeCalendar *calendar;
+
+ g_return_val_if_fail (
+ E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
+
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+
+ return gnome_calendar_get_model (calendar);
+}
+
+GnomeCalendar *
+e_cal_shell_content_get_calendar (ECalShellContent *cal_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
+
+ return GNOME_CALENDAR (cal_shell_content->priv->calendar);
+}
+
+EMemoTable *
+e_cal_shell_content_get_memo_table (ECalShellContent *cal_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
+
+ return E_MEMO_TABLE (cal_shell_content->priv->memo_table);
+}
+
+ETaskTable *
+e_cal_shell_content_get_task_table (ECalShellContent *cal_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
+
+ return E_TASK_TABLE (cal_shell_content->priv->task_table);
+}
+
+EShellSearchbar *
+e_cal_shell_content_get_searchbar (ECalShellContent *cal_shell_content)
+{
+ EShellView *shell_view;
+ EShellContent *shell_content;
+ GtkWidget *widget;
+
+ g_return_val_if_fail (
+ E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
+
+ shell_content = E_SHELL_CONTENT (cal_shell_content);
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ widget = e_shell_view_get_searchbar (shell_view);
+
+ return E_SHELL_SEARCHBAR (widget);
+}
+
diff --git a/modules/calendar/e-cal-shell-content.h b/modules/calendar/e-cal-shell-content.h
new file mode 100644
index 0000000000..b42d099cb6
--- /dev/null
+++ b/modules/calendar/e-cal-shell-content.h
@@ -0,0 +1,98 @@
+/*
+ * e-cal-shell-content.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_CAL_SHELL_CONTENT_H
+#define E_CAL_SHELL_CONTENT_H
+
+#include <shell/e-shell-content.h>
+#include <shell/e-shell-searchbar.h>
+#include <shell/e-shell-view.h>
+
+#include <calendar/gui/e-memo-table.h>
+#include <calendar/gui/e-task-table.h>
+#include <calendar/gui/gnome-cal.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CAL_SHELL_CONTENT \
+ (e_cal_shell_content_get_type ())
+#define E_CAL_SHELL_CONTENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_CAL_SHELL_CONTENT, ECalShellContent))
+#define E_CAL_SHELL_CONTENT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_CAL_SHELL_CONTENT, ECalShellContentClass))
+#define E_IS_CAL_SHELL_CONTENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_CAL_SHELL_CONTENT))
+#define E_IS_CAL_SHELL_CONTENT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_CAL_SHELL_CONTENT))
+#define E_CAL_SHELL_CONTENT_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_CAL_SHELL_CONTENT, ECalShellContentClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ECalShellContent ECalShellContent;
+typedef struct _ECalShellContentClass ECalShellContentClass;
+typedef struct _ECalShellContentPrivate ECalShellContentPrivate;
+
+enum {
+ E_CAL_SHELL_CONTENT_SELECTION_SINGLE = 1 << 0,
+ E_CAL_SHELL_CONTENT_SELECTION_MULTIPLE = 1 << 1,
+ E_CAL_SHELL_CONTENT_SELECTION_IS_EDITABLE = 1 << 2,
+ E_CAL_SHELL_CONTENT_SELECTION_IS_INSTANCE = 1 << 3,
+ E_CAL_SHELL_CONTENT_SELECTION_IS_MEETING = 1 << 4,
+ E_CAL_SHELL_CONTENT_SELECTION_IS_ORGANIZER = 1 << 5,
+ E_CAL_SHELL_CONTENT_SELECTION_IS_RECURRING = 1 << 6,
+ E_CAL_SHELL_CONTENT_SELECTION_CAN_DELEGATE = 1 << 7
+};
+
+struct _ECalShellContent {
+ EShellContent parent;
+ ECalShellContentPrivate *priv;
+};
+
+struct _ECalShellContentClass {
+ EShellContentClass parent_class;
+};
+
+GType e_cal_shell_content_get_type (void);
+void e_cal_shell_content_type_register
+ (GTypeModule *type_module);
+GtkWidget * e_cal_shell_content_new (EShellView *shell_view);
+ECalModel * e_cal_shell_content_get_model
+ (ECalShellContent *cal_shell_content);
+GnomeCalendar * e_cal_shell_content_get_calendar
+ (ECalShellContent *cal_shell_content);
+EMemoTable * e_cal_shell_content_get_memo_table
+ (ECalShellContent *cal_shell_content);
+ETaskTable * e_cal_shell_content_get_task_table
+ (ECalShellContent *cal_shell_content);
+EShellSearchbar *
+ e_cal_shell_content_get_searchbar
+ (ECalShellContent *cal_shell_content);
+void e_cal_shell_content_save_state
+ (ECalShellContent *cal_shell_content);
+
+G_END_DECLS
+
+#endif /* E_CAL_SHELL_CONTENT_H */
diff --git a/modules/calendar/e-cal-shell-migrate.c b/modules/calendar/e-cal-shell-migrate.c
new file mode 100644
index 0000000000..3b92c996e7
--- /dev/null
+++ b/modules/calendar/e-cal-shell-migrate.c
@@ -0,0 +1,37 @@
+/*
+ * e-cal-shell-backend-migrate.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-cal-shell-migrate.h"
+
+gboolean
+e_cal_shell_backend_migrate (EShellBackend *shell_backend,
+ gint major,
+ gint minor,
+ gint micro,
+ GError **error)
+{
+ return TRUE;
+}
+
diff --git a/modules/calendar/e-cal-shell-migrate.h b/modules/calendar/e-cal-shell-migrate.h
new file mode 100644
index 0000000000..6c021978a0
--- /dev/null
+++ b/modules/calendar/e-cal-shell-migrate.h
@@ -0,0 +1,37 @@
+/*
+ * e-cal-shell-backend-migrate.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_CAL_SHELL_BACKEND_MIGRATE_H
+#define E_CAL_SHELL_BACKEND_MIGRATE_H
+
+#include <shell/e-shell-backend.h>
+
+G_BEGIN_DECLS
+
+gboolean e_cal_shell_backend_migrate (EShellBackend *shell_backend,
+ gint major,
+ gint minor,
+ gint micro,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* E_CAL_SHELL_BACKEND_MIGRATE_H */
diff --git a/modules/calendar/e-cal-shell-sidebar.c b/modules/calendar/e-cal-shell-sidebar.c
new file mode 100644
index 0000000000..f8d982a681
--- /dev/null
+++ b/modules/calendar/e-cal-shell-sidebar.c
@@ -0,0 +1,889 @@
+/*
+ * e-cal-shell-sidebar.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-cal-shell-sidebar.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+
+#include "calendar/gui/e-calendar-selector.h"
+#include "calendar/gui/misc.h"
+
+#define E_CAL_SHELL_SIDEBAR_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_CAL_SHELL_SIDEBAR, ECalShellSidebarPrivate))
+
+typedef struct _ConnectClosure ConnectClosure;
+
+struct _ECalShellSidebarPrivate {
+ GtkWidget *paned;
+ GtkWidget *selector;
+ GtkWidget *date_navigator;
+
+ /* The default client is for ECalModel. It follows the
+ * sidebar's primary selection, even if the highlighted
+ * source is not selected. The tricky part is we don't
+ * update the property until the client is successfully
+ * opened. So the user first highlights a source, then
+ * sometime later we update our default-client property
+ * which is bound by an EBinding to ECalModel. */
+ EClient *default_client;
+
+ /* Not referenced, only for pointer comparison. */
+ ESource *connecting_default_source_instance;
+
+ EActivity *connecting_default_client;
+};
+
+struct _ConnectClosure {
+ ECalShellSidebar *cal_shell_sidebar;
+ EActivity *activity;
+
+ /* For error messages. */
+ gchar *unique_display_name;
+};
+
+enum {
+ PROP_0,
+ PROP_DATE_NAVIGATOR,
+ PROP_DEFAULT_CLIENT,
+ PROP_SELECTOR
+};
+
+enum {
+ CLIENT_ADDED,
+ CLIENT_REMOVED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+G_DEFINE_DYNAMIC_TYPE (
+ ECalShellSidebar,
+ e_cal_shell_sidebar,
+ E_TYPE_SHELL_SIDEBAR)
+
+static ConnectClosure *
+connect_closure_new (ECalShellSidebar *cal_shell_sidebar,
+ ESource *source)
+{
+ ConnectClosure *closure;
+ EAlertSink *alert_sink;
+ GCancellable *cancellable;
+ ESourceRegistry *registry;
+ ESourceSelector *selector;
+ EShellView *shell_view;
+ EShellBackend *shell_backend;
+ EShellContent *shell_content;
+ EShellSidebar *shell_sidebar;
+ gchar *text;
+
+ shell_sidebar = E_SHELL_SIDEBAR (cal_shell_sidebar);
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+ shell_content = e_shell_view_get_shell_content (shell_view);
+
+ selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+ registry = e_source_selector_get_registry (selector);
+
+ closure = g_slice_new0 (ConnectClosure);
+ closure->cal_shell_sidebar = g_object_ref (cal_shell_sidebar);
+ closure->activity = e_activity_new ();
+ closure->unique_display_name =
+ e_source_registry_dup_unique_display_name (
+ registry, source, E_SOURCE_EXTENSION_CALENDAR);
+
+ text = g_strdup_printf (
+ _("Opening calendar '%s'"),
+ closure->unique_display_name);
+ e_activity_set_text (closure->activity, text);
+ g_free (text);
+
+ alert_sink = E_ALERT_SINK (shell_content);
+ e_activity_set_alert_sink (closure->activity, alert_sink);
+
+ cancellable = g_cancellable_new ();
+ e_activity_set_cancellable (closure->activity, cancellable);
+ g_object_unref (cancellable);
+
+ e_shell_backend_add_activity (shell_backend, closure->activity);
+
+ return closure;
+}
+
+static void
+connect_closure_free (ConnectClosure *closure)
+{
+ g_clear_object (&closure->cal_shell_sidebar);
+ g_clear_object (&closure->activity);
+
+ g_free (closure->unique_display_name);
+
+ g_slice_free (ConnectClosure, closure);
+}
+
+static gboolean
+cal_shell_sidebar_map_uid_to_source (GValue *value,
+ GVariant *variant,
+ gpointer user_data)
+{
+ ESourceRegistry *registry;
+ ESource *source;
+ const gchar *uid;
+
+ registry = E_SOURCE_REGISTRY (user_data);
+ uid = g_variant_get_string (variant, NULL);
+ if (uid != NULL && *uid != '\0')
+ source = e_source_registry_ref_source (registry, uid);
+ else
+ source = e_source_registry_ref_default_calendar (registry);
+ g_value_take_object (value, source);
+
+ return (source != NULL);
+}
+
+static GVariant *
+cal_shell_sidebar_map_source_to_uid (const GValue *value,
+ const GVariantType *expected_type,
+ gpointer user_data)
+{
+ GVariant *variant = NULL;
+ ESource *source;
+
+ source = g_value_get_object (value);
+
+ if (source != NULL) {
+ const gchar *uid;
+
+ uid = e_source_get_uid (source);
+ variant = g_variant_new_string (uid);
+ }
+
+ return variant;
+}
+
+static void
+cal_shell_sidebar_emit_client_added (ECalShellSidebar *cal_shell_sidebar,
+ EClient *client)
+{
+ guint signal_id = signals[CLIENT_ADDED];
+
+ g_signal_emit (cal_shell_sidebar, signal_id, 0, client);
+}
+
+static void
+cal_shell_sidebar_emit_client_removed (ECalShellSidebar *cal_shell_sidebar,
+ EClient *client)
+{
+ guint signal_id = signals[CLIENT_REMOVED];
+
+ g_signal_emit (cal_shell_sidebar, signal_id, 0, client);
+}
+
+static void
+cal_shell_sidebar_handle_connect_error (EActivity *activity,
+ const gchar *unique_display_name,
+ const GError *error)
+{
+ EAlertSink *alert_sink;
+ gboolean cancelled = FALSE;
+ gboolean offline_error;
+
+ alert_sink = e_activity_get_alert_sink (activity);
+
+ cancelled |= g_error_matches (
+ error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
+ cancelled |= g_error_matches (
+ error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED);
+
+ offline_error = g_error_matches (
+ error, E_CLIENT_ERROR, E_CLIENT_ERROR_REPOSITORY_OFFLINE);
+
+ if (e_activity_handle_cancellation (activity, error)) {
+ /* do nothing */
+ } else if (offline_error) {
+ e_alert_submit (
+ alert_sink,
+ "calendar:prompt-no-contents-offline-calendar",
+ unique_display_name,
+ NULL);
+ } else {
+ e_alert_submit (
+ alert_sink,
+ "calendar:failed-open-calendar",
+ unique_display_name,
+ error->message,
+ NULL);
+ }
+}
+
+static void
+cal_shell_sidebar_client_connect_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EClient *client;
+ ConnectClosure *closure = user_data;
+ GError *error = NULL;
+
+ client = e_client_selector_get_client_finish (
+ E_CLIENT_SELECTOR (source_object), result, &error);
+
+ /* Sanity check. */
+ g_return_if_fail (
+ ((client != NULL) && (error == NULL)) ||
+ ((client == NULL) && (error != NULL)));
+
+ if (error != NULL) {
+ cal_shell_sidebar_handle_connect_error (
+ closure->activity,
+ closure->unique_display_name,
+ error);
+ g_error_free (error);
+ goto exit;
+ }
+
+ e_activity_set_state (closure->activity, E_ACTIVITY_COMPLETED);
+
+ e_cal_shell_sidebar_add_client (closure->cal_shell_sidebar, client);
+
+ g_object_unref (client);
+
+exit:
+ connect_closure_free (closure);
+}
+
+static void
+cal_shell_sidebar_default_connect_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EClient *client;
+ ESource *source;
+ ConnectClosure *closure = user_data;
+ ECalShellSidebarPrivate *priv;
+ GError *error = NULL;
+
+ priv = E_CAL_SHELL_SIDEBAR_GET_PRIVATE (closure->cal_shell_sidebar);
+
+ client = e_client_selector_get_client_finish (
+ E_CLIENT_SELECTOR (source_object), result, &error);
+
+ /* Sanity check. */
+ g_return_if_fail (
+ ((client != NULL) && (error == NULL)) ||
+ ((client == NULL) && (error != NULL)));
+
+ g_clear_object (&priv->connecting_default_client);
+
+ if (error != NULL) {
+ cal_shell_sidebar_handle_connect_error (
+ closure->activity,
+ closure->unique_display_name,
+ error);
+ g_error_free (error);
+ goto exit;
+ }
+
+ e_activity_set_state (closure->activity, E_ACTIVITY_COMPLETED);
+
+ source = e_client_get_source (client);
+
+ if (source == priv->connecting_default_source_instance)
+ priv->connecting_default_source_instance = NULL;
+
+ if (priv->default_client != NULL)
+ g_object_unref (priv->default_client);
+
+ priv->default_client = g_object_ref (client);
+
+ g_object_notify (
+ G_OBJECT (closure->cal_shell_sidebar), "default-client");
+
+ g_object_unref (client);
+
+exit:
+ connect_closure_free (closure);
+}
+
+static void
+cal_shell_sidebar_set_default (ECalShellSidebar *cal_shell_sidebar,
+ ESource *source)
+{
+ ECalShellSidebarPrivate *priv;
+ ESourceSelector *selector;
+ ConnectClosure *closure;
+
+ priv = cal_shell_sidebar->priv;
+
+ selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+
+ /* already loading that source as default source */
+ if (source == priv->connecting_default_source_instance)
+ return;
+
+ /* Cancel the previous request if unfinished. */
+ if (priv->connecting_default_client != NULL) {
+ e_activity_cancel (priv->connecting_default_client);
+ g_object_unref (priv->connecting_default_client);
+ priv->connecting_default_client = NULL;
+ }
+
+ closure = connect_closure_new (cal_shell_sidebar, source);
+
+ /* it's only for pointer comparison, no need to ref it */
+ priv->connecting_default_source_instance = source;
+ priv->connecting_default_client = g_object_ref (closure->activity);
+
+ e_client_selector_get_client (
+ E_CLIENT_SELECTOR (selector), source,
+ e_activity_get_cancellable (closure->activity),
+ cal_shell_sidebar_default_connect_cb, closure);
+}
+
+static void
+cal_shell_sidebar_row_changed_cb (ECalShellSidebar *cal_shell_sidebar,
+ GtkTreePath *tree_path,
+ GtkTreeIter *tree_iter,
+ GtkTreeModel *tree_model)
+{
+ ESourceSelector *selector;
+ ESource *source;
+
+ selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+ source = e_source_selector_ref_source_by_path (selector, tree_path);
+
+ /* XXX This signal gets emitted a lot while the model is being
+ * rebuilt, during which time we won't get a valid ESource.
+ * ESourceSelector should probably block this signal while
+ * rebuilding the model, but we'll be forgiving and not
+ * emit a warning. */
+ if (source == NULL)
+ return;
+
+ if (e_source_selector_source_is_selected (selector, source))
+ e_cal_shell_sidebar_add_source (cal_shell_sidebar, source);
+ else
+ e_cal_shell_sidebar_remove_source (cal_shell_sidebar, source);
+
+ g_object_unref (source);
+}
+
+static void
+cal_shell_sidebar_primary_selection_changed_cb (ECalShellSidebar *cal_shell_sidebar,
+ ESourceSelector *selector)
+{
+ ESource *source;
+
+ source = e_source_selector_ref_primary_selection (selector);
+ if (source == NULL)
+ return;
+
+ cal_shell_sidebar_set_default (cal_shell_sidebar, source);
+
+ g_object_unref (source);
+}
+
+static void
+cal_shell_sidebar_restore_state_cb (EShellWindow *shell_window,
+ EShellView *shell_view,
+ EShellSidebar *shell_sidebar)
+{
+ ECalShellSidebarPrivate *priv;
+ ESourceRegistry *registry;
+ ESourceSelector *selector;
+ GSettings *settings;
+ GtkTreeModel *model;
+
+ priv = E_CAL_SHELL_SIDEBAR_GET_PRIVATE (shell_sidebar);
+
+ g_signal_handlers_disconnect_by_func (
+ shell_window,
+ cal_shell_sidebar_restore_state_cb, shell_sidebar);
+
+ selector = E_SOURCE_SELECTOR (priv->selector);
+ registry = e_source_selector_get_registry (selector);
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector));
+
+ g_signal_connect_swapped (
+ registry, "source-removed",
+ G_CALLBACK (e_cal_shell_sidebar_remove_source), shell_sidebar);
+
+ g_signal_connect_swapped (
+ model, "row-changed",
+ G_CALLBACK (cal_shell_sidebar_row_changed_cb),
+ shell_sidebar);
+
+ g_signal_connect_swapped (
+ selector, "primary-selection-changed",
+ G_CALLBACK (cal_shell_sidebar_primary_selection_changed_cb),
+ shell_sidebar);
+
+ /* This will trigger our "row-changed" signal handler for each
+ * calendar source, so the appropriate ECalClients get added to
+ * the ECalModel, which will then create view objects to display
+ * the calendar content. This all happens asynchronously. */
+ e_source_selector_update_all_rows (selector);
+
+ /* Bind GObject properties to settings keys. */
+
+ settings = g_settings_new ("org.gnome.evolution.calendar");
+
+ g_settings_bind_with_mapping (
+ settings, "primary-calendar",
+ selector, "primary-selection",
+ G_SETTINGS_BIND_DEFAULT,
+ cal_shell_sidebar_map_uid_to_source,
+ cal_shell_sidebar_map_source_to_uid,
+ g_object_ref (registry),
+ (GDestroyNotify) g_object_unref);
+
+ g_settings_bind (
+ settings, "date-navigator-pane-position",
+ priv->paned, "vposition",
+ G_SETTINGS_BIND_DEFAULT);
+
+ g_object_unref (settings);
+}
+
+static void
+cal_shell_sidebar_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_DATE_NAVIGATOR:
+ g_value_set_object (
+ value,
+ e_cal_shell_sidebar_get_date_navigator (
+ E_CAL_SHELL_SIDEBAR (object)));
+ return;
+
+ case PROP_DEFAULT_CLIENT:
+ g_value_set_object (
+ value,
+ e_cal_shell_sidebar_get_default_client (
+ E_CAL_SHELL_SIDEBAR (object)));
+ return;
+
+ case PROP_SELECTOR:
+ g_value_set_object (
+ value,
+ e_cal_shell_sidebar_get_selector (
+ E_CAL_SHELL_SIDEBAR (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+cal_shell_sidebar_dispose (GObject *object)
+{
+ ECalShellSidebarPrivate *priv;
+
+ priv = E_CAL_SHELL_SIDEBAR_GET_PRIVATE (object);
+
+ if (priv->paned != NULL) {
+ g_object_unref (priv->paned);
+ priv->paned = NULL;
+ }
+
+ if (priv->selector != NULL) {
+ g_object_unref (priv->selector);
+ priv->selector = NULL;
+ }
+
+ if (priv->date_navigator != NULL) {
+ g_object_unref (priv->date_navigator);
+ priv->date_navigator = NULL;
+ }
+
+ if (priv->default_client != NULL) {
+ g_object_unref (priv->default_client);
+ priv->default_client = NULL;
+ }
+
+ if (priv->connecting_default_client != NULL) {
+ e_activity_cancel (priv->connecting_default_client);
+ g_object_unref (priv->connecting_default_client);
+ priv->connecting_default_client = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_cal_shell_sidebar_parent_class)->dispose (object);
+}
+
+static void
+cal_shell_sidebar_constructed (GObject *object)
+{
+ ECalShellSidebarPrivate *priv;
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellBackend *shell_backend;
+ EShellSidebar *shell_sidebar;
+ EClientCache *client_cache;
+ ECalendarItem *calitem;
+ GtkWidget *container;
+ GtkWidget *widget;
+ AtkObject *a11y;
+
+ priv = E_CAL_SHELL_SIDEBAR_GET_PRIVATE (object);
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_cal_shell_sidebar_parent_class)->constructed (object);
+
+ shell_sidebar = E_SHELL_SIDEBAR (object);
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_backend_get_shell (shell_backend);
+
+ container = GTK_WIDGET (shell_sidebar);
+
+ widget = e_paned_new (GTK_ORIENTATION_VERTICAL);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ priv->paned = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+ gtk_paned_pack1 (GTK_PANED (container), widget, TRUE, TRUE);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (
+ GTK_SCROLLED_WINDOW (widget),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (
+ GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ client_cache = e_shell_get_client_cache (shell);
+ widget = e_calendar_selector_new (client_cache);
+ e_source_selector_set_select_new (E_SOURCE_SELECTOR (widget), TRUE);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ a11y = gtk_widget_get_accessible (widget);
+ atk_object_set_name (a11y, _("Calendar Selector"));
+ priv->selector = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ container = priv->paned;
+
+ widget = e_calendar_new ();
+ calitem = E_CALENDAR (widget)->calitem;
+ e_calendar_item_set_days_start_week_sel (calitem, 9);
+ e_calendar_item_set_max_days_sel (calitem, 42);
+ gtk_paned_pack2 (GTK_PANED (container), widget, FALSE, FALSE);
+ priv->date_navigator = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ /* Restore widget state from the last session once
+ * the shell view is fully initialized and visible. */
+ g_signal_connect (
+ shell_window, "shell-view-created::calendar",
+ G_CALLBACK (cal_shell_sidebar_restore_state_cb),
+ shell_sidebar);
+}
+
+static guint32
+cal_shell_sidebar_check_state (EShellSidebar *shell_sidebar)
+{
+ ECalShellSidebar *cal_shell_sidebar;
+ ESourceSelector *selector;
+ ESourceRegistry *registry;
+ ESource *source;
+ gboolean is_writable = FALSE;
+ gboolean is_removable = FALSE;
+ gboolean is_remote_creatable = FALSE;
+ gboolean is_remote_deletable = FALSE;
+ gboolean in_collection = FALSE;
+ gboolean refresh_supported = FALSE;
+ gboolean has_primary_source = FALSE;
+ guint32 state = 0;
+
+ cal_shell_sidebar = E_CAL_SHELL_SIDEBAR (shell_sidebar);
+ selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+ source = e_source_selector_ref_primary_selection (selector);
+ registry = e_source_selector_get_registry (selector);
+
+ if (source != NULL) {
+ EClient *client;
+ ESource *collection;
+
+ has_primary_source = TRUE;
+ is_writable = e_source_get_writable (source);
+ is_removable = e_source_get_removable (source);
+ is_remote_creatable = e_source_get_remote_creatable (source);
+ is_remote_deletable = e_source_get_remote_deletable (source);
+
+ collection = e_source_registry_find_extension (
+ registry, source, E_SOURCE_EXTENSION_COLLECTION);
+ if (collection != NULL) {
+ in_collection = TRUE;
+ g_object_unref (collection);
+ }
+
+ client = e_client_selector_ref_cached_client (
+ E_CLIENT_SELECTOR (selector), source);
+
+ if (client != NULL) {
+ refresh_supported =
+ e_client_check_refresh_supported (client);
+ g_object_unref (client);
+ }
+
+ g_object_unref (source);
+ }
+
+ if (has_primary_source)
+ state |= E_CAL_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE;
+ if (is_writable)
+ state |= E_CAL_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_WRITABLE;
+ if (is_removable)
+ state |= E_CAL_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOVABLE;
+ if (is_remote_creatable)
+ state |= E_CAL_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_CREATABLE;
+ if (is_remote_deletable)
+ state |= E_CAL_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_DELETABLE;
+ if (in_collection)
+ state |= E_CAL_SHELL_SIDEBAR_PRIMARY_SOURCE_IN_COLLECTION;
+ if (refresh_supported)
+ state |= E_CAL_SHELL_SIDEBAR_SOURCE_SUPPORTS_REFRESH;
+
+ return state;
+}
+
+static void
+cal_shell_sidebar_client_removed (ECalShellSidebar *cal_shell_sidebar,
+ ECalClient *client)
+{
+ ESourceSelector *selector;
+ ESource *source;
+
+ source = e_client_get_source (E_CLIENT (client));
+
+ selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+ e_source_selector_unselect_source (selector, source);
+}
+
+static void
+e_cal_shell_sidebar_class_init (ECalShellSidebarClass *class)
+{
+ GObjectClass *object_class;
+ EShellSidebarClass *shell_sidebar_class;
+
+ g_type_class_add_private (class, sizeof (ECalShellSidebarPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->get_property = cal_shell_sidebar_get_property;
+ object_class->dispose = cal_shell_sidebar_dispose;
+ object_class->constructed = cal_shell_sidebar_constructed;
+
+ shell_sidebar_class = E_SHELL_SIDEBAR_CLASS (class);
+ shell_sidebar_class->check_state = cal_shell_sidebar_check_state;
+
+ class->client_removed = cal_shell_sidebar_client_removed;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_DATE_NAVIGATOR,
+ g_param_spec_object (
+ "date-navigator",
+ "Date Navigator Widget",
+ "This widget displays a miniature calendar",
+ E_TYPE_CALENDAR,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_DEFAULT_CLIENT,
+ g_param_spec_object (
+ "default-client",
+ "Default Calendar ECalClient",
+ "Default client for calendar operations",
+ E_TYPE_CAL_CLIENT,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SELECTOR,
+ g_param_spec_object (
+ "selector",
+ "Source Selector Widget",
+ "This widget displays groups of calendars",
+ E_TYPE_SOURCE_SELECTOR,
+ G_PARAM_READABLE));
+
+ signals[CLIENT_ADDED] = g_signal_new (
+ "client-added",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ECalShellSidebarClass, client_added),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ E_TYPE_CAL_CLIENT);
+
+ signals[CLIENT_REMOVED] = g_signal_new (
+ "client-removed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ECalShellSidebarClass, client_removed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ E_TYPE_CAL_CLIENT);
+}
+
+static void
+e_cal_shell_sidebar_class_finalize (ECalShellSidebarClass *class)
+{
+}
+
+static void
+e_cal_shell_sidebar_init (ECalShellSidebar *cal_shell_sidebar)
+{
+ cal_shell_sidebar->priv =
+ E_CAL_SHELL_SIDEBAR_GET_PRIVATE (cal_shell_sidebar);
+
+ /* Postpone widget construction until we have a shell view. */
+}
+
+void
+e_cal_shell_sidebar_type_register (GTypeModule *type_module)
+{
+ /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
+ * function, so we have to wrap it with a public function in
+ * order to register types from a separate compilation unit. */
+ e_cal_shell_sidebar_register_type (type_module);
+}
+
+GtkWidget *
+e_cal_shell_sidebar_new (EShellView *shell_view)
+{
+ g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
+
+ return g_object_new (
+ E_TYPE_CAL_SHELL_SIDEBAR,
+ "shell-view", shell_view, NULL);
+}
+
+ECalendar *
+e_cal_shell_sidebar_get_date_navigator (ECalShellSidebar *cal_shell_sidebar)
+{
+ g_return_val_if_fail (
+ E_IS_CAL_SHELL_SIDEBAR (cal_shell_sidebar), NULL);
+
+ return E_CALENDAR (cal_shell_sidebar->priv->date_navigator);
+}
+
+ECalClient *
+e_cal_shell_sidebar_get_default_client (ECalShellSidebar *cal_shell_sidebar)
+{
+ g_return_val_if_fail (
+ E_IS_CAL_SHELL_SIDEBAR (cal_shell_sidebar), NULL);
+
+ return (ECalClient *) cal_shell_sidebar->priv->default_client;
+}
+
+ESourceSelector *
+e_cal_shell_sidebar_get_selector (ECalShellSidebar *cal_shell_sidebar)
+{
+ g_return_val_if_fail (
+ E_IS_CAL_SHELL_SIDEBAR (cal_shell_sidebar), NULL);
+
+ return E_SOURCE_SELECTOR (cal_shell_sidebar->priv->selector);
+}
+
+void
+e_cal_shell_sidebar_add_client (ECalShellSidebar *cal_shell_sidebar,
+ EClient *client)
+{
+ ESource *source;
+ ESourceSelector *selector;
+
+ g_return_if_fail (E_IS_CAL_SHELL_SIDEBAR (cal_shell_sidebar));
+ g_return_if_fail (E_IS_CAL_CLIENT (client));
+
+ source = e_client_get_source (client);
+
+ selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+ e_source_selector_select_source (selector, source);
+
+ cal_shell_sidebar_emit_client_added (cal_shell_sidebar, client);
+}
+
+void
+e_cal_shell_sidebar_add_source (ECalShellSidebar *cal_shell_sidebar,
+ ESource *source)
+{
+ ESourceSelector *selector;
+ ConnectClosure *closure;
+
+ g_return_if_fail (E_IS_CAL_SHELL_SIDEBAR (cal_shell_sidebar));
+ g_return_if_fail (E_IS_SOURCE (source));
+
+ selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+
+ e_source_selector_select_source (selector, source);
+
+ closure = connect_closure_new (cal_shell_sidebar, source);
+
+ e_client_selector_get_client (
+ E_CLIENT_SELECTOR (selector), source,
+ e_activity_get_cancellable (closure->activity),
+ cal_shell_sidebar_client_connect_cb, closure);
+}
+
+void
+e_cal_shell_sidebar_remove_source (ECalShellSidebar *cal_shell_sidebar,
+ ESource *source)
+{
+ ESourceSelector *selector;
+ EClient *client;
+
+ g_return_if_fail (E_IS_CAL_SHELL_SIDEBAR (cal_shell_sidebar));
+ g_return_if_fail (E_IS_SOURCE (source));
+
+ selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+
+ client = e_client_selector_ref_cached_client (
+ E_CLIENT_SELECTOR (selector), source);
+
+ if (client != NULL) {
+ cal_shell_sidebar_emit_client_removed (
+ cal_shell_sidebar, client);
+ g_object_unref (client);
+ }
+}
diff --git a/modules/calendar/e-cal-shell-sidebar.h b/modules/calendar/e-cal-shell-sidebar.h
new file mode 100644
index 0000000000..f751e61892
--- /dev/null
+++ b/modules/calendar/e-cal-shell-sidebar.h
@@ -0,0 +1,104 @@
+/*
+ * e-cal-shell-sidebar.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_CAL_SHELL_SIDEBAR_H
+#define E_CAL_SHELL_SIDEBAR_H
+
+#include <libecal/libecal.h>
+
+#include <shell/e-shell-sidebar.h>
+#include <shell/e-shell-view.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CAL_SHELL_SIDEBAR \
+ (e_cal_shell_sidebar_get_type ())
+#define E_CAL_SHELL_SIDEBAR(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_CAL_SHELL_SIDEBAR, ECalShellSidebar))
+#define E_CAL_SHELL_SIDEBAR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_CAL_SHELL_SIDEBAR, ECalShellSidebarClass))
+#define E_IS_CAL_SHELL_SIDEBAR(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_CAL_SHELL_SIDEBAR))
+#define E_IS_CAL_SHELL_SIDEBAR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_CAL_SHELL_SIDEBAR))
+#define E_CAL_SHELL_SIDEBAR_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_CAL_SHELL_SIDEBAR, ECalShellSidebarClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ECalShellSidebar ECalShellSidebar;
+typedef struct _ECalShellSidebarClass ECalShellSidebarClass;
+typedef struct _ECalShellSidebarPrivate ECalShellSidebarPrivate;
+
+enum {
+ E_CAL_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE = 1 << 0,
+ E_CAL_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_WRITABLE = 1 << 1,
+ E_CAL_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOVABLE = 1 << 2,
+ E_CAL_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_CREATABLE = 1 << 3,
+ E_CAL_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_DELETABLE = 1 << 4,
+ E_CAL_SHELL_SIDEBAR_PRIMARY_SOURCE_IN_COLLECTION = 1 << 5,
+ E_CAL_SHELL_SIDEBAR_SOURCE_SUPPORTS_REFRESH = 1 << 6
+};
+
+struct _ECalShellSidebar {
+ EShellSidebar parent;
+ ECalShellSidebarPrivate *priv;
+};
+
+struct _ECalShellSidebarClass {
+ EShellSidebarClass parent_class;
+
+ /* Signals */
+ void (*client_added) (ECalShellSidebar *cal_shell_sidebar,
+ ECalClient *client);
+ void (*client_removed)
+ (ECalShellSidebar *cal_shell_sidebar,
+ ECalClient *client);
+};
+
+GType e_cal_shell_sidebar_get_type (void);
+void e_cal_shell_sidebar_type_register
+ (GTypeModule *type_module);
+GtkWidget * e_cal_shell_sidebar_new (EShellView *shell_view);
+ECalendar * e_cal_shell_sidebar_get_date_navigator
+ (ECalShellSidebar *cal_shell_sidebar);
+ECalClient * e_cal_shell_sidebar_get_default_client
+ (ECalShellSidebar *cal_shell_sidebar);
+ESourceSelector *
+ e_cal_shell_sidebar_get_selector
+ (ECalShellSidebar *cal_shell_sidebar);
+void e_cal_shell_sidebar_add_client
+ (ECalShellSidebar *cal_shell_sidebar,
+ EClient *client);
+void e_cal_shell_sidebar_add_source
+ (ECalShellSidebar *cal_shell_sidebar,
+ ESource *source);
+void e_cal_shell_sidebar_remove_source
+ (ECalShellSidebar *cal_shell_sidebar,
+ ESource *source);
+
+G_END_DECLS
+
+#endif /* E_CAL_SHELL_SIDEBAR_H */
diff --git a/modules/calendar/e-cal-shell-view-actions.c b/modules/calendar/e-cal-shell-view-actions.c
new file mode 100644
index 0000000000..b59a3f3ef4
--- /dev/null
+++ b/modules/calendar/e-cal-shell-view-actions.c
@@ -0,0 +1,2021 @@
+/*
+ * e-cal-shell-view-actions.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-cal-shell-view-private.h"
+
+/* This is for radio action groups whose value is persistent. We
+ * initialize it to a bogus value to ensure a "changed" signal is
+ * emitted when a valid value is restored. */
+#define BOGUS_INITIAL_VALUE G_MININT
+
+static void
+action_calendar_copy_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellSidebar *cal_shell_sidebar;
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ESourceRegistry *registry;
+ ESourceSelector *selector;
+ ESource *source;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ registry = e_shell_get_registry (shell);
+
+ cal_shell_sidebar = cal_shell_view->priv->cal_shell_sidebar;
+ selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+ source = e_source_selector_ref_primary_selection (selector);
+ g_return_if_fail (source != NULL);
+
+ copy_source_dialog (
+ GTK_WINDOW (shell_window), registry,
+ source, E_CAL_CLIENT_SOURCE_TYPE_EVENTS);
+
+ g_object_unref (source);
+}
+
+static void
+action_calendar_delete_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellSidebar *cal_shell_sidebar;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ ESource *source;
+ ESourceSelector *selector;
+ gint response;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ cal_shell_sidebar = cal_shell_view->priv->cal_shell_sidebar;
+ selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+
+ source = e_source_selector_ref_primary_selection (selector);
+ g_return_if_fail (source != NULL);
+
+ if (e_source_get_remote_deletable (source)) {
+ response = e_alert_run_dialog_for_args (
+ GTK_WINDOW (shell_window),
+ "calendar:prompt-delete-remote-calendar",
+ e_source_get_display_name (source), NULL);
+
+ if (response == GTK_RESPONSE_YES)
+ e_shell_view_remote_delete_source (shell_view, source);
+
+ } else {
+ response = e_alert_run_dialog_for_args (
+ GTK_WINDOW (shell_window),
+ "calendar:prompt-delete-calendar",
+ e_source_get_display_name (source), NULL);
+
+ if (response == GTK_RESPONSE_YES)
+ e_shell_view_remove_source (shell_view, source);
+ }
+
+ g_object_unref (source);
+}
+
+static void
+action_calendar_go_back_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ GnomeCalendar *calendar;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+
+ gnome_calendar_previous (calendar);
+}
+
+static void
+action_calendar_go_forward_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ GnomeCalendar *calendar;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+
+ gnome_calendar_next (calendar);
+}
+
+static void
+action_calendar_go_today_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ GnomeCalendar *calendar;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+
+ gnome_calendar_goto_today (calendar);
+}
+
+static void
+action_calendar_jump_to_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ GnomeCalendar *calendar;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+
+ goto_dialog (GTK_WINDOW (shell_window), calendar);
+}
+
+static void
+action_calendar_new_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ESourceRegistry *registry;
+ ECalClientSourceType source_type;
+ GtkWidget *config;
+ GtkWidget *dialog;
+ const gchar *icon_name;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ registry = e_shell_get_registry (shell);
+ source_type = E_CAL_CLIENT_SOURCE_TYPE_EVENTS;
+ config = e_cal_source_config_new (registry, NULL, source_type);
+
+ dialog = e_source_config_dialog_new (E_SOURCE_CONFIG (config));
+
+ gtk_window_set_transient_for (
+ GTK_WINDOW (dialog), GTK_WINDOW (shell_window));
+
+ icon_name = gtk_action_get_icon_name (action);
+ gtk_window_set_icon_name (GTK_WINDOW (dialog), icon_name);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), _("New Calendar"));
+
+ gtk_widget_show (dialog);
+}
+
+static void
+action_calendar_print_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ GnomeCalendarViewType view_type;
+ GnomeCalendar *calendar;
+ ECalendarView *view;
+ GtkPrintOperationAction print_action;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ view_type = gnome_calendar_get_view (calendar);
+ view = gnome_calendar_get_calendar_view (calendar, view_type);
+ print_action = GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG;
+
+ if (E_IS_CAL_LIST_VIEW (view)) {
+ ETable *table;
+
+ table = E_CAL_LIST_VIEW (view)->table;
+ print_table (table, _("Print"), _("Calendar"), print_action);
+ } else {
+ time_t start;
+
+ gnome_calendar_get_current_time_range (calendar, &start, NULL);
+ print_calendar (calendar, print_action, start);
+ }
+}
+
+static void
+action_calendar_print_preview_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ GnomeCalendarViewType view_type;
+ GnomeCalendar *calendar;
+ ECalendarView *view;
+ GtkPrintOperationAction print_action;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ view_type = gnome_calendar_get_view (calendar);
+ view = gnome_calendar_get_calendar_view (calendar, view_type);
+ print_action = GTK_PRINT_OPERATION_ACTION_PREVIEW;
+
+ if (E_IS_CAL_LIST_VIEW (view)) {
+ ETable *table;
+
+ table = E_CAL_LIST_VIEW (view)->table;
+ print_table (table, _("Print"), _("Calendar"), print_action);
+ } else {
+ time_t start;
+
+ gnome_calendar_get_current_time_range (calendar, &start, NULL);
+ print_calendar (calendar, print_action, start);
+ }
+}
+
+static void
+action_calendar_properties_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ECalShellSidebar *cal_shell_sidebar;
+ ECalClientSourceType source_type;
+ ESource *source;
+ ESourceSelector *selector;
+ ESourceRegistry *registry;
+ GtkWidget *config;
+ GtkWidget *dialog;
+ const gchar *icon_name;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ cal_shell_sidebar = cal_shell_view->priv->cal_shell_sidebar;
+ selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+ source = e_source_selector_ref_primary_selection (selector);
+ g_return_if_fail (source != NULL);
+
+ source_type = E_CAL_CLIENT_SOURCE_TYPE_EVENTS;
+ registry = e_source_selector_get_registry (selector);
+ config = e_cal_source_config_new (registry, source, source_type);
+
+ g_object_unref (source);
+
+ dialog = e_source_config_dialog_new (E_SOURCE_CONFIG (config));
+
+ gtk_window_set_transient_for (
+ GTK_WINDOW (dialog), GTK_WINDOW (shell_window));
+
+ icon_name = gtk_action_get_icon_name (action);
+ gtk_window_set_icon_name (GTK_WINDOW (dialog), icon_name);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), _("Calendar Properties"));
+
+ gtk_widget_show (dialog);
+}
+
+static void
+action_calendar_purge_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ECalShellContent *cal_shell_content;
+ GnomeCalendar *calendar;
+ GtkSpinButton *spin_button;
+ GtkWidget *container;
+ GtkWidget *dialog;
+ GtkWidget *widget;
+ gint days;
+ time_t tt;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+
+ dialog = gtk_message_dialog_new (
+ GTK_WINDOW (shell_window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_OK_CANCEL,
+ _("This operation will permanently erase all events older "
+ "than the selected amount of time. If you continue, you "
+ "will not be able to recover these events."));
+
+ gtk_dialog_set_default_response (
+ GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL);
+
+ container = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+
+ widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, FALSE, 6);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ /* Translators: This is the first part of the sentence:
+ * "Purge events older than <<spin-button>> days" */
+ widget = gtk_label_new (_("Purge events older than"));
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, FALSE, 6);
+ gtk_widget_show (widget);
+
+ widget = gtk_spin_button_new_with_range (0.0, 1000.0, 1.0);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), 60.0);
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 6);
+ gtk_widget_show (widget);
+
+ spin_button = GTK_SPIN_BUTTON (widget);
+
+ /* Translators: This is the last part of the sentence:
+ * "Purge events older than <<spin-button>> days" */
+ widget = gtk_label_new (_("days"));
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, FALSE, 6);
+ gtk_widget_show (widget);
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK)
+ goto exit;
+
+ days = gtk_spin_button_get_value_as_int (spin_button);
+
+ tt = time (NULL);
+ tt -= (days * (24 * 3600));
+
+ gnome_calendar_purge (calendar, tt);
+
+exit:
+ gtk_widget_destroy (dialog);
+}
+
+static void
+action_calendar_refresh_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellSidebar *cal_shell_sidebar;
+ ESourceSelector *selector;
+ EClient *client = NULL;
+ ESource *source;
+ GError *error = NULL;
+
+ cal_shell_sidebar = cal_shell_view->priv->cal_shell_sidebar;
+ selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+
+ source = e_source_selector_ref_primary_selection (selector);
+
+ if (source != NULL) {
+ client = e_client_selector_ref_cached_client (
+ E_CLIENT_SELECTOR (selector), source);
+ g_object_unref (source);
+ }
+
+ if (client == NULL)
+ return;
+
+ g_return_if_fail (e_client_check_refresh_supported (client));
+
+ e_client_refresh_sync (client, NULL, &error);
+
+ if (error != NULL) {
+ g_warning (
+ "%s: Failed to refresh '%s', %s",
+ G_STRFUNC, e_source_get_display_name (source),
+ error->message);
+ g_error_free (error);
+ }
+
+ g_object_unref (client);
+}
+
+static void
+action_calendar_rename_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellSidebar *cal_shell_sidebar;
+ ESourceSelector *selector;
+
+ cal_shell_sidebar = cal_shell_view->priv->cal_shell_sidebar;
+ selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+
+ e_source_selector_edit_primary_selection (selector);
+}
+
+static void
+action_calendar_search_next_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ e_cal_shell_view_search_events (cal_shell_view, TRUE);
+}
+
+static void
+action_calendar_search_prev_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ e_cal_shell_view_search_events (cal_shell_view, FALSE);
+}
+
+static void
+action_calendar_search_stop_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ e_cal_shell_view_search_stop (cal_shell_view);
+}
+
+static void
+action_calendar_select_one_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellSidebar *cal_shell_sidebar;
+ ESourceSelector *selector;
+ ESource *primary;
+
+ cal_shell_sidebar = cal_shell_view->priv->cal_shell_sidebar;
+ selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+
+ primary = e_source_selector_ref_primary_selection (selector);
+ g_return_if_fail (primary != NULL);
+
+ e_source_selector_select_exclusive (selector, primary);
+
+ g_object_unref (primary);
+}
+
+static void
+action_calendar_view_cb (GtkRadioAction *action,
+ GtkRadioAction *current,
+ ECalShellView *cal_shell_view)
+{
+ EShellView *shell_view;
+ GnomeCalendarViewType view_type;
+ const gchar *view_id;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ view_type = gtk_radio_action_get_current_value (action);
+
+ switch (view_type) {
+ case GNOME_CAL_DAY_VIEW:
+ view_id = "Day_View";
+ break;
+
+ case GNOME_CAL_WORK_WEEK_VIEW:
+ view_id = "Work_Week_View";
+ break;
+
+ case GNOME_CAL_WEEK_VIEW:
+ view_id = "Week_View";
+ break;
+
+ case GNOME_CAL_MONTH_VIEW:
+ view_id = "Month_View";
+ break;
+
+ case GNOME_CAL_LIST_VIEW:
+ view_id = "List_View";
+ break;
+
+ default:
+ g_return_if_reached ();
+ }
+
+ e_shell_view_set_view_id (shell_view, view_id);
+}
+
+static void
+action_event_all_day_new_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ GnomeCalendarViewType view_type;
+ ECalendarView *calendar_view;
+ GnomeCalendar *calendar;
+
+ /* These are just for readability. */
+ gboolean all_day = TRUE;
+ gboolean meeting = FALSE;
+ gboolean no_past_date = FALSE;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ view_type = gnome_calendar_get_view (calendar);
+ calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+
+ e_calendar_view_new_appointment_full (
+ calendar_view, all_day, meeting, no_past_date);
+}
+
+static void
+action_event_copy_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ECalShellContent *cal_shell_content;
+ GnomeCalendarViewType view_type;
+ GnomeCalendar *calendar;
+ ECalendarView *calendar_view;
+ ESource *source_source = NULL;
+ ESource *destination_source = NULL;
+ ESourceRegistry *registry;
+ EClient *destination_client = NULL;
+ GList *selected, *iter;
+ GError *error = NULL;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ registry = gnome_calendar_get_registry (calendar);
+
+ view_type = gnome_calendar_get_view (calendar);
+ calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+
+ selected = e_calendar_view_get_selected_events (calendar_view);
+ g_return_if_fail (selected != NULL);
+
+ if (selected->data) {
+ ECalendarViewEvent *event = selected->data;
+
+ if (is_comp_data_valid (event) && event->comp_data->client)
+ source_source = e_client_get_source (
+ E_CLIENT (event->comp_data->client));
+ }
+
+ /* Get a destination source from the user. */
+ destination_source = select_source_dialog (
+ GTK_WINDOW (shell_window), registry,
+ E_CAL_CLIENT_SOURCE_TYPE_EVENTS, source_source);
+ if (destination_source == NULL)
+ return;
+
+ /* Open the destination calendar. */
+ destination_client = e_cal_client_connect_sync (
+ destination_source,
+ E_CAL_CLIENT_SOURCE_TYPE_EVENTS,
+ NULL, &error);
+
+ if (error != NULL) {
+ g_warning (
+ "%s: Failed to open destination client: %s",
+ G_STRFUNC, error->message);
+ g_error_free (error);
+ goto exit;
+ }
+
+ e_cal_shell_view_set_status_message (
+ cal_shell_view, _("Copying Items"), -1.0);
+
+ for (iter = selected; iter != NULL; iter = iter->next) {
+ ECalendarViewEvent *event = iter->data;
+ gboolean remove = FALSE;
+
+ e_cal_shell_view_transfer_item_to (
+ cal_shell_view, event,
+ E_CAL_CLIENT (destination_client), remove);
+ }
+
+ e_cal_shell_view_set_status_message (cal_shell_view, NULL, -1.0);
+
+exit:
+ if (destination_client != NULL)
+ g_object_unref (destination_client);
+ if (destination_source != NULL)
+ g_object_unref (destination_source);
+ g_list_free (selected);
+}
+
+static void
+action_event_delegate_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ESourceRegistry *registry;
+ ECalShellContent *cal_shell_content;
+ GnomeCalendarViewType view_type;
+ GnomeCalendar *calendar;
+ ECalendarView *calendar_view;
+ ECalendarViewEvent *event;
+ ECalComponent *component;
+ ECalClient *client;
+ ECalModel *model;
+ GList *selected;
+ icalcomponent *clone;
+ icalproperty *property;
+ gboolean found = FALSE;
+ gchar *attendee;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ view_type = gnome_calendar_get_view (calendar);
+ calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+
+ selected = e_calendar_view_get_selected_events (calendar_view);
+ g_return_if_fail (g_list_length (selected) == 1);
+
+ model = e_calendar_view_get_model (calendar_view);
+ registry = e_cal_model_get_registry (model);
+
+ event = selected->data;
+
+ if (!is_comp_data_valid (event))
+ return;
+
+ client = event->comp_data->client;
+ clone = icalcomponent_new_clone (event->comp_data->icalcomp);
+
+ /* Set the attendee status for the delegate. */
+
+ component = e_cal_component_new ();
+ e_cal_component_set_icalcomponent (
+ component, icalcomponent_new_clone (clone));
+
+ attendee = itip_get_comp_attendee (
+ registry, component, client);
+ property = icalcomponent_get_first_property (
+ clone, ICAL_ATTENDEE_PROPERTY);
+
+ while (property != NULL) {
+ const gchar *candidate;
+
+ candidate = icalproperty_get_attendee (property);
+ candidate = itip_strip_mailto (candidate);
+
+ if (g_ascii_strcasecmp (candidate, attendee) == 0) {
+ icalparameter *parameter;
+
+ parameter = icalparameter_new_role (
+ ICAL_ROLE_NONPARTICIPANT);
+ icalproperty_set_parameter (property, parameter);
+
+ parameter = icalparameter_new_partstat (
+ ICAL_PARTSTAT_DELEGATED);
+ icalproperty_set_parameter (property, parameter);
+
+ found = TRUE;
+ break;
+ }
+
+ property = icalcomponent_get_next_property (
+ clone, ICAL_ATTENDEE_PROPERTY);
+ }
+
+ /* If the attendee is not already in the component, add it. */
+ if (!found) {
+ icalparameter *parameter;
+ gchar *address;
+
+ address = g_strdup_printf ("MAILTO:%s", attendee);
+
+ property = icalproperty_new_attendee (address);
+ icalcomponent_add_property (clone, property);
+
+ parameter = icalparameter_new_role (ICAL_ROLE_NONPARTICIPANT);
+ icalproperty_add_parameter (property, parameter);
+
+ parameter = icalparameter_new_cutype (ICAL_CUTYPE_INDIVIDUAL);
+ icalproperty_add_parameter (property, parameter);
+
+ parameter = icalparameter_new_rsvp (ICAL_RSVP_TRUE);
+ icalproperty_add_parameter (property, parameter);
+
+ g_free (address);
+ }
+
+ g_free (attendee);
+ g_object_unref (component);
+
+ e_calendar_view_open_event_with_flags (
+ calendar_view, event->comp_data->client, clone,
+ COMP_EDITOR_MEETING | COMP_EDITOR_DELEGATE);
+
+ icalcomponent_free (clone);
+ g_list_free (selected);
+}
+
+static void
+action_event_delete_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ GnomeCalendar *calendar;
+ GnomeCalendarViewType view_type;
+ ECalendarView *calendar_view;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+
+ view_type = gnome_calendar_get_view (calendar);
+ calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+
+ e_selectable_delete_selection (E_SELECTABLE (calendar_view));
+}
+
+static void
+action_event_delete_occurrence_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ GnomeCalendar *calendar;
+ GnomeCalendarViewType view_type;
+ ECalendarView *calendar_view;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+
+ view_type = gnome_calendar_get_view (calendar);
+ calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+
+ e_calendar_view_delete_selected_occurrence (calendar_view);
+}
+
+static void
+action_event_forward_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ GnomeCalendarViewType view_type;
+ ECalendarView *calendar_view;
+ GnomeCalendar *calendar;
+ ESourceRegistry *registry;
+ ECalendarViewEvent *event;
+ ECalComponent *component;
+ ECalClient *client;
+ icalcomponent *icalcomp;
+ GList *selected;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ registry = gnome_calendar_get_registry (calendar);
+
+ view_type = gnome_calendar_get_view (calendar);
+ calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+
+ selected = e_calendar_view_get_selected_events (calendar_view);
+ g_return_if_fail (g_list_length (selected) == 1);
+
+ event = selected->data;
+
+ if (!is_comp_data_valid (event))
+ return;
+
+ client = event->comp_data->client;
+ icalcomp = event->comp_data->icalcomp;
+
+ component = e_cal_component_new ();
+
+ e_cal_component_set_icalcomponent (
+ component, icalcomponent_new_clone (icalcomp));
+ itip_send_comp (
+ registry, E_CAL_COMPONENT_METHOD_PUBLISH,
+ component, client, NULL, NULL, NULL, TRUE, FALSE);
+
+ g_object_unref (component);
+
+ g_list_free (selected);
+}
+
+static void
+action_event_meeting_new_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ GnomeCalendarViewType view_type;
+ ECalendarView *calendar_view;
+ GnomeCalendar *calendar;
+
+ /* These are just for readability. */
+ gboolean all_day = FALSE;
+ gboolean meeting = TRUE;
+ gboolean no_past_date = FALSE;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ view_type = gnome_calendar_get_view (calendar);
+ calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+
+ e_calendar_view_new_appointment_full (
+ calendar_view, all_day, meeting, no_past_date);
+}
+
+static void
+action_event_move_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ECalShellContent *cal_shell_content;
+ GnomeCalendarViewType view_type;
+ GnomeCalendar *calendar;
+ ECalendarView *calendar_view;
+ ESource *source_source = NULL;
+ ESource *destination_source = NULL;
+ ESourceRegistry *registry;
+ EClient *destination_client = NULL;
+ GList *selected, *iter;
+ GError *error = NULL;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ registry = gnome_calendar_get_registry (calendar);
+
+ view_type = gnome_calendar_get_view (calendar);
+ calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+
+ selected = e_calendar_view_get_selected_events (calendar_view);
+ g_return_if_fail (selected != NULL);
+
+ if (selected->data) {
+ ECalendarViewEvent *event = selected->data;
+
+ if (is_comp_data_valid (event) && event->comp_data->client)
+ source_source = e_client_get_source (
+ E_CLIENT (event->comp_data->client));
+ }
+
+ /* Get a destination source from the user. */
+ destination_source = select_source_dialog (
+ GTK_WINDOW (shell_window), registry,
+ E_CAL_CLIENT_SOURCE_TYPE_EVENTS, source_source);
+ if (destination_source == NULL)
+ return;
+
+ /* Open the destination calendar. */
+ destination_client = e_cal_client_connect_sync (
+ destination_source,
+ E_CAL_CLIENT_SOURCE_TYPE_EVENTS,
+ NULL, &error);
+
+ if (error != NULL) {
+ g_warning (
+ "%s: Failed to open destination client: %s",
+ G_STRFUNC, error->message);
+ g_clear_error (&error);
+ goto exit;
+ }
+
+ e_cal_shell_view_set_status_message (
+ cal_shell_view, _("Moving Items"), -1.0);
+
+ for (iter = selected; iter != NULL; iter = iter->next) {
+ ECalendarViewEvent *event = iter->data;
+ gboolean remove = TRUE;
+
+ e_cal_shell_view_transfer_item_to (
+ cal_shell_view, event,
+ E_CAL_CLIENT (destination_client), remove);
+ }
+
+ e_cal_shell_view_set_status_message (cal_shell_view, NULL, -1.0);
+
+exit:
+ if (destination_client != NULL)
+ g_object_unref (destination_client);
+ if (destination_source != NULL)
+ g_object_unref (destination_source);
+ g_list_free (selected);
+}
+
+static void
+action_event_new_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ GnomeCalendarViewType view_type;
+ ECalendarView *calendar_view;
+ GnomeCalendar *calendar;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ view_type = gnome_calendar_get_view (calendar);
+ calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+
+ e_calendar_view_new_appointment (calendar_view);
+}
+
+static void
+action_event_occurrence_movable_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ GnomeCalendarViewType view_type;
+ GnomeCalendar *calendar;
+ ECalModel *model;
+ ECalendarView *calendar_view;
+ ECalendarViewEvent *event;
+ ECalComponent *exception_component;
+ ECalComponent *recurring_component;
+ ECalComponentDateTime date;
+ ECalComponentId *id;
+ ECalClient *client;
+ icalcomponent *icalcomp;
+ icaltimetype itt;
+ icaltimezone *timezone;
+ GList *selected;
+ gchar *uid;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ view_type = gnome_calendar_get_view (calendar);
+ calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+
+ model = e_calendar_view_get_model (calendar_view);
+ timezone = e_cal_model_get_timezone (model);
+
+ selected = e_calendar_view_get_selected_events (calendar_view);
+ g_return_if_fail (g_list_length (selected) == 1);
+
+ event = selected->data;
+
+ if (!is_comp_data_valid (event))
+ return;
+
+ client = event->comp_data->client;
+ icalcomp = event->comp_data->icalcomp;
+
+ /* For the recurring object, we add an exception
+ * to get rid of the instance. */
+
+ recurring_component = e_cal_component_new ();
+ e_cal_component_set_icalcomponent (
+ recurring_component, icalcomponent_new_clone (icalcomp));
+ id = e_cal_component_get_id (recurring_component);
+
+ /* For the unrecurred instance, we duplicate the original object,
+ * create a new UID for it, get rid of the recurrence rules, and
+ * set the start and end times to the instance times. */
+
+ exception_component = e_cal_component_new ();
+ e_cal_component_set_icalcomponent (
+ exception_component, icalcomponent_new_clone (icalcomp));
+
+ uid = e_cal_component_gen_uid ();
+ e_cal_component_set_uid (exception_component, uid);
+ g_free (uid);
+
+ e_cal_component_set_recurid (exception_component, NULL);
+ e_cal_component_set_rdate_list (exception_component, NULL);
+ e_cal_component_set_rrule_list (exception_component, NULL);
+ e_cal_component_set_exdate_list (exception_component, NULL);
+ e_cal_component_set_exrule_list (exception_component, NULL);
+
+ date.value = &itt;
+ date.tzid = icaltimezone_get_tzid (timezone);
+ *date.value = icaltime_from_timet_with_zone (
+ event->comp_data->instance_start, FALSE, timezone);
+ cal_comp_set_dtstart_with_oldzone (client, exception_component, &date);
+ *date.value = icaltime_from_timet_with_zone (
+ event->comp_data->instance_end, FALSE, timezone);
+ cal_comp_set_dtstart_with_oldzone (client, exception_component, &date);
+ e_cal_component_commit_sequence (exception_component);
+
+ /* Now update both ECalComponents. Note that we do this last
+ * since at present the updates happend synchronously so our
+ * event may disappear. */
+
+ e_cal_client_remove_object_sync (
+ client, id->uid, id->rid, CALOBJ_MOD_THIS, NULL, NULL);
+
+ e_cal_component_free_id (id);
+ g_object_unref (recurring_component);
+
+ icalcomp = e_cal_component_get_icalcomponent (exception_component);
+ if (e_cal_client_create_object_sync (client, icalcomp, &uid, NULL, NULL))
+ g_free (uid);
+
+ g_object_unref (exception_component);
+
+ g_list_free (selected);
+}
+
+static void
+action_event_open_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ GnomeCalendarViewType view_type;
+ GnomeCalendar *calendar;
+ ECalendarView *view;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ view_type = gnome_calendar_get_view (calendar);
+ view = gnome_calendar_get_calendar_view (calendar, view_type);
+
+ e_calendar_view_open_event (view);
+}
+
+static void
+action_event_print_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ GnomeCalendarViewType view_type;
+ GnomeCalendar *calendar;
+ ECalendarView *calendar_view;
+ ECalendarViewEvent *event;
+ ECalComponent *component;
+ ECalModel *model;
+ ECalClient *client;
+ icalcomponent *icalcomp;
+ GList *selected;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ view_type = gnome_calendar_get_view (calendar);
+ calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+ model = e_calendar_view_get_model (calendar_view);
+
+ selected = e_calendar_view_get_selected_events (calendar_view);
+ g_return_if_fail (g_list_length (selected) == 1);
+
+ event = selected->data;
+
+ if (!is_comp_data_valid (event))
+ return;
+
+ client = event->comp_data->client;
+ icalcomp = event->comp_data->icalcomp;
+
+ component = e_cal_component_new ();
+
+ e_cal_component_set_icalcomponent (
+ component, icalcomponent_new_clone (icalcomp));
+ print_comp (
+ component, client,
+ e_cal_model_get_timezone (model),
+ e_cal_model_get_use_24_hour_format (model),
+ GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG);
+
+ g_object_unref (component);
+
+ g_list_free (selected);
+}
+
+static void
+action_event_reply_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ GnomeCalendarViewType view_type;
+ ECalendarView *calendar_view;
+ GnomeCalendar *calendar;
+ ECalendarViewEvent *event;
+ ECalComponent *component;
+ ECalClient *client;
+ ESourceRegistry *registry;
+ icalcomponent *icalcomp;
+ GList *selected;
+ gboolean reply_all = FALSE;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ registry = gnome_calendar_get_registry (calendar);
+
+ view_type = gnome_calendar_get_view (calendar);
+ calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+
+ selected = e_calendar_view_get_selected_events (calendar_view);
+ g_return_if_fail (g_list_length (selected) == 1);
+
+ event = selected->data;
+
+ if (!is_comp_data_valid (event))
+ return;
+
+ client = event->comp_data->client;
+ icalcomp = event->comp_data->icalcomp;
+
+ component = e_cal_component_new ();
+
+ e_cal_component_set_icalcomponent (
+ component, icalcomponent_new_clone (icalcomp));
+ reply_to_calendar_comp (
+ registry, E_CAL_COMPONENT_METHOD_REPLY,
+ component, client, reply_all, NULL, NULL);
+
+ g_object_unref (component);
+
+ g_list_free (selected);
+}
+
+static void
+action_event_reply_all_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ GnomeCalendarViewType view_type;
+ ECalendarView *calendar_view;
+ GnomeCalendar *calendar;
+ ECalendarViewEvent *event;
+ ECalComponent *component;
+ ECalClient *client;
+ ESourceRegistry *registry;
+ icalcomponent *icalcomp;
+ GList *selected;
+ gboolean reply_all = TRUE;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ registry = gnome_calendar_get_registry (calendar);
+
+ view_type = gnome_calendar_get_view (calendar);
+ calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+
+ selected = e_calendar_view_get_selected_events (calendar_view);
+ g_return_if_fail (g_list_length (selected) == 1);
+
+ event = selected->data;
+
+ if (!is_comp_data_valid (event))
+ return;
+
+ client = event->comp_data->client;
+ icalcomp = event->comp_data->icalcomp;
+
+ component = e_cal_component_new ();
+
+ e_cal_component_set_icalcomponent (
+ component, icalcomponent_new_clone (icalcomp));
+ reply_to_calendar_comp (
+ registry, E_CAL_COMPONENT_METHOD_REPLY,
+ component, client, reply_all, NULL, NULL);
+
+ g_object_unref (component);
+
+ g_list_free (selected);
+}
+
+static void
+action_event_save_as_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellBackend *shell_backend;
+ ECalShellContent *cal_shell_content;
+ GnomeCalendarViewType view_type;
+ GnomeCalendar *calendar;
+ ECalendarView *calendar_view;
+ ECalendarViewEvent *event;
+ ECalClient *client;
+ icalcomponent *icalcomp;
+ EActivity *activity;
+ GList *selected;
+ GFile *file;
+ gchar *string = NULL;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ view_type = gnome_calendar_get_view (calendar);
+ calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+
+ selected = e_calendar_view_get_selected_events (calendar_view);
+ g_return_if_fail (g_list_length (selected) == 1);
+
+ event = selected->data;
+
+ if (!is_comp_data_valid (event))
+ return;
+
+ client = event->comp_data->client;
+ icalcomp = event->comp_data->icalcomp;
+
+ /* Translators: Default filename part saving an event to a file when
+ * no summary is filed, the '.ics' extension is concatenated to it. */
+ string = icalcomp_suggest_filename (icalcomp, _("event"));
+ file = e_shell_run_save_dialog (
+ shell, _("Save as iCalendar"), string,
+ "*.ics:text/calendar", NULL, NULL);
+ g_free (string);
+ if (file == NULL)
+ return;
+
+ string = e_cal_client_get_component_as_string (client, icalcomp);
+ if (string == NULL) {
+ g_warning ("Could not convert item to a string");
+ goto exit;
+ }
+
+ /* XXX No callbacks means errors are discarded. */
+ activity = e_file_replace_contents_async (
+ file, string, strlen (string), NULL, FALSE,
+ G_FILE_CREATE_NONE, (GAsyncReadyCallback) NULL, NULL);
+ e_shell_backend_add_activity (shell_backend, activity);
+
+ /* Free the string when the activity is finalized. */
+ g_object_set_data_full (
+ G_OBJECT (activity),
+ "file-content", string,
+ (GDestroyNotify) g_free);
+
+exit:
+ g_object_unref (file);
+
+ g_list_free (selected);
+}
+
+static void
+edit_event_as (ECalShellView *cal_shell_view,
+ gboolean as_meeting)
+{
+ ECalShellContent *cal_shell_content;
+ GnomeCalendarViewType view_type;
+ GnomeCalendar *calendar;
+ ECalendarView *calendar_view;
+ ECalendarViewEvent *event;
+ ECalClient *client;
+ icalcomponent *icalcomp;
+ GList *selected;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ view_type = gnome_calendar_get_view (calendar);
+ calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+
+ selected = e_calendar_view_get_selected_events (calendar_view);
+ g_return_if_fail (g_list_length (selected) == 1);
+
+ event = selected->data;
+
+ if (!is_comp_data_valid (event))
+ return;
+
+ client = event->comp_data->client;
+ icalcomp = event->comp_data->icalcomp;
+
+ if (!as_meeting && icalcomp) {
+ /* remove organizer and all attendees */
+ icalproperty *prop;
+
+ /* do it on a copy, as user can cancel changes */
+ icalcomp = icalcomponent_new_clone (icalcomp);
+
+ prop = icalcomponent_get_first_property (
+ icalcomp, ICAL_ATTENDEE_PROPERTY);
+ while (prop != NULL) {
+ icalcomponent_remove_property (icalcomp, prop);
+ icalproperty_free (prop);
+
+ prop = icalcomponent_get_first_property (
+ icalcomp, ICAL_ATTENDEE_PROPERTY);
+ }
+
+ prop = icalcomponent_get_first_property (
+ icalcomp, ICAL_ORGANIZER_PROPERTY);
+ while (prop != NULL) {
+ icalcomponent_remove_property (icalcomp, prop);
+ icalproperty_free (prop);
+
+ prop = icalcomponent_get_first_property (
+ icalcomp, ICAL_ORGANIZER_PROPERTY);
+ }
+ }
+
+ e_calendar_view_edit_appointment (
+ calendar_view, client, icalcomp, as_meeting ?
+ EDIT_EVENT_FORCE_MEETING : EDIT_EVENT_FORCE_APPOINTMENT);
+
+ if (!as_meeting && icalcomp) {
+ icalcomponent_free (icalcomp);
+ }
+
+ g_list_free (selected);
+}
+
+static void
+action_event_schedule_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ edit_event_as (cal_shell_view, TRUE);
+}
+
+static void
+quit_calendar_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ GdkWindow *window;
+ GdkEvent *event;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ /* Synthesize a delete_event on this window. */
+ event = gdk_event_new (GDK_DELETE);
+ window = gtk_widget_get_window (GTK_WIDGET (shell_window));
+ event->any.window = g_object_ref (window);
+ event->any.send_event = TRUE;
+ gtk_main_do_event (event);
+ gdk_event_free (event);
+
+}
+
+static void
+action_event_schedule_appointment_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ edit_event_as (cal_shell_view, FALSE);
+}
+
+static GtkActionEntry calendar_entries[] = {
+
+ { "calendar-copy",
+ GTK_STOCK_COPY,
+ N_("_Copy..."),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_calendar_copy_cb) },
+
+ { "calendar-delete",
+ GTK_STOCK_DELETE,
+ N_("D_elete Calendar"),
+ NULL,
+ N_("Delete the selected calendar"),
+ G_CALLBACK (action_calendar_delete_cb) },
+
+ { "calendar-go-back",
+ GTK_STOCK_GO_BACK,
+ N_("Previous"),
+ NULL,
+ N_("Go Back"),
+ G_CALLBACK (action_calendar_go_back_cb) },
+
+ { "calendar-go-forward",
+ GTK_STOCK_GO_FORWARD,
+ N_("Next"),
+ NULL,
+ N_("Go Forward"),
+ G_CALLBACK (action_calendar_go_forward_cb) },
+
+ { "calendar-go-today",
+ "go-today",
+ N_("Select _Today"),
+ "<Control>t",
+ N_("Select today"),
+ G_CALLBACK (action_calendar_go_today_cb) },
+
+ { "calendar-jump-to",
+ GTK_STOCK_JUMP_TO,
+ N_("Select _Date"),
+ "<Control>g",
+ N_("Select a specific date"),
+ G_CALLBACK (action_calendar_jump_to_cb) },
+
+ { "calendar-new",
+ "x-office-calendar",
+ N_("_New Calendar"),
+ NULL,
+ N_("Create a new calendar"),
+ G_CALLBACK (action_calendar_new_cb) },
+
+ { "calendar-properties",
+ GTK_STOCK_PROPERTIES,
+ NULL,
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_calendar_properties_cb) },
+
+ { "calendar-purge",
+ NULL,
+ N_("Purg_e"),
+ "<Control>e",
+ N_("Purge old appointments and meetings"),
+ G_CALLBACK (action_calendar_purge_cb) },
+
+ { "calendar-refresh",
+ GTK_STOCK_REFRESH,
+ N_("Re_fresh"),
+ NULL,
+ N_("Refresh the selected calendar"),
+ G_CALLBACK (action_calendar_refresh_cb) },
+
+ { "calendar-rename",
+ NULL,
+ N_("_Rename..."),
+ "F2",
+ N_("Rename the selected calendar"),
+ G_CALLBACK (action_calendar_rename_cb) },
+
+ { "calendar-search-next",
+ GTK_STOCK_GO_FORWARD,
+ N_("Find _next"),
+ "<Control><Shift>n",
+ N_("Find next occurrence of the current search string"),
+ G_CALLBACK (action_calendar_search_next_cb) },
+
+ { "calendar-search-prev",
+ GTK_STOCK_GO_BACK,
+ N_("Find _previous"),
+ "<Control><Shift>p",
+ N_("Find previous occurrence of the current search string"),
+ G_CALLBACK (action_calendar_search_prev_cb) },
+
+ { "calendar-search-stop",
+ GTK_STOCK_STOP,
+ N_("Stop _running search"),
+ NULL,
+ N_("Stop currently running search"),
+ G_CALLBACK (action_calendar_search_stop_cb) },
+
+ { "calendar-select-one",
+ "stock_check-filled",
+ N_("Show _Only This Calendar"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_calendar_select_one_cb) },
+
+ { "event-copy",
+ NULL,
+ N_("Cop_y to Calendar..."),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_event_copy_cb) },
+
+ { "event-delegate",
+ NULL,
+ N_("_Delegate Meeting..."),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_event_delegate_cb) },
+
+ { "event-delete",
+ GTK_STOCK_DELETE,
+ N_("_Delete Appointment"),
+ "<Control>d",
+ N_("Delete selected appointments"),
+ G_CALLBACK (action_event_delete_cb) },
+
+ { "event-delete-occurrence",
+ GTK_STOCK_DELETE,
+ N_("Delete This _Occurrence"),
+ NULL,
+ N_("Delete this occurrence"),
+ G_CALLBACK (action_event_delete_occurrence_cb) },
+
+ { "event-delete-occurrence-all",
+ GTK_STOCK_DELETE,
+ N_("Delete All Occ_urrences"),
+ NULL,
+ N_("Delete all occurrences"),
+ G_CALLBACK (action_event_delete_cb) },
+
+ { "event-all-day-new",
+ "stock_new-24h-appointment",
+ N_("New All Day _Event..."),
+ NULL,
+ N_("Create a new all day event"),
+ G_CALLBACK (action_event_all_day_new_cb) },
+
+ { "event-forward",
+ "mail-forward",
+ N_("_Forward as iCalendar..."),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_event_forward_cb) },
+
+ { "event-meeting-new",
+ "stock_new-meeting",
+ N_("New _Meeting..."),
+ NULL,
+ N_("Create a new meeting"),
+ G_CALLBACK (action_event_meeting_new_cb) },
+
+ { "event-move",
+ NULL,
+ N_("Mo_ve to Calendar..."),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_event_move_cb) },
+
+ { "event-new",
+ "appointment-new",
+ N_("New _Appointment..."),
+ NULL,
+ N_("Create a new appointment"),
+ G_CALLBACK (action_event_new_cb) },
+
+ { "event-occurrence-movable",
+ NULL,
+ N_("Make this Occurrence _Movable"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_event_occurrence_movable_cb) },
+
+ { "event-open",
+ GTK_STOCK_OPEN,
+ N_("_Open Appointment"),
+ "<Control>o",
+ N_("View the current appointment"),
+ G_CALLBACK (action_event_open_cb) },
+
+ { "event-reply",
+ "mail-reply-sender",
+ N_("_Reply"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_event_reply_cb) },
+
+ { "event-reply-all",
+ "mail-reply-all",
+ N_("Reply to _All"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_event_reply_all_cb) },
+
+ { "event-schedule",
+ NULL,
+ N_("_Schedule Meeting..."),
+ NULL,
+ N_("Converts an appointment to a meeting"),
+ G_CALLBACK (action_event_schedule_cb) },
+
+ { "event-schedule-appointment",
+ NULL,
+ N_("Conv_ert to Appointment..."),
+ NULL,
+ N_("Converts a meeting to an appointment"),
+ G_CALLBACK (action_event_schedule_appointment_cb) },
+
+ { "quit-calendar",
+ GTK_STOCK_CLOSE,
+ N_("Quit"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (quit_calendar_cb) },
+
+ /*** Menus ***/
+
+ { "calendar-actions-menu",
+ NULL,
+ N_("_Actions"),
+ NULL,
+ NULL,
+ NULL }
+};
+
+static EPopupActionEntry calendar_popup_entries[] = {
+
+ /* FIXME No equivalent main menu items for the any of the calendar
+ * popup menu items and for many of the event popup menu items.
+ * This is an accessibility issue. */
+
+ { "calendar-popup-copy",
+ NULL,
+ "calendar-copy" },
+
+ { "calendar-popup-delete",
+ N_("_Delete"),
+ "calendar-delete" },
+
+ { "calendar-popup-go-today",
+ NULL,
+ "calendar-go-today" },
+
+ { "calendar-popup-jump-to",
+ NULL,
+ "calendar-jump-to" },
+
+ { "calendar-popup-properties",
+ NULL,
+ "calendar-properties" },
+
+ { "calendar-popup-refresh",
+ NULL,
+ "calendar-refresh" },
+
+ { "calendar-popup-rename",
+ NULL,
+ "calendar-rename" },
+
+ { "calendar-popup-select-one",
+ NULL,
+ "calendar-select-one" },
+
+ { "event-popup-copy",
+ NULL,
+ "event-copy" },
+
+ { "event-popup-delegate",
+ NULL,
+ "event-delegate" },
+
+ { "event-popup-delete",
+ NULL,
+ "event-delete" },
+
+ { "event-popup-delete-occurrence",
+ NULL,
+ "event-delete-occurrence" },
+
+ { "event-popup-delete-occurrence-all",
+ NULL,
+ "event-delete-occurrence-all" },
+
+ { "event-popup-forward",
+ NULL,
+ "event-forward" },
+
+ { "event-popup-move",
+ NULL,
+ "event-move" },
+
+ { "event-popup-occurrence-movable",
+ NULL,
+ "event-occurrence-movable" },
+
+ { "event-popup-open",
+ NULL,
+ "event-open" },
+
+ { "event-popup-reply",
+ NULL,
+ "event-reply" },
+
+ { "event-popup-reply-all",
+ NULL,
+ "event-reply-all" },
+
+ { "event-popup-schedule",
+ NULL,
+ "event-schedule" },
+
+ { "event-popup-schedule-appointment",
+ NULL,
+ "event-schedule-appointment" }
+};
+
+static GtkRadioActionEntry calendar_view_entries[] = {
+
+ /* This action represents the initial calendar view.
+ * It should not be visible in the UI, nor should it be
+ * possible to switch to it from another calendar view. */
+ { "calendar-view-initial",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ BOGUS_INITIAL_VALUE },
+
+ { "calendar-view-day",
+ "view-calendar-day",
+ N_("Day"),
+ NULL,
+ N_("Show one day"),
+ GNOME_CAL_DAY_VIEW },
+
+ { "calendar-view-list",
+ "view-calendar-list",
+ N_("List"),
+ NULL,
+ N_("Show as list"),
+ GNOME_CAL_LIST_VIEW },
+
+ { "calendar-view-month",
+ "view-calendar-month",
+ N_("Month"),
+ NULL,
+ N_("Show one month"),
+ GNOME_CAL_MONTH_VIEW },
+
+ { "calendar-view-week",
+ "view-calendar-week",
+ N_("Week"),
+ NULL,
+ N_("Show one week"),
+ GNOME_CAL_WEEK_VIEW },
+
+ { "calendar-view-workweek",
+ "view-calendar-workweek",
+ N_("Work Week"),
+ NULL,
+ N_("Show one work week"),
+ GNOME_CAL_WORK_WEEK_VIEW }
+};
+
+static GtkRadioActionEntry calendar_filter_entries[] = {
+
+ { "calendar-filter-active-appointments",
+ NULL,
+ N_("Active Appointments"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ CALENDAR_FILTER_ACTIVE_APPOINTMENTS },
+
+ { "calendar-filter-any-category",
+ NULL,
+ N_("Any Category"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ CALENDAR_FILTER_ANY_CATEGORY },
+
+ { "calendar-filter-next-7-days-appointments",
+ NULL,
+ N_("Next 7 Days' Appointments"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ CALENDAR_FILTER_NEXT_7_DAYS_APPOINTMENTS },
+
+ { "calendar-filter-occurs-less-than-5-times",
+ NULL,
+ N_("Occurs Less Than 5 Times"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ CALENDAR_FILTER_OCCURS_LESS_THAN_5_TIMES },
+
+ { "calendar-filter-unmatched",
+ NULL,
+ N_("Unmatched"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ CALENDAR_FILTER_UNMATCHED }
+};
+
+static GtkRadioActionEntry calendar_search_entries[] = {
+
+ { "calendar-search-advanced-hidden",
+ NULL,
+ N_("Advanced Search"),
+ NULL,
+ NULL,
+ CALENDAR_SEARCH_ADVANCED },
+
+ { "calendar-search-any-field-contains",
+ NULL,
+ N_("Any field contains"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ CALENDAR_SEARCH_ANY_FIELD_CONTAINS },
+
+ { "calendar-search-description-contains",
+ NULL,
+ N_("Description contains"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ CALENDAR_SEARCH_DESCRIPTION_CONTAINS },
+
+ { "calendar-search-summary-contains",
+ NULL,
+ N_("Summary contains"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ CALENDAR_SEARCH_SUMMARY_CONTAINS }
+};
+
+static GtkActionEntry lockdown_printing_entries[] = {
+
+ { "calendar-print",
+ GTK_STOCK_PRINT,
+ NULL,
+ "<Control>p",
+ N_("Print this calendar"),
+ G_CALLBACK (action_calendar_print_cb) },
+
+ { "calendar-print-preview",
+ GTK_STOCK_PRINT_PREVIEW,
+ NULL,
+ NULL,
+ N_("Preview the calendar to be printed"),
+ G_CALLBACK (action_calendar_print_preview_cb) },
+
+ { "event-print",
+ GTK_STOCK_PRINT,
+ NULL,
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_event_print_cb) }
+};
+
+static EPopupActionEntry lockdown_printing_popup_entries[] = {
+
+ { "event-popup-print",
+ NULL,
+ "event-print" }
+};
+
+static GtkActionEntry lockdown_save_to_disk_entries[] = {
+
+ { "event-save-as",
+ GTK_STOCK_SAVE_AS,
+ N_("_Save as iCalendar..."),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_event_save_as_cb) },
+};
+
+static EPopupActionEntry lockdown_save_to_disk_popup_entries[] = {
+
+ { "event-popup-save-as",
+ NULL,
+ "event-save-as" },
+};
+
+void
+e_cal_shell_view_actions_init (ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellSearchbar *searchbar;
+ GtkActionGroup *action_group;
+ GtkAction *action;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ searchbar = e_cal_shell_content_get_searchbar (cal_shell_content);
+
+ /* Calendar Actions */
+ action_group = ACTION_GROUP (CALENDAR);
+ gtk_action_group_add_actions (
+ action_group, calendar_entries,
+ G_N_ELEMENTS (calendar_entries), cal_shell_view);
+ e_action_group_add_popup_actions (
+ action_group, calendar_popup_entries,
+ G_N_ELEMENTS (calendar_popup_entries));
+ gtk_action_group_add_radio_actions (
+ action_group, calendar_view_entries,
+ G_N_ELEMENTS (calendar_view_entries), BOGUS_INITIAL_VALUE,
+ G_CALLBACK (action_calendar_view_cb), cal_shell_view);
+ gtk_action_group_add_radio_actions (
+ action_group, calendar_search_entries,
+ G_N_ELEMENTS (calendar_search_entries),
+ -1, NULL, NULL);
+
+ /* Advanced Search Action */
+ action = ACTION (CALENDAR_SEARCH_ADVANCED_HIDDEN);
+ gtk_action_set_visible (action, FALSE);
+ if (searchbar)
+ e_shell_searchbar_set_search_option (
+ searchbar, GTK_RADIO_ACTION (action));
+
+ /* Lockdown Printing Actions */
+ action_group = ACTION_GROUP (LOCKDOWN_PRINTING);
+ gtk_action_group_add_actions (
+ action_group, lockdown_printing_entries,
+ G_N_ELEMENTS (lockdown_printing_entries), cal_shell_view);
+ e_action_group_add_popup_actions (
+ action_group, lockdown_printing_popup_entries,
+ G_N_ELEMENTS (lockdown_printing_popup_entries));
+
+ /* Lockdown Save-to-Disk Actions */
+ action_group = ACTION_GROUP (LOCKDOWN_SAVE_TO_DISK);
+ gtk_action_group_add_actions (
+ action_group, lockdown_save_to_disk_entries,
+ G_N_ELEMENTS (lockdown_save_to_disk_entries), cal_shell_view);
+ e_action_group_add_popup_actions (
+ action_group, lockdown_save_to_disk_popup_entries,
+ G_N_ELEMENTS (lockdown_save_to_disk_popup_entries));
+
+ /* Fine tuning. */
+
+ action = ACTION (CALENDAR_GO_TODAY);
+ gtk_action_set_short_label (action, _("Today"));
+
+ action = ACTION (CALENDAR_JUMP_TO);
+ gtk_action_set_short_label (action, _("Go To"));
+
+ action = ACTION (CALENDAR_VIEW_DAY);
+ gtk_action_set_is_important (action, TRUE);
+
+ action = ACTION (CALENDAR_VIEW_LIST);
+ gtk_action_set_is_important (action, TRUE);
+
+ action = ACTION (CALENDAR_VIEW_MONTH);
+ gtk_action_set_is_important (action, TRUE);
+
+ action = ACTION (CALENDAR_VIEW_WEEK);
+ gtk_action_set_is_important (action, TRUE);
+
+ action = ACTION (CALENDAR_VIEW_WORKWEEK);
+ gtk_action_set_is_important (action, TRUE);
+
+ /* Initialize the memo and task pad actions. */
+ e_cal_shell_view_memopad_actions_init (cal_shell_view);
+ e_cal_shell_view_taskpad_actions_init (cal_shell_view);
+}
+
+void
+e_cal_shell_view_update_search_filter (ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellSearchbar *searchbar;
+ EActionComboBox *combo_box;
+ GtkActionGroup *action_group;
+ GtkRadioAction *radio_action;
+ GList *list, *iter;
+ GSList *group;
+ gint ii;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ action_group = ACTION_GROUP (CALENDAR_FILTER);
+ e_action_group_remove_all_actions (action_group);
+
+ /* Add the standard filter actions. No callback is needed
+ * because changes in the EActionComboBox are detected and
+ * handled by EShellSearchbar. */
+ gtk_action_group_add_radio_actions (
+ action_group, calendar_filter_entries,
+ G_N_ELEMENTS (calendar_filter_entries),
+ CALENDAR_FILTER_ANY_CATEGORY, NULL, NULL);
+
+ /* Retrieve the radio group from an action we just added. */
+ list = gtk_action_group_list_actions (action_group);
+ radio_action = GTK_RADIO_ACTION (list->data);
+ group = gtk_radio_action_get_group (radio_action);
+ g_list_free (list);
+
+ /* Build the category actions. */
+
+ list = e_util_get_searchable_categories ();
+ for (iter = list, ii = 0; iter != NULL; iter = iter->next, ii++) {
+ const gchar *category_name = iter->data;
+ const gchar *filename;
+ GtkAction *action;
+ gchar *action_name;
+
+ action_name = g_strdup_printf (
+ "calendar-filter-category-%d", ii);
+ radio_action = gtk_radio_action_new (
+ action_name, category_name, NULL, NULL, ii);
+ g_free (action_name);
+
+ /* Convert the category icon file to a themed icon name. */
+ filename = e_categories_get_icon_file_for (category_name);
+ if (filename != NULL && *filename != '\0') {
+ gchar *basename;
+ gchar *cp;
+
+ basename = g_path_get_basename (filename);
+
+ /* Lose the file extension. */
+ if ((cp = strrchr (basename, '.')) != NULL)
+ *cp = '\0';
+
+ g_object_set (
+ radio_action, "icon-name", basename, NULL);
+
+ g_free (basename);
+ }
+
+ gtk_radio_action_set_group (radio_action, group);
+ group = gtk_radio_action_get_group (radio_action);
+
+ /* The action group takes ownership of the action. */
+ action = GTK_ACTION (radio_action);
+ gtk_action_group_add_action (action_group, action);
+ g_object_unref (radio_action);
+ }
+ g_list_free (list);
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ searchbar = e_cal_shell_content_get_searchbar (cal_shell_content);
+ if (searchbar) {
+ combo_box = e_shell_searchbar_get_filter_combo_box (searchbar);
+
+ e_shell_view_block_execute_search (shell_view);
+
+ /* Use any action in the group; doesn't matter which. */
+ e_action_combo_box_set_action (combo_box, radio_action);
+
+ ii = CALENDAR_FILTER_UNMATCHED;
+ e_action_combo_box_add_separator_after (combo_box, ii);
+
+ ii = CALENDAR_FILTER_OCCURS_LESS_THAN_5_TIMES;
+ e_action_combo_box_add_separator_after (combo_box, ii);
+
+ e_shell_view_unblock_execute_search (shell_view);
+ }
+}
diff --git a/modules/calendar/e-cal-shell-view-actions.h b/modules/calendar/e-cal-shell-view-actions.h
new file mode 100644
index 0000000000..079f0ab546
--- /dev/null
+++ b/modules/calendar/e-cal-shell-view-actions.h
@@ -0,0 +1,163 @@
+/*
+ * e-cal-shell-view-actions.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_CAL_SHELL_VIEW_ACTIONS_H
+#define E_CAL_SHELL_VIEW_ACTIONS_H
+
+#include <shell/e-shell-window-actions.h>
+
+/* Calendar Actions */
+#define E_SHELL_WINDOW_ACTION_CALENDAR_COPY(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-copy")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_DELETE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-delete")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_GO_BACK(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-go-back")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_GO_FORWARD(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-go-forward")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_GO_TODAY(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-go-today")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_JUMP_TO(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-jump-to")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_NEW(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-new")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_PRINT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-print")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_PRINT_PREVIEW(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-print-preview")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_PROPERTIES(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-properties")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_PURGE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-purge")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_REFRESH(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-refresh")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_RENAME(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-rename")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_SEARCH_PREV(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-search-prev")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_SEARCH_NEXT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-search-next")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_SEARCH_STOP(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-search-stop")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_SELECT_ONE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-select-one")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_VIEW_DAY(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-view-day")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_VIEW_LIST(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-view-list")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_VIEW_MONTH(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-view-month")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_VIEW_WEEK(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-view-week")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_VIEW_WORKWEEK(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-view-workweek")
+
+/* Event Actions */
+#define E_SHELL_WINDOW_ACTION_EVENT_DELEGATE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "event-delegate")
+#define E_SHELL_WINDOW_ACTION_EVENT_DELETE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "event-delete")
+#define E_SHELL_WINDOW_ACTION_EVENT_DELETE_OCCURRENCE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "event-delete-occurrence")
+#define E_SHELL_WINDOW_ACTION_EVENT_DELETE_OCCURRENCE_ALL(window) \
+ E_SHELL_WINDOW_ACTION ((window), "event-delete-occurrence-all")
+#define E_SHELL_WINDOW_ACTION_EVENT_FORWARD(window) \
+ E_SHELL_WINDOW_ACTION ((window), "event-forward")
+#define E_SHELL_WINDOW_ACTION_EVENT_OPEN(window) \
+ E_SHELL_WINDOW_ACTION ((window), "event-open")
+#define E_SHELL_WINDOW_ACTION_EVENT_PRINT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "event-print")
+#define E_SHELL_WINDOW_ACTION_EVENT_SAVE_AS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "event-save-as")
+#define E_SHELL_WINDOW_ACTION_EVENT_SCHEDULE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "event-schedule")
+#define E_SHELL_WINDOW_ACTION_EVENT_SCHEDULE_APPOINTMENT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "event-schedule-appointment")
+#define E_SHELL_WINDOW_ACTION_EVENT_REPLY(window) \
+ E_SHELL_WINDOW_ACTION ((window), "event-reply")
+#define E_SHELL_WINDOW_ACTION_EVENT_REPLY_ALL(window) \
+ E_SHELL_WINDOW_ACTION ((window), "event-reply-all")
+#define E_SHELL_WINDOW_ACTION_EVENT_OCCURRENCE_MOVABLE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "event-occurrence-movable")
+#define E_SHELL_WINDOW_ACTION_EVENT_MEETING_NEW(window) \
+ E_SHELL_WINDOW_ACTION ((window), "event-meeting-new")
+
+/* Memo Pad Actions */
+#define E_SHELL_WINDOW_ACTION_CALENDAR_MEMOPAD_FORWARD(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-memopad-forward")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_MEMOPAD_NEW(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-memopad-new")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_MEMOPAD_OPEN(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-memopad-open")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_MEMOPAD_OPEN_URL(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-memopad-open-url")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_MEMOPAD_PRINT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-memopad-print")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_MEMOPAD_SAVE_AS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-memopad-save-as")
+
+/* Task Pad Actions */
+#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_ASSIGN(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-assign")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_FORWARD(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-forward")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_MARK_COMPLETE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-mark-complete")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_MARK_INCOMPLETE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-mark-incomplete")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_NEW(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-new")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_OPEN(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-open")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_OPEN_URL(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-open-url")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_PRINT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-print")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_SAVE_AS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-save-as")
+
+/* Calendar Query Actions */
+#define E_SHELL_WINDOW_ACTION_CALENDAR_FILTER_ACTIVE_APPOINTMENTS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-filter-active-appointments")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_FILTER_ANY_CATEGORY(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-filter-any-category")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_FILTER_NEXT_7_DAYS_APPOINTMENTS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-filter-next-7-days-appointments")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_FILTER_OCCURS_LESS_THAN_5_TIMES(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-filter-occurs-less-than-5-times")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_FILTER_UNMATCHED(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-filter-unmatched")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_SEARCH_ADVANCED_HIDDEN(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-search-advanced-hidden")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_SEARCH_ANY_FIELD_CONTAINS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-search-any-field-contains")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_SEARCH_DESCRIPTION_CONTAINS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-search-description-contains")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_SEARCH_SUMMARY_CONTAINS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-search-summary-contains")
+
+/* Action Groups */
+#define E_SHELL_WINDOW_ACTION_GROUP_CALENDAR(window) \
+ E_SHELL_WINDOW_ACTION_GROUP ((window), "calendar")
+#define E_SHELL_WINDOW_ACTION_GROUP_CALENDAR_FILTER(window) \
+ E_SHELL_WINDOW_ACTION_GROUP ((window), "calendar-filter")
+
+#endif /* E_CAL_SHELL_VIEW_ACTIONS_H */
diff --git a/modules/calendar/e-cal-shell-view-memopad.c b/modules/calendar/e-cal-shell-view-memopad.c
new file mode 100644
index 0000000000..f8a0e2da0a
--- /dev/null
+++ b/modules/calendar/e-cal-shell-view-memopad.c
@@ -0,0 +1,482 @@
+/*
+ * e-cal-shell-view-memopad.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-cal-shell-view-private.h"
+
+/* Much of this file is based on e-memo-shell-view-actions.c. */
+
+static void
+action_calendar_memopad_forward_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ESourceRegistry *registry;
+ EMemoTable *memo_table;
+ ECalModelComponent *comp_data;
+ ECalComponent *comp;
+ icalcomponent *clone;
+ GSList *list;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ registry = e_shell_get_registry (shell);
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
+
+ list = e_memo_table_get_selected (memo_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only forward the first selected memo. */
+ comp = e_cal_component_new ();
+ clone = icalcomponent_new_clone (comp_data->icalcomp);
+ e_cal_component_set_icalcomponent (comp, clone);
+
+ itip_send_comp (
+ registry, E_CAL_COMPONENT_METHOD_PUBLISH, comp,
+ comp_data->client, NULL, NULL, NULL, TRUE, FALSE);
+
+ g_object_unref (comp);
+}
+
+static void
+action_calendar_memopad_new_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ECalShellContent *cal_shell_content;
+ EMemoTable *memo_table;
+ ECalModelComponent *comp_data;
+ ECalClient *client;
+ ECalComponent *comp;
+ CompEditor *editor;
+ GSList *list;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
+
+ list = e_memo_table_get_selected (memo_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ client = comp_data->client;
+ comp = cal_comp_memo_new_with_defaults (client);
+ cal_comp_update_time_by_active_window (comp, shell);
+ editor = memo_editor_new (client, shell, COMP_EDITOR_NEW_ITEM);
+ comp_editor_edit_comp (editor, comp);
+
+ gtk_window_present (GTK_WINDOW (editor));
+
+ g_object_unref (comp);
+}
+
+static void
+action_calendar_memopad_open_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ EMemoTable *memo_table;
+ ECalModelComponent *comp_data;
+ GSList *list;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
+
+ list = e_memo_table_get_selected (memo_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only open the first selected memo. */
+ e_cal_shell_view_memopad_open_memo (cal_shell_view, comp_data);
+}
+
+static void
+action_calendar_memopad_open_url_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ECalShellContent *cal_shell_content;
+ EMemoTable *memo_table;
+ ECalModelComponent *comp_data;
+ icalproperty *prop;
+ const gchar *uri;
+ GSList *list;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
+
+ list = e_memo_table_get_selected (memo_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only open the URI of the first selected memo. */
+ prop = icalcomponent_get_first_property (
+ comp_data->icalcomp, ICAL_URL_PROPERTY);
+ g_return_if_fail (prop != NULL);
+
+ uri = icalproperty_get_url (prop);
+ e_show_uri (GTK_WINDOW (shell_window), uri);
+}
+
+static void
+action_calendar_memopad_print_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ EMemoTable *memo_table;
+ ECalModelComponent *comp_data;
+ ECalComponent *comp;
+ ECalModel *model;
+ icalcomponent *clone;
+ GSList *list;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
+ model = e_memo_table_get_model (memo_table);
+
+ list = e_memo_table_get_selected (memo_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only print the first selected memo. */
+ comp = e_cal_component_new ();
+ clone = icalcomponent_new_clone (comp_data->icalcomp);
+ e_cal_component_set_icalcomponent (comp, clone);
+
+ print_comp (
+ comp, comp_data->client,
+ e_cal_model_get_timezone (model),
+ e_cal_model_get_use_24_hour_format (model),
+ GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG);
+
+ g_object_unref (comp);
+}
+
+static void
+action_calendar_memopad_save_as_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellBackend *shell_backend;
+ ECalShellContent *cal_shell_content;
+ EMemoTable *memo_table;
+ ECalModelComponent *comp_data;
+ EActivity *activity;
+ GSList *list;
+ GFile *file;
+ gchar *string;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
+
+ list = e_memo_table_get_selected (memo_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* Translators: Default filename part saving a memo to a file when
+ * no summary is filed, the '.ics' extension is concatenated to it. */
+ string = icalcomp_suggest_filename (comp_data->icalcomp, _("memo"));
+ file = e_shell_run_save_dialog (
+ shell, _("Save as iCalendar"), string,
+ "*.ics:text/calendar", NULL, NULL);
+ g_free (string);
+ if (file == NULL)
+ return;
+
+ /* XXX We only save the first selected memo. */
+ string = e_cal_client_get_component_as_string (
+ comp_data->client, comp_data->icalcomp);
+ if (string == NULL) {
+ g_warning ("Could not convert memo to a string.");
+ g_object_unref (file);
+ return;
+ }
+
+ /* XXX No callback means errors are discarded. */
+ activity = e_file_replace_contents_async (
+ file, string, strlen (string), NULL, FALSE,
+ G_FILE_CREATE_NONE, (GAsyncReadyCallback) NULL, NULL);
+ e_shell_backend_add_activity (shell_backend, activity);
+
+ /* Free the string when the activity is finalized. */
+ g_object_set_data_full (
+ G_OBJECT (activity),
+ "file-content", string,
+ (GDestroyNotify) g_free);
+
+ g_object_unref (file);
+}
+
+static GtkActionEntry calendar_memopad_entries[] = {
+
+ { "calendar-memopad-forward",
+ "mail-forward",
+ N_("_Forward as iCalendar..."),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_calendar_memopad_forward_cb) },
+
+ { "calendar-memopad-new",
+ "stock_insert-note",
+ N_("New _Memo"),
+ NULL,
+ N_("Create a new memo"),
+ G_CALLBACK (action_calendar_memopad_new_cb) },
+
+ { "calendar-memopad-open",
+ GTK_STOCK_OPEN,
+ N_("_Open Memo"),
+ NULL,
+ N_("View the selected memo"),
+ G_CALLBACK (action_calendar_memopad_open_cb) },
+
+ { "calendar-memopad-open-url",
+ "applications-internet",
+ N_("Open _Web Page"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_calendar_memopad_open_url_cb) },
+};
+
+static GtkActionEntry lockdown_printing_entries[] = {
+
+ { "calendar-memopad-print",
+ GTK_STOCK_PRINT,
+ NULL,
+ NULL,
+ N_("Print the selected memo"),
+ G_CALLBACK (action_calendar_memopad_print_cb) }
+};
+
+static GtkActionEntry lockdown_save_to_disk_entries[] = {
+
+ { "calendar-memopad-save-as",
+ GTK_STOCK_SAVE_AS,
+ N_("_Save as iCalendar..."),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_calendar_memopad_save_as_cb) }
+};
+
+void
+e_cal_shell_view_memopad_actions_init (ECalShellView *cal_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ GtkActionGroup *action_group;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ /* Calendar Actions */
+ action_group = ACTION_GROUP (CALENDAR);
+ gtk_action_group_add_actions (
+ action_group, calendar_memopad_entries,
+ G_N_ELEMENTS (calendar_memopad_entries), cal_shell_view);
+
+ /* Lockdown Printing Actions */
+ action_group = ACTION_GROUP (LOCKDOWN_PRINTING);
+ gtk_action_group_add_actions (
+ action_group, lockdown_printing_entries,
+ G_N_ELEMENTS (lockdown_printing_entries), cal_shell_view);
+
+ /* Lockdown Save-to-Disk Actions */
+ action_group = ACTION_GROUP (LOCKDOWN_SAVE_TO_DISK);
+ gtk_action_group_add_actions (
+ action_group, lockdown_save_to_disk_entries,
+ G_N_ELEMENTS (lockdown_save_to_disk_entries), cal_shell_view);
+}
+
+void
+e_cal_shell_view_memopad_actions_update (ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ EMemoTable *memo_table;
+ GtkAction *action;
+ GSList *list, *iter;
+ gboolean editable = TRUE;
+ gboolean has_url = FALSE;
+ gboolean sensitive;
+ gint n_selected;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
+
+ n_selected = e_table_selected_count (E_TABLE (memo_table));
+
+ list = e_memo_table_get_selected (memo_table);
+ for (iter = list; iter != NULL; iter = iter->next) {
+ ECalModelComponent *comp_data = iter->data;
+ icalproperty *prop;
+ gboolean read_only;
+
+ read_only = e_client_is_readonly (E_CLIENT (comp_data->client));
+ editable &= !read_only;
+
+ prop = icalcomponent_get_first_property (
+ comp_data->icalcomp, ICAL_URL_PROPERTY);
+ has_url |= (prop != NULL);
+ }
+ g_slist_free (list);
+
+ action = ACTION (CALENDAR_MEMOPAD_FORWARD);
+ sensitive = (n_selected == 1);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_MEMOPAD_OPEN);
+ sensitive = (n_selected == 1);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_MEMOPAD_OPEN_URL);
+ sensitive = (n_selected == 1) && has_url;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_MEMOPAD_PRINT);
+ sensitive = (n_selected == 1);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_MEMOPAD_SAVE_AS);
+ sensitive = (n_selected == 1);
+ gtk_action_set_sensitive (action, sensitive);
+}
+
+void
+e_cal_shell_view_memopad_open_memo (ECalShellView *cal_shell_view,
+ ECalModelComponent *comp_data)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ESourceRegistry *registry;
+ CompEditor *editor;
+ CompEditorFlags flags = 0;
+ ECalComponent *comp;
+ icalcomponent *clone;
+ const gchar *uid;
+
+ g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
+ g_return_if_fail (E_IS_CAL_MODEL_COMPONENT (comp_data));
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ registry = e_shell_get_registry (shell);
+
+ uid = icalcomponent_get_uid (comp_data->icalcomp);
+ editor = comp_editor_find_instance (uid);
+
+ if (editor != NULL)
+ goto exit;
+
+ comp = e_cal_component_new ();
+ clone = icalcomponent_new_clone (comp_data->icalcomp);
+ e_cal_component_set_icalcomponent (comp, clone);
+
+ if (e_cal_component_has_organizer (comp))
+ flags |= COMP_EDITOR_IS_SHARED;
+
+ if (itip_organizer_is_user (registry, comp, comp_data->client))
+ flags |= COMP_EDITOR_USER_ORG;
+
+ editor = memo_editor_new (comp_data->client, shell, flags);
+ comp_editor_edit_comp (editor, comp);
+
+ g_object_unref (comp);
+
+exit:
+ gtk_window_present (GTK_WINDOW (editor));
+}
+
+void
+e_cal_shell_view_memopad_set_status_message (ECalShellView *cal_shell_view,
+ const gchar *status_message,
+ gdouble percent)
+{
+ EActivity *activity;
+ EShellView *shell_view;
+ EShellBackend *shell_backend;
+
+ g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+
+ activity = cal_shell_view->priv->memopad_activity;
+
+ if (status_message == NULL || *status_message == '\0') {
+ if (activity != NULL) {
+ e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
+ g_object_unref (activity);
+ activity = NULL;
+ }
+
+ } else if (activity == NULL) {
+ activity = e_activity_new ();
+ e_activity_set_percent (activity, percent);
+ e_activity_set_text (activity, status_message);
+ e_shell_backend_add_activity (shell_backend, activity);
+
+ } else {
+ e_activity_set_percent (activity, percent);
+ e_activity_set_text (activity, status_message);
+ }
+
+ cal_shell_view->priv->memopad_activity = activity;
+}
diff --git a/modules/calendar/e-cal-shell-view-private.c b/modules/calendar/e-cal-shell-view-private.c
new file mode 100644
index 0000000000..6b93828f65
--- /dev/null
+++ b/modules/calendar/e-cal-shell-view-private.c
@@ -0,0 +1,1787 @@
+/*
+ * e-cal-shell-view-private.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-util/e-util-private.h"
+
+#include "e-cal-shell-view-private.h"
+
+#define CHECK_NB 5
+
+/* be compatible with older e-d-s for MeeGo */
+#ifndef ETC_TIMEZONE
+# define ETC_TIMEZONE "/etc/timezone"
+# define ETC_TIMEZONE_MAJ "/etc/TIMEZONE"
+# define ETC_RC_CONF "/etc/rc.conf"
+# define ETC_SYSCONFIG_CLOCK "/etc/sysconfig/clock"
+# define ETC_CONF_D_CLOCK "/etc/conf.d/clock"
+# define ETC_LOCALTIME "/etc/localtime"
+#endif
+
+static const gchar * files_to_check[CHECK_NB] = {
+ ETC_TIMEZONE,
+ ETC_TIMEZONE_MAJ,
+ ETC_SYSCONFIG_CLOCK,
+ ETC_CONF_D_CLOCK,
+ ETC_LOCALTIME
+};
+
+static struct tm
+cal_shell_view_get_current_time (ECalendarItem *calitem,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ struct icaltimetype tt;
+ icaltimezone *timezone;
+ ECalModel *model;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ model = e_cal_shell_content_get_model (cal_shell_content);
+ timezone = e_cal_model_get_timezone (model);
+
+ tt = icaltime_from_timet_with_zone (time (NULL), FALSE, timezone);
+
+ return icaltimetype_to_tm (&tt);
+}
+
+static void
+cal_shell_view_date_navigator_date_range_changed_cb (ECalShellView *cal_shell_view,
+ ECalendarItem *calitem)
+{
+ ECalShellContent *cal_shell_content;
+ GnomeCalendar *calendar;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+
+ gnome_calendar_update_query (calendar);
+}
+
+static void
+cal_shell_view_date_navigator_selection_changed_cb (ECalShellView *cal_shell_view,
+ ECalendarItem *calitem)
+{
+ ECalShellContent *cal_shell_content;
+ GnomeCalendarViewType switch_to;
+ GnomeCalendarViewType view_type;
+ GnomeCalendar *calendar;
+ ECalModel *model;
+ GDate start_date, end_date;
+ GDate new_start_date, new_end_date;
+ icaltimetype tt;
+ icaltimezone *timezone;
+ time_t start, end, new_time;
+ gboolean starts_on_week_start_day;
+ gint new_days_shown, old_days_shown;
+ GDateWeekday week_start_day;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+
+ model = gnome_calendar_get_model (calendar);
+ view_type = gnome_calendar_get_view (calendar);
+ switch_to = view_type;
+
+ timezone = e_cal_model_get_timezone (model);
+ week_start_day = e_cal_model_get_week_start_day (model);
+ e_cal_model_get_time_range (model, &start, &end);
+
+ time_to_gdate_with_zone (&start_date, start, timezone);
+ time_to_gdate_with_zone (&end_date, end, timezone);
+
+ if (view_type == GNOME_CAL_MONTH_VIEW) {
+ EWeekView *week_view;
+ ECalendarView *calendar_view;
+ gboolean multi_week_view;
+ gboolean compress_weekend;
+
+ calendar_view = gnome_calendar_get_calendar_view (
+ calendar, GNOME_CAL_MONTH_VIEW);
+
+ week_view = E_WEEK_VIEW (calendar_view);
+ multi_week_view = e_week_view_get_multi_week_view (week_view);
+ compress_weekend = e_week_view_get_compress_weekend (week_view);
+
+ if (week_start_day == G_DATE_SUNDAY &&
+ (!multi_week_view || compress_weekend))
+ g_date_add_days (&start_date, 1);
+ }
+
+ g_date_subtract_days (&end_date, 1);
+
+ e_calendar_item_get_selection (
+ calitem, &new_start_date, &new_end_date);
+
+ /* If the selection hasn't changed, just return. */
+ if (g_date_compare (&start_date, &new_start_date) == 0 &&
+ g_date_compare (&end_date, &new_end_date) == 0)
+ return;
+
+ old_days_shown =
+ g_date_get_julian (&end_date) -
+ g_date_get_julian (&start_date) + 1;
+ new_days_shown =
+ g_date_get_julian (&new_end_date) -
+ g_date_get_julian (&new_start_date) + 1;
+
+ /* If a complete week is selected we show the week view.
+ * Note that if weekends are compressed and the week start
+ * day is set to Sunday, we don't actually show complete
+ * weeks in the week view, so this may need tweaking. */
+ starts_on_week_start_day =
+ (g_date_get_weekday (&new_start_date) == week_start_day);
+
+ /* Update selection to be in the new time range. */
+ tt = icaltime_null_time ();
+ tt.year = g_date_get_year (&new_start_date);
+ tt.month = g_date_get_month (&new_start_date);
+ tt.day = g_date_get_day (&new_start_date);
+ new_time = icaltime_as_timet_with_zone (tt, timezone);
+
+ /* Switch views as appropriate, and change the number of
+ * days or weeks shown. */
+ if (view_type == GNOME_CAL_WORK_WEEK_VIEW && old_days_shown == new_days_shown) {
+ /* keep the work week view when has same days shown */
+ switch_to = GNOME_CAL_WORK_WEEK_VIEW;
+ } else if (new_days_shown > 9) {
+ if (view_type != GNOME_CAL_LIST_VIEW) {
+ ECalendarView *calendar_view;
+
+ calendar_view = gnome_calendar_get_calendar_view (
+ calendar, GNOME_CAL_MONTH_VIEW);
+ e_week_view_set_weeks_shown (
+ E_WEEK_VIEW (calendar_view),
+ (new_days_shown + 6) / 7);
+ switch_to = GNOME_CAL_MONTH_VIEW;
+ }
+ } else if (new_days_shown == 7 && starts_on_week_start_day) {
+ switch_to = GNOME_CAL_WEEK_VIEW;
+ } else if (new_days_shown == 1 && (view_type == GNOME_CAL_WORK_WEEK_VIEW || view_type == GNOME_CAL_WEEK_VIEW)) {
+ /* preserve week views when clicking on one day */
+ switch_to = view_type;
+ } else {
+ ECalendarView *calendar_view;
+
+ calendar_view = gnome_calendar_get_calendar_view (
+ calendar, GNOME_CAL_DAY_VIEW);
+ e_day_view_set_days_shown (
+ E_DAY_VIEW (calendar_view), new_days_shown);
+
+ if (new_days_shown != 5 || !starts_on_week_start_day)
+ switch_to = GNOME_CAL_DAY_VIEW;
+
+ else if (view_type != GNOME_CAL_WORK_WEEK_VIEW)
+ switch_to = GNOME_CAL_DAY_VIEW;
+ }
+
+ /* Make the views display things properly. */
+ gnome_calendar_update_view_times (calendar, new_time);
+ gnome_calendar_set_view (calendar, switch_to);
+ gnome_calendar_set_range_selected (calendar, TRUE);
+
+ gnome_calendar_notify_dates_shown_changed (calendar);
+
+ g_signal_handlers_block_by_func (
+ calitem,
+ cal_shell_view_date_navigator_selection_changed_cb, cal_shell_view);
+
+ /* make sure the selected days in the calendar matches shown days */
+ e_cal_model_get_time_range (model, &start, &end);
+
+ time_to_gdate_with_zone (&start_date, start, timezone);
+ time_to_gdate_with_zone (&end_date, end, timezone);
+
+ g_date_subtract_days (&end_date, 1);
+
+ e_calendar_item_set_selection (calitem, &start_date, &end_date);
+
+ g_signal_handlers_unblock_by_func (
+ calitem,
+ cal_shell_view_date_navigator_selection_changed_cb, cal_shell_view);
+}
+
+static gboolean
+cal_shell_view_date_navigator_scroll_event_cb (ECalShellView *cal_shell_view,
+ GdkEventScroll *event,
+ ECalendar *date_navigator)
+{
+ ECalendarItem *calitem;
+ GDate start_date, end_date;
+ GdkScrollDirection direction;
+
+ calitem = date_navigator->calitem;
+ if (!e_calendar_item_get_selection (calitem, &start_date, &end_date))
+ return FALSE;
+
+ direction = event->direction;
+
+ if (direction == GDK_SCROLL_SMOOTH) {
+ static gdouble total_delta_y = 0.0;
+
+ total_delta_y += event->delta_y;
+
+ if (total_delta_y >= 1.0) {
+ total_delta_y = 0.0;
+ direction = GDK_SCROLL_DOWN;
+ } else if (total_delta_y <= -1.0) {
+ total_delta_y = 0.0;
+ direction = GDK_SCROLL_UP;
+ } else {
+ return FALSE;
+ }
+ }
+
+ switch (direction) {
+ case GDK_SCROLL_UP:
+ g_date_subtract_months (&start_date, 1);
+ g_date_subtract_months (&end_date, 1);
+ break;
+
+ case GDK_SCROLL_DOWN:
+ g_date_add_months (&start_date, 1);
+ g_date_add_months (&end_date, 1);
+ break;
+
+ default:
+ g_return_val_if_reached (FALSE);
+ }
+
+ /* XXX Does ECalendarItem emit a signal for this? If so, maybe
+ * we could move this handler into ECalShellSidebar. */
+ e_calendar_item_set_selection (calitem, &start_date, &end_date);
+
+ cal_shell_view_date_navigator_selection_changed_cb (
+ cal_shell_view, calitem);
+
+ return TRUE;
+}
+
+static void
+cal_shell_view_popup_event_cb (EShellView *shell_view,
+ GdkEvent *button_event)
+{
+ GList *list;
+ GnomeCalendar *calendar;
+ GnomeCalendarViewType view_type;
+ ECalendarView *view;
+ ECalShellViewPrivate *priv;
+ const gchar *widget_path;
+ gint n_selected;
+
+ priv = E_CAL_SHELL_VIEW_GET_PRIVATE (shell_view);
+
+ calendar = e_cal_shell_content_get_calendar (priv->cal_shell_content);
+
+ view_type = gnome_calendar_get_view (calendar);
+ view = gnome_calendar_get_calendar_view (calendar, view_type);
+
+ list = e_calendar_view_get_selected_events (view);
+ n_selected = g_list_length (list);
+ g_list_free (list);
+
+ if (n_selected <= 0)
+ widget_path = "/calendar-empty-popup";
+ else
+ widget_path = "/calendar-event-popup";
+
+ e_shell_view_show_popup_menu (shell_view, widget_path, button_event);
+}
+
+static gboolean
+cal_shell_view_selector_popup_event_cb (EShellView *shell_view,
+ ESource *primary_source,
+ GdkEvent *button_event)
+{
+ const gchar *widget_path;
+
+ widget_path = "/calendar-popup";
+ e_shell_view_show_popup_menu (shell_view, widget_path, button_event);
+
+ return TRUE;
+}
+
+static void
+cal_shell_view_selector_client_added_cb (ECalShellView *cal_shell_view,
+ ECalClient *client)
+{
+ ECalShellContent *cal_shell_content;
+ GnomeCalendar *calendar;
+ ECalModel *model;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ model = gnome_calendar_get_model (calendar);
+
+ if (e_cal_model_add_client (model, client))
+ gnome_calendar_update_query (calendar);
+}
+
+static void
+cal_shell_view_selector_client_removed_cb (ECalShellView *cal_shell_view,
+ ECalClient *client)
+{
+ ECalShellContent *cal_shell_content;
+ GnomeCalendar *calendar;
+ ECalModel *model;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ model = gnome_calendar_get_model (calendar);
+
+ if (e_cal_model_remove_client (model, client))
+ gnome_calendar_update_query (calendar);
+}
+
+static void
+cal_shell_view_memopad_popup_event_cb (EShellView *shell_view,
+ GdkEvent *button_event)
+{
+ const gchar *widget_path;
+
+ widget_path = "/calendar-memopad-popup";
+ e_shell_view_show_popup_menu (shell_view, widget_path, button_event);
+}
+
+static void
+cal_shell_view_taskpad_popup_event_cb (EShellView *shell_view,
+ GdkEvent *button_event)
+{
+ const gchar *widget_path;
+
+ widget_path = "/calendar-taskpad-popup";
+ e_shell_view_show_popup_menu (shell_view, widget_path, button_event);
+}
+
+static void
+cal_shell_view_user_created_cb (ECalShellView *cal_shell_view,
+ ECalClient *client,
+ ECalendarView *calendar_view)
+{
+ ECalShellSidebar *cal_shell_sidebar;
+
+ cal_shell_sidebar = cal_shell_view->priv->cal_shell_sidebar;
+
+ e_cal_shell_sidebar_add_client (cal_shell_sidebar, E_CLIENT (client));
+}
+
+static void
+cal_shell_view_backend_error_cb (EClientCache *client_cache,
+ EClient *client,
+ EAlert *alert,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ ESource *source;
+ const gchar *extension_name;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+
+ source = e_client_get_source (client);
+ extension_name = E_SOURCE_EXTENSION_CALENDAR;
+
+ /* Only submit alerts from calendar backends. */
+ if (e_source_has_extension (source, extension_name)) {
+ EAlertSink *alert_sink;
+
+ alert_sink = E_ALERT_SINK (cal_shell_content);
+ e_alert_sink_submit_alert (alert_sink, alert);
+ }
+}
+
+static void
+cal_shell_view_notify_view_id_cb (EShellView *shell_view)
+{
+ GalViewInstance *view_instance;
+ const gchar *view_id;
+
+ view_id = e_shell_view_get_view_id (shell_view);
+ view_instance = e_shell_view_get_view_instance (shell_view);
+
+ /* A NULL view ID implies we're in a custom view. But you can
+ * only get to a custom view via the "Define Views" dialog, which
+ * would have already modified the view instance appropriately.
+ * Furthermore, there's no way to refer to a custom view by ID
+ * anyway, since custom views have no IDs. */
+ if (view_id == NULL)
+ return;
+
+ gal_view_instance_set_current_view_id (view_instance, view_id);
+}
+
+void
+e_cal_shell_view_private_init (ECalShellView *cal_shell_view)
+{
+ g_signal_connect (
+ cal_shell_view, "notify::view-id",
+ G_CALLBACK (cal_shell_view_notify_view_id_cb), NULL);
+}
+
+static void
+system_timezone_monitor_changed (GFileMonitor *handle,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event,
+ gpointer user_data)
+{
+ GSettings *settings;
+
+ if (event != G_FILE_MONITOR_EVENT_CHANGED &&
+ event != G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT &&
+ event != G_FILE_MONITOR_EVENT_DELETED &&
+ event != G_FILE_MONITOR_EVENT_CREATED)
+ return;
+
+ settings = g_settings_new ("org.gnome.evolution.calendar");
+ g_signal_emit_by_name (settings, "changed::timezone", "timezone");
+ g_object_unref (settings);
+}
+
+static void
+init_timezone_monitors (ECalShellView *view)
+{
+ ECalShellViewPrivate *priv = view->priv;
+ gint i;
+
+ for (i = 0; i < CHECK_NB; i++) {
+ GFile *file;
+
+ file = g_file_new_for_path (files_to_check[i]);
+ priv->monitors[i] = g_file_monitor_file (
+ file, G_FILE_MONITOR_NONE, NULL, NULL);
+ g_object_unref (file);
+
+ if (priv->monitors[i])
+ g_signal_connect (
+ priv->monitors[i], "changed",
+ G_CALLBACK (system_timezone_monitor_changed),
+ NULL);
+ }
+}
+
+void
+e_cal_shell_view_private_constructed (ECalShellView *cal_shell_view)
+{
+ ECalShellViewPrivate *priv = cal_shell_view->priv;
+ EShellBackend *shell_backend;
+ EShellContent *shell_content;
+ EShellSidebar *shell_sidebar;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ EShell *shell;
+ gulong handler_id;
+ gint ii;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+ shell_content = e_shell_view_get_shell_content (shell_view);
+ shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ e_shell_window_add_action_group (shell_window, "calendar");
+ e_shell_window_add_action_group (shell_window, "calendar-filter");
+
+ /* Cache these to avoid lots of awkward casting. */
+ priv->cal_shell_backend = g_object_ref (shell_backend);
+ priv->cal_shell_content = g_object_ref (shell_content);
+ priv->cal_shell_sidebar = g_object_ref (shell_sidebar);
+
+ handler_id = g_signal_connect_swapped (
+ priv->cal_shell_sidebar, "client-added",
+ G_CALLBACK (cal_shell_view_selector_client_added_cb),
+ cal_shell_view);
+ priv->client_added_handler_id = handler_id;
+
+ handler_id = g_signal_connect_swapped (
+ priv->cal_shell_sidebar, "client-removed",
+ G_CALLBACK (cal_shell_view_selector_client_removed_cb),
+ cal_shell_view);
+ priv->client_removed_handler_id = handler_id;
+
+ /* Keep our own reference to this so we can
+ * disconnect our signal handlers in dispose(). */
+ priv->client_cache = e_shell_get_client_cache (shell);
+ g_object_ref (priv->client_cache);
+
+ handler_id = g_signal_connect (
+ priv->client_cache, "backend-error",
+ G_CALLBACK (cal_shell_view_backend_error_cb),
+ cal_shell_view);
+ priv->backend_error_handler_id = handler_id;
+
+ /* Keep our own reference to this so we can
+ * disconnect our signal handlers in dispose(). */
+ priv->calendar = e_cal_shell_content_get_calendar (
+ E_CAL_SHELL_CONTENT (shell_content));
+ g_object_ref (priv->calendar);
+
+ handler_id = g_signal_connect_swapped (
+ priv->calendar, "dates-shown-changed",
+ G_CALLBACK (e_cal_shell_view_update_sidebar),
+ cal_shell_view);
+ priv->dates_shown_changed_handler_id = handler_id;
+
+ for (ii = 0; ii < GNOME_CAL_LAST_VIEW; ii++) {
+ ECalendarView *calendar_view;
+
+ /* Keep our own reference to this so we can
+ * disconnect our signal handlers in dispose(). */
+ calendar_view =
+ gnome_calendar_get_calendar_view (priv->calendar, ii);
+ priv->views[ii].calendar_view = g_object_ref (calendar_view);
+
+ handler_id = g_signal_connect_swapped (
+ calendar_view, "popup-event",
+ G_CALLBACK (cal_shell_view_popup_event_cb),
+ cal_shell_view);
+ priv->views[ii].popup_event_handler_id = handler_id;
+
+ handler_id = g_signal_connect_swapped (
+ calendar_view, "selection-changed",
+ G_CALLBACK (e_shell_view_update_actions),
+ cal_shell_view);
+ priv->views[ii].selection_changed_handler_id = handler_id;
+
+ handler_id = g_signal_connect_swapped (
+ calendar_view, "user-created",
+ G_CALLBACK (cal_shell_view_user_created_cb),
+ cal_shell_view);
+ priv->views[ii].user_created_handler_id = handler_id;
+ }
+
+ /* Keep our own reference to this so we can
+ * disconnect our signal handlers in dispose(). */
+ priv->model = e_cal_shell_content_get_model (
+ E_CAL_SHELL_CONTENT (shell_content));
+ g_object_ref (priv->model);
+
+ handler_id = g_signal_connect_swapped (
+ priv->model, "status-message",
+ G_CALLBACK (e_cal_shell_view_set_status_message),
+ cal_shell_view);
+ priv->status_message_handler_id = handler_id;
+
+ /* Keep our own reference to this so we can
+ * disconnect our signal handlers in dispose(). */
+ priv->date_navigator = e_cal_shell_sidebar_get_date_navigator (
+ E_CAL_SHELL_SIDEBAR (shell_sidebar));
+
+ handler_id = g_signal_connect_swapped (
+ priv->date_navigator, "scroll-event",
+ G_CALLBACK (cal_shell_view_date_navigator_scroll_event_cb),
+ cal_shell_view);
+ priv->scroll_event_handler_id = handler_id;
+
+ handler_id = g_signal_connect_swapped (
+ priv->date_navigator->calitem, "date-range-changed",
+ G_CALLBACK (cal_shell_view_date_navigator_date_range_changed_cb),
+ cal_shell_view);
+ priv->date_range_changed_handler_id = handler_id;
+
+ handler_id = g_signal_connect_swapped (
+ priv->date_navigator->calitem, "selection-changed",
+ G_CALLBACK (cal_shell_view_date_navigator_selection_changed_cb),
+ cal_shell_view);
+ priv->selection_changed_handler_id = handler_id;
+
+ /* Keep our own reference to this so we can
+ * disconnect our signal handlers in dispose(). */
+ priv->selector = e_cal_shell_sidebar_get_selector (
+ E_CAL_SHELL_SIDEBAR (shell_sidebar));
+ g_object_ref (priv->selector);
+
+ handler_id = g_signal_connect_swapped (
+ priv->selector, "popup-event",
+ G_CALLBACK (cal_shell_view_selector_popup_event_cb),
+ cal_shell_view);
+ priv->selector_popup_event_handler_id = handler_id;
+
+ /* Keep our own reference to this so we can
+ * disconnect our signal handlers in dispose(). */
+ priv->memo_table = e_cal_shell_content_get_memo_table (
+ E_CAL_SHELL_CONTENT (shell_content));
+ g_object_ref (priv->memo_table);
+
+ handler_id = g_signal_connect_swapped (
+ priv->memo_table, "popup-event",
+ G_CALLBACK (cal_shell_view_memopad_popup_event_cb),
+ cal_shell_view);
+ priv->memo_table_popup_event_handler_id = handler_id;
+
+ handler_id = g_signal_connect_swapped (
+ priv->memo_table, "selection-change",
+ G_CALLBACK (e_cal_shell_view_memopad_actions_update),
+ cal_shell_view);
+ priv->memo_table_selection_change_handler_id = handler_id;
+
+ handler_id = g_signal_connect_swapped (
+ priv->memo_table, "status-message",
+ G_CALLBACK (e_cal_shell_view_memopad_set_status_message),
+ cal_shell_view);
+ priv->memo_table_status_message_handler_id = handler_id;
+
+ /* Keep our own reference to this so we can
+ * disconnect our signal handlers in dispose(). */
+ priv->task_table = e_cal_shell_content_get_task_table (
+ E_CAL_SHELL_CONTENT (shell_content));
+ g_object_ref (priv->task_table);
+
+ handler_id = g_signal_connect_swapped (
+ priv->task_table, "popup-event",
+ G_CALLBACK (cal_shell_view_taskpad_popup_event_cb),
+ cal_shell_view);
+ priv->task_table_popup_event_handler_id = handler_id;
+
+ handler_id = g_signal_connect_swapped (
+ priv->task_table, "selection-change",
+ G_CALLBACK (e_cal_shell_view_taskpad_actions_update),
+ cal_shell_view);
+ priv->task_table_selection_change_handler_id = handler_id;
+
+ handler_id = g_signal_connect_swapped (
+ priv->task_table, "status-message",
+ G_CALLBACK (e_cal_shell_view_taskpad_set_status_message),
+ cal_shell_view);
+ priv->task_table_status_message_handler_id = handler_id;
+
+ e_categories_add_change_hook (
+ (GHookFunc) e_cal_shell_view_update_search_filter,
+ cal_shell_view);
+
+ /* Give GnomeCalendar a handle to the date navigator,
+ * memo and task table. */
+ gnome_calendar_set_date_navigator (
+ priv->calendar, priv->date_navigator);
+ gnome_calendar_set_memo_table (
+ priv->calendar, GTK_WIDGET (priv->memo_table));
+ gnome_calendar_set_task_table (
+ priv->calendar, GTK_WIDGET (priv->task_table));
+
+ e_calendar_item_set_get_time_callback (
+ priv->date_navigator->calitem, (ECalendarItemGetTimeCallback)
+ cal_shell_view_get_current_time, cal_shell_view, NULL);
+
+ init_timezone_monitors (cal_shell_view);
+ e_cal_shell_view_actions_init (cal_shell_view);
+ e_cal_shell_view_update_sidebar (cal_shell_view);
+ e_cal_shell_view_update_search_filter (cal_shell_view);
+
+ /* Keep the ECalModel in sync with the sidebar. */
+ g_object_bind_property (
+ shell_sidebar, "default-client",
+ priv->model, "default-client",
+ G_BINDING_SYNC_CREATE);
+
+ /* Keep the toolbar view buttons in sync with the calendar. */
+ g_object_bind_property (
+ priv->calendar, "view",
+ ACTION (CALENDAR_VIEW_DAY), "current-value",
+ G_BINDING_BIDIRECTIONAL |
+ G_BINDING_SYNC_CREATE);
+
+ /* Force the main calendar to update its default source. */
+ g_signal_emit_by_name (priv->selector, "primary-selection-changed");
+}
+
+void
+e_cal_shell_view_private_dispose (ECalShellView *cal_shell_view)
+{
+ ECalShellViewPrivate *priv = cal_shell_view->priv;
+ gint ii;
+
+ e_cal_shell_view_search_stop (cal_shell_view);
+
+ /* Calling ECalShellContent's save state from here,
+ * because it is too late in its own dispose(). */
+ if (priv->cal_shell_content != NULL)
+ e_cal_shell_content_save_state (priv->cal_shell_content);
+
+ if (priv->client_added_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->cal_shell_sidebar,
+ priv->client_added_handler_id);
+ priv->client_added_handler_id = 0;
+ }
+
+ if (priv->client_removed_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->cal_shell_sidebar,
+ priv->client_removed_handler_id);
+ priv->client_removed_handler_id = 0;
+ }
+
+ if (priv->prepare_for_quit_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->shell,
+ priv->prepare_for_quit_handler_id);
+ priv->prepare_for_quit_handler_id = 0;
+ }
+
+ if (priv->backend_error_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->client_cache,
+ priv->backend_error_handler_id);
+ priv->backend_error_handler_id = 0;
+ }
+
+ if (priv->dates_shown_changed_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->calendar,
+ priv->dates_shown_changed_handler_id);
+ priv->dates_shown_changed_handler_id = 0;
+ }
+
+ if (priv->status_message_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->model,
+ priv->status_message_handler_id);
+ priv->status_message_handler_id = 0;
+ }
+
+ if (priv->scroll_event_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->date_navigator,
+ priv->scroll_event_handler_id);
+ priv->scroll_event_handler_id = 0;
+ }
+
+ if (priv->date_range_changed_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->date_navigator->calitem,
+ priv->date_range_changed_handler_id);
+ priv->date_range_changed_handler_id = 0;
+ }
+
+ if (priv->selection_changed_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->date_navigator->calitem,
+ priv->selection_changed_handler_id);
+ priv->selection_changed_handler_id = 0;
+ }
+
+ if (priv->selector_popup_event_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->selector,
+ priv->selector_popup_event_handler_id);
+ priv->selector_popup_event_handler_id = 0;
+ }
+
+ if (priv->memo_table_popup_event_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->memo_table,
+ priv->memo_table_popup_event_handler_id);
+ priv->memo_table_popup_event_handler_id = 0;
+ }
+
+ if (priv->memo_table_selection_change_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->memo_table,
+ priv->memo_table_selection_change_handler_id);
+ priv->memo_table_selection_change_handler_id = 0;
+ }
+
+ if (priv->memo_table_status_message_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->memo_table,
+ priv->memo_table_status_message_handler_id);
+ priv->memo_table_status_message_handler_id = 0;
+ }
+
+ if (priv->task_table_popup_event_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->task_table,
+ priv->task_table_popup_event_handler_id);
+ priv->task_table_popup_event_handler_id = 0;
+ }
+
+ if (priv->task_table_selection_change_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->task_table,
+ priv->task_table_selection_change_handler_id);
+ priv->task_table_selection_change_handler_id = 0;
+ }
+
+ if (priv->task_table_status_message_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->task_table,
+ priv->task_table_status_message_handler_id);
+ priv->task_table_status_message_handler_id = 0;
+ }
+
+ for (ii = 0; ii < GNOME_CAL_LAST_VIEW; ii++) {
+ if (priv->views[ii].popup_event_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->views[ii].calendar_view,
+ priv->views[ii].popup_event_handler_id);
+ priv->views[ii].popup_event_handler_id = 0;
+ }
+
+ if (priv->views[ii].selection_changed_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->views[ii].calendar_view,
+ priv->views[ii].selection_changed_handler_id);
+ priv->views[ii].selection_changed_handler_id = 0;
+ }
+
+ if (priv->views[ii].user_created_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->views[ii].calendar_view,
+ priv->views[ii].user_created_handler_id);
+ priv->views[ii].user_created_handler_id = 0;
+ }
+
+ g_clear_object (&priv->views[ii].calendar_view);
+ }
+
+ g_clear_object (&priv->cal_shell_backend);
+ g_clear_object (&priv->cal_shell_content);
+ g_clear_object (&priv->cal_shell_sidebar);
+
+ g_clear_object (&priv->shell);
+ g_clear_object (&priv->client_cache);
+ g_clear_object (&priv->calendar);
+ g_clear_object (&priv->model);
+ g_clear_object (&priv->date_navigator);
+ g_clear_object (&priv->selector);
+ g_clear_object (&priv->memo_table);
+ g_clear_object (&priv->task_table);
+
+ if (priv->calendar_activity != NULL) {
+ /* XXX Activity is not cancellable. */
+ e_activity_set_state (
+ priv->calendar_activity, E_ACTIVITY_COMPLETED);
+ g_object_unref (priv->calendar_activity);
+ priv->calendar_activity = NULL;
+ }
+
+ if (priv->memopad_activity != NULL) {
+ /* XXX Activity is not cancellable. */
+ e_activity_set_state (
+ priv->memopad_activity, E_ACTIVITY_COMPLETED);
+ g_object_unref (priv->memopad_activity);
+ priv->memopad_activity = NULL;
+ }
+
+ if (priv->taskpad_activity != NULL) {
+ /* XXX Activity is not cancellable. */
+ e_activity_set_state (
+ priv->taskpad_activity, E_ACTIVITY_COMPLETED);
+ g_object_unref (priv->taskpad_activity);
+ priv->taskpad_activity = NULL;
+ }
+
+ for (ii = 0; ii < CHECK_NB; ii++)
+ g_clear_object (&priv->monitors[ii]);
+}
+
+void
+e_cal_shell_view_private_finalize (ECalShellView *cal_shell_view)
+{
+ /* XXX Nothing to do? */
+}
+
+void
+e_cal_shell_view_open_event (ECalShellView *cal_shell_view,
+ ECalModelComponent *comp_data)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ESourceRegistry *registry;
+ CompEditor *editor;
+ CompEditorFlags flags = 0;
+ ECalComponent *comp;
+ icalcomponent *clone;
+ icalproperty *prop;
+ const gchar *uid;
+
+ g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
+ g_return_if_fail (E_IS_CAL_MODEL_COMPONENT (comp_data));
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ registry = e_shell_get_registry (shell);
+
+ uid = icalcomponent_get_uid (comp_data->icalcomp);
+ editor = comp_editor_find_instance (uid);
+
+ if (editor != NULL)
+ goto exit;
+
+ comp = e_cal_component_new ();
+ clone = icalcomponent_new_clone (comp_data->icalcomp);
+ e_cal_component_set_icalcomponent (comp, clone);
+
+ prop = icalcomponent_get_first_property (
+ comp_data->icalcomp, ICAL_ATTENDEE_PROPERTY);
+ if (prop != NULL)
+ flags |= COMP_EDITOR_MEETING;
+
+ if (itip_organizer_is_user (registry, comp, comp_data->client))
+ flags |= COMP_EDITOR_USER_ORG;
+
+ if (itip_sentby_is_user (registry, comp, comp_data->client))
+ flags |= COMP_EDITOR_USER_ORG;
+
+ if (!e_cal_component_has_attendees (comp))
+ flags |= COMP_EDITOR_USER_ORG;
+
+ editor = event_editor_new (comp_data->client, shell, flags);
+ comp_editor_edit_comp (editor, comp);
+
+ g_object_unref (comp);
+
+exit:
+ gtk_window_present (GTK_WINDOW (editor));
+}
+
+void
+e_cal_shell_view_set_status_message (ECalShellView *cal_shell_view,
+ const gchar *status_message,
+ gdouble percent)
+{
+ EActivity *activity;
+ EShellView *shell_view;
+ EShellBackend *shell_backend;
+
+ g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+
+ activity = cal_shell_view->priv->calendar_activity;
+
+ if (status_message == NULL || *status_message == '\0') {
+ if (activity != NULL) {
+ e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
+ g_object_unref (activity);
+ activity = NULL;
+ }
+ } else if (activity == NULL) {
+ activity = e_activity_new ();
+ e_activity_set_percent (activity, percent);
+ e_activity_set_text (activity, status_message);
+ e_shell_backend_add_activity (shell_backend, activity);
+ } else {
+ e_activity_set_percent (activity, percent);
+ e_activity_set_text (activity, status_message);
+ }
+
+ cal_shell_view->priv->calendar_activity = activity;
+}
+
+struct ForeachTzidData
+{
+ ECalClient *source_client;
+ ECalClient *dest_client;
+};
+
+static void
+add_timezone_to_cal_cb (icalparameter *param,
+ gpointer data)
+{
+ struct ForeachTzidData *ftd = data;
+ icaltimezone *tz = NULL;
+ const gchar *tzid;
+
+ g_return_if_fail (ftd != NULL);
+ g_return_if_fail (ftd->source_client != NULL);
+ g_return_if_fail (ftd->dest_client != NULL);
+
+ tzid = icalparameter_get_tzid (param);
+ if (!tzid || !*tzid)
+ return;
+
+ if (e_cal_client_get_timezone_sync (ftd->source_client, tzid, &tz, NULL, NULL) && tz)
+ e_cal_client_add_timezone_sync (ftd->dest_client, tz, NULL, NULL);
+}
+
+void
+e_cal_shell_view_transfer_item_to (ECalShellView *cal_shell_view,
+ ECalendarViewEvent *event,
+ ECalClient *destination_client,
+ gboolean remove)
+{
+ icalcomponent *icalcomp;
+ icalcomponent *icalcomp_clone;
+ icalcomponent *icalcomp_event;
+ gboolean success;
+ const gchar *uid;
+
+ /* XXX This function should be split up into
+ * smaller, more understandable pieces. */
+
+ g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
+ g_return_if_fail (event != NULL);
+ g_return_if_fail (E_IS_CAL_CLIENT (destination_client));
+
+ if (!is_comp_data_valid (event))
+ return;
+
+ icalcomp_event = event->comp_data->icalcomp;
+ uid = icalcomponent_get_uid (icalcomp_event);
+
+ /* Put the new object into the destination calendar. */
+
+ success = e_cal_client_get_object_sync (
+ destination_client, uid, NULL, &icalcomp, NULL, NULL);
+
+ if (success) {
+ icalcomponent_free (icalcomp);
+ success = e_cal_client_modify_object_sync (
+ destination_client, icalcomp_event,
+ CALOBJ_MOD_ALL, NULL, NULL);
+
+ /* do not delete the event when it was found in the calendar */
+ return;
+ } else {
+ icalproperty *icalprop;
+ gchar *new_uid;
+ GError *error = NULL;
+ struct ForeachTzidData ftd;
+
+ ftd.source_client = event->comp_data->client;
+ ftd.dest_client = destination_client;
+
+ if (e_cal_util_component_is_instance (icalcomp_event)) {
+ success = e_cal_client_get_object_sync (
+ event->comp_data->client,
+ uid, NULL, &icalcomp, NULL, NULL);
+ if (success) {
+ /* Use master object when working
+ * with a recurring event ... */
+ icalcomp_clone = icalcomponent_new_clone (icalcomp);
+ icalcomponent_free (icalcomp);
+ } else {
+ /* ... or remove the recurrence ID ... */
+ icalcomp_clone =
+ icalcomponent_new_clone (icalcomp_event);
+ if (e_cal_util_component_has_recurrences (icalcomp_clone)) {
+ /* ... for non-detached instances,
+ * to make it a master object. */
+ icalprop = icalcomponent_get_first_property (
+ icalcomp_clone, ICAL_RECURRENCEID_PROPERTY);
+ if (icalprop != NULL)
+ icalcomponent_remove_property (
+ icalcomp_clone, icalprop);
+ }
+ }
+ } else
+ icalcomp_clone =
+ icalcomponent_new_clone (icalcomp_event);
+
+ icalprop = icalproperty_new_x ("1");
+ icalproperty_set_x_name (icalprop, "X-EVOLUTION-MOVE-CALENDAR");
+ icalcomponent_add_property (icalcomp_clone, icalprop);
+
+ if (!remove) {
+ /* Change the UID to avoid problems with
+ * duplicated UIDs. */
+ new_uid = e_cal_component_gen_uid ();
+ icalcomponent_set_uid (icalcomp_clone, new_uid);
+ g_free (new_uid);
+ }
+
+ new_uid = NULL;
+ icalcomponent_foreach_tzid (
+ icalcomp_clone, add_timezone_to_cal_cb, &ftd);
+ success = e_cal_client_create_object_sync (
+ destination_client, icalcomp_clone,
+ &new_uid, NULL, &error);
+ if (!success) {
+ icalcomponent_free (icalcomp_clone);
+ g_warning (
+ "%s: Failed to create object: %s",
+ G_STRFUNC, error->message);
+ g_error_free (error);
+ return;
+ }
+
+ icalcomponent_free (icalcomp_clone);
+ g_free (new_uid);
+ }
+
+ if (remove) {
+ ECalClient *source_client = event->comp_data->client;
+
+ /* Remove the item from the source calendar. */
+ if (e_cal_util_component_is_instance (icalcomp_event) ||
+ e_cal_util_component_has_recurrences (icalcomp_event)) {
+ icaltimetype icaltime;
+ gchar *rid;
+
+ icaltime =
+ icalcomponent_get_recurrenceid (icalcomp_event);
+ if (!icaltime_is_null_time (icaltime))
+ rid = icaltime_as_ical_string_r (icaltime);
+ else
+ rid = NULL;
+ e_cal_client_remove_object_sync (
+ source_client, uid, rid,
+ CALOBJ_MOD_ALL, NULL, NULL);
+ g_free (rid);
+ } else
+ e_cal_client_remove_object_sync (
+ source_client, uid, NULL,
+ CALOBJ_MOD_THIS, NULL, NULL);
+ }
+}
+
+void
+e_cal_shell_view_update_sidebar (ECalShellView *cal_shell_view)
+{
+ EShellView *shell_view;
+ EShellSidebar *shell_sidebar;
+ ECalShellContent *cal_shell_content;
+ GnomeCalendar *calendar;
+ GnomeCalendarViewType view_type;
+ ECalendarView *calendar_view;
+ ECalModel *model;
+ time_t start_time, end_time;
+ struct tm start_tm, end_tm;
+ struct icaltimetype start_tt, end_tt;
+ icaltimezone *timezone;
+ gchar buffer[512] = { 0 };
+ gchar end_buffer[512] = { 0 };
+
+ g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+
+ model = gnome_calendar_get_model (calendar);
+ timezone = e_cal_model_get_timezone (model);
+
+ view_type = gnome_calendar_get_view (calendar);
+ calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+
+ if (!e_calendar_view_get_visible_time_range (
+ calendar_view, &start_time, &end_time)) {
+ e_shell_sidebar_set_secondary_text (shell_sidebar, "");
+ return;
+ }
+
+ start_tt = icaltime_from_timet_with_zone (start_time, FALSE, timezone);
+ start_tm.tm_year = start_tt.year - 1900;
+ start_tm.tm_mon = start_tt.month - 1;
+ start_tm.tm_mday = start_tt.day;
+ start_tm.tm_hour = start_tt.hour;
+ start_tm.tm_min = start_tt.minute;
+ start_tm.tm_sec = start_tt.second;
+ start_tm.tm_isdst = -1;
+ start_tm.tm_wday = time_day_of_week (
+ start_tt.day, start_tt.month - 1, start_tt.year);
+
+ /* Subtract one from end_time so we don't get an extra day. */
+ end_tt = icaltime_from_timet_with_zone (end_time - 1, FALSE, timezone);
+ end_tm.tm_year = end_tt.year - 1900;
+ end_tm.tm_mon = end_tt.month - 1;
+ end_tm.tm_mday = end_tt.day;
+ end_tm.tm_hour = end_tt.hour;
+ end_tm.tm_min = end_tt.minute;
+ end_tm.tm_sec = end_tt.second;
+ end_tm.tm_isdst = -1;
+ end_tm.tm_wday = time_day_of_week (
+ end_tt.day, end_tt.month - 1, end_tt.year);
+
+ switch (view_type) {
+ case GNOME_CAL_DAY_VIEW:
+ case GNOME_CAL_WORK_WEEK_VIEW:
+ case GNOME_CAL_WEEK_VIEW:
+ if (start_tm.tm_year == end_tm.tm_year &&
+ start_tm.tm_mon == end_tm.tm_mon &&
+ start_tm.tm_mday == end_tm.tm_mday) {
+ e_utf8_strftime (
+ buffer, sizeof (buffer),
+ _("%A %d %b %Y"), &start_tm);
+ } else if (start_tm.tm_year == end_tm.tm_year) {
+ e_utf8_strftime (
+ buffer, sizeof (buffer),
+ _("%a %d %b"), &start_tm);
+ e_utf8_strftime (
+ end_buffer, sizeof (end_buffer),
+ _("%a %d %b %Y"), &end_tm);
+ strcat (buffer, " - ");
+ strcat (buffer, end_buffer);
+ } else {
+ e_utf8_strftime (
+ buffer, sizeof (buffer),
+ _("%a %d %b %Y"), &start_tm);
+ e_utf8_strftime (
+ end_buffer, sizeof (end_buffer),
+ _("%a %d %b %Y"), &end_tm);
+ strcat (buffer, " - ");
+ strcat (buffer, end_buffer);
+ }
+ break;
+
+ case GNOME_CAL_MONTH_VIEW:
+ case GNOME_CAL_LIST_VIEW:
+ if (start_tm.tm_year == end_tm.tm_year) {
+ if (start_tm.tm_mon == end_tm.tm_mon) {
+ e_utf8_strftime (
+ buffer,
+ sizeof (buffer),
+ "%d", &start_tm);
+ e_utf8_strftime (
+ end_buffer,
+ sizeof (end_buffer),
+ _("%d %b %Y"), &end_tm);
+ strcat (buffer, " - ");
+ strcat (buffer, end_buffer);
+ } else {
+ e_utf8_strftime (
+ buffer,
+ sizeof (buffer),
+ _("%d %b"), &start_tm);
+ e_utf8_strftime (
+ end_buffer,
+ sizeof (end_buffer),
+ _("%d %b %Y"), &end_tm);
+ strcat (buffer, " - ");
+ strcat (buffer, end_buffer);
+ }
+ } else {
+ e_utf8_strftime (
+ buffer, sizeof (buffer),
+ _("%d %b %Y"), &start_tm);
+ e_utf8_strftime (
+ end_buffer, sizeof (end_buffer),
+ _("%d %b %Y"), &end_tm);
+ strcat (buffer, " - ");
+ strcat (buffer, end_buffer);
+ }
+ break;
+
+ default:
+ g_return_if_reached ();
+ }
+
+ e_shell_sidebar_set_secondary_text (shell_sidebar, buffer);
+}
+
+static gint
+cal_searching_get_search_range_years (ECalShellView *cal_shell_view)
+{
+ GSettings *settings;
+ gint search_range_years;
+
+ settings = g_settings_new ("org.gnome.evolution.calendar");
+
+ search_range_years =
+ g_settings_get_int (settings, "search-range-years");
+ if (search_range_years <= 0)
+ search_range_years = 10;
+
+ g_object_unref (settings);
+
+ return search_range_years;
+}
+
+static gint
+cal_time_t_ptr_compare (gconstpointer a,
+ gconstpointer b)
+{
+ const time_t *ta = a, *tb = b;
+
+ return (ta ? *ta : 0) - (tb ? *tb : 0);
+}
+
+static void cal_iterate_searching (ECalShellView *cal_shell_view);
+
+struct GenerateInstancesData {
+ ECalClient *client;
+ ECalShellView *cal_shell_view;
+ GCancellable *cancellable;
+};
+
+static void
+cal_searching_instances_done_cb (gpointer user_data)
+{
+ struct GenerateInstancesData *gid = user_data;
+
+ g_return_if_fail (gid != NULL);
+ g_return_if_fail (gid->cal_shell_view != NULL);
+
+ if (!g_cancellable_is_cancelled (gid->cancellable)) {
+ gid->cal_shell_view->priv->search_pending_count--;
+ if (!gid->cal_shell_view->priv->search_pending_count) {
+ gid->cal_shell_view->priv->search_hit_cache =
+ g_slist_sort (
+ gid->cal_shell_view->priv->search_hit_cache,
+ cal_time_t_ptr_compare);
+ cal_iterate_searching (gid->cal_shell_view);
+ }
+ }
+
+ g_object_unref (gid->cancellable);
+ g_free (gid);
+}
+
+static gboolean
+cal_searching_got_instance_cb (ECalComponent *comp,
+ time_t instance_start,
+ time_t instance_end,
+ gpointer user_data)
+{
+ struct GenerateInstancesData *gid = user_data;
+ ECalShellViewPrivate *priv;
+ ECalComponentDateTime dt;
+ time_t *value;
+
+ g_return_val_if_fail (gid != NULL, FALSE);
+
+ if (g_cancellable_is_cancelled (gid->cancellable))
+ return FALSE;
+
+ g_return_val_if_fail (gid->cal_shell_view != NULL, FALSE);
+ g_return_val_if_fail (gid->cal_shell_view->priv != NULL, FALSE);
+
+ e_cal_component_get_dtstart (comp, &dt);
+
+ if (dt.tzid && dt.value) {
+ icaltimezone *zone = NULL;
+ if (!e_cal_client_get_timezone_sync (gid->client, dt.tzid, &zone, gid->cancellable, NULL)) {
+ zone = NULL;
+ }
+
+ if (g_cancellable_is_cancelled (gid->cancellable))
+ return FALSE;
+
+ if (zone)
+ instance_start = icaltime_as_timet_with_zone (*dt.value, zone);
+ }
+
+ e_cal_component_free_datetime (&dt);
+
+ priv = gid->cal_shell_view->priv;
+ value = g_new (time_t, 1);
+ *value = instance_start;
+ if (!g_slist_find_custom (priv->search_hit_cache, value, cal_time_t_ptr_compare))
+ priv->search_hit_cache = g_slist_append (priv->search_hit_cache, value);
+ else
+ g_free (value);
+
+ return TRUE;
+}
+
+static void
+cal_search_get_object_list_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ ECalClient *client = E_CAL_CLIENT (source);
+ ECalShellView *cal_shell_view = user_data;
+ GSList *icalcomps = NULL;
+ GError *error = NULL;
+
+ g_return_if_fail (client != NULL);
+ g_return_if_fail (result != NULL);
+ g_return_if_fail (cal_shell_view != NULL);
+
+ if (!e_cal_client_get_object_list_finish (client, result, &icalcomps, &error) || !icalcomps) {
+ if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
+ g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ g_clear_error (&error);
+ return;
+ }
+
+ g_clear_error (&error);
+ cal_shell_view->priv->search_pending_count--;
+ if (!cal_shell_view->priv->search_pending_count) {
+ cal_shell_view->priv->search_hit_cache =
+ g_slist_sort (
+ cal_shell_view->priv->search_hit_cache,
+ cal_time_t_ptr_compare);
+ cal_iterate_searching (cal_shell_view);
+ }
+ } else {
+ GSList *iter;
+ GCancellable *cancellable;
+ time_t start, end;
+
+ cancellable = e_activity_get_cancellable (
+ cal_shell_view->priv->searching_activity);
+ start = time_add_day (
+ cal_shell_view->priv->search_time,
+ (-1) * cal_shell_view->priv->search_direction);
+ end = cal_shell_view->priv->search_time;
+ if (start > end) {
+ time_t tmp = start;
+ start = end;
+ end = tmp;
+ }
+
+ for (iter = icalcomps; iter; iter = iter->next) {
+ icalcomponent *icalcomp = iter->data;
+ struct GenerateInstancesData *gid;
+
+ gid = g_new0 (struct GenerateInstancesData, 1);
+ gid->client = client;
+ gid->cal_shell_view = cal_shell_view;
+ gid->cancellable = g_object_ref (cancellable);
+
+ e_cal_client_generate_instances_for_object (
+ client, icalcomp, start, end, cancellable,
+ cal_searching_got_instance_cb, gid,
+ cal_searching_instances_done_cb);
+ }
+
+ e_cal_client_free_icalcomp_slist (icalcomps);
+ }
+}
+
+static gboolean
+cal_searching_check_candidates (ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ GnomeCalendarViewType view_type;
+ ECalendarView *calendar_view;
+ GnomeCalendar *calendar;
+ GSList *iter;
+ time_t value, candidate = -1;
+
+ g_return_val_if_fail (cal_shell_view != NULL, FALSE);
+ g_return_val_if_fail (cal_shell_view->priv != NULL, FALSE);
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ view_type = gnome_calendar_get_view (calendar);
+ calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+
+ if (!e_calendar_view_get_selected_time_range (calendar_view, &value, NULL))
+ return FALSE;
+
+ if (cal_shell_view->priv->search_direction > 0 && (view_type == GNOME_CAL_WEEK_VIEW || view_type == GNOME_CAL_MONTH_VIEW))
+ value = time_add_day (value, 1);
+
+ for (iter = cal_shell_view->priv->search_hit_cache; iter; iter = iter->next) {
+ time_t cache = *((time_t *) iter->data);
+
+ /* list is sorted, once the search iteration is complete */
+ if (cache > value) {
+ if (cal_shell_view->priv->search_direction > 0)
+ candidate = cache;
+ break;
+ } else if (cal_shell_view->priv->search_direction < 0 && cache != value)
+ candidate = cache;
+ }
+
+ if (candidate > 0) {
+ gnome_calendar_goto (calendar, candidate);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+cal_searching_update_alert (ECalShellView *cal_shell_view,
+ const gchar *message)
+{
+ ECalShellViewPrivate *priv;
+ EShellContent *shell_content;
+ EAlert *alert;
+
+ g_return_if_fail (cal_shell_view != NULL);
+ g_return_if_fail (cal_shell_view->priv != NULL);
+
+ priv = cal_shell_view->priv;
+
+ if (priv->search_alert) {
+ e_alert_response (
+ priv->search_alert,
+ e_alert_get_default_response (priv->search_alert));
+ priv->search_alert = NULL;
+ }
+
+ if (!message)
+ return;
+
+ alert = e_alert_new ("calendar:search-error-generic", message, NULL);
+ g_return_if_fail (alert != NULL);
+
+ priv->search_alert = alert;
+ g_object_add_weak_pointer (G_OBJECT (alert), &priv->search_alert);
+ e_alert_start_timer (priv->search_alert, 5);
+
+ shell_content = e_shell_view_get_shell_content (
+ E_SHELL_VIEW (cal_shell_view));
+ e_alert_sink_submit_alert (
+ E_ALERT_SINK (shell_content), priv->search_alert);
+ g_object_unref (priv->search_alert);
+}
+
+static void
+cal_iterate_searching (ECalShellView *cal_shell_view)
+{
+ ECalShellViewPrivate *priv;
+ GList *list, *link;
+ ECalModel *model;
+ time_t new_time, range1, range2;
+ icaltimezone *timezone;
+ const gchar *default_tzloc = NULL;
+ GCancellable *cancellable;
+ gchar *sexp, *start, *end;
+
+ g_return_if_fail (cal_shell_view != NULL);
+ g_return_if_fail (cal_shell_view->priv != NULL);
+
+ priv = cal_shell_view->priv;
+ g_return_if_fail (priv->search_direction != 0);
+ g_return_if_fail (priv->search_pending_count == 0);
+
+ cal_searching_update_alert (cal_shell_view, NULL);
+
+ if (cal_searching_check_candidates (cal_shell_view)) {
+ if (priv->searching_activity) {
+ e_activity_set_state (
+ priv->searching_activity,
+ E_ACTIVITY_COMPLETED);
+ g_object_unref (priv->searching_activity);
+ priv->searching_activity = NULL;
+ }
+
+ e_shell_view_update_actions (E_SHELL_VIEW (cal_shell_view));
+
+ return;
+ }
+
+ if (!priv->searching_activity) {
+ EShellBackend *shell_backend;
+
+ shell_backend = e_shell_view_get_shell_backend (
+ E_SHELL_VIEW (cal_shell_view));
+
+ cancellable = g_cancellable_new ();
+ priv->searching_activity = e_activity_new ();
+ e_activity_set_cancellable (
+ priv->searching_activity, cancellable);
+ e_activity_set_state (
+ priv->searching_activity, E_ACTIVITY_RUNNING);
+ e_activity_set_text (
+ priv->searching_activity,
+ priv->search_direction > 0 ?
+ _("Searching next matching event") :
+ _("Searching previous matching event"));
+
+ e_shell_backend_add_activity (
+ shell_backend, priv->searching_activity);
+ }
+
+ new_time = time_add_day (priv->search_time, priv->search_direction);
+ if (new_time > priv->search_max_time || new_time < priv->search_min_time) {
+ gchar *alert_msg;
+ gint range_years;
+
+ /* would get out of bounds, stop searching */
+ e_activity_set_state (
+ priv->searching_activity, E_ACTIVITY_COMPLETED);
+ g_object_unref (priv->searching_activity);
+ priv->searching_activity = NULL;
+
+ range_years = cal_searching_get_search_range_years (cal_shell_view);
+ alert_msg = g_strdup_printf (
+ priv->search_direction > 0 ?
+ ngettext (
+ "Cannot find matching event in the next %d year",
+ "Cannot find matching event in the next %d years",
+ range_years) :
+ ngettext (
+ "Cannot find matching event in the previous %d year",
+ "Cannot find matching event in the previous %d years",
+ range_years),
+ range_years);
+ cal_searching_update_alert (cal_shell_view, alert_msg);
+ g_free (alert_msg);
+
+ e_shell_view_update_actions (E_SHELL_VIEW (cal_shell_view));
+
+ return;
+ }
+
+ model = gnome_calendar_get_model (
+ e_cal_shell_content_get_calendar (
+ cal_shell_view->priv->cal_shell_content));
+ list = e_cal_model_list_clients (model);
+
+ if (list == NULL) {
+ e_activity_set_state (
+ priv->searching_activity, E_ACTIVITY_COMPLETED);
+ g_object_unref (priv->searching_activity);
+ priv->searching_activity = NULL;
+
+ cal_searching_update_alert (
+ cal_shell_view,
+ _("Cannot search with no active calendar"));
+
+ e_shell_view_update_actions (E_SHELL_VIEW (cal_shell_view));
+
+ return;
+ }
+
+ timezone = e_cal_model_get_timezone (model);
+ range1 = priv->search_time;
+ range2 = time_add_day (range1, priv->search_direction);
+ if (range1 < range2) {
+ start = isodate_from_time_t (time_day_begin (range1));
+ end = isodate_from_time_t (time_day_end (range2));
+ } else {
+ start = isodate_from_time_t (time_day_begin (range2));
+ end = isodate_from_time_t (time_day_end (range1));
+ }
+
+ if (timezone && timezone != icaltimezone_get_utc_timezone ())
+ default_tzloc = icaltimezone_get_location (timezone);
+ if (!default_tzloc)
+ default_tzloc = "";
+
+ sexp = g_strdup_printf (
+ "(and %s (occur-in-time-range? "
+ "(make-time \"%s\") "
+ "(make-time \"%s\") \"%s\"))",
+ e_cal_model_get_search_query (model), start, end, default_tzloc);
+
+ g_free (start);
+ g_free (end);
+
+ cancellable = e_activity_get_cancellable (priv->searching_activity);
+ priv->search_pending_count = g_list_length (list);
+ priv->search_time = new_time;
+
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ ECalClient *client = E_CAL_CLIENT (link->data);
+
+ e_cal_client_get_object_list (
+ client, sexp, cancellable,
+ cal_search_get_object_list_cb, cal_shell_view);
+ }
+
+ g_list_free_full (list, (GDestroyNotify) g_object_unref);
+ g_free (sexp);
+
+ e_shell_view_update_actions (E_SHELL_VIEW (cal_shell_view));
+}
+
+void
+e_cal_shell_view_search_events (ECalShellView *cal_shell_view,
+ gboolean search_forward)
+{
+ ECalShellViewPrivate *priv = cal_shell_view->priv;
+ ECalShellContent *cal_shell_content;
+ GnomeCalendarViewType view_type;
+ ECalendarView *calendar_view;
+ GnomeCalendar *calendar;
+ time_t start_time = 0;
+ gint range_years;
+
+ if (priv->searching_activity || !priv->search_direction)
+ e_cal_shell_view_search_stop (cal_shell_view);
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ view_type = gnome_calendar_get_view (calendar);
+ calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+
+ if (!e_calendar_view_get_selected_time_range (calendar_view, &start_time, NULL)) {
+ e_shell_view_update_actions (E_SHELL_VIEW (cal_shell_view));
+ return;
+ }
+
+ start_time = time_day_begin (start_time);
+ if (priv->search_direction) {
+ time_t cached_start, cached_end, tmp;
+
+ cached_start = priv->search_time;
+ cached_end = time_add_day (
+ cached_start, (-1) * priv->search_direction);
+
+ if (priv->search_direction > 0) {
+ tmp = cached_start;
+ cached_start = cached_end;
+ cached_end = tmp;
+ }
+
+ /* clear cached results if searching out of cached bounds */
+ if (start_time < cached_start || start_time > cached_end)
+ e_cal_shell_view_search_stop (cal_shell_view);
+ }
+
+ priv->search_direction = search_forward ? +30 : -30;
+
+ if (cal_searching_check_candidates (cal_shell_view)) {
+ e_shell_view_update_actions (E_SHELL_VIEW (cal_shell_view));
+ return;
+ }
+
+ range_years = cal_searching_get_search_range_years (cal_shell_view);
+
+ priv->search_pending_count = 0;
+ priv->search_time = start_time;
+ priv->search_min_time = start_time - (range_years * 365 * 24 * 60 * 60);
+ priv->search_max_time = start_time + (range_years * 365 * 24 * 60 * 60);
+
+ if (priv->search_min_time < 0)
+ priv->search_min_time = 0;
+ if (priv->search_hit_cache) {
+ g_slist_free_full (priv->search_hit_cache, g_free);
+ priv->search_hit_cache = NULL;
+ }
+
+ cal_iterate_searching (cal_shell_view);
+}
+
+void
+e_cal_shell_view_search_stop (ECalShellView *cal_shell_view)
+{
+ ECalShellViewPrivate *priv;
+
+ g_return_if_fail (cal_shell_view != NULL);
+ g_return_if_fail (cal_shell_view->priv != NULL);
+
+ priv = cal_shell_view->priv;
+
+ cal_searching_update_alert (cal_shell_view, NULL);
+
+ if (priv->searching_activity) {
+ g_cancellable_cancel (
+ e_activity_get_cancellable (priv->searching_activity));
+ e_activity_set_state (
+ priv->searching_activity, E_ACTIVITY_CANCELLED);
+ g_object_unref (priv->searching_activity);
+ priv->searching_activity = NULL;
+ }
+
+ if (priv->search_hit_cache) {
+ g_slist_free_full (priv->search_hit_cache, g_free);
+ priv->search_hit_cache = NULL;
+ }
+
+ priv->search_direction = 0;
+}
diff --git a/modules/calendar/e-cal-shell-view-private.h b/modules/calendar/e-cal-shell-view-private.h
new file mode 100644
index 0000000000..000602b991
--- /dev/null
+++ b/modules/calendar/e-cal-shell-view-private.h
@@ -0,0 +1,223 @@
+/*
+ * e-cal-shell-view-private.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_CAL_SHELL_VIEW_PRIVATE_H
+#define E_CAL_SHELL_VIEW_PRIVATE_H
+
+#include "e-cal-shell-view.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+
+#include <libecal/libecal.h>
+
+#include <shell/e-shell-utils.h>
+
+#include <calendar/gui/calendar-config.h>
+#include <calendar/gui/comp-util.h>
+#include <calendar/gui/e-cal-list-view.h>
+#include <calendar/gui/e-cal-model-tasks.h>
+#include <calendar/gui/e-calendar-view.h>
+#include <calendar/gui/e-day-view.h>
+#include <calendar/gui/e-week-view.h>
+#include <calendar/gui/gnome-cal.h>
+#include <calendar/gui/print.h>
+#include <calendar/gui/dialogs/copy-source-dialog.h>
+#include <calendar/gui/dialogs/event-editor.h>
+#include <calendar/gui/dialogs/goto-dialog.h>
+#include <calendar/gui/dialogs/memo-editor.h>
+#include <calendar/gui/dialogs/select-source-dialog.h>
+#include <calendar/gui/dialogs/task-editor.h>
+
+#include "e-cal-shell-backend.h"
+#include "e-cal-shell-content.h"
+#include "e-cal-shell-sidebar.h"
+#include "e-cal-shell-view-actions.h"
+
+#define E_CAL_SHELL_VIEW_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_CAL_SHELL_VIEW, ECalShellViewPrivate))
+
+/* Shorthand, requires a variable named "shell_window". */
+#define ACTION(name) \
+ (E_SHELL_WINDOW_ACTION_##name (shell_window))
+#define ACTION_GROUP(name) \
+ (E_SHELL_WINDOW_ACTION_GROUP_##name (shell_window))
+
+/* ETable Specifications */
+#define ETSPEC_FILENAME "e-calendar-table.etspec"
+#define CHECK_NB 5
+
+G_BEGIN_DECLS
+
+/* Filter items are displayed in ascending order.
+ * Non-negative values are reserved for categories. */
+enum {
+ CALENDAR_FILTER_ANY_CATEGORY = -5,
+ CALENDAR_FILTER_UNMATCHED = -4,
+ CALENDAR_FILTER_ACTIVE_APPOINTMENTS = -3,
+ CALENDAR_FILTER_NEXT_7_DAYS_APPOINTMENTS = -2,
+ CALENDAR_FILTER_OCCURS_LESS_THAN_5_TIMES = -1
+};
+
+/* Search items are displayed in ascending order. */
+enum {
+ CALENDAR_SEARCH_ADVANCED = -1,
+ CALENDAR_SEARCH_SUMMARY_CONTAINS,
+ CALENDAR_SEARCH_DESCRIPTION_CONTAINS,
+ CALENDAR_SEARCH_ANY_FIELD_CONTAINS
+};
+
+struct _ECalShellViewPrivate {
+
+ /* These are just for convenience. */
+ ECalShellBackend *cal_shell_backend;
+ ECalShellContent *cal_shell_content;
+ ECalShellSidebar *cal_shell_sidebar;
+
+ /* sidebar signal handlers */
+ gulong client_added_handler_id;
+ gulong client_removed_handler_id;
+
+ EShell *shell;
+ gulong prepare_for_quit_handler_id;
+
+ EClientCache *client_cache;
+ gulong backend_error_handler_id;
+
+ GnomeCalendar *calendar;
+ gulong dates_shown_changed_handler_id;
+
+ struct {
+ ECalendarView *calendar_view;
+ gulong popup_event_handler_id;
+ gulong selection_changed_handler_id;
+ gulong user_created_handler_id;
+ } views[GNOME_CAL_LAST_VIEW];
+
+ ECalModel *model;
+ gulong status_message_handler_id;
+
+ ECalendar *date_navigator;
+ gulong scroll_event_handler_id;
+ gulong date_range_changed_handler_id;
+ gulong selection_changed_handler_id;
+
+ ESourceSelector *selector;
+ gulong selector_popup_event_handler_id;
+
+ EMemoTable *memo_table;
+ gulong memo_table_popup_event_handler_id;
+ gulong memo_table_selection_change_handler_id;
+ gulong memo_table_status_message_handler_id;
+
+ ETaskTable *task_table;
+ gulong task_table_popup_event_handler_id;
+ gulong task_table_selection_change_handler_id;
+ gulong task_table_status_message_handler_id;
+
+ /* The last time explicitly selected by the user. */
+ time_t base_view_time;
+
+ EActivity *calendar_activity;
+ EActivity *memopad_activity;
+ EActivity *taskpad_activity;
+
+ /* Time-range searching */
+ EActivity *searching_activity;
+ gpointer search_alert; /* weak pointer to EAlert * */
+ gint search_pending_count; /* how many clients are pending */
+ time_t search_time; /* current search time from */
+ time_t search_min_time, search_max_time; /* time boundary for searching */
+ gint search_direction; /* negative value is backward, positive is forward, zero is error; in days */
+ GSList *search_hit_cache; /* pointers on time_t for matched events */
+
+ GFileMonitor *monitors[CHECK_NB];
+};
+
+void e_cal_shell_view_private_init
+ (ECalShellView *cal_shell_view);
+void e_cal_shell_view_private_constructed
+ (ECalShellView *cal_shell_view);
+void e_cal_shell_view_private_dispose
+ (ECalShellView *cal_shell_view);
+void e_cal_shell_view_private_finalize
+ (ECalShellView *cal_shell_view);
+
+/* Private Utilities */
+
+void e_cal_shell_view_actions_init
+ (ECalShellView *cal_shell_view);
+void e_cal_shell_view_execute_search
+ (ECalShellView *cal_shell_view);
+void e_cal_shell_view_open_event
+ (ECalShellView *cal_shell_view,
+ ECalModelComponent *comp_data);
+void e_cal_shell_view_set_status_message
+ (ECalShellView *cal_shell_view,
+ const gchar *status_message,
+ gdouble percent);
+void e_cal_shell_view_transfer_item_to
+ (ECalShellView *cal_shell_view,
+ ECalendarViewEvent *event,
+ ECalClient *destination_client,
+ gboolean remove);
+void e_cal_shell_view_update_sidebar
+ (ECalShellView *cal_shell_view);
+void e_cal_shell_view_update_search_filter
+ (ECalShellView *cal_shell_view);
+void e_cal_shell_view_search_events
+ (ECalShellView *cal_shell_view,
+ gboolean search_forward);
+void e_cal_shell_view_search_stop
+ (ECalShellView *cal_shell_view);
+
+/* Memo Pad Utilities */
+
+void e_cal_shell_view_memopad_actions_init
+ (ECalShellView *cal_shell_view);
+void e_cal_shell_view_memopad_actions_update
+ (ECalShellView *cal_shell_view);
+void e_cal_shell_view_memopad_open_memo
+ (ECalShellView *cal_shell_view,
+ ECalModelComponent *comp_data);
+void e_cal_shell_view_memopad_set_status_message
+ (ECalShellView *cal_shell_view,
+ const gchar *status_message,
+ gdouble percent);
+
+/* Task Pad Utilities */
+
+void e_cal_shell_view_taskpad_actions_init
+ (ECalShellView *cal_shell_view);
+void e_cal_shell_view_taskpad_actions_update
+ (ECalShellView *cal_shell_view);
+void e_cal_shell_view_taskpad_open_task
+ (ECalShellView *cal_shell_view,
+ ECalModelComponent *comp_data);
+void e_cal_shell_view_taskpad_set_status_message
+ (ECalShellView *cal_shell_view,
+ const gchar *status_message,
+ gdouble percent);
+
+G_END_DECLS
+
+#endif /* E_CAL_SHELL_VIEW_PRIVATE_H */
diff --git a/modules/calendar/e-cal-shell-view-taskpad.c b/modules/calendar/e-cal-shell-view-taskpad.c
new file mode 100644
index 0000000000..ec268775e9
--- /dev/null
+++ b/modules/calendar/e-cal-shell-view-taskpad.c
@@ -0,0 +1,609 @@
+/*
+ * e-cal-shell-view-taskpad.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-cal-shell-view-private.h"
+
+/* Much of this file is based on e-task-shell-view-actions.c. */
+
+static void
+action_calendar_taskpad_assign_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ ECalModelComponent *comp_data;
+ ETaskTable *task_table;
+ GSList *list;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ task_table = e_cal_shell_content_get_task_table (cal_shell_content);
+
+ list = e_task_table_get_selected (task_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only open the first selected task. */
+ e_cal_shell_view_taskpad_open_task (cal_shell_view, comp_data);
+
+ /* FIXME Need to actually assign the task. */
+}
+
+static void
+action_calendar_taskpad_forward_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ESourceRegistry *registry;
+ ECalModelComponent *comp_data;
+ ETaskTable *task_table;
+ ECalComponent *comp;
+ icalcomponent *clone;
+ GSList *list;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ registry = e_shell_get_registry (shell);
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ task_table = e_cal_shell_content_get_task_table (cal_shell_content);
+
+ list = e_task_table_get_selected (task_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only forward the first selected task. */
+ comp = e_cal_component_new ();
+ clone = icalcomponent_new_clone (comp_data->icalcomp);
+ e_cal_component_set_icalcomponent (comp, clone);
+
+ itip_send_comp (
+ registry, E_CAL_COMPONENT_METHOD_PUBLISH, comp,
+ comp_data->client, NULL, NULL, NULL, TRUE, FALSE);
+
+ g_object_unref (comp);
+}
+
+static void
+action_calendar_taskpad_mark_complete_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ ETaskTable *task_table;
+ ECalModel *model;
+ GSList *list, *iter;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ task_table = e_cal_shell_content_get_task_table (cal_shell_content);
+ list = e_task_table_get_selected (task_table);
+ model = e_task_table_get_model (task_table);
+
+ for (iter = list; iter != NULL; iter = iter->next) {
+ ECalModelComponent *comp_data = iter->data;
+ e_cal_model_tasks_mark_comp_complete (
+ E_CAL_MODEL_TASKS (model), comp_data);
+ }
+
+ g_slist_free (list);
+}
+
+static void
+action_calendar_taskpad_mark_incomplete_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ ETaskTable *task_table;
+ ECalModel *model;
+ GSList *list, *iter;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ task_table = e_cal_shell_content_get_task_table (cal_shell_content);
+ list = e_task_table_get_selected (task_table);
+ model = e_task_table_get_model (task_table);
+
+ for (iter = list; iter != NULL; iter = iter->next) {
+ ECalModelComponent *comp_data = iter->data;
+ e_cal_model_tasks_mark_comp_incomplete (
+ E_CAL_MODEL_TASKS (model), comp_data);
+ }
+
+ g_slist_free (list);
+}
+
+static void
+action_calendar_taskpad_new_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ECalShellContent *cal_shell_content;
+ ECalModelComponent *comp_data;
+ ETaskTable *task_table;
+ ECalClient *client;
+ ECalComponent *comp;
+ CompEditor *editor;
+ GSList *list;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ task_table = e_cal_shell_content_get_task_table (cal_shell_content);
+
+ list = e_task_table_get_selected (task_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ client = comp_data->client;
+ editor = task_editor_new (client, shell, COMP_EDITOR_NEW_ITEM);
+ comp = cal_comp_task_new_with_defaults (client);
+ comp_editor_edit_comp (editor, comp);
+
+ gtk_window_present (GTK_WINDOW (editor));
+
+ g_object_unref (comp);
+}
+
+static void
+action_calendar_taskpad_open_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ ECalModelComponent *comp_data;
+ ETaskTable *task_table;
+ GSList *list;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ task_table = e_cal_shell_content_get_task_table (cal_shell_content);
+
+ list = e_task_table_get_selected (task_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only open the first selected task. */
+ e_cal_shell_view_taskpad_open_task (cal_shell_view, comp_data);
+}
+
+static void
+action_calendar_taskpad_open_url_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ECalShellContent *cal_shell_content;
+ ECalModelComponent *comp_data;
+ ETaskTable *task_table;
+ icalproperty *prop;
+ const gchar *uri;
+ GSList *list;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ task_table = e_cal_shell_content_get_task_table (cal_shell_content);
+
+ list = e_task_table_get_selected (task_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+
+ /* XXX We only open the URI of the first selected task. */
+ prop = icalcomponent_get_first_property (
+ comp_data->icalcomp, ICAL_URL_PROPERTY);
+ g_return_if_fail (prop != NULL);
+
+ uri = icalproperty_get_url (prop);
+ e_show_uri (GTK_WINDOW (shell_window), uri);
+}
+
+static void
+action_calendar_taskpad_print_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ ECalModelComponent *comp_data;
+ ETaskTable *task_table;
+ ECalComponent *comp;
+ ECalModel *model;
+ icalcomponent *clone;
+ GSList *list;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ task_table = e_cal_shell_content_get_task_table (cal_shell_content);
+ model = e_task_table_get_model (task_table);
+
+ list = e_task_table_get_selected (task_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only print the first selected task. */
+ comp = e_cal_component_new ();
+ clone = icalcomponent_new_clone (comp_data->icalcomp);
+ e_cal_component_set_icalcomponent (comp, clone);
+
+ print_comp (
+ comp, comp_data->client,
+ e_cal_model_get_timezone (model),
+ e_cal_model_get_use_24_hour_format (model),
+ GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG);
+
+ g_object_unref (comp);
+}
+
+static void
+action_calendar_taskpad_save_as_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellBackend *shell_backend;
+ ECalShellContent *cal_shell_content;
+ ECalModelComponent *comp_data;
+ ETaskTable *task_table;
+ EActivity *activity;
+ GSList *list;
+ GFile *file;
+ gchar *string;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ task_table = e_cal_shell_content_get_task_table (cal_shell_content);
+
+ list = e_task_table_get_selected (task_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* Translators: Default filename part saving a task to a file when
+ * no summary is filed, the '.ics' extension is concatenated to it. */
+ string = icalcomp_suggest_filename (comp_data->icalcomp, _("task"));
+ file = e_shell_run_save_dialog (
+ shell, _("Save as iCalendar"), string,
+ "*.ics:text/calendar", NULL, NULL);
+ g_free (string);
+ if (file == NULL)
+ return;
+
+ string = e_cal_client_get_component_as_string (
+ comp_data->client, comp_data->icalcomp);
+ if (string == NULL) {
+ g_warning ("Could not convert task to a string");
+ g_object_unref (file);
+ return;
+ }
+
+ /* XXX No callback means errors are discarded. */
+ activity = e_file_replace_contents_async (
+ file, string, strlen (string), NULL, FALSE,
+ G_FILE_CREATE_NONE, (GAsyncReadyCallback) NULL, NULL);
+ e_shell_backend_add_activity (shell_backend, activity);
+
+ /* Free the string when the activity is finalized. */
+ g_object_set_data_full (
+ G_OBJECT (activity),
+ "file-content", string,
+ (GDestroyNotify) g_free);
+
+ g_object_unref (file);
+}
+
+static GtkActionEntry calendar_taskpad_entries[] = {
+
+ { "calendar-taskpad-assign",
+ NULL,
+ N_("_Assign Task"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_calendar_taskpad_assign_cb) },
+
+ { "calendar-taskpad-forward",
+ "mail-forward",
+ N_("_Forward as iCalendar..."),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_calendar_taskpad_forward_cb) },
+
+ { "calendar-taskpad-mark-complete",
+ NULL,
+ N_("_Mark as Complete"),
+ NULL,
+ N_("Mark selected tasks as complete"),
+ G_CALLBACK (action_calendar_taskpad_mark_complete_cb) },
+
+ { "calendar-taskpad-mark-incomplete",
+ NULL,
+ N_("_Mark as Incomplete"),
+ NULL,
+ N_("Mark selected tasks as incomplete"),
+ G_CALLBACK (action_calendar_taskpad_mark_incomplete_cb) },
+
+ { "calendar-taskpad-new",
+ "stock_task",
+ N_("New _Task"),
+ NULL,
+ N_("Create a new task"),
+ G_CALLBACK (action_calendar_taskpad_new_cb) },
+
+ { "calendar-taskpad-open",
+ GTK_STOCK_OPEN,
+ N_("_Open Task"),
+ NULL,
+ N_("View the selected task"),
+ G_CALLBACK (action_calendar_taskpad_open_cb) },
+
+ { "calendar-taskpad-open-url",
+ "applications-internet",
+ N_("Open _Web Page"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_calendar_taskpad_open_url_cb) },
+};
+
+static GtkActionEntry lockdown_printing_entries[] = {
+
+ { "calendar-taskpad-print",
+ GTK_STOCK_PRINT,
+ NULL,
+ NULL,
+ N_("Print the selected task"),
+ G_CALLBACK (action_calendar_taskpad_print_cb) }
+};
+
+static GtkActionEntry lockdown_save_to_disk_entries[] = {
+
+ { "calendar-taskpad-save-as",
+ GTK_STOCK_SAVE_AS,
+ N_("_Save as iCalendar..."),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_calendar_taskpad_save_as_cb) }
+};
+
+void
+e_cal_shell_view_taskpad_actions_init (ECalShellView *cal_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ GtkActionGroup *action_group;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ /* Calendar Actions */
+ action_group = ACTION_GROUP (CALENDAR);
+ gtk_action_group_add_actions (
+ action_group, calendar_taskpad_entries,
+ G_N_ELEMENTS (calendar_taskpad_entries), cal_shell_view);
+
+ /* Lockdown Printing Actions */
+ action_group = ACTION_GROUP (LOCKDOWN_PRINTING);
+ gtk_action_group_add_actions (
+ action_group, lockdown_printing_entries,
+ G_N_ELEMENTS (lockdown_printing_entries), cal_shell_view);
+
+ /* Lockdown Save-to-Disk Actions */
+ action_group = ACTION_GROUP (LOCKDOWN_SAVE_TO_DISK);
+ gtk_action_group_add_actions (
+ action_group, lockdown_save_to_disk_entries,
+ G_N_ELEMENTS (lockdown_save_to_disk_entries), cal_shell_view);
+}
+
+void
+e_cal_shell_view_taskpad_actions_update (ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ ETaskTable *task_table;
+ GtkAction *action;
+ GSList *list, *iter;
+ gboolean assignable = TRUE;
+ gboolean editable = TRUE;
+ gboolean has_url = FALSE;
+ gboolean sensitive;
+ gint n_selected;
+ gint n_complete = 0;
+ gint n_incomplete = 0;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ task_table = e_cal_shell_content_get_task_table (cal_shell_content);
+
+ n_selected = e_table_selected_count (E_TABLE (task_table));
+
+ list = e_task_table_get_selected (task_table);
+ for (iter = list; iter != NULL; iter = iter->next) {
+ ECalModelComponent *comp_data = iter->data;
+ icalproperty *prop;
+ const gchar *cap;
+ gboolean read_only;
+
+ read_only = e_client_is_readonly (E_CLIENT (comp_data->client));
+ editable &= !read_only;
+
+ cap = CAL_STATIC_CAPABILITY_NO_TASK_ASSIGNMENT;
+ if (e_client_check_capability (E_CLIENT (comp_data->client), cap))
+ assignable = FALSE;
+
+ cap = CAL_STATIC_CAPABILITY_NO_CONV_TO_ASSIGN_TASK;
+ if (e_client_check_capability (E_CLIENT (comp_data->client), cap))
+ assignable = FALSE;
+
+ prop = icalcomponent_get_first_property (
+ comp_data->icalcomp, ICAL_URL_PROPERTY);
+ has_url |= (prop != NULL);
+
+ prop = icalcomponent_get_first_property (
+ comp_data->icalcomp, ICAL_COMPLETED_PROPERTY);
+ if (prop != NULL)
+ n_complete++;
+ else
+ n_incomplete++;
+ }
+ g_slist_free (list);
+
+ action = ACTION (CALENDAR_TASKPAD_ASSIGN);
+ sensitive = (n_selected == 1) && editable && assignable;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_TASKPAD_FORWARD);
+ sensitive = (n_selected == 1);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_TASKPAD_MARK_COMPLETE);
+ sensitive = (n_selected > 0) && editable && (n_incomplete > 0);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_TASKPAD_MARK_INCOMPLETE);
+ sensitive = (n_selected > 0) && editable && (n_complete > 0);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_TASKPAD_OPEN);
+ sensitive = (n_selected == 1);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_TASKPAD_OPEN_URL);
+ sensitive = (n_selected == 1) && has_url;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_TASKPAD_PRINT);
+ sensitive = (n_selected == 1);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_TASKPAD_SAVE_AS);
+ sensitive = (n_selected == 1);
+ gtk_action_set_sensitive (action, sensitive);
+}
+
+void
+e_cal_shell_view_taskpad_open_task (ECalShellView *cal_shell_view,
+ ECalModelComponent *comp_data)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ESourceRegistry *registry;
+ CompEditor *editor;
+ CompEditorFlags flags = 0;
+ ECalComponent *comp;
+ icalcomponent *clone;
+ icalproperty *prop;
+ const gchar *uid;
+
+ g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
+ g_return_if_fail (E_IS_CAL_MODEL_COMPONENT (comp_data));
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ registry = e_shell_get_registry (shell);
+
+ uid = icalcomponent_get_uid (comp_data->icalcomp);
+ editor = comp_editor_find_instance (uid);
+
+ if (editor != NULL)
+ goto exit;
+
+ comp = e_cal_component_new ();
+ clone = icalcomponent_new_clone (comp_data->icalcomp);
+ e_cal_component_set_icalcomponent (comp, clone);
+
+ prop = icalcomponent_get_first_property (
+ comp_data->icalcomp, ICAL_ATTENDEE_PROPERTY);
+ if (prop != NULL)
+ flags |= COMP_EDITOR_IS_ASSIGNED;
+
+ if (itip_organizer_is_user (registry, comp, comp_data->client))
+ flags |= COMP_EDITOR_USER_ORG;
+
+ if (!e_cal_component_has_attendees (comp))
+ flags |= COMP_EDITOR_USER_ORG;
+
+ editor = task_editor_new (comp_data->client, shell, flags);
+ comp_editor_edit_comp (editor, comp);
+
+ g_object_unref (comp);
+
+ if (flags & COMP_EDITOR_IS_ASSIGNED)
+ task_editor_show_assignment (TASK_EDITOR (editor));
+
+exit:
+ gtk_window_present (GTK_WINDOW (editor));
+}
+
+void
+e_cal_shell_view_taskpad_set_status_message (ECalShellView *cal_shell_view,
+ const gchar *status_message,
+ gdouble percent)
+{
+ EActivity *activity;
+ EShellView *shell_view;
+ EShellBackend *shell_backend;
+
+ g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+
+ activity = cal_shell_view->priv->taskpad_activity;
+
+ if (status_message == NULL || *status_message == '\0') {
+ if (activity != NULL) {
+ e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
+ g_object_unref (activity);
+ activity = NULL;
+ }
+
+ } else if (activity == NULL) {
+ activity = e_activity_new ();
+ e_activity_set_percent (activity, percent);
+ e_activity_set_text (activity, status_message);
+ e_shell_backend_add_activity (shell_backend, activity);
+
+ } else {
+ e_activity_set_percent (activity, percent);
+ e_activity_set_text (activity, status_message);
+ }
+
+ cal_shell_view->priv->taskpad_activity = activity;
+}
diff --git a/modules/calendar/e-cal-shell-view.c b/modules/calendar/e-cal-shell-view.c
new file mode 100644
index 0000000000..624647bafb
--- /dev/null
+++ b/modules/calendar/e-cal-shell-view.c
@@ -0,0 +1,632 @@
+/*
+ * e-cal-shell-view.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-cal-shell-view-private.h"
+
+#include "calendar/gui/calendar-view.h"
+
+G_DEFINE_DYNAMIC_TYPE (
+ ECalShellView,
+ e_cal_shell_view,
+ E_TYPE_SHELL_VIEW)
+
+static void
+cal_shell_view_add_action_button (GtkBox *box,
+ GtkAction *action)
+{
+ GtkWidget *button, *icon;
+
+ button = gtk_button_new ();
+ icon = gtk_action_create_icon (action, GTK_ICON_SIZE_BUTTON);
+ gtk_button_set_image (GTK_BUTTON (button), icon);
+ gtk_box_pack_start (box, button, FALSE, FALSE, 0);
+ gtk_widget_show (button);
+
+ g_object_bind_property (
+ action, "visible",
+ button, "visible",
+ G_BINDING_SYNC_CREATE);
+
+ g_object_bind_property (
+ action, "sensitive",
+ button, "sensitive",
+ G_BINDING_SYNC_CREATE);
+
+ g_object_bind_property (
+ action, "tooltip",
+ button, "tooltip-text",
+ G_BINDING_SYNC_CREATE);
+
+ g_signal_connect_swapped (
+ button, "clicked",
+ G_CALLBACK (gtk_action_activate), action);
+}
+
+static void
+cal_shell_view_prepare_for_quit_cb (EShell *shell,
+ EActivity *activity,
+ ECalShellView *cal_shell_view)
+{
+ g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
+
+ /* Stop running searches, if any; the activity tight
+ * on the search prevents application from quitting. */
+ e_cal_shell_view_search_stop (cal_shell_view);
+}
+
+static void
+cal_shell_view_dispose (GObject *object)
+{
+ e_cal_shell_view_private_dispose (E_CAL_SHELL_VIEW (object));
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_cal_shell_view_parent_class)->dispose (object);
+}
+
+static void
+cal_shell_view_finalize (GObject *object)
+{
+ e_cal_shell_view_private_finalize (E_CAL_SHELL_VIEW (object));
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_cal_shell_view_parent_class)->finalize (object);
+}
+
+static void
+cal_shell_view_constructed (GObject *object)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellSearchbar *searchbar;
+ ECalShellView *cal_shell_view;
+ ECalShellContent *cal_shell_content;
+ GtkWidget *container;
+ GtkWidget *widget;
+ gulong handler_id;
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_cal_shell_view_parent_class)->constructed (object);
+
+ cal_shell_view = E_CAL_SHELL_VIEW (object);
+ e_cal_shell_view_private_constructed (cal_shell_view);
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ searchbar = e_cal_shell_content_get_searchbar (cal_shell_content);
+ container = e_shell_searchbar_get_search_box (searchbar);
+
+ widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ cal_shell_view_add_action_button (
+ GTK_BOX (widget), ACTION (CALENDAR_SEARCH_PREV));
+ cal_shell_view_add_action_button (
+ GTK_BOX (widget), ACTION (CALENDAR_SEARCH_NEXT));
+ cal_shell_view_add_action_button (
+ GTK_BOX (widget), ACTION (CALENDAR_SEARCH_STOP));
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ gtk_widget_show (widget);
+
+ handler_id = g_signal_connect (
+ shell, "prepare-for-quit",
+ G_CALLBACK (cal_shell_view_prepare_for_quit_cb),
+ cal_shell_view);
+
+ cal_shell_view->priv->shell = g_object_ref (shell);
+ cal_shell_view->priv->prepare_for_quit_handler_id = handler_id;
+}
+
+static void
+cal_shell_view_execute_search (EShellView *shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ ECalShellSidebar *cal_shell_sidebar;
+ EShellWindow *shell_window;
+ EShellContent *shell_content;
+ EShellSidebar *shell_sidebar;
+ EShellSearchbar *searchbar;
+ EActionComboBox *combo_box;
+ GnomeCalendar *calendar;
+ ECalendar *date_navigator;
+ ECalModel *model;
+ GtkRadioAction *action;
+ icaltimezone *timezone;
+ const gchar *default_tzloc = NULL;
+ struct icaltimetype current_time;
+ time_t start_range;
+ time_t end_range;
+ time_t now_time;
+ gboolean range_search;
+ gchar *start, *end;
+ gchar *query;
+ gchar *temp;
+ gint value;
+
+ e_cal_shell_view_search_stop (E_CAL_SHELL_VIEW (shell_view));
+
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell_content = e_shell_view_get_shell_content (shell_view);
+ shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+
+ cal_shell_content = E_CAL_SHELL_CONTENT (shell_content);
+ cal_shell_sidebar = E_CAL_SHELL_SIDEBAR (shell_sidebar);
+
+ searchbar = e_cal_shell_content_get_searchbar (cal_shell_content);
+
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ model = gnome_calendar_get_model (calendar);
+ timezone = e_cal_model_get_timezone (model);
+ current_time = icaltime_current_time_with_zone (timezone);
+ now_time = time_day_begin (icaltime_as_timet (current_time));
+
+ if (timezone && timezone != icaltimezone_get_utc_timezone ())
+ default_tzloc = icaltimezone_get_location (timezone);
+ if (!default_tzloc)
+ default_tzloc = "";
+
+ action = GTK_RADIO_ACTION (ACTION (CALENDAR_SEARCH_ANY_FIELD_CONTAINS));
+ value = gtk_radio_action_get_current_value (action);
+
+ if (value == CALENDAR_SEARCH_ADVANCED) {
+ query = e_shell_view_get_search_query (shell_view);
+
+ if (!query)
+ query = g_strdup ("");
+ } else {
+ const gchar *format;
+ const gchar *text;
+ GString *string;
+
+ text = e_shell_searchbar_get_search_text (searchbar);
+
+ if (text == NULL || *text == '\0') {
+ text = "";
+ value = CALENDAR_SEARCH_SUMMARY_CONTAINS;
+ }
+
+ switch (value) {
+ default:
+ text = "";
+ /* fall through */
+
+ case CALENDAR_SEARCH_SUMMARY_CONTAINS:
+ format = "(contains? \"summary\" %s)";
+ break;
+
+ case CALENDAR_SEARCH_DESCRIPTION_CONTAINS:
+ format = "(contains? \"description\" %s)";
+ break;
+
+ case CALENDAR_SEARCH_ANY_FIELD_CONTAINS:
+ format = "(contains? \"any\" %s)";
+ break;
+ }
+
+ /* Build the query. */
+ string = g_string_new ("");
+ e_sexp_encode_string (string, text);
+ query = g_strdup_printf (format, string->str);
+ g_string_free (string, TRUE);
+ }
+
+ range_search = FALSE;
+ start_range = end_range = 0;
+
+ /* Apply selected filter. */
+ combo_box = e_shell_searchbar_get_filter_combo_box (searchbar);
+ value = e_action_combo_box_get_current_value (combo_box);
+ switch (value) {
+ case CALENDAR_FILTER_ANY_CATEGORY:
+ break;
+
+ case CALENDAR_FILTER_UNMATCHED:
+ temp = g_strdup_printf (
+ "(and (has-categories? #f) %s)", query);
+ g_free (query);
+ query = temp;
+ break;
+
+ case CALENDAR_FILTER_ACTIVE_APPOINTMENTS:
+ /* Show a year's worth of appointments. */
+ start_range = now_time;
+ end_range = time_day_end (time_add_day (start_range, 365));
+ start = isodate_from_time_t (start_range);
+ end = isodate_from_time_t (end_range);
+
+ temp = g_strdup_printf (
+ "(and %s (occur-in-time-range? "
+ "(make-time \"%s\") "
+ "(make-time \"%s\") \"%s\"))",
+ query, start, end, default_tzloc);
+ g_free (query);
+ query = temp;
+
+ range_search = TRUE;
+ break;
+
+ case CALENDAR_FILTER_NEXT_7_DAYS_APPOINTMENTS:
+ start_range = now_time;
+ end_range = time_day_end (time_add_day (start_range, 7));
+ start = isodate_from_time_t (start_range);
+ end = isodate_from_time_t (end_range);
+
+ temp = g_strdup_printf (
+ "(and %s (occur-in-time-range? "
+ "(make-time \"%s\") "
+ "(make-time \"%s\") \"%s\"))",
+ query, start, end, default_tzloc);
+ g_free (query);
+ query = temp;
+
+ range_search = TRUE;
+ break;
+
+ case CALENDAR_FILTER_OCCURS_LESS_THAN_5_TIMES:
+ temp = g_strdup_printf (
+ "(and %s (< (occurrences-count?) 5))", query);
+ g_free (query);
+ query = temp;
+ break;
+
+ default:
+ {
+ GList *categories;
+ const gchar *category_name;
+
+ categories = e_util_get_searchable_categories ();
+ category_name = g_list_nth_data (categories, value);
+ g_list_free (categories);
+
+ temp = g_strdup_printf (
+ "(and (has-categories? \"%s\") %s)",
+ category_name, query);
+ g_free (query);
+ query = temp;
+ break;
+ }
+ }
+
+ date_navigator = e_cal_shell_sidebar_get_date_navigator (cal_shell_sidebar);
+
+ if (range_search) {
+ /* Switch to list view and hide the date navigator. */
+ action = GTK_RADIO_ACTION (ACTION (CALENDAR_VIEW_LIST));
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
+ gtk_widget_hide (GTK_WIDGET (date_navigator));
+ } else {
+ /* Ensure the date navigator is visible. */
+ gtk_widget_show (GTK_WIDGET (date_navigator));
+ }
+
+ /* Submit the query. */
+ gnome_calendar_set_search_query (
+ calendar, query, range_search, start_range, end_range);
+ g_free (query);
+
+ /* Update actions so Find Prev/Next/Stop
+ * buttons will be sensitive as expected. */
+ e_shell_view_update_actions (shell_view);
+}
+
+static void
+cal_shell_view_update_actions (EShellView *shell_view)
+{
+ ECalShellViewPrivate *priv;
+ ECalShellContent *cal_shell_content;
+ EShellContent *shell_content;
+ EShellSidebar *shell_sidebar;
+ EShellWindow *shell_window;
+ EShell *shell;
+ ESource *source;
+ ESourceRegistry *registry;
+ GnomeCalendar *calendar;
+ ECalendarView *cal_view;
+ EMemoTable *memo_table;
+ ETaskTable *task_table;
+ ECalModel *model;
+ GtkAction *action;
+ const gchar *model_sexp;
+ gboolean is_searching;
+ gboolean sensitive;
+ guint32 state;
+
+ /* Be descriptive. */
+ gboolean any_events_selected;
+ gboolean has_mail_identity = FALSE;
+ gboolean has_primary_source;
+ gboolean primary_source_is_writable;
+ gboolean primary_source_is_removable;
+ gboolean primary_source_is_remote_deletable;
+ gboolean primary_source_in_collection;
+ gboolean multiple_events_selected;
+ gboolean selection_is_editable;
+ gboolean selection_is_instance;
+ gboolean selection_is_meeting;
+ gboolean selection_is_recurring;
+ gboolean selection_can_delegate;
+ gboolean single_event_selected;
+ gboolean refresh_supported;
+
+ /* Chain up to parent's update_actions() method. */
+ E_SHELL_VIEW_CLASS (e_cal_shell_view_parent_class)->
+ update_actions (shell_view);
+
+ priv = E_CAL_SHELL_VIEW_GET_PRIVATE (shell_view);
+
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ registry = e_shell_get_registry (shell);
+ source = e_source_registry_ref_default_mail_identity (registry);
+ has_mail_identity = (source != NULL);
+ if (source != NULL) {
+ has_mail_identity = TRUE;
+ g_object_unref (source);
+ }
+
+ cal_shell_content = priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ cal_view = gnome_calendar_get_calendar_view (calendar, gnome_calendar_get_view (calendar));
+ memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
+ task_table = e_cal_shell_content_get_task_table (cal_shell_content);
+ model = gnome_calendar_get_model (calendar);
+ model_sexp = e_cal_model_get_search_query (model);
+ is_searching = model_sexp && *model_sexp &&
+ g_strcmp0 (model_sexp, "#t") != 0 &&
+ g_strcmp0 (model_sexp, "(contains? \"summary\" \"\")") != 0;
+
+ shell_content = e_shell_view_get_shell_content (shell_view);
+ state = e_shell_content_check_state (shell_content);
+
+ single_event_selected =
+ (state & E_CAL_SHELL_CONTENT_SELECTION_SINGLE);
+ multiple_events_selected =
+ (state & E_CAL_SHELL_CONTENT_SELECTION_MULTIPLE);
+ selection_is_editable =
+ (state & E_CAL_SHELL_CONTENT_SELECTION_IS_EDITABLE);
+ selection_is_instance =
+ (state & E_CAL_SHELL_CONTENT_SELECTION_IS_INSTANCE);
+ selection_is_meeting =
+ (state & E_CAL_SHELL_CONTENT_SELECTION_IS_MEETING);
+ selection_is_recurring =
+ (state & E_CAL_SHELL_CONTENT_SELECTION_IS_RECURRING);
+ selection_can_delegate =
+ (state & E_CAL_SHELL_CONTENT_SELECTION_CAN_DELEGATE);
+
+ shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+ state = e_shell_sidebar_check_state (shell_sidebar);
+
+ has_primary_source =
+ (state & E_CAL_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE);
+ primary_source_is_writable =
+ (state & E_CAL_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_WRITABLE);
+ primary_source_is_removable =
+ (state & E_CAL_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOVABLE);
+ primary_source_is_remote_deletable =
+ (state & E_CAL_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_DELETABLE);
+ primary_source_in_collection =
+ (state & E_CAL_SHELL_SIDEBAR_PRIMARY_SOURCE_IN_COLLECTION);
+ refresh_supported =
+ (state & E_CAL_SHELL_SIDEBAR_SOURCE_SUPPORTS_REFRESH);
+
+ any_events_selected =
+ (single_event_selected || multiple_events_selected);
+
+ action = ACTION (CALENDAR_COPY);
+ sensitive = has_primary_source;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_DELETE);
+ sensitive =
+ primary_source_is_removable ||
+ primary_source_is_remote_deletable;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_PROPERTIES);
+ sensitive = primary_source_is_writable;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_REFRESH);
+ sensitive = refresh_supported;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_RENAME);
+ sensitive =
+ primary_source_is_writable &&
+ !primary_source_in_collection;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_SEARCH_PREV);
+ gtk_action_set_sensitive (action, is_searching);
+
+ action = ACTION (CALENDAR_SEARCH_NEXT);
+ gtk_action_set_sensitive (action, is_searching);
+
+ action = ACTION (CALENDAR_SEARCH_STOP);
+ sensitive = is_searching && priv->searching_activity != NULL;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (EVENT_DELEGATE);
+ sensitive =
+ single_event_selected &&
+ selection_is_editable &&
+ selection_can_delegate &&
+ selection_is_meeting;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (EVENT_DELETE);
+ sensitive =
+ any_events_selected &&
+ selection_is_editable &&
+ !selection_is_recurring;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (EVENT_DELETE_OCCURRENCE);
+ sensitive =
+ any_events_selected &&
+ selection_is_editable &&
+ selection_is_recurring;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (EVENT_DELETE_OCCURRENCE_ALL);
+ sensitive =
+ any_events_selected &&
+ selection_is_editable &&
+ selection_is_recurring;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (EVENT_FORWARD);
+ sensitive = single_event_selected;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (EVENT_OCCURRENCE_MOVABLE);
+ sensitive =
+ single_event_selected &&
+ selection_is_editable &&
+ selection_is_recurring &&
+ selection_is_instance;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (EVENT_OPEN);
+ sensitive = single_event_selected;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (EVENT_PRINT);
+ sensitive = single_event_selected;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (EVENT_SAVE_AS);
+ sensitive = single_event_selected;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (EVENT_SCHEDULE);
+ sensitive =
+ single_event_selected &&
+ selection_is_editable &&
+ !selection_is_meeting;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (EVENT_SCHEDULE_APPOINTMENT);
+ sensitive =
+ single_event_selected &&
+ selection_is_editable &&
+ selection_is_meeting;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (EVENT_REPLY);
+ sensitive = single_event_selected && selection_is_meeting;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (EVENT_REPLY_ALL);
+ sensitive = single_event_selected && selection_is_meeting;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (EVENT_MEETING_NEW);
+ gtk_action_set_visible (action, has_mail_identity);
+
+ if ((cal_view && e_calendar_view_is_editing (cal_view)) ||
+ e_table_is_editing (E_TABLE (memo_table)) ||
+ e_table_is_editing (E_TABLE (task_table))) {
+ EFocusTracker *focus_tracker;
+
+ /* disable all clipboard actions, if any of the views is in editing mode */
+ focus_tracker = e_shell_window_get_focus_tracker (shell_window);
+
+ action = e_focus_tracker_get_cut_clipboard_action (focus_tracker);
+ if (action)
+ gtk_action_set_sensitive (action, FALSE);
+
+ action = e_focus_tracker_get_copy_clipboard_action (focus_tracker);
+ if (action)
+ gtk_action_set_sensitive (action, FALSE);
+
+ action = e_focus_tracker_get_paste_clipboard_action (focus_tracker);
+ if (action)
+ gtk_action_set_sensitive (action, FALSE);
+
+ action = e_focus_tracker_get_delete_selection_action (focus_tracker);
+ if (action)
+ gtk_action_set_sensitive (action, FALSE);
+ }
+}
+
+static void
+e_cal_shell_view_class_init (ECalShellViewClass *class)
+{
+ GObjectClass *object_class;
+ EShellViewClass *shell_view_class;
+
+ g_type_class_add_private (class, sizeof (ECalShellViewPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = cal_shell_view_dispose;
+ object_class->finalize = cal_shell_view_finalize;
+ object_class->constructed = cal_shell_view_constructed;
+
+ shell_view_class = E_SHELL_VIEW_CLASS (class);
+ shell_view_class->label = _("Calendar");
+ shell_view_class->icon_name = "x-office-calendar";
+ shell_view_class->ui_definition = "evolution-calendars.ui";
+ shell_view_class->ui_manager_id = "org.gnome.evolution.calendars";
+ shell_view_class->search_options = "/calendar-search-options";
+ shell_view_class->search_rules = "caltypes.xml";
+ shell_view_class->new_shell_content = e_cal_shell_content_new;
+ shell_view_class->new_shell_sidebar = e_cal_shell_sidebar_new;
+ shell_view_class->execute_search = cal_shell_view_execute_search;
+ shell_view_class->update_actions = cal_shell_view_update_actions;
+
+ /* Ensure the GalView types we need are registered. */
+ g_type_ensure (GAL_TYPE_VIEW_CALENDAR_DAY);
+ g_type_ensure (GAL_TYPE_VIEW_CALENDAR_WORK_WEEK);
+ g_type_ensure (GAL_TYPE_VIEW_CALENDAR_WEEK);
+ g_type_ensure (GAL_TYPE_VIEW_CALENDAR_MONTH);
+ g_type_ensure (GAL_TYPE_VIEW_ETABLE);
+}
+
+static void
+e_cal_shell_view_class_finalize (ECalShellViewClass *class)
+{
+}
+
+static void
+e_cal_shell_view_init (ECalShellView *cal_shell_view)
+{
+ cal_shell_view->priv =
+ E_CAL_SHELL_VIEW_GET_PRIVATE (cal_shell_view);
+
+ e_cal_shell_view_private_init (cal_shell_view);
+}
+
+void
+e_cal_shell_view_type_register (GTypeModule *type_module)
+{
+ /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
+ * function, so we have to wrap it with a public function in
+ * order to register types from a separate compilation unit. */
+ e_cal_shell_view_register_type (type_module);
+}
+
diff --git a/modules/calendar/e-cal-shell-view.h b/modules/calendar/e-cal-shell-view.h
new file mode 100644
index 0000000000..312033221e
--- /dev/null
+++ b/modules/calendar/e-cal-shell-view.h
@@ -0,0 +1,66 @@
+/*
+ * e-cal-shell-view.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_CAL_SHELL_VIEW_H
+#define E_CAL_SHELL_VIEW_H
+
+#include <shell/e-shell-view.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CAL_SHELL_VIEW \
+ (e_cal_shell_view_get_type ())
+#define E_CAL_SHELL_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_CAL_SHELL_VIEW, ECalShellView))
+#define E_CAL_SHELL_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_CAL_SHELL_VIEW, ECalShellViewClass))
+#define E_IS_CAL_SHELL_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_CAL_SHELL_VIEW))
+#define E_IS_CAL_SHELL_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_CAL_SHELL_VIEW))
+#define E_CAL_SHELL_VIEW_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_CAL_SHELL_VIEW, ECalShellViewClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ECalShellView ECalShellView;
+typedef struct _ECalShellViewClass ECalShellViewClass;
+typedef struct _ECalShellViewPrivate ECalShellViewPrivate;
+
+struct _ECalShellView {
+ EShellView parent;
+ ECalShellViewPrivate *priv;
+};
+
+struct _ECalShellViewClass {
+ EShellViewClass parent_class;
+};
+
+GType e_cal_shell_view_get_type (void);
+void e_cal_shell_view_type_register (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* E_CAL_SHELL_VIEW_H */
diff --git a/modules/calendar/e-calendar-preferences.c b/modules/calendar/e-calendar-preferences.c
new file mode 100644
index 0000000000..7e1f458b8d
--- /dev/null
+++ b/modules/calendar/e-calendar-preferences.c
@@ -0,0 +1,972 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Damon Chaplin <damon@ximian.com>
+ * Ettore Perazzoli <ettore@ximian.com>
+ * David Trowbridge <trowbrds cs colorado edu>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-calendar-preferences.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+
+#include "calendar/gui/e-cal-config.h"
+#include "calendar/gui/e-timezone-entry.h"
+#include "calendar/gui/calendar-config.h"
+#include "shell/e-shell-utils.h"
+
+/* same is used for Birthdays & Anniversaries calendar */
+static const gint default_reminder_units_map[] = {
+ E_DURATION_MINUTES, E_DURATION_HOURS, E_DURATION_DAYS, -1
+};
+
+G_DEFINE_DYNAMIC_TYPE (
+ ECalendarPreferences,
+ e_calendar_preferences,
+ GTK_TYPE_VBOX)
+
+static gboolean
+calendar_preferences_map_string_to_integer (GValue *value,
+ GVariant *variant,
+ gpointer user_data)
+{
+ GEnumClass *enum_class = G_ENUM_CLASS (user_data);
+ GEnumValue *enum_value;
+ const gchar *nick;
+
+ /* XXX GSettings should know how to bind enum settings to
+ * integer properties. I filed a bug asking for this:
+ * https://bugzilla.gnome.org/show_bug.cgi?id=695217 */
+
+ nick = g_variant_get_string (variant, NULL);
+ enum_value = g_enum_get_value_by_nick (enum_class, nick);
+ g_return_val_if_fail (enum_value != NULL, FALSE);
+ g_value_set_int (value, enum_value->value);
+
+ return TRUE;
+}
+
+static GVariant *
+calendar_preferences_map_integer_to_string (const GValue *value,
+ const GVariantType *expected_type,
+ gpointer user_data)
+{
+ GEnumClass *enum_class = G_ENUM_CLASS (user_data);
+ GEnumValue *enum_value;
+
+ /* XXX GSettings should know how to bind enum settings to
+ * integer properties. I filed a bug asking for this:
+ * https://bugzilla.gnome.org/show_bug.cgi?id=695217 */
+
+ enum_value = g_enum_get_value (enum_class, g_value_get_int (value));
+ g_return_val_if_fail (enum_value != NULL, NULL);
+
+ return g_variant_new_string (enum_value->value_nick);
+}
+
+static gboolean
+calendar_preferences_map_string_to_icaltimezone (GValue *value,
+ GVariant *variant,
+ gpointer user_data)
+{
+ GSettings *settings;
+ const gchar *location = NULL;
+ icaltimezone *timezone = NULL;
+
+ settings = g_settings_new ("org.gnome.evolution.calendar");
+
+ if (g_settings_get_boolean (settings, "use-system-timezone"))
+ timezone = e_cal_util_get_system_timezone ();
+ else
+ location = g_variant_get_string (variant, NULL);
+
+ if (location != NULL && *location != '\0')
+ timezone = icaltimezone_get_builtin_timezone (location);
+
+ if (timezone == NULL)
+ timezone = icaltimezone_get_utc_timezone ();
+
+ g_value_set_pointer (value, timezone);
+
+ g_object_unref (settings);
+
+ return TRUE;
+}
+
+static GVariant *
+calendar_preferences_map_icaltimezone_to_string (const GValue *value,
+ const GVariantType *expected_type,
+ gpointer user_data)
+{
+ GVariant *variant;
+ GSettings *settings;
+ const gchar *location = NULL;
+ gchar *location_str = NULL;
+ icaltimezone *timezone;
+
+ settings = g_settings_new ("org.gnome.evolution.calendar");
+
+ if (g_settings_get_boolean (settings, "use-system-timezone")) {
+ location_str = g_settings_get_string (settings, "timezone");
+ location = location_str;
+ } else {
+ timezone = g_value_get_pointer (value);
+
+ if (timezone != NULL)
+ location = icaltimezone_get_location (timezone);
+ }
+
+ if (location == NULL)
+ location = "UTC";
+
+ variant = g_variant_new_string (location);
+
+ g_free (location_str);
+
+ g_object_unref (settings);
+
+ return variant;
+}
+
+static gboolean
+calendar_preferences_map_time_divisions_to_index (GValue *value,
+ GVariant *variant,
+ gpointer user_data)
+{
+ gboolean success = TRUE;
+
+ switch (g_variant_get_int32 (variant)) {
+ case 60:
+ g_value_set_int (value, 0);
+ break;
+ case 30:
+ g_value_set_int (value, 1);
+ break;
+ case 15:
+ g_value_set_int (value, 2);
+ break;
+ case 10:
+ g_value_set_int (value, 3);
+ break;
+ case 5:
+ g_value_set_int (value, 4);
+ break;
+ default:
+ success = FALSE;
+ }
+
+ return success;
+}
+
+static GVariant *
+calendar_preferences_map_index_to_time_divisions (const GValue *value,
+ const GVariantType *expected_type,
+ gpointer user_data)
+{
+ switch (g_value_get_int (value)) {
+ case 0:
+ return g_variant_new_int32 (60);
+ case 1:
+ return g_variant_new_int32 (30);
+ case 2:
+ return g_variant_new_int32 (15);
+ case 3:
+ return g_variant_new_int32 (10);
+ case 4:
+ return g_variant_new_int32 (5);
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+static gboolean
+calendar_preferences_map_string_to_gdk_color (GValue *value,
+ GVariant *variant,
+ gpointer user_data)
+{
+ GdkColor color;
+ const gchar *string;
+ gboolean success = FALSE;
+
+ string = g_variant_get_string (variant, NULL);
+ if (gdk_color_parse (string, &color)) {
+ g_value_set_boxed (value, &color);
+ success = TRUE;
+ }
+
+ return success;
+}
+
+static GVariant *
+calendar_preferences_map_gdk_color_to_string (const GValue *value,
+ const GVariantType *expected_type,
+ gpointer user_data)
+{
+ GVariant *variant;
+ const GdkColor *color;
+
+ color = g_value_get_boxed (value);
+ if (color == NULL) {
+ variant = g_variant_new_string ("");
+ } else {
+ gchar *string;
+
+ string = gdk_color_to_string (color);
+ variant = g_variant_new_string (string);
+ g_free (string);
+ }
+
+ return variant;
+}
+
+static void
+calendar_preferences_dispose (GObject *object)
+{
+ ECalendarPreferences *prefs = (ECalendarPreferences *) object;
+
+ if (prefs->builder != NULL) {
+ g_object_unref (prefs->builder);
+ prefs->builder = NULL;
+ }
+
+ if (prefs->registry != NULL) {
+ g_object_unref (prefs->registry);
+ prefs->registry = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_calendar_preferences_parent_class)->dispose (object);
+}
+
+static void
+e_calendar_preferences_class_init (ECalendarPreferencesClass *class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = calendar_preferences_dispose;
+}
+
+static void
+e_calendar_preferences_class_finalize (ECalendarPreferencesClass *class)
+{
+}
+
+static void
+e_calendar_preferences_init (ECalendarPreferences *preferences)
+{
+}
+
+static GtkWidget *
+calendar_preferences_get_config_widget (EConfig *ec,
+ EConfigItem *item,
+ GtkWidget *parent,
+ GtkWidget *old,
+ gint position,
+ gpointer data)
+{
+ ECalendarPreferences *preferences = data;
+
+ return e_builder_get_widget (preferences->builder, item->label);
+}
+
+static void
+update_day_second_zone_caption (ECalendarPreferences *prefs)
+{
+ gchar *location;
+ const gchar *caption;
+ icaltimezone *zone;
+
+ g_return_if_fail (prefs != NULL);
+
+ /* Translators: "None" indicates no second time zone set for a day view */
+ caption = C_("cal-second-zone", "None");
+
+ location = calendar_config_get_day_second_zone ();
+ if (location && *location) {
+ zone = icaltimezone_get_builtin_timezone (location);
+ if (zone && icaltimezone_get_display_name (zone)) {
+ caption = icaltimezone_get_display_name (zone);
+ }
+ }
+ g_free (location);
+
+ gtk_button_set_label (GTK_BUTTON (prefs->day_second_zone), caption);
+}
+
+static void
+on_set_day_second_zone (GtkWidget *item,
+ ECalendarPreferences *prefs)
+{
+ if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (item)))
+ return;
+
+ calendar_config_set_day_second_zone (g_object_get_data (G_OBJECT (item), "timezone"));
+ update_day_second_zone_caption (prefs);
+}
+
+static void
+on_select_day_second_zone (GtkWidget *item,
+ ECalendarPreferences *prefs)
+{
+ g_return_if_fail (prefs != NULL);
+
+ calendar_config_select_day_second_zone ();
+ update_day_second_zone_caption (prefs);
+}
+
+static void
+day_second_zone_clicked (GtkWidget *widget,
+ ECalendarPreferences *prefs)
+{
+ GtkWidget *menu, *item;
+ GSList *group = NULL, *recent_zones, *s;
+ gchar *location;
+ icaltimezone *zone, *second_zone = NULL;
+
+ menu = gtk_menu_new ();
+
+ location = calendar_config_get_day_second_zone ();
+ if (location && *location)
+ second_zone = icaltimezone_get_builtin_timezone (location);
+ g_free (location);
+
+ group = NULL;
+ item = gtk_radio_menu_item_new_with_label (group, C_("cal-second-zone", "None"));
+ group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item));
+ if (!second_zone)
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ g_signal_connect (
+ item, "toggled",
+ G_CALLBACK (on_set_day_second_zone), prefs);
+
+ recent_zones = calendar_config_get_day_second_zones ();
+ for (s = recent_zones; s != NULL; s = s->next) {
+ zone = icaltimezone_get_builtin_timezone (s->data);
+ if (!zone)
+ continue;
+
+ item = gtk_radio_menu_item_new_with_label (group, icaltimezone_get_display_name (zone));
+ group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item));
+ /* both comes from builtin, thus no problem to compare pointers */
+ if (zone == second_zone)
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+ g_object_set_data_full (G_OBJECT (item), "timezone", g_strdup (s->data), g_free);
+ g_signal_connect (
+ item, "toggled",
+ G_CALLBACK (on_set_day_second_zone), prefs);
+ }
+ calendar_config_free_day_second_zones (recent_zones);
+
+ item = gtk_separator_menu_item_new ();
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ item = gtk_menu_item_new_with_label (_("Select..."));
+ g_signal_connect (
+ item, "activate",
+ G_CALLBACK (on_select_day_second_zone), prefs);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ gtk_widget_show_all (menu);
+
+ gtk_menu_popup (
+ GTK_MENU (menu), NULL, NULL, NULL, NULL,
+ 0, gtk_get_current_event_time ());
+}
+
+static void
+start_of_day_changed (GtkWidget *widget,
+ ECalendarPreferences *prefs)
+{
+ EDateEdit *start, *end;
+ GSettings *settings;
+ gint start_hour;
+ gint start_minute;
+ gint end_hour;
+ gint end_minute;
+
+ start = E_DATE_EDIT (prefs->start_of_day);
+ end = E_DATE_EDIT (prefs->end_of_day);
+
+ e_date_edit_get_time_of_day (start, &start_hour, &start_minute);
+ e_date_edit_get_time_of_day (end, &end_hour, &end_minute);
+
+ if ((start_hour > end_hour) || (start_hour == end_hour && start_minute > end_minute)) {
+ if (start_hour < 23)
+ e_date_edit_set_time_of_day (end, start_hour + 1, start_minute);
+ else
+ e_date_edit_set_time_of_day (end, 23, 59);
+
+ return;
+ }
+
+ settings = g_settings_new ("org.gnome.evolution.calendar");
+
+ g_settings_set_int (settings, "day-start-hour", start_hour);
+ g_settings_set_int (settings, "day-start-minute", start_minute);
+
+ g_object_unref (settings);
+}
+
+static void
+end_of_day_changed (GtkWidget *widget,
+ ECalendarPreferences *prefs)
+{
+ EDateEdit *start, *end;
+ GSettings *settings;
+ gint start_hour;
+ gint start_minute;
+ gint end_hour;
+ gint end_minute;
+
+ start = E_DATE_EDIT (prefs->start_of_day);
+ end = E_DATE_EDIT (prefs->end_of_day);
+
+ e_date_edit_get_time_of_day (start, &start_hour, &start_minute);
+ e_date_edit_get_time_of_day (end, &end_hour, &end_minute);
+
+ if ((end_hour < start_hour) || (end_hour == start_hour && end_minute < start_minute)) {
+ if (end_hour < 1)
+ e_date_edit_set_time_of_day (start, 0, 0);
+ else
+ e_date_edit_set_time_of_day (start, end_hour - 1, end_minute);
+
+ return;
+ }
+
+ settings = g_settings_new ("org.gnome.evolution.calendar");
+
+ g_settings_set_int (settings, "day-end-hour", end_hour);
+ g_settings_set_int (settings, "day-end-minute", end_minute);
+
+ g_object_unref (settings);
+}
+
+static void
+update_system_tz_widgets (GtkCheckButton *button,
+ ECalendarPreferences *prefs)
+{
+ GtkWidget *widget;
+ icaltimezone *zone;
+ const gchar *display_name;
+ gchar *text;
+
+ widget = e_builder_get_widget (prefs->builder, "system-tz-label");
+ g_return_if_fail (GTK_IS_LABEL (widget));
+
+ zone = e_cal_util_get_system_timezone ();
+ if (zone != NULL)
+ display_name = gettext (icaltimezone_get_display_name (zone));
+ else
+ display_name = "UTC";
+
+ text = g_strdup_printf ("(%s)", display_name);
+ gtk_label_set_text (GTK_LABEL (widget), text);
+ g_free (text);
+}
+
+static void
+setup_changes (ECalendarPreferences *prefs)
+{
+ g_signal_connect (
+ prefs->day_second_zone, "clicked",
+ G_CALLBACK (day_second_zone_clicked), prefs);
+
+ g_signal_connect (
+ prefs->start_of_day, "changed",
+ G_CALLBACK (start_of_day_changed), prefs);
+
+ g_signal_connect (
+ prefs->end_of_day, "changed",
+ G_CALLBACK (end_of_day_changed), prefs);
+}
+
+static void
+show_alarms_config (ECalendarPreferences *prefs)
+{
+ GtkWidget *widget;
+
+ widget = e_alarm_selector_new (prefs->registry);
+ atk_object_set_name (
+ gtk_widget_get_accessible (widget),
+ _("Selected Calendars for Alarms"));
+ gtk_container_add (GTK_CONTAINER (prefs->scrolled_window), widget);
+ gtk_widget_show (widget);
+}
+
+/* Shows the current config settings in the dialog. */
+static void
+show_config (ECalendarPreferences *prefs)
+{
+ GSettings *settings;
+
+ settings = g_settings_new ("org.gnome.evolution.calendar");
+
+ /* Day's second zone */
+ update_day_second_zone_caption (prefs);
+
+ /* Start of Day. */
+ e_date_edit_set_time_of_day (
+ E_DATE_EDIT (prefs->start_of_day),
+ g_settings_get_int (settings, "day-start-hour"),
+ g_settings_get_int (settings, "day-start-minute"));
+
+ /* End of Day. */
+ e_date_edit_set_time_of_day (
+ E_DATE_EDIT (prefs->end_of_day),
+ g_settings_get_int (settings, "day-end-hour"),
+ g_settings_get_int (settings, "day-end-minute"));
+
+ /* Alarms list */
+ show_alarms_config (prefs);
+
+ g_object_unref (settings);
+}
+
+/* plugin meta-data */
+static ECalConfigItem eccp_items[] = {
+ { E_CONFIG_BOOK, (gchar *) "", (gchar *) "toplevel-notebook", calendar_preferences_get_config_widget },
+ { E_CONFIG_PAGE, (gchar *) "00.general", (gchar *) "general", calendar_preferences_get_config_widget },
+ { E_CONFIG_SECTION_TABLE, (gchar *) "00.general/00.time", (gchar *) "time", calendar_preferences_get_config_widget },
+ { E_CONFIG_SECTION_TABLE, (gchar *) "00.general/10.workWeek", (gchar *) "workWeek", calendar_preferences_get_config_widget },
+ { E_CONFIG_SECTION, (gchar *) "00.general/20.alerts", (gchar *) "alerts", calendar_preferences_get_config_widget },
+ { E_CONFIG_PAGE, (gchar *) "10.display", (gchar *) "display", calendar_preferences_get_config_widget },
+ { E_CONFIG_SECTION, (gchar *) "10.display/00.general", (gchar *) "displayGeneral", calendar_preferences_get_config_widget },
+ { E_CONFIG_SECTION, (gchar *) "10.display/10.taskList", (gchar *) "taskList", calendar_preferences_get_config_widget },
+ { E_CONFIG_PAGE, (gchar *) "12.tasks", (gchar *) "tasks-vbox", calendar_preferences_get_config_widget },
+ { E_CONFIG_PAGE, (gchar *) "15.alarms", (gchar *) "alarms", calendar_preferences_get_config_widget },
+ { E_CONFIG_PAGE, (gchar *) "20.freeBusy", (gchar *) "freebusy", calendar_preferences_get_config_widget },
+ { E_CONFIG_SECTION, (gchar *) "20.freeBusy/00.defaultServer", (gchar *) "default-freebusy-vbox", calendar_preferences_get_config_widget },
+};
+
+static void
+eccp_free (EConfig *ec,
+ GSList *items,
+ gpointer data)
+{
+ g_slist_free (items);
+}
+
+static void
+calendar_preferences_construct (ECalendarPreferences *prefs,
+ EShell *shell)
+{
+ ECalConfig *ec;
+ ECalConfigTargetPrefs *target;
+ GSettings *settings;
+ GSettings *eds_settings;
+ gboolean locale_supports_12_hour_format;
+ gint i;
+ GtkWidget *toplevel;
+ GtkWidget *widget;
+ GtkWidget *table;
+ GSList *l;
+
+ settings = g_settings_new ("org.gnome.evolution.calendar");
+
+ locale_supports_12_hour_format =
+ calendar_config_locale_supports_12_hour_format ();
+
+ /* Force 24 hour format for locales which don't support 12 hour format */
+ if (!locale_supports_12_hour_format)
+ g_settings_set_boolean (settings, "use-24hour-format", TRUE);
+
+ /* Make sure our custom widget classes are registered with
+ * GType before we load the GtkBuilder definition file. */
+ g_type_ensure (E_TYPE_DATE_EDIT);
+ g_type_ensure (E_TYPE_TIMEZONE_ENTRY);
+
+ prefs->builder = gtk_builder_new ();
+ e_load_ui_builder_definition (prefs->builder, "e-calendar-preferences.ui");
+
+ /** @HookPoint-ECalConfig: Calendar Preferences Page
+ * @Id: org.gnome.evolution.calendar.prefs
+ * @Class: org.gnome.evolution.calendar.config:1.0
+ * @Target: ECalConfigTargetPrefs
+ *
+ * The mail calendar preferences page
+ */
+ ec = e_cal_config_new ("org.gnome.evolution.calendar.prefs");
+ l = NULL;
+ for (i = 0; i < G_N_ELEMENTS (eccp_items); i++)
+ l = g_slist_prepend (l, &eccp_items[i]);
+ e_config_add_items ((EConfig *) ec, l, eccp_free, prefs);
+
+ widget = e_builder_get_widget (prefs->builder, "use-system-tz-check");
+ g_settings_bind (
+ settings, "use-system-timezone",
+ widget, "active",
+ G_SETTINGS_BIND_DEFAULT);
+ g_signal_connect (
+ widget, "toggled",
+ G_CALLBACK (update_system_tz_widgets), prefs);
+ update_system_tz_widgets (GTK_CHECK_BUTTON (widget), prefs);
+
+ widget = e_builder_get_widget (prefs->builder, "timezone");
+ g_settings_bind_with_mapping (
+ settings, "timezone",
+ widget, "timezone",
+ G_SETTINGS_BIND_DEFAULT,
+ calendar_preferences_map_string_to_icaltimezone,
+ calendar_preferences_map_icaltimezone_to_string,
+ NULL, (GDestroyNotify) NULL);
+ g_settings_bind (
+ settings, "use-system-timezone",
+ widget, "sensitive",
+ G_SETTINGS_BIND_DEFAULT |
+ G_SETTINGS_BIND_INVERT_BOOLEAN);
+
+ /* General tab */
+ prefs->day_second_zone = e_builder_get_widget (prefs->builder, "day_second_zone");
+
+ widget = e_builder_get_widget (prefs->builder, "sun_button");
+ g_settings_bind (
+ settings, "work-day-sunday",
+ widget, "active",
+ G_SETTINGS_BIND_DEFAULT);
+
+ widget = e_builder_get_widget (prefs->builder, "mon_button");
+ g_settings_bind (
+ settings, "work-day-monday",
+ widget, "active",
+ G_SETTINGS_BIND_DEFAULT);
+
+ widget = e_builder_get_widget (prefs->builder, "tue_button");
+ g_settings_bind (
+ settings, "work-day-tuesday",
+ widget, "active",
+ G_SETTINGS_BIND_DEFAULT);
+
+ widget = e_builder_get_widget (prefs->builder, "wed_button");
+ g_settings_bind (
+ settings, "work-day-wednesday",
+ widget, "active",
+ G_SETTINGS_BIND_DEFAULT);
+
+ widget = e_builder_get_widget (prefs->builder, "thu_button");
+ g_settings_bind (
+ settings, "work-day-thursday",
+ widget, "active",
+ G_SETTINGS_BIND_DEFAULT);
+
+ widget = e_builder_get_widget (prefs->builder, "fri_button");
+ g_settings_bind (
+ settings, "work-day-friday",
+ widget, "active",
+ G_SETTINGS_BIND_DEFAULT);
+
+ widget = e_builder_get_widget (prefs->builder, "sat_button");
+ g_settings_bind (
+ settings, "work-day-saturday",
+ widget, "active",
+ G_SETTINGS_BIND_DEFAULT);
+
+ widget = e_builder_get_widget (prefs->builder, "week_start_day");
+ g_settings_bind (
+ settings, "week-start-day-name",
+ widget, "active-id",
+ G_SETTINGS_BIND_DEFAULT);
+
+ widget = e_builder_get_widget (prefs->builder, "start_of_day");
+ prefs->start_of_day = widget; /* XXX delete this */
+ if (locale_supports_12_hour_format)
+ g_settings_bind (
+ settings, "use-24hour-format",
+ widget, "use-24-hour-format",
+ G_SETTINGS_BIND_GET);
+
+ widget = e_builder_get_widget (prefs->builder, "end_of_day");
+ prefs->end_of_day = widget; /* XXX delete this */
+ if (locale_supports_12_hour_format)
+ g_settings_bind (
+ settings, "use-24hour-format",
+ widget, "use-24-hour-format",
+ G_SETTINGS_BIND_GET);
+
+ widget = e_builder_get_widget (prefs->builder, "use_12_hour");
+ gtk_widget_set_sensitive (widget, locale_supports_12_hour_format);
+ g_settings_bind (
+ settings, "use-24hour-format",
+ widget, "active",
+ G_SETTINGS_BIND_DEFAULT |
+ G_SETTINGS_BIND_INVERT_BOOLEAN);
+
+ widget = e_builder_get_widget (prefs->builder, "use_24_hour");
+ gtk_widget_set_sensitive (widget, locale_supports_12_hour_format);
+ g_settings_bind (
+ settings, "use-24hour-format",
+ widget, "active",
+ G_SETTINGS_BIND_DEFAULT);
+
+ widget = e_builder_get_widget (prefs->builder, "confirm_delete");
+ g_settings_bind (
+ settings, "confirm-delete",
+ widget, "active",
+ G_SETTINGS_BIND_DEFAULT);
+
+ widget = e_builder_get_widget (prefs->builder, "default_reminder");
+ g_settings_bind (
+ settings, "use-default-reminder",
+ widget, "active",
+ G_SETTINGS_BIND_DEFAULT);
+
+ widget = e_builder_get_widget (prefs->builder, "default_reminder_interval");
+ g_settings_bind (
+ settings, "default-reminder-interval",
+ widget, "value",
+ G_SETTINGS_BIND_DEFAULT);
+ g_settings_bind (
+ settings, "use-default-reminder",
+ widget, "sensitive",
+ G_SETTINGS_BIND_GET);
+
+ widget = e_builder_get_widget (prefs->builder, "default_reminder_units");
+ g_settings_bind_with_mapping (
+ settings, "default-reminder-units",
+ widget, "active",
+ G_SETTINGS_BIND_DEFAULT,
+ calendar_preferences_map_string_to_integer,
+ calendar_preferences_map_integer_to_string,
+ g_type_class_ref (E_TYPE_DURATION_TYPE),
+ (GDestroyNotify) g_type_class_unref);
+ g_settings_bind (
+ settings, "use-default-reminder",
+ widget, "sensitive",
+ G_SETTINGS_BIND_GET);
+
+ /* These settings control the "Birthdays & Anniversaries" backend. */
+
+ eds_settings =
+ g_settings_new ("org.gnome.evolution-data-server.calendar");
+
+ widget = e_builder_get_widget (prefs->builder, "ba_reminder");
+ g_settings_bind (
+ eds_settings, "contacts-reminder-enabled",
+ widget, "active",
+ G_SETTINGS_BIND_DEFAULT);
+
+ widget = e_builder_get_widget (prefs->builder, "ba_reminder_interval");
+ g_settings_bind (
+ eds_settings, "contacts-reminder-interval",
+ widget, "value",
+ G_SETTINGS_BIND_DEFAULT);
+ g_settings_bind (
+ eds_settings, "contacts-reminder-enabled",
+ widget, "sensitive",
+ G_SETTINGS_BIND_GET);
+
+ widget = e_builder_get_widget (prefs->builder, "ba_reminder_units");
+ g_settings_bind_with_mapping (
+ eds_settings, "contacts-reminder-units",
+ widget, "active",
+ G_SETTINGS_BIND_DEFAULT,
+ calendar_preferences_map_string_to_integer,
+ calendar_preferences_map_integer_to_string,
+ g_type_class_ref (E_TYPE_DURATION_TYPE),
+ (GDestroyNotify) g_type_class_unref);
+ g_settings_bind (
+ eds_settings, "contacts-reminder-enabled",
+ widget, "sensitive",
+ G_SETTINGS_BIND_GET);
+
+ g_object_unref (eds_settings);
+
+ /* Display tab */
+ widget = e_builder_get_widget (prefs->builder, "time_divisions");
+ g_settings_bind_with_mapping (
+ settings, "time-divisions",
+ widget, "active",
+ G_SETTINGS_BIND_DEFAULT,
+ calendar_preferences_map_time_divisions_to_index,
+ calendar_preferences_map_index_to_time_divisions,
+ NULL, (GDestroyNotify) NULL);
+
+ widget = e_builder_get_widget (prefs->builder, "show_end_times");
+ g_settings_bind (
+ settings, "show-event-end",
+ widget, "active",
+ G_SETTINGS_BIND_DEFAULT);
+
+ widget = e_builder_get_widget (prefs->builder, "compress_weekend");
+ g_settings_bind (
+ settings, "compress-weekend",
+ widget, "active",
+ G_SETTINGS_BIND_DEFAULT);
+
+ widget = e_builder_get_widget (prefs->builder, "show_week_numbers");
+ g_settings_bind (
+ settings, "show-week-numbers",
+ widget, "active",
+ G_SETTINGS_BIND_DEFAULT);
+
+ widget = e_builder_get_widget (prefs->builder, "recur_events_italic");
+ g_settings_bind (
+ settings, "recur-events-italic",
+ widget, "active",
+ G_SETTINGS_BIND_DEFAULT);
+
+ widget = e_builder_get_widget (prefs->builder, "month_scroll_by_week");
+ g_settings_bind (
+ settings, "month-scroll-by-week",
+ widget, "active",
+ G_SETTINGS_BIND_DEFAULT);
+
+ widget = e_builder_get_widget (prefs->builder, "tasks_due_today_highlight");
+ g_settings_bind (
+ settings, "task-due-today-highlight",
+ widget, "active",
+ G_SETTINGS_BIND_DEFAULT);
+
+ widget = e_builder_get_widget (prefs->builder, "tasks_due_today_color");
+ g_settings_bind_with_mapping (
+ settings, "task-due-today-color",
+ widget, "color",
+ G_SETTINGS_BIND_DEFAULT,
+ calendar_preferences_map_string_to_gdk_color,
+ calendar_preferences_map_gdk_color_to_string,
+ NULL, (GDestroyNotify) NULL);
+ g_settings_bind (
+ settings, "task-due-today-highlight",
+ widget, "sensitive",
+ G_SETTINGS_BIND_GET);
+
+ widget = e_builder_get_widget (prefs->builder, "tasks_overdue_highlight");
+ g_settings_bind (
+ settings, "task-overdue-highlight",
+ widget, "active",
+ G_SETTINGS_BIND_DEFAULT);
+
+ widget = e_builder_get_widget (prefs->builder, "tasks_overdue_color");
+ g_settings_bind_with_mapping (
+ settings, "task-overdue-color",
+ widget, "color",
+ G_SETTINGS_BIND_DEFAULT,
+ calendar_preferences_map_string_to_gdk_color,
+ calendar_preferences_map_gdk_color_to_string,
+ NULL, (GDestroyNotify) NULL);
+ g_settings_bind (
+ settings, "task-overdue-highlight",
+ widget, "sensitive",
+ G_SETTINGS_BIND_GET);
+
+ widget = e_builder_get_widget (prefs->builder, "tasks_hide_completed");
+ g_settings_bind (
+ settings, "hide-completed-tasks",
+ widget, "active",
+ G_SETTINGS_BIND_DEFAULT);
+
+ widget = e_builder_get_widget (prefs->builder, "tasks_hide_completed_interval");
+ g_settings_bind (
+ settings, "hide-completed-tasks-value",
+ widget, "value",
+ G_SETTINGS_BIND_DEFAULT);
+ g_settings_bind (
+ settings, "hide-completed-tasks",
+ widget, "sensitive",
+ G_SETTINGS_BIND_GET);
+
+ widget = e_builder_get_widget (prefs->builder, "tasks_hide_completed_units");
+ g_settings_bind_with_mapping (
+ settings, "hide-completed-tasks-units",
+ widget, "active",
+ G_SETTINGS_BIND_DEFAULT,
+ calendar_preferences_map_string_to_integer,
+ calendar_preferences_map_integer_to_string,
+ g_type_class_ref (E_TYPE_DURATION_TYPE),
+ (GDestroyNotify) g_type_class_unref);
+ g_settings_bind (
+ settings, "hide-completed-tasks",
+ widget, "sensitive",
+ G_SETTINGS_BIND_GET);
+
+ /* Alarms tab */
+ widget = e_builder_get_widget (prefs->builder, "notify_with_tray");
+ g_settings_bind (
+ settings, "notify-with-tray",
+ widget, "active",
+ G_SETTINGS_BIND_DEFAULT);
+
+ prefs->scrolled_window = e_builder_get_widget (prefs->builder, "calendar-source-scrolled-window");
+
+ /* Free/Busy tab */
+ widget = e_builder_get_widget (prefs->builder, "template_url");
+ g_settings_bind (
+ settings, "publish-template",
+ widget, "text",
+ G_SETTINGS_BIND_DEFAULT);
+
+ /* date/time format */
+ table = e_builder_get_widget (prefs->builder, "datetime_format_table");
+ e_datetime_format_add_setup_widget (table, 0, "calendar", "table", DTFormatKindDateTime, _("Ti_me and date:"));
+ e_datetime_format_add_setup_widget (table, 1, "calendar", "table", DTFormatKindDate, _("_Date only:"));
+
+ /* Hook up and add the toplevel widget */
+
+ target = e_cal_config_target_new_prefs (ec);
+ e_config_set_target ((EConfig *) ec, (EConfigTarget *) target);
+ toplevel = e_config_create_widget ((EConfig *) ec);
+ gtk_container_add (GTK_CONTAINER (prefs), toplevel);
+
+ show_config (prefs);
+ /* FIXME: weakref? */
+ setup_changes (prefs);
+
+ g_object_unref (settings);
+}
+
+void
+e_calendar_preferences_type_register (GTypeModule *type_module)
+{
+ /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
+ * function, so we have to wrap it with a public function in
+ * order to register types from a separate compilation unit. */
+ e_calendar_preferences_register_type (type_module);
+}
+
+GtkWidget *
+e_calendar_preferences_new (EPreferencesWindow *window)
+{
+ EShell *shell;
+ ESourceRegistry *registry;
+ ECalendarPreferences *preferences;
+
+ shell = e_preferences_window_get_shell (window);
+
+ registry = e_shell_get_registry (shell);
+
+ g_return_val_if_fail (E_IS_SHELL (shell), NULL);
+
+ preferences = g_object_new (E_TYPE_CALENDAR_PREFERENCES, NULL);
+
+ preferences->registry = g_object_ref (registry);
+
+ /* FIXME Kill this function. */
+ calendar_preferences_construct (preferences, shell);
+
+ return GTK_WIDGET (preferences);
+}
diff --git a/modules/calendar/e-calendar-preferences.h b/modules/calendar/e-calendar-preferences.h
new file mode 100644
index 0000000000..3920cd1916
--- /dev/null
+++ b/modules/calendar/e-calendar-preferences.h
@@ -0,0 +1,83 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * David Trowbridge <trowbrds cs colorado edu>
+ * Damon Chaplin <damon@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef CAL_PREFERENCES_H
+#define CAL_PREFERENCES_H
+
+#include <shell/e-shell.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CALENDAR_PREFERENCES \
+ (e_calendar_preferences_get_type ())
+#define E_CALENDAR_PREFERENCES(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_CALENDAR_PREFERENCES, ECalendarPreferences))
+#define E_CALENDAR_PREFERENCES_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_CALENDAR_PREFERENCES, ECalendarPreferencesClass))
+#define E_CALENDAR_IS_PREFERENCES(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_CALENDAR_PREFERENCES))
+#define E_CALENDAR_IS_PREFERENCES_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_CALENDAR_PREFERENCES))
+#define E_CALENDAR_PREFERENCES_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_CALENDAR_PREFERENCES, ECalendarPreferencesClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ECalendarPreferences ECalendarPreferences;
+typedef struct _ECalendarPreferencesClass ECalendarPreferencesClass;
+
+struct _ECalendarPreferences {
+ GtkBox parent;
+
+ GtkBuilder *builder;
+
+ ESourceRegistry *registry;
+
+ /* General tab */
+ GtkWidget *day_second_zone;
+ GtkWidget *start_of_day;
+ GtkWidget *end_of_day;
+ GtkWidget *ba_reminder;
+ GtkWidget *ba_reminder_interval;
+ GtkWidget *ba_reminder_units;
+
+ /* Alarms tab */
+ GtkWidget *scrolled_window;
+};
+
+struct _ECalendarPreferencesClass {
+ GtkBoxClass parent;
+};
+
+GType e_calendar_preferences_get_type (void);
+void e_calendar_preferences_type_register
+ (GTypeModule *type_module);
+GtkWidget * e_calendar_preferences_new (EPreferencesWindow *window);
+
+G_END_DECLS
+
+#endif /* CAL_PREFERENCES_H */
diff --git a/modules/calendar/e-calendar-preferences.ui b/modules/calendar/e-calendar-preferences.ui
new file mode 100644
index 0000000000..7af3f2036d
--- /dev/null
+++ b/modules/calendar/e-calendar-preferences.ui
@@ -0,0 +1,1508 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.16"/>
+ <!-- interface-requires evolution 0.0 -->
+ <!-- interface-naming-policy toplevel-contextual -->
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="upper">9999</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment2">
+ <property name="upper">9999</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment3">
+ <property name="value">1</property>
+ <property name="upper">9999</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkListStore" id="model2">
+ <columns>
+ <!-- column-name gchararray -->
+ <column type="gchararray"/>
+ </columns>
+ <data>
+ <row>
+ <col id="0" translatable="yes">Minutes</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Hours</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Days</col>
+ </row>
+ </data>
+ </object>
+ <object class="GtkListStore" id="model3">
+ <columns>
+ <!-- column-name gchararray -->
+ <column type="gchararray"/>
+ </columns>
+ <data>
+ <row>
+ <col id="0" translatable="yes">Minutes</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Hours</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Days</col>
+ </row>
+ </data>
+ </object>
+ <object class="GtkListStore" id="model4">
+ <columns>
+ <!-- column-name gchararray -->
+ <column type="gchararray"/>
+ </columns>
+ <data>
+ <row>
+ <col id="0" translatable="yes">60 minutes</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">30 minutes</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">15 minutes</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">10 minutes</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">05 minutes</col>
+ </row>
+ </data>
+ </object>
+ <object class="GtkListStore" id="model5">
+ <columns>
+ <!-- column-name gchararray -->
+ <column type="gchararray"/>
+ </columns>
+ <data>
+ <row>
+ <col id="0" translatable="yes">Minutes</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Hours</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Days</col>
+ </row>
+ </data>
+ </object>
+ <object class="GtkNotebook" id="toplevel-notebook">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <object class="GtkVBox" id="general">
+ <property name="visible">True</property>
+ <property name="border_width">12</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Time</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label7">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="time">
+ <property name="visible">True</property>
+ <property name="n_rows">4</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">6</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label_second_zone">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Se_cond zone:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">day_second_zone</property>
+ </object>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox_second_zone">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkButton" id="day_second_zone">
+ <property name="label" translatable="yes" context="cal-second-zone">None</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label64">
+ <property name="visible">True</property>
+ <property name="xpad">6</property>
+ <property name="label" translatable="yes">(Shown in a Day View)</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="ETimezoneEntry" id="timezone">
+ <property name="visible">True</property>
+ <accessibility>
+ <relation type="labelled-by" target="timezone_label"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="timezone_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Time _zone:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">timezone</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox_use_system_timezone">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkCheckButton" id="use-system-tz-check">
+ <property name="label" translatable="yes">Use s_ystem time zone</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="system-tz-label">
+ <property name="visible">True</property>
+ <property name="xpad">5</property>
+ <property name="label">(system/tz)</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_time_format">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Time format:</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox_time_format">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkRadioButton" id="use_12_hour">
+ <property name="label" translatable="yes">_12 hour (AM/PM)</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="use_24_hour">
+ <property name="label" translatable="yes">_24 hour</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">use_12_hour</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Work Week</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox2">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label8">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="workWeek">
+ <property name="visible">True</property>
+ <property name="n_rows">3</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">6</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label12">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes" comments="A weekday like &quot;Monday&quot; follows">Wee_k starts on:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">week_start_day</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label13">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Work days:</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="day_start_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Day begins:</property>
+ <property name="mnemonic_widget">start_of_day</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox5">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="mon_button">
+ <property name="label" translatable="yes" comments="Monday">_Mon</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="mon_button-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes">Monday</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="tue_button">
+ <property name="label" translatable="yes" comments="Tuesday">_Tue</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="tue_button-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes">Tuesday</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="wed_button">
+ <property name="label" translatable="yes" comments="Wednesday">_Wed</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="wed_button-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes">Wednesday</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="thu_button">
+ <property name="label" translatable="yes" comments="Thursday">T_hu</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="thu_button-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes">Thursday</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="fri_button">
+ <property name="label" translatable="yes" comments="Friday">_Fri</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="fri_button-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes">Friday</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="sat_button">
+ <property name="label" translatable="yes" comments="Saturday">_Sat</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="sat_button-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes">Saturday</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="sun_button">
+ <property name="label" translatable="yes" comments="Sunday">S_un</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="sun_button-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes">Sunday</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">6</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="week_start_day">
+ <property name="visible">True</property>
+ <items>
+ <item translatable="yes" id="monday">Monday</item>
+ <item translatable="yes" id="tuesday">Tuesday</item>
+ <item translatable="yes" id="wednesday">Wednesday</item>
+ <item translatable="yes" id="thursday">Thursday</item>
+ <item translatable="yes" id="friday">Friday</item>
+ <item translatable="yes" id="saturday">Saturday</item>
+ <item translatable="yes" id="sunday">Sunday</item>
+ </items>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox13">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="EDateEdit" id="start_of_day">
+ <property name="visible">True</property>
+ <property name="show_date">False</property>
+ <property name="show_week_numbers">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="day_end_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Day _ends:</property>
+ <property name="mnemonic_widget">end_of_day</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="EDateEdit" id="end_of_day">
+ <property name="visible">True</property>
+ <property name="show_date">False</property>
+ <property name="show_week_numbers">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Alerts</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox3">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label9">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="alerts">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="confirm_delete">
+ <property name="label" translatable="yes">_Ask for confirmation when deleting items</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="general-space-label">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">6</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="tab_fill">False</property>
+ <property name="tab_expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">General</property>
+ </object>
+ <packing>
+ <property name="tab_fill">False</property>
+ <property name="tab_expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="display">
+ <property name="visible">True</property>
+ <property name="border_width">12</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label17">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">General</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox8">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label19">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="displayGeneral">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkHBox" id="hbox_time_divisions">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label23">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Time divisions:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">time_divisions</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="time_divisions">
+ <property name="visible">True</property>
+ <property name="model">model4</property>
+ <child>
+ <object class="GtkCellRendererText" id="renderer4"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="show_end_times">
+ <property name="label" translatable="yes">_Show appointment end times in week and month view</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="compress_weekend">
+ <property name="label" translatable="yes">_Compress weekends in month view</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="show_week_numbers">
+ <property name="label" translatable="yes">Show week _numbers</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="recur_events_italic">
+ <property name="label" translatable="yes">Show r_ecurring events in italic in bottom left calendar</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="month_scroll_by_week">
+ <property name="label" translatable="yes">Sc_roll Month View by a week</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label65">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Date/Time Format</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox27">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label66">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="datetime_format_table">
+ <property name="visible">True</property>
+ <property name="n_columns">3</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="tab_fill">False</property>
+ <property name="tab_expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Display</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="tasks-vbox">
+ <property name="visible">True</property>
+ <property name="border_width">12</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label18">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Task List</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox9">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label20">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="taskList">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkHBox" id="hbox14">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkCheckButton" id="tasks_due_today_highlight">
+ <property name="label" translatable="yes">Highlight t_asks due today</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkColorButton" id="tasks_due_today_color">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="title" translatable="yes">Pick a color</property>
+ <property name="color">#000000000000</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox15">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkCheckButton" id="tasks_overdue_highlight">
+ <property name="label" translatable="yes">Highlight _overdue tasks</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkColorButton" id="tasks_overdue_color">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="title" translatable="yes">Pick a color</property>
+ <property name="color">#000000000000</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox11">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="tasks_hide_completed">
+ <property name="label" translatable="yes">_Hide completed tasks after</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="tasks_hide_completed_interval">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="adjustment">adjustment3</property>
+ <property name="climb_rate">1</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="tasks_hide_completed_units">
+ <property name="visible">True</property>
+ <property name="model">model5</property>
+ <child>
+ <object class="GtkCellRendererText" id="renderer5"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="tab_fill">False</property>
+ <property name="tab_expand">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="tasks-tab-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Tasks</property>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="alarms">
+ <property name="visible">True</property>
+ <property name="border_width">12</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label67">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Reminders</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="left_padding">10</property>
+ <property name="bottom_padding">10</property>
+ <child>
+ <object class="GtkVBox" id="alarm_options_vbox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">4</property>
+ <child>
+ <object class="GtkCheckButton" id="notify_with_tray">
+ <property name="label" translatable="yes">Display reminders in _notification area only</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="fill">False</property>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox6">
+ <property name="visible">True</property>
+ <property name="spacing">4</property>
+ <child>
+ <object class="GtkCheckButton" id="default_reminder">
+ <property name="label" translatable="yes" comments="This is the first half of a user preference. &quot;Show a reminder [time-period] before every appointment&quot;">Sh_ow a reminder</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="default_reminder_interval">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="adjustment">adjustment1</property>
+ <property name="climb_rate">1</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="default_reminder_units">
+ <property name="visible">True</property>
+ <property name="model">model2</property>
+ <child>
+ <object class="GtkCellRendererText" id="renderer2"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label16">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes" comments="This is the last half of a user preference. &quot;Show a reminder [time-period] before every appointment&quot;">before every appointment</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="fill">False</property>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox7">
+ <property name="visible">True</property>
+ <property name="spacing">4</property>
+ <child>
+ <object class="GtkCheckButton" id="ba_reminder">
+ <property name="label" translatable="yes" comments="This is the first half of a user preference. &quot;Show a reminder [time-period] before every anniversary/birthday&quot;">Show a _reminder</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="ba_reminder_interval">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="adjustment">adjustment2</property>
+ <property name="climb_rate">1</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="ba_reminder_units">
+ <property name="visible">True</property>
+ <property name="model">model3</property>
+ <child>
+ <object class="GtkCellRendererText" id="renderer3"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="ba_reminder_label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes" comments="This is the last half of a user preference. &quot;Show a reminder [time-period] before every anniversary/birthday&quot;">before every anniversary/birthday</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="fill">False</property>
+ <property name="expand">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="fill">False</property>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label62">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Select the calendars for reminder notification</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="calendar-source-scrolled-window">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="tab_fill">False</property>
+ <property name="tab_expand">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="alarm-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Reminders</property>
+ </object>
+ <packing>
+ <property name="tab_fill">False</property>
+ <property name="tab_expand">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="freebusy">
+ <property name="visible">True</property>
+ <property name="border_width">12</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="default-freebusy-header">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Default Free/Busy Server</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="default-freebusy-alignment">
+ <property name="visible">True</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkVBox" id="default-freebusy-vbox">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkHBox" id="hbox18">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label33">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Template:</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="template_url">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">&#x25CF;</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label32">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">%u and %d will be replaced by user and domain from the email address.</property>
+ <property name="wrap">True</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">4</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Publishing Information</property>
+ </object>
+ <packing>
+ <property name="position">4</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ </object>
+ <object class="GtkSizeGroup" id="day_begins_ends_sizegroup">
+ <widgets>
+ <widget name="day_end_label"/>
+ <widget name="day_start_label"/>
+ </widgets>
+ </object>
+</interface>
diff --git a/modules/calendar/e-memo-shell-backend.c b/modules/calendar/e-memo-shell-backend.c
new file mode 100644
index 0000000000..a277569f0c
--- /dev/null
+++ b/modules/calendar/e-memo-shell-backend.c
@@ -0,0 +1,488 @@
+/*
+ * e-memo-shell-backend.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-memo-shell-backend.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <libecal/libecal.h>
+
+#include "shell/e-shell.h"
+#include "shell/e-shell-backend.h"
+#include "shell/e-shell-window.h"
+
+#include "calendar/gui/comp-util.h"
+#include "calendar/gui/dialogs/memo-editor.h"
+
+#include "e-memo-shell-migrate.h"
+#include "e-memo-shell-view.h"
+
+#define E_MEMO_SHELL_BACKEND_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MEMO_SHELL_BACKEND, EMemoShellBackendPrivate))
+
+#define E_MEMO_SHELL_BACKEND_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MEMO_SHELL_BACKEND, EMemoShellBackendPrivate))
+
+struct _EMemoShellBackendPrivate {
+ gint placeholder;
+};
+
+G_DEFINE_DYNAMIC_TYPE (
+ EMemoShellBackend,
+ e_memo_shell_backend,
+ E_TYPE_SHELL_BACKEND)
+
+static void
+memo_shell_backend_new_memo (ECalClient *cal_client,
+ EShell *shell,
+ CompEditorFlags flags)
+{
+ ECalComponent *comp;
+ CompEditor *editor;
+
+ comp = cal_comp_memo_new_with_defaults (cal_client);
+ cal_comp_update_time_by_active_window (comp, shell);
+ editor = memo_editor_new (cal_client, shell, flags);
+ comp_editor_edit_comp (editor, comp);
+
+ gtk_window_present (GTK_WINDOW (editor));
+
+ g_object_unref (comp);
+}
+
+static void
+memo_shell_backend_memo_new_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EShell *shell = E_SHELL (user_data);
+ EClient *client;
+ CompEditorFlags flags = 0;
+ GError *error = NULL;
+
+ flags |= COMP_EDITOR_NEW_ITEM;
+
+ client = e_client_cache_get_client_finish (
+ E_CLIENT_CACHE (source_object), result, &error);
+
+ /* Sanity check. */
+ g_return_if_fail (
+ ((client != NULL) && (error == NULL)) ||
+ ((client == NULL) && (error != NULL)));
+
+ if (client != NULL) {
+ memo_shell_backend_new_memo (
+ E_CAL_CLIENT (client), shell, flags);
+ g_object_unref (client);
+ } else {
+ /* XXX Handle errors better. */
+ g_warning ("%s: %s", G_STRFUNC, error->message);
+ g_error_free (error);
+ }
+
+ g_object_unref (shell);
+}
+
+static void
+memo_shell_backend_memo_shared_new_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EShell *shell = E_SHELL (user_data);
+ EClient *client;
+ CompEditorFlags flags = 0;
+ GError *error = NULL;
+
+ flags |= COMP_EDITOR_NEW_ITEM;
+ flags |= COMP_EDITOR_IS_SHARED;
+ flags |= COMP_EDITOR_USER_ORG;
+
+ client = e_client_cache_get_client_finish (
+ E_CLIENT_CACHE (source_object), result, &error);
+
+ /* Sanity check. */
+ g_return_if_fail (
+ ((client != NULL) && (error == NULL)) ||
+ ((client == NULL) && (error != NULL)));
+
+ if (client != NULL) {
+ memo_shell_backend_new_memo (
+ E_CAL_CLIENT (client), shell, flags);
+ g_object_unref (client);
+ } else {
+ /* XXX Handle errors better. */
+ g_warning ("%s: %s", G_STRFUNC, error->message);
+ g_error_free (error);
+ }
+
+ g_object_unref (shell);
+}
+
+static void
+action_memo_new_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ EShell *shell;
+ ESource *source;
+ ESourceRegistry *registry;
+ EClientCache *client_cache;
+ const gchar *action_name;
+
+ /* This callback is used for both memos and shared memos. */
+
+ shell = e_shell_window_get_shell (shell_window);
+ client_cache = e_shell_get_client_cache (shell);
+
+ registry = e_shell_get_registry (shell);
+ source = e_source_registry_ref_default_memo_list (registry);
+
+ /* Use a callback function appropriate for the action. */
+ action_name = gtk_action_get_name (action);
+ if (g_strcmp0 (action_name, "memo-shared-new") == 0)
+ e_client_cache_get_client (
+ client_cache, source,
+ E_SOURCE_EXTENSION_MEMO_LIST,
+ NULL,
+ memo_shell_backend_memo_shared_new_cb,
+ g_object_ref (shell));
+ else
+ e_client_cache_get_client (
+ client_cache, source,
+ E_SOURCE_EXTENSION_MEMO_LIST,
+ NULL,
+ memo_shell_backend_memo_new_cb,
+ g_object_ref (shell));
+
+ g_object_unref (source);
+}
+
+static void
+action_memo_list_new_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ EShell *shell;
+ ESourceRegistry *registry;
+ ECalClientSourceType source_type;
+ GtkWidget *config;
+ GtkWidget *dialog;
+ const gchar *icon_name;
+
+ shell = e_shell_window_get_shell (shell_window);
+
+ registry = e_shell_get_registry (shell);
+ source_type = E_CAL_CLIENT_SOURCE_TYPE_MEMOS;
+ config = e_cal_source_config_new (registry, NULL, source_type);
+
+ dialog = e_source_config_dialog_new (E_SOURCE_CONFIG (config));
+
+ gtk_window_set_transient_for (
+ GTK_WINDOW (dialog), GTK_WINDOW (shell_window));
+
+ icon_name = gtk_action_get_icon_name (action);
+ gtk_window_set_icon_name (GTK_WINDOW (dialog), icon_name);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), _("New Memo List"));
+
+ gtk_widget_show (dialog);
+}
+
+static GtkActionEntry item_entries[] = {
+
+ { "memo-new",
+ "stock_insert-note",
+ NC_("New", "Mem_o"),
+ "<Shift><Control>o",
+ N_("Create a new memo"),
+ G_CALLBACK (action_memo_new_cb) },
+
+ { "memo-shared-new",
+ "stock_insert-note",
+ NC_("New", "_Shared Memo"),
+ "<Shift><Control>h",
+ N_("Create a new shared memo"),
+ G_CALLBACK (action_memo_new_cb) }
+};
+
+static GtkActionEntry source_entries[] = {
+
+ { "memo-list-new",
+ "stock_notes",
+ NC_("New", "Memo Li_st"),
+ NULL,
+ N_("Create a new memo list"),
+ G_CALLBACK (action_memo_list_new_cb) }
+};
+
+static gboolean
+memo_shell_backend_handle_uri_cb (EShellBackend *shell_backend,
+ const gchar *uri)
+{
+ EShell *shell;
+ CompEditor *editor;
+ CompEditorFlags flags = 0;
+ EClient *client;
+ EClientCache *client_cache;
+ ECalComponent *comp;
+ ESource *source;
+ ESourceRegistry *registry;
+ SoupURI *soup_uri;
+ icalcomponent *icalcomp;
+ const gchar *cp;
+ gchar *source_uid = NULL;
+ gchar *comp_uid = NULL;
+ gchar *comp_rid = NULL;
+ gboolean handled = FALSE;
+ GError *error = NULL;
+
+ shell = e_shell_backend_get_shell (shell_backend);
+ client_cache = e_shell_get_client_cache (shell);
+
+ if (strncmp (uri, "memo:", 5) != 0)
+ return FALSE;
+
+ soup_uri = soup_uri_new (uri);
+
+ if (soup_uri == NULL)
+ return FALSE;
+
+ cp = soup_uri_get_query (soup_uri);
+ if (cp == NULL)
+ goto exit;
+
+ while (*cp != '\0') {
+ gchar *header;
+ gchar *content;
+ gsize header_len;
+ gsize content_len;
+
+ header_len = strcspn (cp, "=&");
+
+ /* If it's malformed, give up. */
+ if (cp[header_len] != '=')
+ break;
+
+ header = (gchar *) cp;
+ header[header_len] = '\0';
+ cp += header_len + 1;
+
+ content_len = strcspn (cp, "&");
+
+ content = g_strndup (cp, content_len);
+ if (g_ascii_strcasecmp (header, "source-uid") == 0)
+ source_uid = g_strdup (content);
+ else if (g_ascii_strcasecmp (header, "comp-uid") == 0)
+ comp_uid = g_strdup (content);
+ else if (g_ascii_strcasecmp (header, "comp-rid") == 0)
+ comp_rid = g_strdup (content);
+ g_free (content);
+
+ cp += content_len;
+ if (*cp == '&') {
+ cp++;
+ if (strcmp (cp, "amp;") == 0)
+ cp += 4;
+ }
+ }
+
+ if (source_uid == NULL || comp_uid == NULL)
+ goto exit;
+
+ /* URI is valid, so consider it handled. Whether
+ * we successfully open it is another matter... */
+ handled = TRUE;
+
+ registry = e_shell_get_registry (shell);
+ source = e_source_registry_ref_source (registry, source_uid);
+ if (source == NULL) {
+ g_printerr ("No source for UID '%s'\n", source_uid);
+ goto exit;
+ }
+
+ client = e_client_cache_get_client_sync (
+ client_cache, source,
+ E_SOURCE_EXTENSION_MEMO_LIST,
+ NULL, &error);
+
+ /* Sanity check. */
+ g_return_val_if_fail (
+ ((client != NULL) && (error == NULL)) ||
+ ((client == NULL) && (error != NULL)), FALSE);
+
+ if (error != NULL) {
+ g_warning (
+ "%s: Failed to create/open client: %s",
+ G_STRFUNC, error->message);
+ g_object_unref (source);
+ g_error_free (error);
+ goto exit;
+ }
+
+ g_object_unref (source);
+ source = NULL;
+
+ /* XXX Copied from e_memo_shell_view_open_memo().
+ * Clearly a new utility function is needed. */
+
+ editor = comp_editor_find_instance (comp_uid);
+
+ if (editor != NULL)
+ goto present;
+
+ e_cal_client_get_object_sync (
+ E_CAL_CLIENT (client), comp_uid,
+ comp_rid, &icalcomp, NULL, &error);
+
+ if (error != NULL) {
+ g_warning (
+ "%s: Failed to get object: %s",
+ G_STRFUNC, error->message);
+ g_object_unref (client);
+ g_error_free (error);
+ goto exit;
+ }
+
+ comp = e_cal_component_new ();
+ if (!e_cal_component_set_icalcomponent (comp, icalcomp)) {
+ g_warning ("%s: Failed to set icalcomp to comp\n", G_STRFUNC);
+ icalcomponent_free (icalcomp);
+ icalcomp = NULL;
+ }
+
+ if (e_cal_component_has_organizer (comp))
+ flags |= COMP_EDITOR_IS_SHARED;
+
+ if (itip_organizer_is_user (registry, comp, E_CAL_CLIENT (client)))
+ flags |= COMP_EDITOR_USER_ORG;
+
+ editor = memo_editor_new (E_CAL_CLIENT (client), shell, flags);
+ comp_editor_edit_comp (editor, comp);
+
+ g_object_unref (comp);
+
+present:
+ gtk_window_present (GTK_WINDOW (editor));
+
+ g_object_unref (client);
+
+exit:
+ g_free (source_uid);
+ g_free (comp_uid);
+ g_free (comp_rid);
+
+ soup_uri_free (soup_uri);
+
+ return handled;
+}
+
+static void
+memo_shell_backend_window_added_cb (EShellBackend *shell_backend,
+ GtkWindow *window)
+{
+ const gchar *module_name;
+
+ if (!E_IS_SHELL_WINDOW (window))
+ return;
+
+ module_name = E_SHELL_BACKEND_GET_CLASS (shell_backend)->name;
+
+ e_shell_window_register_new_item_actions (
+ E_SHELL_WINDOW (window), module_name,
+ item_entries, G_N_ELEMENTS (item_entries));
+
+ e_shell_window_register_new_source_actions (
+ E_SHELL_WINDOW (window), module_name,
+ source_entries, G_N_ELEMENTS (source_entries));
+}
+
+static void
+memo_shell_backend_constructed (GObject *object)
+{
+ EShell *shell;
+ EShellBackend *shell_backend;
+
+ shell_backend = E_SHELL_BACKEND (object);
+ shell = e_shell_backend_get_shell (shell_backend);
+
+ g_signal_connect_swapped (
+ shell, "handle-uri",
+ G_CALLBACK (memo_shell_backend_handle_uri_cb),
+ shell_backend);
+
+ g_signal_connect_swapped (
+ shell, "window-added",
+ G_CALLBACK (memo_shell_backend_window_added_cb),
+ shell_backend);
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_memo_shell_backend_parent_class)->constructed (object);
+}
+
+static void
+e_memo_shell_backend_class_init (EMemoShellBackendClass *class)
+{
+ GObjectClass *object_class;
+ EShellBackendClass *shell_backend_class;
+
+ g_type_class_add_private (class, sizeof (EMemoShellBackendPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->constructed = memo_shell_backend_constructed;
+
+ shell_backend_class = E_SHELL_BACKEND_CLASS (class);
+ shell_backend_class->shell_view_type = E_TYPE_MEMO_SHELL_VIEW;
+ shell_backend_class->name = "memos";
+ shell_backend_class->aliases = "";
+ shell_backend_class->schemes = "memo";
+ shell_backend_class->sort_order = 600;
+ shell_backend_class->preferences_page = "calendar-and-tasks";
+ shell_backend_class->start = NULL;
+ shell_backend_class->migrate = e_memo_shell_backend_migrate;
+
+ /* Register relevant ESource extensions. */
+ E_TYPE_SOURCE_MEMO_LIST;
+}
+
+static void
+e_memo_shell_backend_class_finalize (EMemoShellBackendClass *class)
+{
+}
+
+static void
+e_memo_shell_backend_init (EMemoShellBackend *memo_shell_backend)
+{
+ memo_shell_backend->priv =
+ E_MEMO_SHELL_BACKEND_GET_PRIVATE (memo_shell_backend);
+}
+
+void
+e_memo_shell_backend_type_register (GTypeModule *type_module)
+{
+ /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
+ * function, so we have to wrap it with a public function in
+ * order to register types from a separate compilation unit. */
+ e_memo_shell_backend_register_type (type_module);
+}
diff --git a/modules/calendar/e-memo-shell-backend.h b/modules/calendar/e-memo-shell-backend.h
new file mode 100644
index 0000000000..f759e5e138
--- /dev/null
+++ b/modules/calendar/e-memo-shell-backend.h
@@ -0,0 +1,67 @@
+/*
+ * e-memo-shell-backend.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MEMO_SHELL_BACKEND_H
+#define E_MEMO_SHELL_BACKEND_H
+
+#include <shell/e-shell-backend.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MEMO_SHELL_BACKEND \
+ (e_memo_shell_backend_get_type ())
+#define E_MEMO_SHELL_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MEMO_SHELL_BACKEND, EMemoShellBackend))
+#define E_MEMO_SHELL_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MEMO_SHELL_BACKEND, EMemoShellBackendClass))
+#define E_IS_MEMO_SHELL_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MEMO_SHELL_BACKEND))
+#define E_IS_MEMO_SHELL_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MEMO_SHELL_BACKEND))
+#define E_MEMO_SHELL_BACKEND_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MEMO_SHELL_BACKEND, EMemoShellBackendClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMemoShellBackend EMemoShellBackend;
+typedef struct _EMemoShellBackendClass EMemoShellBackendClass;
+typedef struct _EMemoShellBackendPrivate EMemoShellBackendPrivate;
+
+struct _EMemoShellBackend {
+ EShellBackend parent;
+ EMemoShellBackendPrivate *priv;
+};
+
+struct _EMemoShellBackendClass {
+ EShellBackendClass parent_class;
+};
+
+GType e_memo_shell_backend_get_type (void);
+void e_memo_shell_backend_type_register
+ (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* E_MEMO_SHELL_BACKEND_H */
diff --git a/modules/calendar/e-memo-shell-content.c b/modules/calendar/e-memo-shell-content.c
new file mode 100644
index 0000000000..bf715ec4d9
--- /dev/null
+++ b/modules/calendar/e-memo-shell-content.c
@@ -0,0 +1,766 @@
+/*
+ * e-memo-shell-content.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-memo-shell-content.h"
+
+#include <glib/gi18n.h>
+
+#include "shell/e-shell-utils.h"
+
+#include "calendar/gui/comp-util.h"
+#include "calendar/gui/e-cal-component-preview.h"
+#include "calendar/gui/e-cal-model-memos.h"
+#include "calendar/gui/e-memo-table.h"
+
+#define E_MEMO_SHELL_CONTENT_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MEMO_SHELL_CONTENT, EMemoShellContentPrivate))
+
+struct _EMemoShellContentPrivate {
+ GtkWidget *paned;
+ GtkWidget *memo_table;
+ GtkWidget *preview_pane;
+
+ ECalModel *memo_model;
+ GtkOrientation orientation;
+
+ gchar *current_uid;
+
+ guint preview_visible : 1;
+};
+
+enum {
+ PROP_0,
+ PROP_MODEL,
+ PROP_ORIENTATION,
+ PROP_PREVIEW_VISIBLE
+};
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (
+ EMemoShellContent,
+ e_memo_shell_content,
+ E_TYPE_SHELL_CONTENT,
+ 0,
+ G_IMPLEMENT_INTERFACE_DYNAMIC (
+ GTK_TYPE_ORIENTABLE, NULL))
+
+static void
+memo_shell_content_display_view_cb (EMemoShellContent *memo_shell_content,
+ GalView *gal_view)
+{
+ EMemoTable *memo_table;
+
+ if (!GAL_IS_VIEW_ETABLE (gal_view))
+ return;
+
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+
+ gal_view_etable_attach_table (
+ GAL_VIEW_ETABLE (gal_view), E_TABLE (memo_table));
+}
+
+static void
+memo_shell_content_table_foreach_cb (gint model_row,
+ gpointer user_data)
+{
+ ECalModelComponent *comp_data;
+ icalcomponent *clone;
+ icalcomponent *vcal;
+ gchar *string;
+
+ struct {
+ ECalModel *model;
+ GSList *list;
+ } *foreach_data = user_data;
+
+ comp_data = e_cal_model_get_component_at (
+ foreach_data->model, model_row);
+
+ vcal = e_cal_util_new_top_level ();
+ clone = icalcomponent_new_clone (comp_data->icalcomp);
+ e_cal_util_add_timezones_from_component (vcal, comp_data->icalcomp);
+ icalcomponent_add_component (vcal, clone);
+
+ /* String is owned by libical; do not free. */
+ string = icalcomponent_as_ical_string (vcal);
+ if (string != NULL) {
+ ESource *source;
+ const gchar *source_uid;
+
+ source = e_client_get_source (E_CLIENT (comp_data->client));
+ source_uid = e_source_get_uid (source);
+
+ foreach_data->list = g_slist_prepend (
+ foreach_data->list,
+ g_strdup_printf ("%s\n%s", source_uid, string));
+ }
+
+ icalcomponent_free (vcal);
+}
+
+static void
+memo_shell_content_table_drag_data_get_cb (EMemoShellContent *memo_shell_content,
+ gint row,
+ gint col,
+ GdkDragContext *context,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint time)
+{
+ EMemoTable *memo_table;
+ GdkAtom target;
+
+ struct {
+ ECalModel *model;
+ GSList *list;
+ } foreach_data;
+
+ /* Sanity check the selection target. */
+ target = gtk_selection_data_get_target (selection_data);
+ if (!e_targets_include_calendar (&target, 1))
+ return;
+
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+
+ foreach_data.model = e_memo_table_get_model (memo_table);
+ foreach_data.list = NULL;
+
+ e_table_selected_row_foreach (
+ E_TABLE (memo_table),
+ memo_shell_content_table_foreach_cb,
+ &foreach_data);
+
+ if (foreach_data.list != NULL) {
+ cal_comp_selection_set_string_list (
+ selection_data, foreach_data.list);
+ g_slist_foreach (foreach_data.list, (GFunc) g_free, NULL);
+ g_slist_free (foreach_data.list);
+ }
+}
+
+static void
+memo_shell_content_table_drag_data_delete_cb (EMemoShellContent *memo_shell_content,
+ gint row,
+ gint col,
+ GdkDragContext *context)
+{
+ /* Moved components are deleted from source immediately when moved,
+ * because some of them can be part of destination source, and we
+ * don't want to delete not-moved memos. There is no such information
+ * which event has been moved and which not, so skip this method. */
+}
+
+static void
+memo_shell_content_cursor_change_cb (EMemoShellContent *memo_shell_content,
+ gint row,
+ ETable *table)
+{
+ ECalComponentPreview *memo_preview;
+ ECalModel *memo_model;
+ ECalModelComponent *comp_data;
+ EPreviewPane *preview_pane;
+ EWebView *web_view;
+ const gchar *uid;
+
+ memo_model = e_memo_shell_content_get_memo_model (memo_shell_content);
+ preview_pane = e_memo_shell_content_get_preview_pane (memo_shell_content);
+
+ web_view = e_preview_pane_get_web_view (preview_pane);
+ memo_preview = E_CAL_COMPONENT_PREVIEW (web_view);
+
+ if (e_table_selected_count (table) != 1) {
+ if (memo_shell_content->priv->preview_visible)
+ e_cal_component_preview_clear (memo_preview);
+ return;
+ }
+
+ row = e_table_get_cursor_row (table);
+ comp_data = e_cal_model_get_component_at (memo_model, row);
+
+ if (memo_shell_content->priv->preview_visible) {
+ ECalComponent *comp;
+
+ comp = e_cal_component_new_from_icalcomponent (
+ icalcomponent_new_clone (comp_data->icalcomp));
+
+ e_cal_component_preview_display (
+ memo_preview, comp_data->client, comp,
+ e_cal_model_get_timezone (memo_model),
+ e_cal_model_get_use_24_hour_format (memo_model));
+
+ g_object_unref (comp);
+ }
+
+ uid = icalcomponent_get_uid (comp_data->icalcomp);
+ g_free (memo_shell_content->priv->current_uid);
+ memo_shell_content->priv->current_uid = g_strdup (uid);
+}
+
+static void
+memo_shell_content_selection_change_cb (EMemoShellContent *memo_shell_content,
+ ETable *table)
+{
+ ECalComponentPreview *memo_preview;
+ EPreviewPane *preview_pane;
+ EWebView *web_view;
+
+ preview_pane = e_memo_shell_content_get_preview_pane (memo_shell_content);
+
+ web_view = e_preview_pane_get_web_view (preview_pane);
+ memo_preview = E_CAL_COMPONENT_PREVIEW (web_view);
+
+ /* XXX Old code emits a "selection-changed" signal here. */
+
+ if (e_table_selected_count (table) != 1)
+ e_cal_component_preview_clear (memo_preview);
+}
+
+static void
+memo_shell_content_model_row_changed_cb (EMemoShellContent *memo_shell_content,
+ gint row,
+ ETableModel *model)
+{
+ ECalModelComponent *comp_data;
+ EMemoTable *memo_table;
+ const gchar *current_uid;
+ const gchar *uid;
+
+ current_uid = memo_shell_content->priv->current_uid;
+ if (current_uid == NULL)
+ return;
+
+ comp_data = e_cal_model_get_component_at (E_CAL_MODEL (model), row);
+ if (comp_data == NULL)
+ return;
+
+ uid = icalcomponent_get_uid (comp_data->icalcomp);
+ if (g_strcmp0 (uid, current_uid) != 0)
+ return;
+
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+
+ memo_shell_content_cursor_change_cb (
+ memo_shell_content, 0, E_TABLE (memo_table));
+}
+
+static void
+memo_shell_content_restore_state_cb (EShellWindow *shell_window,
+ EShellView *shell_view,
+ EShellContent *shell_content)
+{
+ EMemoShellContentPrivate *priv;
+ GSettings *settings;
+
+ priv = E_MEMO_SHELL_CONTENT_GET_PRIVATE (shell_content);
+
+ /* Bind GObject properties to settings keys. */
+
+ settings = g_settings_new ("org.gnome.evolution.calendar");
+
+ g_settings_bind (
+ settings, "memo-hpane-position",
+ priv->paned, "hposition",
+ G_SETTINGS_BIND_DEFAULT);
+
+ g_settings_bind (
+ settings, "memo-vpane-position",
+ priv->paned, "vposition",
+ G_SETTINGS_BIND_DEFAULT);
+}
+
+static void
+memo_shell_content_is_editing_changed_cb (EMemoTable *memo_table,
+ GParamSpec *param,
+ EShellView *shell_view)
+{
+ g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
+
+ e_shell_view_update_actions (shell_view);
+}
+
+static GtkOrientation
+memo_shell_content_get_orientation (EMemoShellContent *memo_shell_content)
+{
+ return memo_shell_content->priv->orientation;
+}
+
+static void
+memo_shell_content_set_orientation (EMemoShellContent *memo_shell_content,
+ GtkOrientation orientation)
+{
+ if (memo_shell_content->priv->orientation == orientation)
+ return;
+
+ memo_shell_content->priv->orientation = orientation;
+
+ g_object_notify (G_OBJECT (memo_shell_content), "orientation");
+}
+
+static void
+memo_shell_content_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ORIENTATION:
+ memo_shell_content_set_orientation (
+ E_MEMO_SHELL_CONTENT (object),
+ g_value_get_enum (value));
+ return;
+
+ case PROP_PREVIEW_VISIBLE:
+ e_memo_shell_content_set_preview_visible (
+ E_MEMO_SHELL_CONTENT (object),
+ g_value_get_boolean (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+memo_shell_content_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_MODEL:
+ g_value_set_object (
+ value,
+ e_memo_shell_content_get_memo_model (
+ E_MEMO_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_ORIENTATION:
+ g_value_set_enum (
+ value,
+ memo_shell_content_get_orientation (
+ E_MEMO_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_PREVIEW_VISIBLE:
+ g_value_set_boolean (
+ value,
+ e_memo_shell_content_get_preview_visible (
+ E_MEMO_SHELL_CONTENT (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+memo_shell_content_dispose (GObject *object)
+{
+ EMemoShellContentPrivate *priv;
+
+ priv = E_MEMO_SHELL_CONTENT_GET_PRIVATE (object);
+
+ if (priv->paned != NULL) {
+ g_object_unref (priv->paned);
+ priv->paned = NULL;
+ }
+
+ if (priv->memo_table != NULL) {
+ g_object_unref (priv->memo_table);
+ priv->memo_table = NULL;
+ }
+
+ if (priv->preview_pane != NULL) {
+ g_object_unref (priv->preview_pane);
+ priv->preview_pane = NULL;
+ }
+
+ if (priv->memo_model != NULL) {
+ g_object_unref (priv->memo_model);
+ priv->memo_model = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_memo_shell_content_parent_class)->dispose (object);
+}
+
+static void
+memo_shell_content_finalize (GObject *object)
+{
+ EMemoShellContentPrivate *priv;
+
+ priv = E_MEMO_SHELL_CONTENT_GET_PRIVATE (object);
+
+ g_free (priv->current_uid);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_memo_shell_content_parent_class)->finalize (object);
+}
+
+static void
+memo_shell_content_constructed (GObject *object)
+{
+ EMemoShellContentPrivate *priv;
+ EShell *shell;
+ EShellView *shell_view;
+ EShellContent *shell_content;
+ EShellTaskbar *shell_taskbar;
+ EShellWindow *shell_window;
+ ESourceRegistry *registry;
+ GalViewInstance *view_instance;
+ GtkTargetList *target_list;
+ GtkTargetEntry *targets;
+ GtkWidget *container;
+ GtkWidget *widget;
+ gint n_targets;
+
+ priv = E_MEMO_SHELL_CONTENT_GET_PRIVATE (object);
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_memo_shell_content_parent_class)->constructed (object);
+
+ shell_content = E_SHELL_CONTENT (object);
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ shell_taskbar = e_shell_view_get_shell_taskbar (shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ registry = e_shell_get_registry (shell);
+ priv->memo_model = e_cal_model_memos_new (registry);
+
+ /* Build content widgets. */
+
+ container = GTK_WIDGET (object);
+
+ widget = e_paned_new (GTK_ORIENTATION_VERTICAL);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ priv->paned = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ g_object_bind_property (
+ object, "orientation",
+ widget, "orientation",
+ G_BINDING_SYNC_CREATE);
+
+ container = priv->paned;
+
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (
+ GTK_SCROLLED_WINDOW (widget),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (
+ GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+ gtk_paned_pack1 (GTK_PANED (container), widget, TRUE, FALSE);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = e_memo_table_new (shell_view, priv->memo_model);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ priv->memo_table = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ container = priv->paned;
+
+ widget = e_cal_component_preview_new ();
+ gtk_widget_show (widget);
+
+ g_signal_connect_swapped (
+ widget, "status-message",
+ G_CALLBACK (e_shell_taskbar_set_message),
+ shell_taskbar);
+
+ widget = e_preview_pane_new (E_WEB_VIEW (widget));
+ gtk_paned_pack2 (GTK_PANED (container), widget, FALSE, FALSE);
+ priv->preview_pane = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ g_object_bind_property (
+ object, "preview-visible",
+ widget, "visible",
+ G_BINDING_SYNC_CREATE);
+
+ target_list = gtk_target_list_new (NULL, 0);
+ e_target_list_add_calendar_targets (target_list, 0);
+ targets = gtk_target_table_new_from_list (target_list, &n_targets);
+
+ e_table_drag_source_set (
+ E_TABLE (priv->memo_table),
+ GDK_BUTTON1_MASK, targets, n_targets,
+ GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_ASK);
+
+ gtk_target_table_free (targets, n_targets);
+ gtk_target_list_unref (target_list);
+
+ g_signal_connect_swapped (
+ priv->memo_table, "table-drag-data-get",
+ G_CALLBACK (memo_shell_content_table_drag_data_get_cb),
+ object);
+
+ g_signal_connect_swapped (
+ priv->memo_table, "table-drag-data-delete",
+ G_CALLBACK (memo_shell_content_table_drag_data_delete_cb),
+ object);
+
+ g_signal_connect_swapped (
+ priv->memo_table, "cursor-change",
+ G_CALLBACK (memo_shell_content_cursor_change_cb),
+ object);
+
+ g_signal_connect_swapped (
+ priv->memo_table, "selection-change",
+ G_CALLBACK (memo_shell_content_selection_change_cb),
+ object);
+
+ g_signal_connect (
+ priv->memo_table, "notify::is-editing",
+ G_CALLBACK (memo_shell_content_is_editing_changed_cb), shell_view);
+
+ g_signal_connect_swapped (
+ priv->memo_model, "model-row-changed",
+ G_CALLBACK (memo_shell_content_model_row_changed_cb),
+ object);
+
+ /* Load the view instance. */
+
+ view_instance = e_shell_view_new_view_instance (shell_view, NULL);
+ g_signal_connect_swapped (
+ view_instance, "display-view",
+ G_CALLBACK (memo_shell_content_display_view_cb),
+ object);
+ e_shell_view_set_view_instance (shell_view, view_instance);
+ gal_view_instance_load (view_instance);
+ g_object_unref (view_instance);
+
+ /* Restore pane positions from the last session once
+ * the shell view is fully initialized and visible. */
+ g_signal_connect (
+ shell_window, "shell-view-created::memos",
+ G_CALLBACK (memo_shell_content_restore_state_cb),
+ shell_content);
+}
+
+static guint32
+memo_shell_content_check_state (EShellContent *shell_content)
+{
+ EMemoShellContent *memo_shell_content;
+ EMemoTable *memo_table;
+ GSList *list, *iter;
+ gboolean editable = TRUE;
+ gboolean has_url = FALSE;
+ gint n_selected;
+ guint32 state = 0;
+
+ memo_shell_content = E_MEMO_SHELL_CONTENT (shell_content);
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+
+ n_selected = e_table_selected_count (E_TABLE (memo_table));
+
+ list = e_memo_table_get_selected (memo_table);
+ for (iter = list; iter != NULL; iter = iter->next) {
+ ECalModelComponent *comp_data = iter->data;
+ icalproperty *prop;
+ gboolean read_only;
+
+ read_only = e_client_is_readonly (E_CLIENT (comp_data->client));
+ editable &= !read_only;
+
+ prop = icalcomponent_get_first_property (
+ comp_data->icalcomp, ICAL_URL_PROPERTY);
+ has_url |= (prop != NULL);
+ }
+ g_slist_free (list);
+
+ if (n_selected == 1)
+ state |= E_MEMO_SHELL_CONTENT_SELECTION_SINGLE;
+ if (n_selected > 1)
+ state |= E_MEMO_SHELL_CONTENT_SELECTION_MULTIPLE;
+ if (editable)
+ state |= E_MEMO_SHELL_CONTENT_SELECTION_CAN_EDIT;
+ if (has_url)
+ state |= E_MEMO_SHELL_CONTENT_SELECTION_HAS_URL;
+
+ return state;
+}
+
+static void
+memo_shell_content_focus_search_results (EShellContent *shell_content)
+{
+ EMemoShellContentPrivate *priv;
+
+ priv = E_MEMO_SHELL_CONTENT_GET_PRIVATE (shell_content);
+
+ gtk_widget_grab_focus (priv->memo_table);
+}
+
+static void
+e_memo_shell_content_class_init (EMemoShellContentClass *class)
+{
+ GObjectClass *object_class;
+ EShellContentClass *shell_content_class;
+
+ g_type_class_add_private (class, sizeof (EMemoShellContentPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = memo_shell_content_set_property;
+ object_class->get_property = memo_shell_content_get_property;
+ object_class->dispose = memo_shell_content_dispose;
+ object_class->finalize = memo_shell_content_finalize;
+ object_class->constructed = memo_shell_content_constructed;
+
+ shell_content_class = E_SHELL_CONTENT_CLASS (class);
+ shell_content_class->check_state = memo_shell_content_check_state;
+ shell_content_class->focus_search_results =
+ memo_shell_content_focus_search_results;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_MODEL,
+ g_param_spec_object (
+ "model",
+ "Model",
+ "The memo table model",
+ E_TYPE_CAL_MODEL,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_PREVIEW_VISIBLE,
+ g_param_spec_boolean (
+ "preview-visible",
+ "Preview is Visible",
+ "Whether the preview pane is visible",
+ TRUE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_override_property (
+ object_class, PROP_ORIENTATION, "orientation");
+}
+
+static void
+e_memo_shell_content_class_finalize (EMemoShellContentClass *class)
+{
+}
+
+static void
+e_memo_shell_content_init (EMemoShellContent *memo_shell_content)
+{
+ memo_shell_content->priv =
+ E_MEMO_SHELL_CONTENT_GET_PRIVATE (memo_shell_content);
+
+ /* Postpone widget construction until we have a shell view. */
+}
+
+void
+e_memo_shell_content_type_register (GTypeModule *type_module)
+{
+ /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
+ * function, so we have to wrap it with a public function in
+ * order to register types from a separate compilation unit. */
+ e_memo_shell_content_register_type (type_module);
+}
+
+GtkWidget *
+e_memo_shell_content_new (EShellView *shell_view)
+{
+ g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
+
+ return g_object_new (
+ E_TYPE_MEMO_SHELL_CONTENT,
+ "shell-view", shell_view, NULL);
+}
+
+ECalModel *
+e_memo_shell_content_get_memo_model (EMemoShellContent *memo_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_MEMO_SHELL_CONTENT (memo_shell_content), NULL);
+
+ return memo_shell_content->priv->memo_model;
+}
+
+EMemoTable *
+e_memo_shell_content_get_memo_table (EMemoShellContent *memo_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_MEMO_SHELL_CONTENT (memo_shell_content), NULL);
+
+ return E_MEMO_TABLE (memo_shell_content->priv->memo_table);
+}
+
+EPreviewPane *
+e_memo_shell_content_get_preview_pane (EMemoShellContent *memo_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_MEMO_SHELL_CONTENT (memo_shell_content), NULL);
+
+ return E_PREVIEW_PANE (memo_shell_content->priv->preview_pane);
+}
+
+gboolean
+e_memo_shell_content_get_preview_visible (EMemoShellContent *memo_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_MEMO_SHELL_CONTENT (memo_shell_content), FALSE);
+
+ return memo_shell_content->priv->preview_visible;
+}
+
+void
+e_memo_shell_content_set_preview_visible (EMemoShellContent *memo_shell_content,
+ gboolean preview_visible)
+{
+ g_return_if_fail (E_IS_MEMO_SHELL_CONTENT (memo_shell_content));
+
+ if (memo_shell_content->priv->preview_visible == preview_visible)
+ return;
+
+ memo_shell_content->priv->preview_visible = preview_visible;
+
+ if (preview_visible && memo_shell_content->priv->preview_pane) {
+ memo_shell_content_cursor_change_cb (
+ memo_shell_content, 0,
+ E_TABLE (memo_shell_content->priv->memo_table));
+ }
+
+ g_object_notify (G_OBJECT (memo_shell_content), "preview-visible");
+}
+
+EShellSearchbar *
+e_memo_shell_content_get_searchbar (EMemoShellContent *memo_shell_content)
+{
+ EShellView *shell_view;
+ EShellContent *shell_content;
+ GtkWidget *widget;
+
+ g_return_val_if_fail (
+ E_IS_MEMO_SHELL_CONTENT (memo_shell_content), NULL);
+
+ shell_content = E_SHELL_CONTENT (memo_shell_content);
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ widget = e_shell_view_get_searchbar (shell_view);
+
+ return E_SHELL_SEARCHBAR (widget);
+}
+
diff --git a/modules/calendar/e-memo-shell-content.h b/modules/calendar/e-memo-shell-content.h
new file mode 100644
index 0000000000..29b6985c4c
--- /dev/null
+++ b/modules/calendar/e-memo-shell-content.h
@@ -0,0 +1,94 @@
+/*
+ * e-memo-shell-content.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MEMO_SHELL_CONTENT_H
+#define E_MEMO_SHELL_CONTENT_H
+
+#include <shell/e-shell-content.h>
+#include <shell/e-shell-searchbar.h>
+#include <shell/e-shell-view.h>
+
+#include <calendar/gui/e-memo-table.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MEMO_SHELL_CONTENT \
+ (e_memo_shell_content_get_type ())
+#define E_MEMO_SHELL_CONTENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MEMO_SHELL_CONTENT, EMemoShellContent))
+#define E_MEMO_SHELL_CONTENT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MEMO_SHELL_CONTENT, EMemoShellContentClass))
+#define E_IS_MEMO_SHELL_CONTENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MEMO_SHELL_CONTENT))
+#define E_IS_MEMO_SHELL_CONTENT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MEMO_SHELL_CONTENT))
+#define E_MEMO_SHELL_CONTENT_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MEMO_SHELL_CONTENT, EMemoShellContentClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMemoShellContent EMemoShellContent;
+typedef struct _EMemoShellContentClass EMemoShellContentClass;
+typedef struct _EMemoShellContentPrivate EMemoShellContentPrivate;
+
+enum {
+ E_MEMO_SHELL_CONTENT_SELECTION_SINGLE = 1 << 0,
+ E_MEMO_SHELL_CONTENT_SELECTION_MULTIPLE = 1 << 1,
+ E_MEMO_SHELL_CONTENT_SELECTION_CAN_EDIT = 1 << 2,
+ E_MEMO_SHELL_CONTENT_SELECTION_HAS_URL = 1 << 3
+};
+
+struct _EMemoShellContent {
+ EShellContent parent;
+ EMemoShellContentPrivate *priv;
+};
+
+struct _EMemoShellContentClass {
+ EShellContentClass parent_class;
+};
+
+GType e_memo_shell_content_get_type (void);
+void e_memo_shell_content_type_register
+ (GTypeModule *type_module);
+GtkWidget * e_memo_shell_content_new
+ (EShellView *shell_view);
+ECalModel * e_memo_shell_content_get_memo_model
+ (EMemoShellContent *memo_shell_conent);
+EMemoTable * e_memo_shell_content_get_memo_table
+ (EMemoShellContent *memo_shell_content);
+EPreviewPane * e_memo_shell_content_get_preview_pane
+ (EMemoShellContent *memo_shell_content);
+gboolean e_memo_shell_content_get_preview_visible
+ (EMemoShellContent *memo_shell_content);
+void e_memo_shell_content_set_preview_visible
+ (EMemoShellContent *memo_shell_content,
+ gboolean preview_visible);
+EShellSearchbar *
+ e_memo_shell_content_get_searchbar
+ (EMemoShellContent *memo_shell_content);
+
+G_END_DECLS
+
+#endif /* E_MEMO_SHELL_CONTENT_H */
diff --git a/modules/calendar/e-memo-shell-migrate.c b/modules/calendar/e-memo-shell-migrate.c
new file mode 100644
index 0000000000..08fe76775e
--- /dev/null
+++ b/modules/calendar/e-memo-shell-migrate.c
@@ -0,0 +1,38 @@
+/*
+ * e-memo-shell-migrate.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-memo-shell-migrate.h"
+
+gboolean
+e_memo_shell_backend_migrate (EShellBackend *shell_backend,
+ gint major,
+ gint minor,
+ gint revision,
+ GError **error)
+{
+ g_return_val_if_fail (E_IS_SHELL_BACKEND (shell_backend), FALSE);
+
+ return TRUE;
+}
diff --git a/modules/calendar/e-memo-shell-migrate.h b/modules/calendar/e-memo-shell-migrate.h
new file mode 100644
index 0000000000..b75612539f
--- /dev/null
+++ b/modules/calendar/e-memo-shell-migrate.h
@@ -0,0 +1,37 @@
+/*
+ * e-memo-shell-backend-migrate.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MEMO_SHELL_BACKEND_MIGRATE_H
+#define E_MEMO_SHELL_BACKEND_MIGRATE_H
+
+#include <shell/e-shell-backend.h>
+
+G_BEGIN_DECLS
+
+gboolean e_memo_shell_backend_migrate (EShellBackend *shell_backend,
+ gint major,
+ gint minor,
+ gint micro,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* E_MEMO_SHELL_BACKEND_MIGRATE_H */
diff --git a/modules/calendar/e-memo-shell-sidebar.c b/modules/calendar/e-memo-shell-sidebar.c
new file mode 100644
index 0000000000..a3ae5079ed
--- /dev/null
+++ b/modules/calendar/e-memo-shell-sidebar.c
@@ -0,0 +1,816 @@
+/*
+ * e-memo-shell-sidebar.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-memo-shell-sidebar.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+
+#include "e-util/e-util.h"
+#include "calendar/gui/e-memo-list-selector.h"
+#include "calendar/gui/misc.h"
+
+#define E_MEMO_SHELL_SIDEBAR_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MEMO_SHELL_SIDEBAR, EMemoShellSidebarPrivate))
+
+typedef struct _ConnectClosure ConnectClosure;
+
+struct _EMemoShellSidebarPrivate {
+ GtkWidget *selector;
+
+ /* The default client is for ECalModel. It follows the
+ * sidebar's primary selection, even if the highlighted
+ * source is not selected. The tricky part is we don't
+ * update the property until the client is successfully
+ * opened. So the user first highlights a source, then
+ * sometime later we update our default-client property
+ * which is bound by an EBinding to ECalModel. */
+ EClient *default_client;
+
+ /* Not referenced, only for pointer comparison. */
+ ESource *connecting_default_source_instance;
+
+ EActivity *connecting_default_client;
+};
+
+struct _ConnectClosure {
+ EMemoShellSidebar *memo_shell_sidebar;
+ EActivity *activity;
+
+ /* For error messages. */
+ gchar *unique_display_name;
+};
+
+enum {
+ PROP_0,
+ PROP_DEFAULT_CLIENT,
+ PROP_SELECTOR
+};
+
+enum {
+ CLIENT_ADDED,
+ CLIENT_REMOVED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+G_DEFINE_DYNAMIC_TYPE (
+ EMemoShellSidebar,
+ e_memo_shell_sidebar,
+ E_TYPE_SHELL_SIDEBAR)
+
+static ConnectClosure *
+connect_closure_new (EMemoShellSidebar *memo_shell_sidebar,
+ ESource *source)
+{
+ ConnectClosure *closure;
+ EAlertSink *alert_sink;
+ GCancellable *cancellable;
+ ESourceRegistry *registry;
+ ESourceSelector *selector;
+ EShellView *shell_view;
+ EShellBackend *shell_backend;
+ EShellContent *shell_content;
+ EShellSidebar *shell_sidebar;
+ gchar *text;
+
+ shell_sidebar = E_SHELL_SIDEBAR (memo_shell_sidebar);
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+ shell_content = e_shell_view_get_shell_content (shell_view);
+
+ selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
+ registry = e_source_selector_get_registry (selector);
+
+ closure = g_slice_new0 (ConnectClosure);
+ closure->memo_shell_sidebar = g_object_ref (memo_shell_sidebar);
+ closure->activity = e_activity_new ();
+ closure->unique_display_name =
+ e_source_registry_dup_unique_display_name (
+ registry, source, E_SOURCE_EXTENSION_MEMO_LIST);
+
+ text = g_strdup_printf (
+ _("Opening memo list '%s'"),
+ closure->unique_display_name);
+ e_activity_set_text (closure->activity, text);
+ g_free (text);
+
+ alert_sink = E_ALERT_SINK (shell_content);
+ e_activity_set_alert_sink (closure->activity, alert_sink);
+
+ cancellable = g_cancellable_new ();
+ e_activity_set_cancellable (closure->activity, cancellable);
+ g_object_unref (cancellable);
+
+ e_shell_backend_add_activity (shell_backend, closure->activity);
+
+ return closure;
+}
+
+static void
+connect_closure_free (ConnectClosure *closure)
+{
+ g_clear_object (&closure->memo_shell_sidebar);
+ g_clear_object (&closure->activity);
+
+ g_free (closure->unique_display_name);
+
+ g_slice_free (ConnectClosure, closure);
+}
+
+static gboolean
+memo_shell_sidebar_map_uid_to_source (GValue *value,
+ GVariant *variant,
+ gpointer user_data)
+{
+ ESourceRegistry *registry;
+ ESource *source;
+ const gchar *uid;
+
+ registry = E_SOURCE_REGISTRY (user_data);
+ uid = g_variant_get_string (variant, NULL);
+ if (uid != NULL && *uid != '\0')
+ source = e_source_registry_ref_source (registry, uid);
+ else
+ source = e_source_registry_ref_default_memo_list (registry);
+ g_value_take_object (value, source);
+
+ return (source != NULL);
+}
+
+static GVariant *
+memo_shell_sidebar_map_source_to_uid (const GValue *value,
+ const GVariantType *expected_type,
+ gpointer user_data)
+{
+ GVariant *variant = NULL;
+ ESource *source;
+
+ source = g_value_get_object (value);
+
+ if (source != NULL) {
+ const gchar *uid;
+
+ uid = e_source_get_uid (source);
+ variant = g_variant_new_string (uid);
+ }
+
+ return variant;
+}
+
+static void
+memo_shell_sidebar_emit_client_added (EMemoShellSidebar *memo_shell_sidebar,
+ EClient *client)
+{
+ guint signal_id = signals[CLIENT_ADDED];
+
+ g_signal_emit (memo_shell_sidebar, signal_id, 0, client);
+}
+
+static void
+memo_shell_sidebar_emit_client_removed (EMemoShellSidebar *memo_shell_sidebar,
+ EClient *client)
+{
+ guint signal_id = signals[CLIENT_REMOVED];
+
+ g_signal_emit (memo_shell_sidebar, signal_id, 0, client);
+}
+
+static void
+memo_shell_sidebar_handle_connect_error (EActivity *activity,
+ const gchar *unique_display_name,
+ const GError *error)
+{
+ EAlertSink *alert_sink;
+ gboolean cancelled = FALSE;
+ gboolean offline_error;
+
+ alert_sink = e_activity_get_alert_sink (activity);
+
+ cancelled |= g_error_matches (
+ error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
+ cancelled |= g_error_matches (
+ error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED);
+
+ offline_error = g_error_matches (
+ error, E_CLIENT_ERROR, E_CLIENT_ERROR_REPOSITORY_OFFLINE);
+
+ if (e_activity_handle_cancellation (activity, error)) {
+ /* do nothing */
+ } else if (offline_error) {
+ e_alert_submit (
+ alert_sink,
+ "calendar:prompt-no-contents-offline-memos",
+ unique_display_name,
+ NULL);
+ } else {
+ e_alert_submit (
+ alert_sink,
+ "calendar:failed-open-memos",
+ unique_display_name,
+ error->message,
+ NULL);
+ }
+}
+
+static void
+memo_shell_sidebar_client_connect_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EClient *client;
+ ConnectClosure *closure = user_data;
+ GError *error = NULL;
+
+ client = e_client_selector_get_client_finish (
+ E_CLIENT_SELECTOR (source_object), result, &error);
+
+ /* Sanity check. */
+ g_return_if_fail (
+ ((client != NULL) && (error == NULL)) ||
+ ((client == NULL) && (error != NULL)));
+
+ if (error != NULL) {
+ memo_shell_sidebar_handle_connect_error (
+ closure->activity,
+ closure->unique_display_name,
+ error);
+ g_error_free (error);
+ goto exit;
+ }
+
+ e_activity_set_state (closure->activity, E_ACTIVITY_COMPLETED);
+
+ e_memo_shell_sidebar_add_client (closure->memo_shell_sidebar, client);
+
+ g_object_unref (client);
+
+exit:
+ connect_closure_free (closure);
+}
+
+static void
+memo_shell_sidebar_default_connect_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EClient *client;
+ ESource *source;
+ ConnectClosure *closure = user_data;
+ EMemoShellSidebarPrivate *priv;
+ GError *error = NULL;
+
+ priv = E_MEMO_SHELL_SIDEBAR_GET_PRIVATE (closure->memo_shell_sidebar);
+
+ client = e_client_selector_get_client_finish (
+ E_CLIENT_SELECTOR (source_object), result, &error);
+
+ /* Sanity check. */
+ g_return_if_fail (
+ ((client != NULL) && (error == NULL)) ||
+ ((client == NULL) && (error != NULL)));
+
+ g_clear_object (&priv->connecting_default_client);
+
+ if (error != NULL) {
+ memo_shell_sidebar_handle_connect_error (
+ closure->activity,
+ closure->unique_display_name,
+ error);
+ g_error_free (error);
+ goto exit;
+ }
+
+ e_activity_set_state (closure->activity, E_ACTIVITY_COMPLETED);
+
+ source = e_client_get_source (client);
+
+ if (source == priv->connecting_default_source_instance)
+ priv->connecting_default_source_instance = NULL;
+
+ if (priv->default_client != NULL)
+ g_object_unref (priv->default_client);
+
+ priv->default_client = g_object_ref (client);
+
+ g_object_notify (
+ G_OBJECT (closure->memo_shell_sidebar), "default-client");
+
+ g_object_unref (client);
+
+exit:
+ connect_closure_free (closure);
+}
+
+static void
+memo_shell_sidebar_set_default (EMemoShellSidebar *memo_shell_sidebar,
+ ESource *source)
+{
+ EMemoShellSidebarPrivate *priv;
+ ESourceSelector *selector;
+ ConnectClosure *closure;
+
+ priv = memo_shell_sidebar->priv;
+
+ selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
+
+ /* already loading that source as default source */
+ if (source == priv->connecting_default_source_instance)
+ return;
+
+ /* Cancel the previous request if unfinished. */
+ if (priv->connecting_default_client != NULL) {
+ e_activity_cancel (priv->connecting_default_client);
+ g_object_unref (priv->connecting_default_client);
+ priv->connecting_default_client = NULL;
+ }
+
+ closure = connect_closure_new (memo_shell_sidebar, source);
+
+ /* it's only for pointer comparison, no need to ref it */
+ priv->connecting_default_source_instance = source;
+ priv->connecting_default_client = g_object_ref (closure->activity);
+
+ e_client_selector_get_client (
+ E_CLIENT_SELECTOR (selector), source,
+ e_activity_get_cancellable (closure->activity),
+ memo_shell_sidebar_default_connect_cb, closure);
+}
+
+static void
+memo_shell_sidebar_row_changed_cb (EMemoShellSidebar *memo_shell_sidebar,
+ GtkTreePath *tree_path,
+ GtkTreeIter *tree_iter,
+ GtkTreeModel *tree_model)
+{
+ ESourceSelector *selector;
+ ESource *source;
+
+ selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
+ source = e_source_selector_ref_source_by_path (selector, tree_path);
+
+ /* XXX This signal gets emitted a lot while the model is being
+ * rebuilt, during which time we won't get a valid ESource.
+ * ESourceSelector should probably block this signal while
+ * rebuilding the model, but we'll be forgiving and not
+ * emit a warning. */
+ if (source == NULL)
+ return;
+
+ if (e_source_selector_source_is_selected (selector, source))
+ e_memo_shell_sidebar_add_source (memo_shell_sidebar, source);
+ else
+ e_memo_shell_sidebar_remove_source (memo_shell_sidebar, source);
+
+ g_object_unref (source);
+}
+
+static void
+memo_shell_sidebar_primary_selection_changed_cb (EMemoShellSidebar *memo_shell_sidebar,
+ ESourceSelector *selector)
+{
+ ESource *source;
+
+ source = e_source_selector_ref_primary_selection (selector);
+ if (source == NULL)
+ return;
+
+ memo_shell_sidebar_set_default (memo_shell_sidebar, source);
+
+ g_object_unref (source);
+}
+
+static void
+memo_shell_sidebar_restore_state_cb (EShellWindow *shell_window,
+ EShellView *shell_view,
+ EShellSidebar *shell_sidebar)
+{
+ EMemoShellSidebarPrivate *priv;
+ ESourceRegistry *registry;
+ ESourceSelector *selector;
+ GSettings *settings;
+ GtkTreeModel *model;
+
+ priv = E_MEMO_SHELL_SIDEBAR_GET_PRIVATE (shell_sidebar);
+
+ selector = E_SOURCE_SELECTOR (priv->selector);
+ registry = e_source_selector_get_registry (selector);
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector));
+
+ g_signal_connect_swapped (
+ registry, "source-removed",
+ G_CALLBACK (e_memo_shell_sidebar_remove_source), shell_sidebar);
+
+ g_signal_connect_swapped (
+ model, "row-changed",
+ G_CALLBACK (memo_shell_sidebar_row_changed_cb),
+ shell_sidebar);
+
+ g_signal_connect_swapped (
+ selector, "primary-selection-changed",
+ G_CALLBACK (memo_shell_sidebar_primary_selection_changed_cb),
+ shell_sidebar);
+
+ /* This will trigger our "row-changed" signal handler for each
+ * memo list source, so the appropriate ECalClients get added to
+ * the ECalModel, which will then create view objects to display
+ * the memo list content. This all happens asynchronously. */
+ e_source_selector_update_all_rows (selector);
+
+ /* Bind GObject properties to settings keys. */
+
+ settings = g_settings_new ("org.gnome.evolution.calendar");
+
+ g_settings_bind_with_mapping (
+ settings, "primary-memos",
+ selector, "primary-selection",
+ G_SETTINGS_BIND_DEFAULT,
+ memo_shell_sidebar_map_uid_to_source,
+ memo_shell_sidebar_map_source_to_uid,
+ g_object_ref (registry),
+ (GDestroyNotify) g_object_unref);
+
+ g_object_unref (settings);
+}
+
+static void
+memo_shell_sidebar_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_DEFAULT_CLIENT:
+ g_value_set_object (
+ value,
+ e_memo_shell_sidebar_get_default_client (
+ E_MEMO_SHELL_SIDEBAR (object)));
+ return;
+
+ case PROP_SELECTOR:
+ g_value_set_object (
+ value,
+ e_memo_shell_sidebar_get_selector (
+ E_MEMO_SHELL_SIDEBAR (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+memo_shell_sidebar_dispose (GObject *object)
+{
+ EMemoShellSidebarPrivate *priv;
+
+ priv = E_MEMO_SHELL_SIDEBAR_GET_PRIVATE (object);
+
+ if (priv->selector != NULL) {
+ g_object_unref (priv->selector);
+ priv->selector = NULL;
+ }
+
+ if (priv->default_client != NULL) {
+ g_object_unref (priv->default_client);
+ priv->default_client = NULL;
+ }
+
+ if (priv->connecting_default_client != NULL) {
+ e_activity_cancel (priv->connecting_default_client);
+ g_object_unref (priv->connecting_default_client);
+ priv->connecting_default_client = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_memo_shell_sidebar_parent_class)->dispose (object);
+}
+
+static void
+memo_shell_sidebar_constructed (GObject *object)
+{
+ EMemoShellSidebarPrivate *priv;
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellSidebar *shell_sidebar;
+ EClientCache *client_cache;
+ GtkContainer *container;
+ GtkWidget *widget;
+ AtkObject *a11y;
+
+ priv = E_MEMO_SHELL_SIDEBAR_GET_PRIVATE (object);
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_memo_shell_sidebar_parent_class)->constructed (object);
+
+ shell_sidebar = E_SHELL_SIDEBAR (object);
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ container = GTK_CONTAINER (shell_sidebar);
+
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (
+ GTK_SCROLLED_WINDOW (widget),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (
+ GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+ gtk_container_add (container, widget);
+ gtk_widget_show (widget);
+
+ container = GTK_CONTAINER (widget);
+
+ client_cache = e_shell_get_client_cache (shell);
+ widget = e_memo_list_selector_new (client_cache);
+ e_source_selector_set_select_new (E_SOURCE_SELECTOR (widget), TRUE);
+ gtk_container_add (container, widget);
+ a11y = gtk_widget_get_accessible (widget);
+ atk_object_set_name (a11y, _("Memo List Selector"));
+ priv->selector = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ /* Restore widget state from the last session once
+ * the shell view is fully initialized and visible. */
+ g_signal_connect (
+ shell_window, "shell-view-created::memos",
+ G_CALLBACK (memo_shell_sidebar_restore_state_cb),
+ shell_sidebar);
+}
+
+static guint32
+memo_shell_sidebar_check_state (EShellSidebar *shell_sidebar)
+{
+ EMemoShellSidebar *memo_shell_sidebar;
+ ESourceSelector *selector;
+ ESourceRegistry *registry;
+ ESource *source;
+ gboolean is_writable = FALSE;
+ gboolean is_removable = FALSE;
+ gboolean is_remote_creatable = FALSE;
+ gboolean is_remote_deletable = FALSE;
+ gboolean in_collection = FALSE;
+ gboolean refresh_supported = FALSE;
+ gboolean has_primary_source = FALSE;
+ guint32 state = 0;
+
+ memo_shell_sidebar = E_MEMO_SHELL_SIDEBAR (shell_sidebar);
+ selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
+ source = e_source_selector_ref_primary_selection (selector);
+ registry = e_source_selector_get_registry (selector);
+
+ if (source != NULL) {
+ EClient *client;
+ ESource *collection;
+
+ has_primary_source = TRUE;
+ is_writable = e_source_get_writable (source);
+ is_removable = e_source_get_removable (source);
+ is_remote_creatable = e_source_get_remote_creatable (source);
+ is_remote_deletable = e_source_get_remote_deletable (source);
+
+ collection = e_source_registry_find_extension (
+ registry, source, E_SOURCE_EXTENSION_COLLECTION);
+ if (collection != NULL) {
+ in_collection = TRUE;
+ g_object_unref (collection);
+ }
+
+ client = e_client_selector_ref_cached_client (
+ E_CLIENT_SELECTOR (selector), source);
+
+ if (client != NULL) {
+ refresh_supported =
+ e_client_check_refresh_supported (client);
+ g_object_unref (client);
+ }
+
+ g_object_unref (source);
+ }
+
+ if (has_primary_source)
+ state |= E_MEMO_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE;
+ if (is_writable)
+ state |= E_MEMO_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_WRITABLE;
+ if (is_removable)
+ state |= E_MEMO_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOVABLE;
+ if (is_remote_creatable)
+ state |= E_MEMO_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_CREATABLE;
+ if (is_remote_deletable)
+ state |= E_MEMO_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_DELETABLE;
+ if (in_collection)
+ state |= E_MEMO_SHELL_SIDEBAR_PRIMARY_SOURCE_IN_COLLECTION;
+ if (refresh_supported)
+ state |= E_MEMO_SHELL_SIDEBAR_SOURCE_SUPPORTS_REFRESH;
+
+ return state;
+}
+
+static void
+memo_shell_sidebar_client_removed (EMemoShellSidebar *memo_shell_sidebar,
+ ECalClient *client)
+{
+ ESourceSelector *selector;
+ ESource *source;
+
+ source = e_client_get_source (E_CLIENT (client));
+
+ selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
+ e_source_selector_unselect_source (selector, source);
+}
+
+static void
+e_memo_shell_sidebar_class_init (EMemoShellSidebarClass *class)
+{
+ GObjectClass *object_class;
+ EShellSidebarClass *shell_sidebar_class;
+
+ g_type_class_add_private (class, sizeof (EMemoShellSidebarPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->get_property = memo_shell_sidebar_get_property;
+ object_class->dispose = memo_shell_sidebar_dispose;
+ object_class->constructed = memo_shell_sidebar_constructed;
+
+ shell_sidebar_class = E_SHELL_SIDEBAR_CLASS (class);
+ shell_sidebar_class->check_state = memo_shell_sidebar_check_state;
+
+ class->client_removed = memo_shell_sidebar_client_removed;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_DEFAULT_CLIENT,
+ g_param_spec_object (
+ "default-client",
+ "Default Memo ECalClient",
+ "Default client for memo operations",
+ E_TYPE_CAL_CLIENT,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SELECTOR,
+ g_param_spec_object (
+ "selector",
+ "Source Selector Widget",
+ "This widget displays groups of memo lists",
+ E_TYPE_SOURCE_SELECTOR,
+ G_PARAM_READABLE));
+
+ signals[CLIENT_ADDED] = g_signal_new (
+ "client-added",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EMemoShellSidebarClass, client_added),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ E_TYPE_CAL_CLIENT);
+
+ signals[CLIENT_REMOVED] = g_signal_new (
+ "client-removed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EMemoShellSidebarClass, client_removed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ E_TYPE_CAL_CLIENT);
+}
+
+static void
+e_memo_shell_sidebar_class_finalize (EMemoShellSidebarClass *class)
+{
+}
+
+static void
+e_memo_shell_sidebar_init (EMemoShellSidebar *memo_shell_sidebar)
+{
+ memo_shell_sidebar->priv =
+ E_MEMO_SHELL_SIDEBAR_GET_PRIVATE (memo_shell_sidebar);
+
+ /* Postpone widget construction until we have a shell view. */
+}
+
+void
+e_memo_shell_sidebar_type_register (GTypeModule *type_module)
+{
+ /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
+ * function, so we have to wrap it with a public function in
+ * order to register types from a separate compilation unit. */
+ e_memo_shell_sidebar_register_type (type_module);
+}
+
+GtkWidget *
+e_memo_shell_sidebar_new (EShellView *shell_view)
+{
+ g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
+
+ return g_object_new (
+ E_TYPE_MEMO_SHELL_SIDEBAR,
+ "shell-view", shell_view, NULL);
+}
+
+ECalClient *
+e_memo_shell_sidebar_get_default_client (EMemoShellSidebar *memo_shell_sidebar)
+{
+ g_return_val_if_fail (
+ E_IS_MEMO_SHELL_SIDEBAR (memo_shell_sidebar), NULL);
+
+ return (ECalClient *) memo_shell_sidebar->priv->default_client;
+}
+
+ESourceSelector *
+e_memo_shell_sidebar_get_selector (EMemoShellSidebar *memo_shell_sidebar)
+{
+ g_return_val_if_fail (
+ E_IS_MEMO_SHELL_SIDEBAR (memo_shell_sidebar), NULL);
+
+ return E_SOURCE_SELECTOR (memo_shell_sidebar->priv->selector);
+}
+
+void
+e_memo_shell_sidebar_add_client (EMemoShellSidebar *memo_shell_sidebar,
+ EClient *client)
+{
+ ESource *source;
+ ESourceSelector *selector;
+
+ g_return_if_fail (E_IS_MEMO_SHELL_SIDEBAR (memo_shell_sidebar));
+ g_return_if_fail (E_IS_CAL_CLIENT (client));
+
+ source = e_client_get_source (client);
+
+ selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
+ e_source_selector_select_source (selector, source);
+
+ memo_shell_sidebar_emit_client_added (memo_shell_sidebar, client);
+}
+
+void
+e_memo_shell_sidebar_add_source (EMemoShellSidebar *memo_shell_sidebar,
+ ESource *source)
+{
+ ESourceSelector *selector;
+ ConnectClosure *closure;
+
+ g_return_if_fail (E_IS_MEMO_SHELL_SIDEBAR (memo_shell_sidebar));
+ g_return_if_fail (E_IS_SOURCE (source));
+
+ selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
+
+ e_source_selector_select_source (selector, source);
+
+ closure = connect_closure_new (memo_shell_sidebar, source);
+
+ e_client_selector_get_client (
+ E_CLIENT_SELECTOR (selector), source,
+ e_activity_get_cancellable (closure->activity),
+ memo_shell_sidebar_client_connect_cb, closure);
+}
+
+void
+e_memo_shell_sidebar_remove_source (EMemoShellSidebar *memo_shell_sidebar,
+ ESource *source)
+{
+ ESourceSelector *selector;
+ EClient *client;
+
+ g_return_if_fail (E_IS_MEMO_SHELL_SIDEBAR (memo_shell_sidebar));
+ g_return_if_fail (E_IS_SOURCE (source));
+
+ selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
+
+ client = e_client_selector_ref_cached_client (
+ E_CLIENT_SELECTOR (selector), source);
+
+ if (client != NULL) {
+ memo_shell_sidebar_emit_client_removed (
+ memo_shell_sidebar, client);
+ g_object_unref (client);
+ }
+}
diff --git a/modules/calendar/e-memo-shell-sidebar.h b/modules/calendar/e-memo-shell-sidebar.h
new file mode 100644
index 0000000000..c9441c7155
--- /dev/null
+++ b/modules/calendar/e-memo-shell-sidebar.h
@@ -0,0 +1,103 @@
+/*
+ * e-memo-shell-sidebar.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MEMO_SHELL_SIDEBAR_H
+#define E_MEMO_SHELL_SIDEBAR_H
+
+#include <libecal/libecal.h>
+
+#include <shell/e-shell-sidebar.h>
+#include <shell/e-shell-view.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MEMO_SHELL_SIDEBAR \
+ (e_memo_shell_sidebar_get_type ())
+#define E_MEMO_SHELL_SIDEBAR(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MEMO_SHELL_SIDEBAR, EMemoShellSidebar))
+#define E_MEMO_SHELL_SIDEBAR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MEMO_SHELL_SIDEBAR, EMemoShellSidebarClass))
+#define E_IS_MEMO_SHELL_SIDEBAR(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MEMO_SHELL_SIDEBAR))
+#define E_IS_MEMO_SHELL_SIDEBAR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MEMO_SHELL_SIDEBAR))
+#define E_MEMO_SHELL_SIDEBAR_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MEMO_SHELL_SIDEBAR, EMemoShellSidebarClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMemoShellSidebar EMemoShellSidebar;
+typedef struct _EMemoShellSidebarClass EMemoShellSidebarClass;
+typedef struct _EMemoShellSidebarPrivate EMemoShellSidebarPrivate;
+
+enum {
+ E_MEMO_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE = 1 << 0,
+ E_MEMO_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_WRITABLE = 1 << 1,
+ E_MEMO_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOVABLE = 1 << 2,
+ E_MEMO_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_CREATABLE = 1 << 3,
+ E_MEMO_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_DELETABLE = 1 << 4,
+ E_MEMO_SHELL_SIDEBAR_PRIMARY_SOURCE_IN_COLLECTION = 1 << 5,
+ E_MEMO_SHELL_SIDEBAR_SOURCE_SUPPORTS_REFRESH = 1 << 6
+};
+
+struct _EMemoShellSidebar {
+ EShellSidebar parent;
+ EMemoShellSidebarPrivate *priv;
+};
+
+struct _EMemoShellSidebarClass {
+ EShellSidebarClass parent_class;
+
+ /* Signals */
+ void (*client_added) (EMemoShellSidebar *memo_shell_sidebar,
+ ECalClient *client);
+ void (*client_removed)
+ (EMemoShellSidebar *memo_shell_sidebar,
+ ECalClient *client);
+};
+
+GType e_memo_shell_sidebar_get_type (void);
+void e_memo_shell_sidebar_type_register
+ (GTypeModule *type_module);
+GtkWidget * e_memo_shell_sidebar_new
+ (EShellView *shell_view);
+ECalClient * e_memo_shell_sidebar_get_default_client
+ (EMemoShellSidebar *memo_shell_sidebar);
+ESourceSelector *
+ e_memo_shell_sidebar_get_selector
+ (EMemoShellSidebar *memo_shell_sidebar);
+void e_memo_shell_sidebar_add_client
+ (EMemoShellSidebar *memo_shell_sidebar,
+ EClient *client);
+void e_memo_shell_sidebar_add_source
+ (EMemoShellSidebar *memo_shell_sidebar,
+ ESource *source);
+void e_memo_shell_sidebar_remove_source
+ (EMemoShellSidebar *memo_shell_sidebar,
+ ESource *source);
+
+G_END_DECLS
+
+#endif /* E_MEMO_SHELL_SIDEBAR_H */
diff --git a/modules/calendar/e-memo-shell-view-actions.c b/modules/calendar/e-memo-shell-view-actions.c
new file mode 100644
index 0000000000..29dd68df9c
--- /dev/null
+++ b/modules/calendar/e-memo-shell-view-actions.c
@@ -0,0 +1,1049 @@
+/*
+ * e-memo-shell-view-actions.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-memo-shell-view-private.h"
+
+static void
+action_memo_delete_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EMemoShellContent *memo_shell_content;
+ EMemoTable *memo_table;
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+
+ e_selectable_delete_selection (E_SELECTABLE (memo_table));
+}
+
+static void
+action_memo_find_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EMemoShellContent *memo_shell_content;
+ EPreviewPane *preview_pane;
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ preview_pane = e_memo_shell_content_get_preview_pane (memo_shell_content);
+
+ e_preview_pane_show_search_bar (preview_pane);
+}
+
+static void
+action_memo_forward_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EMemoShellContent *memo_shell_content;
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ESourceRegistry *registry;
+ EMemoTable *memo_table;
+ ECalModelComponent *comp_data;
+ ECalComponent *comp;
+ icalcomponent *clone;
+ GSList *list;
+
+ shell_view = E_SHELL_VIEW (memo_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ registry = e_shell_get_registry (shell);
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+
+ list = e_memo_table_get_selected (memo_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only forward the first selected memo. */
+ comp = e_cal_component_new ();
+ clone = icalcomponent_new_clone (comp_data->icalcomp);
+ e_cal_component_set_icalcomponent (comp, clone);
+
+ itip_send_comp (
+ registry, E_CAL_COMPONENT_METHOD_PUBLISH, comp,
+ comp_data->client, NULL, NULL, NULL, TRUE, FALSE);
+
+ g_object_unref (comp);
+}
+
+static void
+action_memo_list_copy_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EMemoShellSidebar *memo_shell_sidebar;
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ESourceRegistry *registry;
+ ESourceSelector *selector;
+ ESource *source;
+
+ shell_view = E_SHELL_VIEW (memo_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ registry = e_shell_get_registry (shell);
+
+ memo_shell_sidebar = memo_shell_view->priv->memo_shell_sidebar;
+ selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
+ source = e_source_selector_ref_primary_selection (selector);
+ g_return_if_fail (source != NULL);
+
+ copy_source_dialog (
+ GTK_WINDOW (shell_window), registry,
+ source, E_CAL_CLIENT_SOURCE_TYPE_MEMOS);
+
+ g_object_unref (source);
+}
+
+static void
+action_memo_list_delete_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EMemoShellSidebar *memo_shell_sidebar;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ ESource *source;
+ ESourceSelector *selector;
+ gint response;
+
+ shell_view = E_SHELL_VIEW (memo_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ memo_shell_sidebar = memo_shell_view->priv->memo_shell_sidebar;
+ selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
+
+ source = e_source_selector_ref_primary_selection (selector);
+ g_return_if_fail (source != NULL);
+
+ if (e_source_get_remote_deletable (source)) {
+ response = e_alert_run_dialog_for_args (
+ GTK_WINDOW (shell_window),
+ "calendar:prompt-delete-remote-memo-list",
+ e_source_get_display_name (source), NULL);
+
+ if (response == GTK_RESPONSE_YES)
+ e_shell_view_remote_delete_source (shell_view, source);
+
+ } else {
+ response = e_alert_run_dialog_for_args (
+ GTK_WINDOW (shell_window),
+ "calendar:prompt-delete-memo-list",
+ e_source_get_display_name (source), NULL);
+
+ if (response == GTK_RESPONSE_YES)
+ e_shell_view_remove_source (shell_view, source);
+ }
+
+ g_object_unref (source);
+}
+
+static void
+action_memo_list_new_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ESourceRegistry *registry;
+ ECalClientSourceType source_type;
+ GtkWidget *config;
+ GtkWidget *dialog;
+ const gchar *icon_name;
+
+ shell_view = E_SHELL_VIEW (memo_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ registry = e_shell_get_registry (shell);
+ source_type = E_CAL_CLIENT_SOURCE_TYPE_MEMOS;
+ config = e_cal_source_config_new (registry, NULL, source_type);
+
+ dialog = e_source_config_dialog_new (E_SOURCE_CONFIG (config));
+
+ gtk_window_set_transient_for (
+ GTK_WINDOW (dialog), GTK_WINDOW (shell_window));
+
+ icon_name = gtk_action_get_icon_name (action);
+ gtk_window_set_icon_name (GTK_WINDOW (dialog), icon_name);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), _("New Memo List"));
+
+ gtk_widget_show (dialog);
+}
+
+static void
+action_memo_list_print_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EMemoShellContent *memo_shell_content;
+ EMemoTable *memo_table;
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+
+ print_table (
+ E_TABLE (memo_table), _("Print Memos"), _("Memos"),
+ GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG);
+}
+
+static void
+action_memo_list_print_preview_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EMemoShellContent *memo_shell_content;
+ EMemoTable *memo_table;
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+
+ print_table (
+ E_TABLE (memo_table), _("Print Memos"), _("Memos"),
+ GTK_PRINT_OPERATION_ACTION_PREVIEW);
+}
+
+static void
+action_memo_list_properties_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EMemoShellSidebar *memo_shell_sidebar;
+ ECalClientSourceType source_type;
+ ESource *source;
+ ESourceSelector *selector;
+ ESourceRegistry *registry;
+ GtkWidget *config;
+ GtkWidget *dialog;
+ const gchar *icon_name;
+
+ shell_view = E_SHELL_VIEW (memo_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ memo_shell_sidebar = memo_shell_view->priv->memo_shell_sidebar;
+ selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
+ source = e_source_selector_ref_primary_selection (selector);
+ g_return_if_fail (source != NULL);
+
+ source_type = E_CAL_CLIENT_SOURCE_TYPE_MEMOS;
+ registry = e_source_selector_get_registry (selector);
+ config = e_cal_source_config_new (registry, source, source_type);
+
+ g_object_unref (source);
+
+ dialog = e_source_config_dialog_new (E_SOURCE_CONFIG (config));
+
+ gtk_window_set_transient_for (
+ GTK_WINDOW (dialog), GTK_WINDOW (shell_window));
+
+ icon_name = gtk_action_get_icon_name (action);
+ gtk_window_set_icon_name (GTK_WINDOW (dialog), icon_name);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), _("Memo List Properties"));
+
+ gtk_widget_show (dialog);
+}
+
+static void
+action_memo_list_refresh_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EMemoShellSidebar *memo_shell_sidebar;
+ ESourceSelector *selector;
+ EClient *client = NULL;
+ ESource *source;
+ GError *error = NULL;
+
+ memo_shell_sidebar = memo_shell_view->priv->memo_shell_sidebar;
+ selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
+
+ source = e_source_selector_ref_primary_selection (selector);
+
+ if (source != NULL) {
+ client = e_client_selector_ref_cached_client (
+ E_CLIENT_SELECTOR (selector), source);
+ g_object_unref (source);
+ }
+
+ if (client == NULL)
+ return;
+
+ g_return_if_fail (e_client_check_refresh_supported (client));
+
+ e_client_refresh_sync (client, NULL, &error);
+
+ if (error != NULL) {
+ g_warning (
+ "%s: Failed to refresh '%s', %s",
+ G_STRFUNC, e_source_get_display_name (source),
+ error->message);
+ g_error_free (error);
+ }
+
+ g_object_unref (client);
+}
+
+static void
+action_memo_list_rename_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EMemoShellSidebar *memo_shell_sidebar;
+ ESourceSelector *selector;
+
+ memo_shell_sidebar = memo_shell_view->priv->memo_shell_sidebar;
+ selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
+
+ e_source_selector_edit_primary_selection (selector);
+}
+
+static void
+action_memo_list_select_one_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EMemoShellSidebar *memo_shell_sidebar;
+ ESourceSelector *selector;
+ ESource *primary;
+
+ memo_shell_sidebar = memo_shell_view->priv->memo_shell_sidebar;
+ selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
+
+ primary = e_source_selector_ref_primary_selection (selector);
+ g_return_if_fail (primary != NULL);
+
+ e_source_selector_select_exclusive (selector, primary);
+
+ g_object_unref (primary);
+}
+
+static void
+action_memo_new_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EMemoShellContent *memo_shell_content;
+ EMemoTable *memo_table;
+ ECalClient *client;
+ ECalComponent *comp;
+ CompEditor *editor;
+ GSList *list;
+
+ shell_view = E_SHELL_VIEW (memo_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+
+ list = e_memo_table_get_selected (memo_table);
+ if (list == NULL) {
+ ECalModel *model;
+
+ model = e_memo_table_get_model (memo_table);
+ client = e_cal_model_ref_default_client (model);
+ } else {
+ ECalModelComponent *comp_data;
+
+ comp_data = list->data;
+ client = g_object_ref (comp_data->client);
+ g_slist_free (list);
+ }
+
+ g_return_if_fail (client != NULL);
+
+ comp = cal_comp_memo_new_with_defaults (client);
+ cal_comp_update_time_by_active_window (comp, shell);
+ editor = memo_editor_new (client, shell, COMP_EDITOR_NEW_ITEM);
+ comp_editor_edit_comp (editor, comp);
+
+ gtk_window_present (GTK_WINDOW (editor));
+
+ g_object_unref (comp);
+
+ g_object_unref (client);
+}
+
+static void
+action_memo_open_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EMemoShellContent *memo_shell_content;
+ EMemoTable *memo_table;
+ ECalModelComponent *comp_data;
+ GSList *list;
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+
+ list = e_memo_table_get_selected (memo_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only open the first selected memo. */
+ e_memo_shell_view_open_memo (memo_shell_view, comp_data);
+}
+
+static void
+action_memo_open_url_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EMemoShellContent *memo_shell_content;
+ EMemoTable *memo_table;
+ ECalModelComponent *comp_data;
+ icalproperty *prop;
+ const gchar *uri;
+ GSList *list;
+
+ shell_view = E_SHELL_VIEW (memo_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+
+ list = e_memo_table_get_selected (memo_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only open the URI of the first selected memo. */
+ prop = icalcomponent_get_first_property (
+ comp_data->icalcomp, ICAL_URL_PROPERTY);
+ g_return_if_fail (prop != NULL);
+
+ uri = icalproperty_get_url (prop);
+ e_show_uri (GTK_WINDOW (shell_window), uri);
+}
+
+static void
+action_memo_preview_cb (GtkToggleAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EMemoShellContent *memo_shell_content;
+ gboolean visible;
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ visible = gtk_toggle_action_get_active (action);
+ e_memo_shell_content_set_preview_visible (memo_shell_content, visible);
+}
+
+static void
+action_memo_print_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EMemoShellContent *memo_shell_content;
+ EMemoTable *memo_table;
+ ECalModelComponent *comp_data;
+ ECalComponent *comp;
+ ECalModel *model;
+ icalcomponent *clone;
+ GSList *list;
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+ model = e_memo_table_get_model (memo_table);
+
+ list = e_memo_table_get_selected (memo_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only print the first selected memo. */
+ comp = e_cal_component_new ();
+ clone = icalcomponent_new_clone (comp_data->icalcomp);
+ e_cal_component_set_icalcomponent (comp, clone);
+
+ print_comp (
+ comp, comp_data->client,
+ e_cal_model_get_timezone (model),
+ e_cal_model_get_use_24_hour_format (model),
+ GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG);
+
+ g_object_unref (comp);
+}
+
+static void
+action_memo_save_as_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellBackend *shell_backend;
+ EMemoShellContent *memo_shell_content;
+ EMemoTable *memo_table;
+ ECalModelComponent *comp_data;
+ EActivity *activity;
+ GSList *list;
+ GFile *file;
+ gchar *string;
+
+ shell_view = E_SHELL_VIEW (memo_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+
+ list = e_memo_table_get_selected (memo_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* Translators: Default filename part saving a memo to a file when
+ * no summary is filed, the '.ics' extension is concatenated to it. */
+ string = icalcomp_suggest_filename (comp_data->icalcomp, _("memo"));
+ file = e_shell_run_save_dialog (
+ shell, _("Save as iCalendar"), string,
+ "*.ics:text/calendar", NULL, NULL);
+ g_free (string);
+ if (file == NULL)
+ return;
+
+ /* XXX We only save the first selected memo. */
+ string = e_cal_client_get_component_as_string (
+ comp_data->client, comp_data->icalcomp);
+ if (string == NULL) {
+ g_warning ("Could not convert memo to a string");
+ g_object_unref (file);
+ return;
+ }
+
+ /* XXX No callback means errors are discarded. */
+ activity = e_file_replace_contents_async (
+ file, string, strlen (string), NULL, FALSE,
+ G_FILE_CREATE_NONE, (GAsyncReadyCallback) NULL, NULL);
+ e_shell_backend_add_activity (shell_backend, activity);
+
+ /* Free the string when the activity is finalized. */
+ g_object_set_data_full (
+ G_OBJECT (activity),
+ "file-content", string,
+ (GDestroyNotify) g_free);
+
+ g_object_unref (file);
+}
+
+static void
+action_memo_view_cb (GtkRadioAction *action,
+ GtkRadioAction *current,
+ EMemoShellView *memo_shell_view)
+{
+ EMemoShellContent *memo_shell_content;
+ GtkOrientable *orientable;
+ GtkOrientation orientation;
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ orientable = GTK_ORIENTABLE (memo_shell_content);
+
+ switch (gtk_radio_action_get_current_value (action)) {
+ case 0:
+ orientation = GTK_ORIENTATION_VERTICAL;
+ break;
+ case 1:
+ orientation = GTK_ORIENTATION_HORIZONTAL;
+ break;
+ default:
+ g_return_if_reached ();
+ }
+
+ gtk_orientable_set_orientation (orientable, orientation);
+}
+
+static GtkActionEntry memo_entries[] = {
+
+ { "memo-delete",
+ GTK_STOCK_DELETE,
+ N_("_Delete Memo"),
+ NULL,
+ N_("Delete selected memos"),
+ G_CALLBACK (action_memo_delete_cb) },
+
+ { "memo-find",
+ GTK_STOCK_FIND,
+ N_("_Find in Memo..."),
+ "<Shift><Control>f",
+ N_("Search for text in the displayed memo"),
+ G_CALLBACK (action_memo_find_cb) },
+
+ { "memo-forward",
+ "mail-forward",
+ N_("_Forward as iCalendar..."),
+ "<Control>f",
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_memo_forward_cb) },
+
+ { "memo-list-copy",
+ GTK_STOCK_COPY,
+ N_("_Copy..."),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_memo_list_copy_cb) },
+
+ { "memo-list-delete",
+ GTK_STOCK_DELETE,
+ N_("D_elete Memo List"),
+ NULL,
+ N_("Delete the selected memo list"),
+ G_CALLBACK (action_memo_list_delete_cb) },
+
+ { "memo-list-new",
+ "stock_notes",
+ N_("_New Memo List"),
+ NULL,
+ N_("Create a new memo list"),
+ G_CALLBACK (action_memo_list_new_cb) },
+
+ { "memo-list-properties",
+ GTK_STOCK_PROPERTIES,
+ NULL,
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_memo_list_properties_cb) },
+
+ { "memo-list-refresh",
+ GTK_STOCK_REFRESH,
+ N_("Re_fresh"),
+ NULL,
+ N_("Refresh the selected memo list"),
+ G_CALLBACK (action_memo_list_refresh_cb) },
+
+ { "memo-list-rename",
+ NULL,
+ N_("_Rename..."),
+ "F2",
+ N_("Rename the selected memo list"),
+ G_CALLBACK (action_memo_list_rename_cb) },
+
+ { "memo-list-select-one",
+ "stock_check-filled",
+ N_("Show _Only This Memo List"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_memo_list_select_one_cb) },
+
+ { "memo-new",
+ "stock_insert-note",
+ N_("New _Memo"),
+ NULL,
+ N_("Create a new memo"),
+ G_CALLBACK (action_memo_new_cb) },
+
+ { "memo-open",
+ GTK_STOCK_OPEN,
+ N_("_Open Memo"),
+ "<Control>o",
+ N_("View the selected memo"),
+ G_CALLBACK (action_memo_open_cb) },
+
+ { "memo-open-url",
+ "applications-internet",
+ N_("Open _Web Page"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_memo_open_url_cb) },
+
+ /*** Menus ***/
+
+ { "memo-preview-menu",
+ NULL,
+ N_("_Preview"),
+ NULL,
+ NULL,
+ NULL }
+};
+
+static EPopupActionEntry memo_popup_entries[] = {
+
+ { "memo-list-popup-copy",
+ NULL,
+ "memo-list-copy" },
+
+ { "memo-list-popup-delete",
+ N_("_Delete"),
+ "memo-list-delete" },
+
+ { "memo-list-popup-properties",
+ NULL,
+ "memo-list-properties" },
+
+ { "memo-list-popup-refresh",
+ NULL,
+ "memo-list-refresh" },
+
+ { "memo-list-popup-rename",
+ NULL,
+ "memo-list-rename" },
+
+ { "memo-list-popup-select-one",
+ NULL,
+ "memo-list-select-one" },
+
+ { "memo-popup-forward",
+ NULL,
+ "memo-forward" },
+
+ { "memo-popup-open",
+ NULL,
+ "memo-open" },
+
+ { "memo-popup-open-url",
+ NULL,
+ "memo-open-url" }
+};
+
+static GtkToggleActionEntry memo_toggle_entries[] = {
+
+ { "memo-preview",
+ NULL,
+ N_("Memo _Preview"),
+ "<Control>m",
+ N_("Show memo preview pane"),
+ G_CALLBACK (action_memo_preview_cb),
+ TRUE }
+};
+
+static GtkRadioActionEntry memo_view_entries[] = {
+
+ /* This action represents the initial active memo view.
+ * It should not be visible in the UI, nor should it be
+ * possible to switch to it from another shell view. */
+ { "memo-view-initial",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ -1 },
+
+ { "memo-view-classic",
+ NULL,
+ N_("_Classic View"),
+ NULL,
+ N_("Show memo preview below the memo list"),
+ 0 },
+
+ { "memo-view-vertical",
+ NULL,
+ N_("_Vertical View"),
+ NULL,
+ N_("Show memo preview alongside the memo list"),
+ 1 }
+};
+
+static GtkRadioActionEntry memo_filter_entries[] = {
+
+ { "memo-filter-any-category",
+ NULL,
+ N_("Any Category"),
+ NULL,
+ NULL,
+ MEMO_FILTER_ANY_CATEGORY },
+
+ { "memo-filter-unmatched",
+ NULL,
+ N_("Unmatched"),
+ NULL,
+ NULL,
+ MEMO_FILTER_UNMATCHED }
+};
+
+static GtkRadioActionEntry memo_search_entries[] = {
+
+ { "memo-search-advanced-hidden",
+ NULL,
+ N_("Advanced Search"),
+ NULL,
+ NULL,
+ MEMO_SEARCH_ADVANCED },
+
+ { "memo-search-any-field-contains",
+ NULL,
+ N_("Any field contains"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ MEMO_SEARCH_ANY_FIELD_CONTAINS },
+
+ { "memo-search-description-contains",
+ NULL,
+ N_("Description contains"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ MEMO_SEARCH_DESCRIPTION_CONTAINS },
+
+ { "memo-search-summary-contains",
+ NULL,
+ N_("Summary contains"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ MEMO_SEARCH_SUMMARY_CONTAINS }
+};
+
+static GtkActionEntry lockdown_printing_entries[] = {
+
+ { "memo-list-print",
+ GTK_STOCK_PRINT,
+ NULL,
+ "<Control>p",
+ N_("Print the list of memos"),
+ G_CALLBACK (action_memo_list_print_cb) },
+
+ { "memo-list-print-preview",
+ GTK_STOCK_PRINT_PREVIEW,
+ NULL,
+ NULL,
+ N_("Preview the list of memos to be printed"),
+ G_CALLBACK (action_memo_list_print_preview_cb) },
+
+ { "memo-print",
+ GTK_STOCK_PRINT,
+ NULL,
+ NULL,
+ N_("Print the selected memo"),
+ G_CALLBACK (action_memo_print_cb) }
+};
+
+static EPopupActionEntry lockdown_printing_popup_entries[] = {
+
+ { "memo-popup-print",
+ NULL,
+ "memo-print" }
+};
+
+static GtkActionEntry lockdown_save_to_disk_entries[] = {
+
+ { "memo-save-as",
+ GTK_STOCK_SAVE_AS,
+ N_("_Save as iCalendar..."),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_memo_save_as_cb) },
+};
+
+static EPopupActionEntry lockdown_save_to_disk_popup_entries[] = {
+
+ { "memo-popup-save-as",
+ NULL,
+ "memo-save-as" }
+};
+
+void
+e_memo_shell_view_actions_init (EMemoShellView *memo_shell_view)
+{
+ EMemoShellContent *memo_shell_content;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellSearchbar *searchbar;
+ EPreviewPane *preview_pane;
+ EWebView *web_view;
+ GtkActionGroup *action_group;
+ GSettings *memo_settings;
+ GtkAction *action;
+
+ shell_view = E_SHELL_VIEW (memo_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ searchbar = e_memo_shell_content_get_searchbar (memo_shell_content);
+ preview_pane = e_memo_shell_content_get_preview_pane (memo_shell_content);
+ web_view = e_preview_pane_get_web_view (preview_pane);
+
+ /* Memo Actions */
+ action_group = ACTION_GROUP (MEMOS);
+ gtk_action_group_add_actions (
+ action_group, memo_entries,
+ G_N_ELEMENTS (memo_entries), memo_shell_view);
+ e_action_group_add_popup_actions (
+ action_group, memo_popup_entries,
+ G_N_ELEMENTS (memo_popup_entries));
+ gtk_action_group_add_toggle_actions (
+ action_group, memo_toggle_entries,
+ G_N_ELEMENTS (memo_toggle_entries), memo_shell_view);
+ gtk_action_group_add_radio_actions (
+ action_group, memo_view_entries,
+ G_N_ELEMENTS (memo_view_entries), -1,
+ G_CALLBACK (action_memo_view_cb), memo_shell_view);
+ gtk_action_group_add_radio_actions (
+ action_group, memo_search_entries,
+ G_N_ELEMENTS (memo_search_entries),
+ -1, NULL, NULL);
+
+ /* Advanced Search Action */
+ action = ACTION (MEMO_SEARCH_ADVANCED_HIDDEN);
+ gtk_action_set_visible (action, FALSE);
+ e_shell_searchbar_set_search_option (
+ searchbar, GTK_RADIO_ACTION (action));
+
+ /* Lockdown Printing Actions */
+ action_group = ACTION_GROUP (LOCKDOWN_PRINTING);
+ gtk_action_group_add_actions (
+ action_group, lockdown_printing_entries,
+ G_N_ELEMENTS (lockdown_printing_entries),
+ memo_shell_view);
+ e_action_group_add_popup_actions (
+ action_group, lockdown_printing_popup_entries,
+ G_N_ELEMENTS (lockdown_printing_popup_entries));
+
+ /* Lockdown Save-to-Disk Actions */
+ action_group = ACTION_GROUP (LOCKDOWN_SAVE_TO_DISK);
+ gtk_action_group_add_actions (
+ action_group, lockdown_save_to_disk_entries,
+ G_N_ELEMENTS (lockdown_save_to_disk_entries),
+ memo_shell_view);
+ e_action_group_add_popup_actions (
+ action_group, lockdown_save_to_disk_popup_entries,
+ G_N_ELEMENTS (lockdown_save_to_disk_popup_entries));
+
+ /* Bind GObject properties to settings keys. */
+
+ memo_settings = g_settings_new ("org.gnome.evolution.calendar");
+
+ g_settings_bind (
+ memo_settings, "show-memo-preview",
+ ACTION (MEMO_PREVIEW), "active",
+ G_SETTINGS_BIND_DEFAULT);
+
+ g_settings_bind (
+ memo_settings, "memo-layout",
+ ACTION (MEMO_VIEW_VERTICAL), "current-value",
+ G_SETTINGS_BIND_DEFAULT);
+
+ g_object_unref (memo_settings);
+
+ /* Fine tuning. */
+
+ g_object_bind_property (
+ ACTION (MEMO_PREVIEW), "active",
+ ACTION (MEMO_VIEW_CLASSIC), "sensitive",
+ G_BINDING_SYNC_CREATE);
+
+ g_object_bind_property (
+ ACTION (MEMO_PREVIEW), "active",
+ ACTION (MEMO_VIEW_VERTICAL), "sensitive",
+ G_BINDING_SYNC_CREATE);
+
+ e_web_view_set_open_proxy (web_view, ACTION (MEMO_OPEN));
+ e_web_view_set_print_proxy (web_view, ACTION (MEMO_PRINT));
+ e_web_view_set_save_as_proxy (web_view, ACTION (MEMO_SAVE_AS));
+}
+
+void
+e_memo_shell_view_update_search_filter (EMemoShellView *memo_shell_view)
+{
+ EMemoShellContent *memo_shell_content;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellSearchbar *searchbar;
+ EActionComboBox *combo_box;
+ GtkActionGroup *action_group;
+ GtkRadioAction *radio_action;
+ GList *list, *iter;
+ GSList *group;
+ gint ii;
+
+ shell_view = E_SHELL_VIEW (memo_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ action_group = ACTION_GROUP (MEMOS_FILTER);
+ e_action_group_remove_all_actions (action_group);
+
+ /* Add the standard filter actions. No callback is needed
+ * because changes in the EActionComboBox are detected and
+ * handled by EShellSearchbar. */
+ gtk_action_group_add_radio_actions (
+ action_group, memo_filter_entries,
+ G_N_ELEMENTS (memo_filter_entries),
+ MEMO_FILTER_ANY_CATEGORY, NULL, NULL);
+
+ /* Retrieve the radio group from an action we just added. */
+ list = gtk_action_group_list_actions (action_group);
+ radio_action = GTK_RADIO_ACTION (list->data);
+ group = gtk_radio_action_get_group (radio_action);
+ g_list_free (list);
+
+ /* Build the category actions. */
+
+ list = e_util_get_searchable_categories ();
+ for (iter = list, ii = 0; iter != NULL; iter = iter->next, ii++) {
+ const gchar *category_name = iter->data;
+ const gchar *filename;
+ GtkAction *action;
+ gchar *action_name;
+
+ action_name = g_strdup_printf (
+ "memo-filter-category-%d", ii);
+ radio_action = gtk_radio_action_new (
+ action_name, category_name, NULL, NULL, ii);
+ g_free (action_name);
+
+ /* Convert the category icon file to a themed icon name. */
+ filename = e_categories_get_icon_file_for (category_name);
+ if (filename != NULL && *filename != '\0') {
+ gchar *basename;
+ gchar *cp;
+
+ basename = g_path_get_basename (filename);
+
+ /* Lose the file extension. */
+ if ((cp = strrchr (basename, '.')) != NULL)
+ *cp = '\0';
+
+ g_object_set (
+ radio_action, "icon-name", basename, NULL);
+
+ g_free (basename);
+ }
+
+ gtk_radio_action_set_group (radio_action, group);
+ group = gtk_radio_action_get_group (radio_action);
+
+ /* The action group takes ownership of the action. */
+ action = GTK_ACTION (radio_action);
+ gtk_action_group_add_action (action_group, action);
+ g_object_unref (radio_action);
+ }
+ g_list_free (list);
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ searchbar = e_memo_shell_content_get_searchbar (memo_shell_content);
+ combo_box = e_shell_searchbar_get_filter_combo_box (searchbar);
+
+ e_shell_view_block_execute_search (shell_view);
+
+ /* Use any action in the group; doesn't matter which. */
+ e_action_combo_box_set_action (combo_box, radio_action);
+
+ ii = MEMO_FILTER_UNMATCHED;
+ e_action_combo_box_add_separator_after (combo_box, ii);
+
+ e_shell_view_unblock_execute_search (shell_view);
+}
diff --git a/modules/calendar/e-memo-shell-view-actions.h b/modules/calendar/e-memo-shell-view-actions.h
new file mode 100644
index 0000000000..c9d144b5d4
--- /dev/null
+++ b/modules/calendar/e-memo-shell-view-actions.h
@@ -0,0 +1,91 @@
+/*
+ * e-memo-shell-view-actions.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MEMO_SHELL_VIEW_ACTIONS_H
+#define E_MEMO_SHELL_VIEW_ACTIONS_H
+
+#include <shell/e-shell-window-actions.h>
+
+/* Memo Actions */
+#define E_SHELL_WINDOW_ACTION_MEMO_DELETE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-delete")
+#define E_SHELL_WINDOW_ACTION_MEMO_FIND(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-find")
+#define E_SHELL_WINDOW_ACTION_MEMO_FORWARD(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-forward")
+#define E_SHELL_WINDOW_ACTION_MEMO_NEW(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-new")
+#define E_SHELL_WINDOW_ACTION_MEMO_OPEN(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-open")
+#define E_SHELL_WINDOW_ACTION_MEMO_OPEN_URL(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-open-url")
+#define E_SHELL_WINDOW_ACTION_MEMO_PREVIEW(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-preview")
+#define E_SHELL_WINDOW_ACTION_MEMO_PRINT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-print")
+#define E_SHELL_WINDOW_ACTION_MEMO_SAVE_AS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-save-as")
+#define E_SHELL_WINDOW_ACTION_MEMO_VIEW_CLASSIC(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-view-classic")
+#define E_SHELL_WINDOW_ACTION_MEMO_VIEW_VERTICAL(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-view-vertical")
+
+/* Memo List Actions */
+#define E_SHELL_WINDOW_ACTION_MEMO_LIST_COPY(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-list-copy")
+#define E_SHELL_WINDOW_ACTION_MEMO_LIST_DELETE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-list-delete")
+#define E_SHELL_WINDOW_ACTION_MEMO_LIST_NEW(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-list-new")
+#define E_SHELL_WINDOW_ACTION_MEMO_LIST_PRINT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-list-print")
+#define E_SHELL_WINDOW_ACTION_MEMO_LIST_PRINT_PREVIEW(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-list-print-preview")
+#define E_SHELL_WINDOW_ACTION_MEMO_LIST_PROPERTIES(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-list-properties")
+#define E_SHELL_WINDOW_ACTION_MEMO_LIST_REFRESH(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-list-refresh")
+#define E_SHELL_WINDOW_ACTION_MEMO_LIST_RENAME(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-list-rename")
+#define E_SHELL_WINDOW_ACTION_MEMO_LIST_SELECT_ONE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-list-select-one")
+
+/* Memo Query Actions */
+#define E_SHELL_WINDOW_ACTION_MEMO_FILTER_ANY_CATEGORY(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-filter-any-category")
+#define E_SHELL_WINDOW_ACTION_MEMO_FILTER_UNMATCHED(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-filter-unmatched")
+#define E_SHELL_WINDOW_ACTION_MEMO_SEARCH_ADVANCED_HIDDEN(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-search-advanced-hidden")
+#define E_SHELL_WINDOW_ACTION_MEMO_SEARCH_ANY_FIELD_CONTAINS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-search-any-field-contains")
+#define E_SHELL_WINDOW_ACTION_MEMO_SEARCH_DESCRIPTION_CONTAINS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-search-description-contains")
+#define E_SHELL_WINDOW_ACTION_MEMO_SEARCH_SUMMARY_CONTAINS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-search-summary-contains")
+
+/* Action Groups */
+#define E_SHELL_WINDOW_ACTION_GROUP_MEMOS(window) \
+ E_SHELL_WINDOW_ACTION_GROUP ((window), "memos")
+#define E_SHELL_WINDOW_ACTION_GROUP_MEMOS_FILTER(window) \
+ E_SHELL_WINDOW_ACTION_GROUP ((window), "memos-filter")
+
+#endif /* E_MEMO_SHELL_VIEW_ACTIONS_H */
diff --git a/modules/calendar/e-memo-shell-view-private.c b/modules/calendar/e-memo-shell-view-private.c
new file mode 100644
index 0000000000..df5182731d
--- /dev/null
+++ b/modules/calendar/e-memo-shell-view-private.c
@@ -0,0 +1,551 @@
+/*
+ * e-memo-shell-view-private.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-util/e-util-private.h"
+
+#include "e-memo-shell-view-private.h"
+
+static void
+memo_shell_view_model_row_appended_cb (EMemoShellView *memo_shell_view,
+ ECalModel *model)
+{
+ EMemoShellSidebar *memo_shell_sidebar;
+ ECalClient *client;
+
+ /* This is the "Click to Add" handler. */
+
+ client = e_cal_model_ref_default_client (model);
+
+ memo_shell_sidebar = memo_shell_view->priv->memo_shell_sidebar;
+ e_memo_shell_sidebar_add_client (memo_shell_sidebar, E_CLIENT (client));
+
+ g_object_unref (client);
+}
+
+static void
+memo_shell_view_table_popup_event_cb (EShellView *shell_view,
+ GdkEvent *button_event)
+{
+ const gchar *widget_path;
+
+ widget_path = "/memo-popup";
+ e_shell_view_show_popup_menu (shell_view, widget_path, button_event);
+}
+
+static void
+memo_shell_view_selector_client_added_cb (EMemoShellView *memo_shell_view,
+ ECalClient *client)
+{
+ EMemoShellContent *memo_shell_content;
+ EMemoTable *memo_table;
+ ECalModel *model;
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+ model = e_memo_table_get_model (memo_table);
+
+ e_cal_model_add_client (model, client);
+}
+
+static void
+memo_shell_view_selector_client_removed_cb (EMemoShellView *memo_shell_view,
+ ECalClient *client)
+{
+ EMemoShellContent *memo_shell_content;
+ EMemoTable *memo_table;
+ ECalModel *model;
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+ model = e_memo_table_get_model (memo_table);
+
+ e_cal_model_remove_client (model, client);
+}
+
+static gboolean
+memo_shell_view_selector_popup_event_cb (EShellView *shell_view,
+ ESource *primary_source,
+ GdkEvent *button_event)
+{
+ const gchar *widget_path;
+
+ widget_path = "/memo-list-popup";
+ e_shell_view_show_popup_menu (shell_view, widget_path, button_event);
+
+ return TRUE;
+}
+
+static void
+memo_shell_view_backend_error_cb (EClientCache *client_cache,
+ EClient *client,
+ EAlert *alert,
+ EMemoShellView *memo_shell_view)
+{
+ EMemoShellContent *memo_shell_content;
+ ESource *source;
+ const gchar *extension_name;
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+
+ source = e_client_get_source (client);
+ extension_name = E_SOURCE_EXTENSION_MEMO_LIST;
+
+ /* Only submit alerts from memo list backends. */
+ if (e_source_has_extension (source, extension_name)) {
+ EAlertSink *alert_sink;
+
+ alert_sink = E_ALERT_SINK (memo_shell_content);
+ e_alert_sink_submit_alert (alert_sink, alert);
+ }
+}
+
+static void
+memo_shell_view_notify_view_id_cb (EShellView *shell_view)
+{
+ GalViewInstance *view_instance;
+ const gchar *view_id;
+
+ view_id = e_shell_view_get_view_id (shell_view);
+ view_instance = e_shell_view_get_view_instance (shell_view);
+
+ /* A NULL view ID implies we're in a custom view. But you can
+ * only get to a custom view via the "Define Views" dialog, which
+ * would have already modified the view instance appropriately.
+ * Furthermore, there's no way to refer to a custom view by ID
+ * anyway, since custom views have no IDs. */
+ if (view_id == NULL)
+ return;
+
+ gal_view_instance_set_current_view_id (view_instance, view_id);
+}
+
+void
+e_memo_shell_view_private_init (EMemoShellView *memo_shell_view)
+{
+ g_signal_connect (
+ memo_shell_view, "notify::view-id",
+ G_CALLBACK (memo_shell_view_notify_view_id_cb), NULL);
+}
+
+void
+e_memo_shell_view_private_constructed (EMemoShellView *memo_shell_view)
+{
+ EMemoShellViewPrivate *priv = memo_shell_view->priv;
+ EShellBackend *shell_backend;
+ EShellContent *shell_content;
+ EShellSidebar *shell_sidebar;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ EShell *shell;
+ gulong handler_id;
+
+ shell_view = E_SHELL_VIEW (memo_shell_view);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+ shell_content = e_shell_view_get_shell_content (shell_view);
+ shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ e_shell_window_add_action_group (shell_window, "memos");
+ e_shell_window_add_action_group (shell_window, "memos-filter");
+
+ /* Cache these to avoid lots of awkward casting. */
+ priv->memo_shell_backend = g_object_ref (shell_backend);
+ priv->memo_shell_content = g_object_ref (shell_content);
+ priv->memo_shell_sidebar = g_object_ref (shell_sidebar);
+
+ handler_id = g_signal_connect_swapped (
+ priv->memo_shell_sidebar, "client-added",
+ G_CALLBACK (memo_shell_view_selector_client_added_cb),
+ memo_shell_view);
+ priv->client_added_handler_id = handler_id;
+
+ handler_id = g_signal_connect_swapped (
+ priv->memo_shell_sidebar, "client-removed",
+ G_CALLBACK (memo_shell_view_selector_client_removed_cb),
+ memo_shell_view);
+ priv->client_removed_handler_id = handler_id;
+
+ /* Keep our own reference to this so we can
+ * disconnect our signal handlers in dispose(). */
+ priv->client_cache = e_shell_get_client_cache (shell);
+ g_object_ref (priv->client_cache);
+
+ handler_id = g_signal_connect (
+ priv->client_cache, "backend-error",
+ G_CALLBACK (memo_shell_view_backend_error_cb),
+ memo_shell_view);
+ priv->backend_error_handler_id = handler_id;
+
+ /* Keep our own reference to this so we can
+ * disconnect our signal handlers in dispose(). */
+ priv->memo_table = e_memo_shell_content_get_memo_table (
+ E_MEMO_SHELL_CONTENT (shell_content));
+ g_object_ref (priv->memo_table);
+
+ handler_id = g_signal_connect_swapped (
+ priv->memo_table, "open-component",
+ G_CALLBACK (e_memo_shell_view_open_memo),
+ memo_shell_view);
+ priv->open_component_handler_id = handler_id;
+
+ handler_id = g_signal_connect_swapped (
+ priv->memo_table, "popup-event",
+ G_CALLBACK (memo_shell_view_table_popup_event_cb),
+ memo_shell_view);
+ priv->popup_event_handler_id = handler_id;
+
+ handler_id = g_signal_connect_swapped (
+ priv->memo_table, "selection-change",
+ G_CALLBACK (e_memo_shell_view_update_sidebar),
+ memo_shell_view);
+ priv->selection_change_1_handler_id = handler_id;
+
+ handler_id = g_signal_connect_swapped (
+ priv->memo_table, "selection-change",
+ G_CALLBACK (e_shell_view_update_actions),
+ memo_shell_view);
+ priv->selection_change_2_handler_id = handler_id;
+
+ handler_id = g_signal_connect_swapped (
+ priv->memo_table, "status-message",
+ G_CALLBACK (e_memo_shell_view_set_status_message),
+ memo_shell_view);
+ priv->status_message_handler_id = handler_id;
+
+ /* Keep our own reference to this so we can
+ * disconnect our signal handlers in dispose(). */
+ priv->model = e_memo_table_get_model (priv->memo_table);
+ g_object_ref (priv->model);
+
+ handler_id = g_signal_connect_swapped (
+ priv->model, "model-changed",
+ G_CALLBACK (e_memo_shell_view_update_sidebar),
+ memo_shell_view);
+ priv->model_changed_handler_id = handler_id;
+
+ handler_id = g_signal_connect_swapped (
+ priv->model, "model-rows-deleted",
+ G_CALLBACK (e_memo_shell_view_update_sidebar),
+ memo_shell_view);
+ priv->model_rows_deleted_handler_id = handler_id;
+
+ handler_id = g_signal_connect_swapped (
+ priv->model, "model-rows-inserted",
+ G_CALLBACK (e_memo_shell_view_update_sidebar),
+ memo_shell_view);
+ priv->model_rows_inserted_handler_id = handler_id;
+
+ handler_id = g_signal_connect_swapped (
+ priv->model, "row-appended",
+ G_CALLBACK (memo_shell_view_model_row_appended_cb),
+ memo_shell_view);
+ priv->row_appended_handler_id = handler_id;
+
+ /* Keep our own reference to this so we can
+ * disconnect our signal handlers in dispose(). */
+ priv->selector = e_memo_shell_sidebar_get_selector (
+ E_MEMO_SHELL_SIDEBAR (shell_sidebar));
+ g_object_ref (priv->selector);
+
+ handler_id = g_signal_connect_swapped (
+ priv->selector, "popup-event",
+ G_CALLBACK (memo_shell_view_selector_popup_event_cb),
+ memo_shell_view);
+ priv->selector_popup_event_handler_id = handler_id;
+
+ handler_id = g_signal_connect_swapped (
+ priv->selector, "primary-selection-changed",
+ G_CALLBACK (e_shell_view_update_actions),
+ memo_shell_view);
+ priv->primary_selection_changed_handler_id = handler_id;
+
+ e_categories_add_change_hook (
+ (GHookFunc) e_memo_shell_view_update_search_filter,
+ memo_shell_view);
+
+ /* Keep the ECalModel in sync with the sidebar. */
+ g_object_bind_property (
+ shell_sidebar, "default-client",
+ priv->model, "default-client",
+ G_BINDING_SYNC_CREATE);
+
+ e_memo_shell_view_actions_init (memo_shell_view);
+ e_memo_shell_view_update_sidebar (memo_shell_view);
+ e_memo_shell_view_update_search_filter (memo_shell_view);
+}
+
+void
+e_memo_shell_view_private_dispose (EMemoShellView *memo_shell_view)
+{
+ EMemoShellViewPrivate *priv = memo_shell_view->priv;
+
+ if (priv->client_added_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->memo_shell_sidebar,
+ priv->client_added_handler_id);
+ priv->client_added_handler_id = 0;
+ }
+
+ if (priv->client_removed_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->memo_shell_sidebar,
+ priv->client_removed_handler_id);
+ priv->client_removed_handler_id = 0;
+ }
+
+ if (priv->backend_error_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->client_cache,
+ priv->backend_error_handler_id);
+ priv->backend_error_handler_id = 0;
+ }
+
+ if (priv->open_component_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->memo_table,
+ priv->open_component_handler_id);
+ priv->open_component_handler_id = 0;
+ }
+
+ if (priv->popup_event_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->memo_table,
+ priv->popup_event_handler_id);
+ priv->popup_event_handler_id = 0;
+ }
+
+ if (priv->selection_change_1_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->memo_table,
+ priv->selection_change_1_handler_id);
+ priv->selection_change_1_handler_id = 0;
+ }
+
+ if (priv->selection_change_2_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->memo_table,
+ priv->selection_change_2_handler_id);
+ priv->selection_change_2_handler_id = 0;
+ }
+
+ if (priv->status_message_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->memo_table,
+ priv->status_message_handler_id);
+ priv->status_message_handler_id = 0;
+ }
+
+ if (priv->model_changed_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->model,
+ priv->model_changed_handler_id);
+ priv->model_changed_handler_id = 0;
+ }
+
+ if (priv->model_rows_deleted_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->model,
+ priv->model_rows_deleted_handler_id);
+ priv->model_rows_deleted_handler_id = 0;
+ }
+
+ if (priv->model_rows_inserted_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->model,
+ priv->model_rows_inserted_handler_id);
+ priv->model_rows_inserted_handler_id = 0;
+ }
+
+ if (priv->row_appended_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->model,
+ priv->row_appended_handler_id);
+ priv->row_appended_handler_id = 0;
+ }
+
+ if (priv->selector_popup_event_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->selector,
+ priv->selector_popup_event_handler_id);
+ priv->selector_popup_event_handler_id = 0;
+ }
+
+ if (priv->primary_selection_changed_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->selector,
+ priv->primary_selection_changed_handler_id);
+ priv->primary_selection_changed_handler_id = 0;
+ }
+
+ g_clear_object (&priv->memo_shell_backend);
+ g_clear_object (&priv->memo_shell_content);
+ g_clear_object (&priv->memo_shell_sidebar);
+
+ g_clear_object (&priv->client_cache);
+ g_clear_object (&priv->memo_table);
+ g_clear_object (&priv->model);
+ g_clear_object (&priv->selector);
+
+ if (memo_shell_view->priv->activity != NULL) {
+ /* XXX Activity is not cancellable. */
+ e_activity_set_state (
+ memo_shell_view->priv->activity,
+ E_ACTIVITY_COMPLETED);
+ g_object_unref (memo_shell_view->priv->activity);
+ memo_shell_view->priv->activity = NULL;
+ }
+}
+
+void
+e_memo_shell_view_private_finalize (EMemoShellView *memo_shell_view)
+{
+ /* XXX Nothing to do? */
+}
+
+void
+e_memo_shell_view_open_memo (EMemoShellView *memo_shell_view,
+ ECalModelComponent *comp_data)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ESourceRegistry *registry;
+ CompEditor *editor;
+ CompEditorFlags flags = 0;
+ ECalComponent *comp;
+ icalcomponent *clone;
+ const gchar *uid;
+
+ g_return_if_fail (E_IS_MEMO_SHELL_VIEW (memo_shell_view));
+ g_return_if_fail (E_IS_CAL_MODEL_COMPONENT (comp_data));
+
+ shell_view = E_SHELL_VIEW (memo_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ registry = e_shell_get_registry (shell);
+
+ uid = icalcomponent_get_uid (comp_data->icalcomp);
+ editor = comp_editor_find_instance (uid);
+
+ if (editor != NULL)
+ goto exit;
+
+ comp = e_cal_component_new ();
+ clone = icalcomponent_new_clone (comp_data->icalcomp);
+ e_cal_component_set_icalcomponent (comp, clone);
+
+ if (e_cal_component_has_organizer (comp))
+ flags |= COMP_EDITOR_IS_SHARED;
+
+ if (itip_organizer_is_user (registry, comp, comp_data->client))
+ flags |= COMP_EDITOR_USER_ORG;
+
+ editor = memo_editor_new (comp_data->client, shell, flags);
+ comp_editor_edit_comp (editor, comp);
+
+ g_object_unref (comp);
+
+exit:
+ gtk_window_present (GTK_WINDOW (editor));
+}
+
+void
+e_memo_shell_view_set_status_message (EMemoShellView *memo_shell_view,
+ const gchar *status_message,
+ gdouble percent)
+{
+ EActivity *activity;
+ EShellView *shell_view;
+ EShellBackend *shell_backend;
+
+ g_return_if_fail (E_IS_MEMO_SHELL_VIEW (memo_shell_view));
+
+ activity = memo_shell_view->priv->activity;
+ shell_view = E_SHELL_VIEW (memo_shell_view);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+
+ if (status_message == NULL || *status_message == '\0') {
+ if (activity != NULL) {
+ e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
+ g_object_unref (activity);
+ activity = NULL;
+ }
+
+ } else if (activity == NULL) {
+ activity = e_activity_new ();
+ e_activity_set_percent (activity, percent);
+ e_activity_set_text (activity, status_message);
+ e_shell_backend_add_activity (shell_backend, activity);
+
+ } else {
+ e_activity_set_percent (activity, percent);
+ e_activity_set_text (activity, status_message);
+ }
+
+ memo_shell_view->priv->activity = activity;
+}
+
+void
+e_memo_shell_view_update_sidebar (EMemoShellView *memo_shell_view)
+{
+ EMemoShellContent *memo_shell_content;
+ EShellView *shell_view;
+ EShellSidebar *shell_sidebar;
+ EMemoTable *memo_table;
+ ECalModel *model;
+ GString *string;
+ const gchar *format;
+ gint n_rows;
+ gint n_selected;
+
+ shell_view = E_SHELL_VIEW (memo_shell_view);
+ shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+
+ model = e_memo_table_get_model (memo_table);
+
+ n_rows = e_table_model_row_count (E_TABLE_MODEL (model));
+ n_selected = e_table_selected_count (E_TABLE (memo_table));
+
+ string = g_string_sized_new (64);
+
+ format = ngettext ("%d memo", "%d memos", n_rows);
+ g_string_append_printf (string, format, n_rows);
+
+ if (n_selected > 0) {
+ format = _("%d selected");
+ g_string_append_len (string, ", ", 2);
+ g_string_append_printf (string, format, n_selected);
+ }
+
+ e_shell_sidebar_set_secondary_text (shell_sidebar, string->str);
+
+ g_string_free (string, TRUE);
+}
+
diff --git a/modules/calendar/e-memo-shell-view-private.h b/modules/calendar/e-memo-shell-view-private.h
new file mode 100644
index 0000000000..aa04e60a11
--- /dev/null
+++ b/modules/calendar/e-memo-shell-view-private.h
@@ -0,0 +1,135 @@
+/*
+ * e-memo-shell-view-private.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MEMO_SHELL_VIEW_PRIVATE_H
+#define E_MEMO_SHELL_VIEW_PRIVATE_H
+
+#include "e-memo-shell-view.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+
+#include "shell/e-shell-utils.h"
+
+#include "calendar/gui/comp-util.h"
+#include "calendar/gui/e-cal-component-preview.h"
+#include "calendar/gui/e-calendar-selector.h"
+#include "calendar/gui/print.h"
+#include "calendar/gui/dialogs/copy-source-dialog.h"
+#include "calendar/gui/dialogs/memo-editor.h"
+
+#include "e-memo-shell-backend.h"
+#include "e-memo-shell-content.h"
+#include "e-memo-shell-sidebar.h"
+#include "e-memo-shell-view-actions.h"
+
+#define E_MEMO_SHELL_VIEW_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MEMO_SHELL_VIEW, EMemoShellViewPrivate))
+
+/* Shorthand, requires a variable named "shell_window". */
+#define ACTION(name) \
+ (E_SHELL_WINDOW_ACTION_##name (shell_window))
+#define ACTION_GROUP(name) \
+ (E_SHELL_WINDOW_ACTION_GROUP_##name (shell_window))
+
+/* ETable Specifications */
+#define ETSPEC_FILENAME "e-memo-table.etspec"
+
+G_BEGIN_DECLS
+
+/* Filter items are displayed in ascending order.
+ * Non-negative values are reserved for categories. */
+enum {
+ MEMO_FILTER_ANY_CATEGORY = -2,
+ MEMO_FILTER_UNMATCHED = -1
+};
+
+/* Search items are displayed in ascending order. */
+enum {
+ MEMO_SEARCH_ADVANCED = -1,
+ MEMO_SEARCH_SUMMARY_CONTAINS,
+ MEMO_SEARCH_DESCRIPTION_CONTAINS,
+ MEMO_SEARCH_ANY_FIELD_CONTAINS
+};
+
+struct _EMemoShellViewPrivate {
+
+ /* These are just for convenience. */
+ EMemoShellBackend *memo_shell_backend;
+ EMemoShellContent *memo_shell_content;
+ EMemoShellSidebar *memo_shell_sidebar;
+
+ /* sidebar signal handlers */
+ gulong client_added_handler_id;
+ gulong client_removed_handler_id;
+
+ EClientCache *client_cache;
+ gulong backend_error_handler_id;
+
+ EMemoTable *memo_table;
+ gulong open_component_handler_id;
+ gulong popup_event_handler_id;
+ gulong selection_change_1_handler_id;
+ gulong selection_change_2_handler_id;
+ gulong status_message_handler_id;
+
+ ECalModel *model;
+ gulong model_changed_handler_id;
+ gulong model_rows_deleted_handler_id;
+ gulong model_rows_inserted_handler_id;
+ gulong row_appended_handler_id;
+
+ ESourceSelector *selector;
+ gulong selector_popup_event_handler_id;
+ gulong primary_selection_changed_handler_id;
+
+ EActivity *activity;
+};
+
+void e_memo_shell_view_private_init
+ (EMemoShellView *memo_shell_view);
+void e_memo_shell_view_private_constructed
+ (EMemoShellView *memo_shell_view);
+void e_memo_shell_view_private_dispose
+ (EMemoShellView *memo_shell_view);
+void e_memo_shell_view_private_finalize
+ (EMemoShellView *memo_shell_view);
+
+/* Private Utilities */
+
+void e_memo_shell_view_actions_init
+ (EMemoShellView *memo_shell_view);
+void e_memo_shell_view_open_memo
+ (EMemoShellView *memo_shell_view,
+ ECalModelComponent *comp_data);
+void e_memo_shell_view_set_status_message
+ (EMemoShellView *memo_shell_view,
+ const gchar *status_message,
+ gdouble percent);
+void e_memo_shell_view_update_sidebar
+ (EMemoShellView *memo_shell_view);
+void e_memo_shell_view_update_search_filter
+ (EMemoShellView *memo_shell_view);
+
+G_END_DECLS
+
+#endif /* E_MEMO_SHELL_VIEW_PRIVATE_H */
diff --git a/modules/calendar/e-memo-shell-view.c b/modules/calendar/e-memo-shell-view.c
new file mode 100644
index 0000000000..5e4e48fe30
--- /dev/null
+++ b/modules/calendar/e-memo-shell-view.c
@@ -0,0 +1,344 @@
+/*
+ * e-memo-shell-view.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-memo-shell-view-private.h"
+
+G_DEFINE_DYNAMIC_TYPE (
+ EMemoShellView,
+ e_memo_shell_view,
+ E_TYPE_SHELL_VIEW)
+
+static void
+memo_shell_view_dispose (GObject *object)
+{
+ e_memo_shell_view_private_dispose (E_MEMO_SHELL_VIEW (object));
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_memo_shell_view_parent_class)->dispose (object);
+}
+
+static void
+memo_shell_view_finalize (GObject *object)
+{
+ e_memo_shell_view_private_finalize (E_MEMO_SHELL_VIEW (object));
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_memo_shell_view_parent_class)->finalize (object);
+}
+
+static void
+memo_shell_view_constructed (GObject *object)
+{
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_memo_shell_view_parent_class)->constructed (object);
+
+ e_memo_shell_view_private_constructed (E_MEMO_SHELL_VIEW (object));
+}
+
+static void
+memo_shell_view_execute_search (EShellView *shell_view)
+{
+ EMemoShellContent *memo_shell_content;
+ EShellWindow *shell_window;
+ EShellContent *shell_content;
+ EShellSearchbar *searchbar;
+ EActionComboBox *combo_box;
+ GtkRadioAction *action;
+ ECalComponentPreview *memo_preview;
+ EPreviewPane *preview_pane;
+ EMemoTable *memo_table;
+ EWebView *web_view;
+ ECalModel *model;
+ gchar *query;
+ gchar *temp;
+ gint value;
+
+ shell_content = e_shell_view_get_shell_content (shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ memo_shell_content = E_MEMO_SHELL_CONTENT (shell_content);
+ searchbar = e_memo_shell_content_get_searchbar (memo_shell_content);
+
+ action = GTK_RADIO_ACTION (ACTION (MEMO_SEARCH_ANY_FIELD_CONTAINS));
+ value = gtk_radio_action_get_current_value (action);
+
+ if (value == MEMO_SEARCH_ADVANCED) {
+ query = e_shell_view_get_search_query (shell_view);
+
+ if (!query)
+ query = g_strdup ("");
+ } else {
+ const gchar *format;
+ const gchar *text;
+ GString *string;
+
+ text = e_shell_searchbar_get_search_text (searchbar);
+
+ if (text == NULL || *text == '\0') {
+ text = "";
+ value = MEMO_SEARCH_SUMMARY_CONTAINS;
+ }
+
+ switch (value) {
+ default:
+ text = "";
+ /* fall through */
+
+ case MEMO_SEARCH_SUMMARY_CONTAINS:
+ format = "(contains? \"summary\" %s)";
+ break;
+
+ case MEMO_SEARCH_DESCRIPTION_CONTAINS:
+ format = "(contains? \"description\" %s)";
+ break;
+
+ case MEMO_SEARCH_ANY_FIELD_CONTAINS:
+ format = "(contains? \"any\" %s)";
+ break;
+ }
+
+ /* Build the query. */
+ string = g_string_new ("");
+ e_sexp_encode_string (string, text);
+ query = g_strdup_printf (format, string->str);
+ g_string_free (string, TRUE);
+ }
+
+ /* Apply selected filter. */
+ combo_box = e_shell_searchbar_get_filter_combo_box (searchbar);
+ value = e_action_combo_box_get_current_value (combo_box);
+ switch (value) {
+ case MEMO_FILTER_ANY_CATEGORY:
+ break;
+
+ case MEMO_FILTER_UNMATCHED:
+ temp = g_strdup_printf (
+ "(and (has-categories? #f) %s", query);
+ g_free (query);
+ query = temp;
+ break;
+
+ default:
+ {
+ GList *categories;
+ const gchar *category_name;
+
+ categories = e_util_get_searchable_categories ();
+ category_name = g_list_nth_data (categories, value);
+ g_list_free (categories);
+
+ temp = g_strdup_printf (
+ "(and (has-categories? \"%s\") %s)",
+ category_name, query);
+ g_free (query);
+ query = temp;
+ }
+ }
+
+ /* Submit the query. */
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+ model = e_memo_table_get_model (memo_table);
+ e_cal_model_set_search_query (model, query);
+ g_free (query);
+
+ preview_pane =
+ e_memo_shell_content_get_preview_pane (memo_shell_content);
+
+ web_view = e_preview_pane_get_web_view (preview_pane);
+ memo_preview = E_CAL_COMPONENT_PREVIEW (web_view);
+ e_cal_component_preview_clear (memo_preview);
+}
+
+static void
+memo_shell_view_update_actions (EShellView *shell_view)
+{
+ EShellContent *shell_content;
+ EShellSidebar *shell_sidebar;
+ EShellWindow *shell_window;
+ GtkAction *action;
+ const gchar *label;
+ gboolean sensitive;
+ guint32 state;
+
+ /* Be descriptive. */
+ gboolean any_memos_selected;
+ gboolean has_primary_source;
+ gboolean multiple_memos_selected;
+ gboolean primary_source_is_writable;
+ gboolean primary_source_is_removable;
+ gboolean primary_source_is_remote_deletable;
+ gboolean primary_source_in_collection;
+ gboolean selection_has_url;
+ gboolean single_memo_selected;
+ gboolean sources_are_editable;
+ gboolean refresh_supported;
+
+ /* Chain up to parent's update_actions() method. */
+ E_SHELL_VIEW_CLASS (e_memo_shell_view_parent_class)->
+ update_actions (shell_view);
+
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ shell_content = e_shell_view_get_shell_content (shell_view);
+ state = e_shell_content_check_state (shell_content);
+
+ single_memo_selected =
+ (state & E_MEMO_SHELL_CONTENT_SELECTION_SINGLE);
+ multiple_memos_selected =
+ (state & E_MEMO_SHELL_CONTENT_SELECTION_MULTIPLE);
+ sources_are_editable =
+ (state & E_MEMO_SHELL_CONTENT_SELECTION_CAN_EDIT);
+ selection_has_url =
+ (state & E_MEMO_SHELL_CONTENT_SELECTION_HAS_URL);
+
+ shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+ state = e_shell_sidebar_check_state (shell_sidebar);
+
+ has_primary_source =
+ (state & E_MEMO_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE);
+ primary_source_is_writable =
+ (state & E_MEMO_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_WRITABLE);
+ primary_source_is_removable =
+ (state & E_MEMO_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOVABLE);
+ primary_source_is_remote_deletable =
+ (state & E_MEMO_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_DELETABLE);
+ primary_source_in_collection =
+ (state & E_MEMO_SHELL_SIDEBAR_PRIMARY_SOURCE_IN_COLLECTION);
+ refresh_supported =
+ (state & E_MEMO_SHELL_SIDEBAR_SOURCE_SUPPORTS_REFRESH);
+
+ any_memos_selected =
+ (single_memo_selected || multiple_memos_selected);
+
+ action = ACTION (MEMO_DELETE);
+ sensitive = any_memos_selected && sources_are_editable;
+ gtk_action_set_sensitive (action, sensitive);
+ if (multiple_memos_selected)
+ label = _("Delete Memos");
+ else
+ label = _("Delete Memo");
+ gtk_action_set_label (action, label);
+
+ action = ACTION (MEMO_FIND);
+ sensitive = single_memo_selected;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MEMO_FORWARD);
+ sensitive = single_memo_selected;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MEMO_LIST_COPY);
+ sensitive = has_primary_source;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MEMO_LIST_DELETE);
+ sensitive =
+ primary_source_is_removable ||
+ primary_source_is_remote_deletable;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MEMO_LIST_PROPERTIES);
+ sensitive = primary_source_is_writable;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MEMO_LIST_REFRESH);
+ sensitive = refresh_supported;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MEMO_LIST_RENAME);
+ sensitive =
+ primary_source_is_writable &&
+ !primary_source_in_collection;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MEMO_OPEN);
+ sensitive = single_memo_selected;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MEMO_OPEN_URL);
+ sensitive = single_memo_selected && selection_has_url;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MEMO_PRINT);
+ sensitive = single_memo_selected;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MEMO_SAVE_AS);
+ sensitive = single_memo_selected;
+ gtk_action_set_sensitive (action, sensitive);
+}
+
+static void
+e_memo_shell_view_class_init (EMemoShellViewClass *class)
+{
+ GObjectClass *object_class;
+ EShellViewClass *shell_view_class;
+
+ g_type_class_add_private (class, sizeof (EMemoShellViewPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = memo_shell_view_dispose;
+ object_class->finalize = memo_shell_view_finalize;
+ object_class->constructed = memo_shell_view_constructed;
+
+ shell_view_class = E_SHELL_VIEW_CLASS (class);
+ shell_view_class->label = _("Memos");
+ shell_view_class->icon_name = "evolution-memos";
+ shell_view_class->ui_definition = "evolution-memos.ui";
+ shell_view_class->ui_manager_id = "org.gnome.evolution.memos";
+ shell_view_class->search_options = "/memo-search-options";
+ shell_view_class->search_rules = "memotypes.xml";
+ shell_view_class->new_shell_content = e_memo_shell_content_new;
+ shell_view_class->new_shell_sidebar = e_memo_shell_sidebar_new;
+ shell_view_class->execute_search = memo_shell_view_execute_search;
+ shell_view_class->update_actions = memo_shell_view_update_actions;
+
+ /* Ensure the GalView types we need are registered. */
+ g_type_ensure (GAL_TYPE_VIEW_ETABLE);
+}
+
+static void
+e_memo_shell_view_class_finalize (EMemoShellViewClass *class)
+{
+}
+
+static void
+e_memo_shell_view_init (EMemoShellView *memo_shell_view)
+{
+ memo_shell_view->priv =
+ E_MEMO_SHELL_VIEW_GET_PRIVATE (memo_shell_view);
+
+ e_memo_shell_view_private_init (memo_shell_view);
+}
+
+void
+e_memo_shell_view_type_register (GTypeModule *type_module)
+{
+ /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
+ * function, so we have to wrap it with a public function in
+ * order to register types from a separate compilation unit. */
+ e_memo_shell_view_register_type (type_module);
+}
+
diff --git a/modules/calendar/e-memo-shell-view.h b/modules/calendar/e-memo-shell-view.h
new file mode 100644
index 0000000000..52af4761f2
--- /dev/null
+++ b/modules/calendar/e-memo-shell-view.h
@@ -0,0 +1,66 @@
+/*
+ * e-memo-shell-view.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MEMO_SHELL_VIEW_H
+#define E_MEMO_SHELL_VIEW_H
+
+#include <shell/e-shell-view.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MEMO_SHELL_VIEW \
+ (e_memo_shell_view_get_type ())
+#define E_MEMO_SHELL_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MEMO_SHELL_VIEW, EMemoShellView))
+#define E_MEMO_SHELL_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MEMO_SHELL_VIEW, EMemoShellViewClass))
+#define E_IS_MEMO_SHELL_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MEMO_SHELL_VIEW))
+#define E_IS_MEMO_SHELL_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MEMO_SHELL_VIEW))
+#define E_MEMO_SHELL_VIEW_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MEMO_SHELL_VIEW, EMemoShellViewClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMemoShellView EMemoShellView;
+typedef struct _EMemoShellViewClass EMemoShellViewClass;
+typedef struct _EMemoShellViewPrivate EMemoShellViewPrivate;
+
+struct _EMemoShellView {
+ EShellView parent;
+ EMemoShellViewPrivate *priv;
+};
+
+struct _EMemoShellViewClass {
+ EShellViewClass parent_class;
+};
+
+GType e_memo_shell_view_get_type (void);
+void e_memo_shell_view_type_register (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* E_MEMO_SHELL_VIEW_H */
diff --git a/modules/calendar/e-task-shell-backend.c b/modules/calendar/e-task-shell-backend.c
new file mode 100644
index 0000000000..1ed485fcff
--- /dev/null
+++ b/modules/calendar/e-task-shell-backend.c
@@ -0,0 +1,488 @@
+/*
+ * e-task-shell-backend.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-task-shell-backend.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <libecal/libecal.h>
+
+#include "shell/e-shell.h"
+#include "shell/e-shell-backend.h"
+#include "shell/e-shell-window.h"
+
+#include "calendar/gui/comp-util.h"
+#include "calendar/gui/dialogs/task-editor.h"
+
+#include "e-task-shell-content.h"
+#include "e-task-shell-migrate.h"
+#include "e-task-shell-sidebar.h"
+#include "e-task-shell-view.h"
+
+#define E_TASK_SHELL_BACKEND_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_TASK_SHELL_BACKEND, ETaskShellBackendPrivate))
+
+struct _ETaskShellBackendPrivate {
+ gint placeholder;
+};
+
+G_DEFINE_DYNAMIC_TYPE (
+ ETaskShellBackend,
+ e_task_shell_backend,
+ E_TYPE_SHELL_BACKEND)
+
+static void
+task_shell_backend_new_task (ECalClient *cal_client,
+ EShell *shell,
+ CompEditorFlags flags)
+{
+ ECalComponent *comp;
+ CompEditor *editor;
+
+ editor = task_editor_new (cal_client, shell, flags);
+ comp = cal_comp_task_new_with_defaults (cal_client);
+ comp_editor_edit_comp (editor, comp);
+
+ gtk_window_present (GTK_WINDOW (editor));
+
+ g_object_unref (comp);
+}
+
+static void
+task_shell_backend_task_new_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EShell *shell = user_data;
+ EClient *client;
+ CompEditorFlags flags = 0;
+ GError *error = NULL;
+
+ flags |= COMP_EDITOR_NEW_ITEM;
+
+ client = e_client_cache_get_client_finish (
+ E_CLIENT_CACHE (source_object), result, &error);
+
+ /* Sanity check. */
+ g_return_if_fail (
+ ((client != NULL) && (error == NULL)) ||
+ ((client == NULL) && (error != NULL)));
+
+ if (client != NULL) {
+ task_shell_backend_new_task (
+ E_CAL_CLIENT (client), shell, flags);
+ g_object_unref (client);
+ } else {
+ /* XXX Handle errors better. */
+ g_warning ("%s: %s", G_STRFUNC, error->message);
+ g_error_free (error);
+ }
+
+ g_object_unref (shell);
+}
+
+static void
+task_shell_backend_task_assigned_new_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EShell *shell = E_SHELL (user_data);
+ EClient *client;
+ CompEditorFlags flags = 0;
+ GError *error = NULL;
+
+ flags |= COMP_EDITOR_NEW_ITEM;
+ flags |= COMP_EDITOR_IS_ASSIGNED;
+ flags |= COMP_EDITOR_USER_ORG;
+
+ client = e_client_cache_get_client_finish (
+ E_CLIENT_CACHE (source_object), result, &error);
+
+ /* Sanity check. */
+ g_return_if_fail (
+ ((client != NULL) && (error == NULL)) ||
+ ((client == NULL) && (error != NULL)));
+
+ if (client != NULL) {
+ task_shell_backend_new_task (
+ E_CAL_CLIENT (client), shell, flags);
+ g_object_unref (client);
+ } else {
+ /* XXX Handle errors better. */
+ g_warning ("%s: %s", G_STRFUNC, error->message);
+ g_error_free (error);
+ }
+
+ g_object_unref (shell);
+}
+
+static void
+action_task_new_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ EShell *shell;
+ ESource *source;
+ ESourceRegistry *registry;
+ EClientCache *client_cache;
+ const gchar *action_name;
+
+ /* This callback is used for both tasks and assigned tasks. */
+
+ shell = e_shell_window_get_shell (shell_window);
+ client_cache = e_shell_get_client_cache (shell);
+
+ registry = e_shell_get_registry (shell);
+ source = e_source_registry_ref_default_task_list (registry);
+
+ /* Use a callback function appropriate for the action. */
+ action_name = gtk_action_get_name (action);
+ if (strcmp (action_name, "task-assigned-new") == 0)
+ e_client_cache_get_client (
+ client_cache, source,
+ E_SOURCE_EXTENSION_TASK_LIST,
+ NULL,
+ task_shell_backend_task_assigned_new_cb,
+ g_object_ref (shell));
+ else
+ e_client_cache_get_client (
+ client_cache, source,
+ E_SOURCE_EXTENSION_TASK_LIST,
+ NULL,
+ task_shell_backend_task_new_cb,
+ g_object_ref (shell));
+
+ g_object_unref (source);
+}
+
+static void
+action_task_list_new_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ EShell *shell;
+ ESourceRegistry *registry;
+ ECalClientSourceType source_type;
+ GtkWidget *config;
+ GtkWidget *dialog;
+ const gchar *icon_name;
+
+ shell = e_shell_window_get_shell (shell_window);
+
+ registry = e_shell_get_registry (shell);
+ source_type = E_CAL_CLIENT_SOURCE_TYPE_TASKS;
+ config = e_cal_source_config_new (registry, NULL, source_type);
+
+ dialog = e_source_config_dialog_new (E_SOURCE_CONFIG (config));
+
+ gtk_window_set_transient_for (
+ GTK_WINDOW (dialog), GTK_WINDOW (shell_window));
+
+ icon_name = gtk_action_get_icon_name (action);
+ gtk_window_set_icon_name (GTK_WINDOW (dialog), icon_name);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), _("New Task List"));
+
+ gtk_widget_show (dialog);
+}
+
+static GtkActionEntry item_entries[] = {
+
+ { "task-new",
+ "stock_task",
+ NC_("New", "_Task"),
+ "<Shift><Control>t",
+ N_("Create a new task"),
+ G_CALLBACK (action_task_new_cb) },
+
+ { "task-assigned-new",
+ "stock_task",
+ NC_("New", "Assigne_d Task"),
+ NULL,
+ N_("Create a new assigned task"),
+ G_CALLBACK (action_task_new_cb) }
+};
+
+static GtkActionEntry source_entries[] = {
+
+ { "task-list-new",
+ "stock_todo",
+ NC_("New", "Tas_k List"),
+ NULL,
+ N_("Create a new task list"),
+ G_CALLBACK (action_task_list_new_cb) }
+};
+
+static gboolean
+task_shell_backend_handle_uri_cb (EShellBackend *shell_backend,
+ const gchar *uri)
+{
+ EShell *shell;
+ CompEditor *editor;
+ CompEditorFlags flags = 0;
+ EClient *client;
+ EClientCache *client_cache;
+ ECalComponent *comp;
+ ESource *source;
+ ESourceRegistry *registry;
+ SoupURI *soup_uri;
+ icalcomponent *icalcomp;
+ icalproperty *icalprop;
+ const gchar *cp;
+ gchar *source_uid = NULL;
+ gchar *comp_uid = NULL;
+ gchar *comp_rid = NULL;
+ gboolean handled = FALSE;
+ GError *error = NULL;
+
+ shell = e_shell_backend_get_shell (shell_backend);
+ client_cache = e_shell_get_client_cache (shell);
+
+ if (strncmp (uri, "task:", 5) != 0)
+ return FALSE;
+
+ soup_uri = soup_uri_new (uri);
+
+ if (soup_uri == NULL)
+ return FALSE;
+
+ cp = soup_uri_get_query (soup_uri);
+ if (cp == NULL)
+ goto exit;
+
+ while (*cp != '\0') {
+ gchar *header;
+ gchar *content;
+ gsize header_len;
+ gsize content_len;
+
+ header_len = strcspn (cp, "=&");
+
+ /* If it's malformed, give up. */
+ if (cp[header_len] != '=')
+ break;
+
+ header = (gchar *) cp;
+ header[header_len] = '\0';
+ cp += header_len + 1;
+
+ content_len = strcspn (cp, "&");
+
+ content = g_strndup (cp, content_len);
+ if (g_ascii_strcasecmp (header, "source-uid") == 0)
+ source_uid = g_strdup (content);
+ else if (g_ascii_strcasecmp (header, "comp-uid") == 0)
+ comp_uid = g_strdup (content);
+ else if (g_ascii_strcasecmp (header, "comp-rid") == 0)
+ comp_rid = g_strdup (content);
+ g_free (content);
+
+ cp += content_len;
+ if (*cp == '&') {
+ cp++;
+ if (strcmp (cp, "amp;") == 0)
+ cp += 4;
+ }
+ }
+
+ if (source_uid == NULL || comp_uid == NULL)
+ goto exit;
+
+ /* URI is valid, so consider it handled. Whether
+ * we successfully open it is another matter... */
+ handled = TRUE;
+
+ registry = e_shell_get_registry (shell);
+ source = e_source_registry_ref_source (registry, source_uid);
+ if (source == NULL) {
+ g_printerr ("No source for UID '%s'\n", source_uid);
+ goto exit;
+ }
+
+ client = e_client_cache_get_client_sync (
+ client_cache, source,
+ E_SOURCE_EXTENSION_TASK_LIST,
+ NULL, &error);
+
+ /* Sanity check. */
+ g_return_val_if_fail (
+ ((client != NULL) && (error == NULL)) ||
+ ((client == NULL) && (error != NULL)), FALSE);
+
+ if (error != NULL) {
+ g_warning (
+ "%s: Failed to create/open client: %s",
+ G_STRFUNC, error->message);
+ g_object_unref (source);
+ g_error_free (error);
+ goto exit;
+ }
+
+ g_object_unref (source);
+ source = NULL;
+
+ /* XXX Copied from e_task_shell_view_open_task().
+ * Clearly a new utility function is needed. */
+
+ editor = comp_editor_find_instance (comp_uid);
+
+ if (editor != NULL)
+ goto present;
+
+ e_cal_client_get_object_sync (
+ E_CAL_CLIENT (client), comp_uid,
+ comp_rid, &icalcomp, NULL, &error);
+
+ if (error != NULL) {
+ g_warning (
+ "%s: Failed to get object: %s",
+ G_STRFUNC, error->message);
+ g_object_unref (client);
+ g_error_free (error);
+ goto exit;
+ }
+
+ comp = e_cal_component_new ();
+ if (!e_cal_component_set_icalcomponent (comp, icalcomp)) {
+ g_warning ("%s: Failed to set icalcomp to comp\n", G_STRFUNC);
+ icalcomponent_free (icalcomp);
+ icalcomp = NULL;
+ }
+
+ icalprop = icalcomp ? icalcomponent_get_first_property (
+ icalcomp, ICAL_ATTENDEE_PROPERTY) : NULL;
+ if (icalprop != NULL)
+ flags |= COMP_EDITOR_IS_ASSIGNED;
+
+ if (itip_organizer_is_user (registry, comp, E_CAL_CLIENT (client)))
+ flags |= COMP_EDITOR_USER_ORG;
+
+ if (!e_cal_component_has_attendees (comp))
+ flags |= COMP_EDITOR_USER_ORG;
+
+ editor = task_editor_new (E_CAL_CLIENT (client), shell, flags);
+ comp_editor_edit_comp (editor, comp);
+
+ g_object_unref (comp);
+
+present:
+ gtk_window_present (GTK_WINDOW (editor));
+
+ g_object_unref (client);
+
+exit:
+ g_free (source_uid);
+ g_free (comp_uid);
+ g_free (comp_rid);
+
+ soup_uri_free (soup_uri);
+
+ return handled;
+}
+
+static void
+task_shell_backend_window_added_cb (EShellBackend *shell_backend,
+ GtkWindow *window)
+{
+ const gchar *module_name;
+
+ if (!E_IS_SHELL_WINDOW (window))
+ return;
+
+ module_name = E_SHELL_BACKEND_GET_CLASS (shell_backend)->name;
+
+ e_shell_window_register_new_item_actions (
+ E_SHELL_WINDOW (window), module_name,
+ item_entries, G_N_ELEMENTS (item_entries));
+
+ e_shell_window_register_new_source_actions (
+ E_SHELL_WINDOW (window), module_name,
+ source_entries, G_N_ELEMENTS (source_entries));
+}
+
+static void
+task_shell_backend_constructed (GObject *object)
+{
+ EShell *shell;
+ EShellBackend *shell_backend;
+
+ shell_backend = E_SHELL_BACKEND (object);
+ shell = e_shell_backend_get_shell (shell_backend);
+
+ g_signal_connect_swapped (
+ shell, "handle-uri",
+ G_CALLBACK (task_shell_backend_handle_uri_cb),
+ shell_backend);
+
+ g_signal_connect_swapped (
+ shell, "window-added",
+ G_CALLBACK (task_shell_backend_window_added_cb),
+ shell_backend);
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_task_shell_backend_parent_class)->constructed (object);
+}
+
+static void
+e_task_shell_backend_class_init (ETaskShellBackendClass *class)
+{
+ GObjectClass *object_class;
+ EShellBackendClass *shell_backend_class;
+
+ g_type_class_add_private (class, sizeof (ETaskShellBackendPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->constructed = task_shell_backend_constructed;
+
+ shell_backend_class = E_SHELL_BACKEND_CLASS (class);
+ shell_backend_class->shell_view_type = E_TYPE_TASK_SHELL_VIEW;
+ shell_backend_class->name = "tasks";
+ shell_backend_class->aliases = "";
+ shell_backend_class->schemes = "task";
+ shell_backend_class->sort_order = 500;
+ shell_backend_class->preferences_page = "calendar-and-tasks";
+ shell_backend_class->start = NULL;
+ shell_backend_class->migrate = e_task_shell_backend_migrate;
+}
+
+static void
+e_task_shell_backend_class_finalize (ETaskShellBackendClass *class)
+{
+}
+
+static void
+e_task_shell_backend_init (ETaskShellBackend *task_shell_backend)
+{
+ task_shell_backend->priv =
+ E_TASK_SHELL_BACKEND_GET_PRIVATE (task_shell_backend);
+}
+
+void
+e_task_shell_backend_type_register (GTypeModule *type_module)
+{
+ /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
+ * function, so we have to wrap it with a public function in
+ * order to register types from a separate compilation unit. */
+ e_task_shell_backend_register_type (type_module);
+}
diff --git a/modules/calendar/e-task-shell-backend.h b/modules/calendar/e-task-shell-backend.h
new file mode 100644
index 0000000000..043623592c
--- /dev/null
+++ b/modules/calendar/e-task-shell-backend.h
@@ -0,0 +1,67 @@
+/*
+ * e-task-shell-backend.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_TASK_SHELL_BACKEND_H
+#define E_TASK_SHELL_BACKEND_H
+
+#include <shell/e-shell-backend.h>
+
+/* Standard GObject macros */
+#define E_TYPE_TASK_SHELL_BACKEND \
+ (e_task_shell_backend_get_type ())
+#define E_TASK_SHELL_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_TASK_SHELL_BACKEND, ETaskShellBackend))
+#define E_TASK_SHELL_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_TASK_SHELL_BACKEND, ETaskShellBackendClass))
+#define E_IS_TASK_SHELL_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_TASK_SHELL_BACKEND))
+#define E_IS_TASK_SHELL_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_TASK_SHELL_BACKEND))
+#define E_TASK_SHELL_BACKEND_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_TASK_SHELL_BACKEND, ETaskShellBackendClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ETaskShellBackend ETaskShellBackend;
+typedef struct _ETaskShellBackendClass ETaskShellBackendClass;
+typedef struct _ETaskShellBackendPrivate ETaskShellBackendPrivate;
+
+struct _ETaskShellBackend {
+ EShellBackend parent;
+ ETaskShellBackendPrivate *priv;
+};
+
+struct _ETaskShellBackendClass {
+ EShellBackendClass parent_class;
+};
+
+GType e_task_shell_backend_get_type (void);
+void e_task_shell_backend_type_register
+ (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* E_TASK_SHELL_BACKEND_H */
diff --git a/modules/calendar/e-task-shell-content.c b/modules/calendar/e-task-shell-content.c
new file mode 100644
index 0000000000..cff476d4b0
--- /dev/null
+++ b/modules/calendar/e-task-shell-content.c
@@ -0,0 +1,790 @@
+/*
+ * e-task-shell-content.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-task-shell-content.h"
+
+#include <glib/gi18n.h>
+
+#include "shell/e-shell-utils.h"
+
+#include "calendar/gui/comp-util.h"
+#include "calendar/gui/e-cal-component-preview.h"
+#include "calendar/gui/e-cal-model-tasks.h"
+
+#define E_TASK_SHELL_CONTENT_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_TASK_SHELL_CONTENT, ETaskShellContentPrivate))
+
+struct _ETaskShellContentPrivate {
+ GtkWidget *paned;
+ GtkWidget *task_table;
+ GtkWidget *preview_pane;
+
+ ECalModel *task_model;
+ GtkOrientation orientation;
+
+ gchar *current_uid;
+
+ guint preview_visible : 1;
+};
+
+enum {
+ PROP_0,
+ PROP_MODEL,
+ PROP_ORIENTATION,
+ PROP_PREVIEW_VISIBLE
+};
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (
+ ETaskShellContent,
+ e_task_shell_content,
+ E_TYPE_SHELL_CONTENT,
+ 0,
+ G_IMPLEMENT_INTERFACE_DYNAMIC (
+ GTK_TYPE_ORIENTABLE, NULL))
+
+static void
+task_shell_content_display_view_cb (ETaskShellContent *task_shell_content,
+ GalView *gal_view)
+{
+ ETaskTable *task_table;
+
+ if (!GAL_IS_VIEW_ETABLE (gal_view))
+ return;
+
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+
+ gal_view_etable_attach_table (
+ GAL_VIEW_ETABLE (gal_view), E_TABLE (task_table));
+}
+
+static void
+task_shell_content_table_foreach_cb (gint model_row,
+ gpointer user_data)
+{
+ ECalModelComponent *comp_data;
+ icalcomponent *clone;
+ icalcomponent *vcal;
+ gchar *string;
+
+ struct {
+ ECalModel *model;
+ GSList *list;
+ } *foreach_data = user_data;
+
+ comp_data = e_cal_model_get_component_at (
+ foreach_data->model, model_row);
+
+ vcal = e_cal_util_new_top_level ();
+ clone = icalcomponent_new_clone (comp_data->icalcomp);
+ e_cal_util_add_timezones_from_component (vcal, comp_data->icalcomp);
+ icalcomponent_add_component (vcal, clone);
+
+ /* String is owned by libical; do not free. */
+ string = icalcomponent_as_ical_string (vcal);
+ if (string != NULL) {
+ ESource *source;
+ const gchar *source_uid;
+
+ source = e_client_get_source (E_CLIENT (comp_data->client));
+ source_uid = e_source_get_uid (source);
+
+ foreach_data->list = g_slist_prepend (
+ foreach_data->list,
+ g_strdup_printf ("%s\n%s", source_uid, string));
+ }
+
+ icalcomponent_free (vcal);
+}
+
+static void
+task_shell_content_table_drag_data_get_cb (ETaskShellContent *task_shell_content,
+ gint row,
+ gint col,
+ GdkDragContext *context,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint time)
+{
+ ETaskTable *task_table;
+ GdkAtom target;
+
+ struct {
+ ECalModel *model;
+ GSList *list;
+ } foreach_data;
+
+ /* Sanity check the selection target. */
+ target = gtk_selection_data_get_target (selection_data);
+ if (!e_targets_include_calendar (&target, 1))
+ return;
+
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+
+ foreach_data.model = e_task_table_get_model (task_table);
+ foreach_data.list = NULL;
+
+ e_table_selected_row_foreach (
+ E_TABLE (task_table),
+ task_shell_content_table_foreach_cb,
+ &foreach_data);
+
+ if (foreach_data.list != NULL) {
+ cal_comp_selection_set_string_list (
+ selection_data, foreach_data.list);
+ g_slist_foreach (foreach_data.list, (GFunc) g_free, NULL);
+ g_slist_free (foreach_data.list);
+ }
+}
+
+static void
+task_shell_content_table_drag_data_delete_cb (ETaskShellContent *task_shell_content,
+ gint row,
+ gint col,
+ GdkDragContext *context)
+{
+ /* Moved components are deleted from source immediately when moved,
+ * because some of them can be part of destination source, and we
+ * don't want to delete not-moved tasks. There is no such information
+ * which event has been moved and which not, so skip this method. */
+}
+
+static void
+task_shell_content_cursor_change_cb (ETaskShellContent *task_shell_content,
+ gint row,
+ ETable *table)
+{
+ ECalComponentPreview *task_preview;
+ ECalModel *task_model;
+ ECalModelComponent *comp_data;
+ EPreviewPane *preview_pane;
+ EWebView *web_view;
+ const gchar *uid;
+
+ task_model = e_task_shell_content_get_task_model (task_shell_content);
+ preview_pane = e_task_shell_content_get_preview_pane (task_shell_content);
+
+ web_view = e_preview_pane_get_web_view (preview_pane);
+ task_preview = E_CAL_COMPONENT_PREVIEW (web_view);
+
+ if (e_table_selected_count (table) != 1) {
+ if (task_shell_content->priv->preview_visible)
+ e_cal_component_preview_clear (task_preview);
+ return;
+ }
+
+ row = e_table_get_cursor_row (table);
+ comp_data = e_cal_model_get_component_at (task_model, row);
+
+ if (task_shell_content->priv->preview_visible) {
+ ECalComponent *comp;
+
+ comp = e_cal_component_new_from_icalcomponent (
+ icalcomponent_new_clone (comp_data->icalcomp));
+
+ e_cal_component_preview_display (
+ task_preview, comp_data->client, comp,
+ e_cal_model_get_timezone (task_model),
+ e_cal_model_get_use_24_hour_format (task_model));
+
+ g_object_unref (comp);
+ }
+
+ uid = icalcomponent_get_uid (comp_data->icalcomp);
+ g_free (task_shell_content->priv->current_uid);
+ task_shell_content->priv->current_uid = g_strdup (uid);
+}
+
+static void
+task_shell_content_selection_change_cb (ETaskShellContent *task_shell_content,
+ ETable *table)
+{
+ ECalComponentPreview *task_preview;
+ EPreviewPane *preview_pane;
+ EWebView *web_view;
+
+ preview_pane = e_task_shell_content_get_preview_pane (task_shell_content);
+
+ web_view = e_preview_pane_get_web_view (preview_pane);
+ task_preview = E_CAL_COMPONENT_PREVIEW (web_view);
+
+ if (e_table_selected_count (table) != 1)
+ e_cal_component_preview_clear (task_preview);
+}
+
+static void
+task_shell_content_model_row_changed_cb (ETaskShellContent *task_shell_content,
+ gint row,
+ ETableModel *model)
+{
+ ECalModelComponent *comp_data;
+ ETaskTable *task_table;
+ const gchar *current_uid;
+ const gchar *uid;
+
+ current_uid = task_shell_content->priv->current_uid;
+ if (current_uid == NULL)
+ return;
+
+ comp_data = e_cal_model_get_component_at (E_CAL_MODEL (model), row);
+ if (comp_data == NULL)
+ return;
+
+ uid = icalcomponent_get_uid (comp_data->icalcomp);
+ if (g_strcmp0 (uid, current_uid) != 0)
+ return;
+
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+
+ task_shell_content_cursor_change_cb (
+ task_shell_content, 0, E_TABLE (task_table));
+}
+
+static void
+task_shell_content_restore_state_cb (EShellWindow *shell_window,
+ EShellView *shell_view,
+ EShellContent *shell_content)
+{
+ ETaskShellContentPrivate *priv;
+ GSettings *settings;
+
+ priv = E_TASK_SHELL_CONTENT_GET_PRIVATE (shell_content);
+
+ /* Bind GObject properties to settings keys. */
+
+ settings = g_settings_new ("org.gnome.evolution.calendar");
+
+ g_settings_bind (
+ settings, "task-hpane-position",
+ priv->paned, "hposition",
+ G_SETTINGS_BIND_DEFAULT);
+
+ g_settings_bind (
+ settings, "task-vpane-position",
+ priv->paned, "vposition",
+ G_SETTINGS_BIND_DEFAULT);
+
+ g_object_unref (settings);
+}
+
+static void
+task_shell_content_is_editing_changed_cb (ETaskTable *task_table,
+ GParamSpec *param,
+ EShellView *shell_view)
+{
+ g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
+
+ e_shell_view_update_actions (shell_view);
+}
+
+static GtkOrientation
+task_shell_content_get_orientation (ETaskShellContent *task_shell_content)
+{
+ return task_shell_content->priv->orientation;
+}
+
+static void
+task_shell_content_set_orientation (ETaskShellContent *task_shell_content,
+ GtkOrientation orientation)
+{
+ if (task_shell_content->priv->orientation == orientation)
+ return;
+
+ task_shell_content->priv->orientation = orientation;
+
+ g_object_notify (G_OBJECT (task_shell_content), "orientation");
+}
+
+static void
+task_shell_content_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ORIENTATION:
+ task_shell_content_set_orientation (
+ E_TASK_SHELL_CONTENT (object),
+ g_value_get_enum (value));
+ return;
+
+ case PROP_PREVIEW_VISIBLE:
+ e_task_shell_content_set_preview_visible (
+ E_TASK_SHELL_CONTENT (object),
+ g_value_get_boolean (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+task_shell_content_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_MODEL:
+ g_value_set_object (
+ value,
+ e_task_shell_content_get_task_model (
+ E_TASK_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_ORIENTATION:
+ g_value_set_enum (
+ value,
+ task_shell_content_get_orientation (
+ E_TASK_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_PREVIEW_VISIBLE:
+ g_value_set_boolean (
+ value,
+ e_task_shell_content_get_preview_visible (
+ E_TASK_SHELL_CONTENT (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+task_shell_content_dispose (GObject *object)
+{
+ ETaskShellContentPrivate *priv;
+
+ priv = E_TASK_SHELL_CONTENT_GET_PRIVATE (object);
+
+ if (priv->paned != NULL) {
+ g_object_unref (priv->paned);
+ priv->paned = NULL;
+ }
+
+ if (priv->task_table != NULL) {
+ g_object_unref (priv->task_table);
+ priv->task_table = NULL;
+ }
+
+ if (priv->preview_pane != NULL) {
+ g_object_unref (priv->preview_pane);
+ priv->preview_pane = NULL;
+ }
+
+ if (priv->task_model != NULL) {
+ g_object_unref (priv->task_model);
+ priv->task_model = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_task_shell_content_parent_class)->dispose (object);
+}
+
+static void
+task_shell_content_finalize (GObject *object)
+{
+ ETaskShellContentPrivate *priv;
+
+ priv = E_TASK_SHELL_CONTENT_GET_PRIVATE (object);
+
+ g_free (priv->current_uid);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_task_shell_content_parent_class)->finalize (object);
+}
+
+static void
+task_shell_content_constructed (GObject *object)
+{
+ ETaskShellContentPrivate *priv;
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellContent *shell_content;
+ EShellTaskbar *shell_taskbar;
+ ESourceRegistry *registry;
+ GalViewInstance *view_instance;
+ GtkTargetList *target_list;
+ GtkTargetEntry *targets;
+ GtkWidget *container;
+ GtkWidget *widget;
+ gint n_targets;
+
+ priv = E_TASK_SHELL_CONTENT_GET_PRIVATE (object);
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_task_shell_content_parent_class)->constructed (object);
+
+ shell_content = E_SHELL_CONTENT (object);
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ shell_taskbar = e_shell_view_get_shell_taskbar (shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ registry = e_shell_get_registry (shell);
+ priv->task_model = e_cal_model_tasks_new (registry);
+
+ /* Build content widgets. */
+
+ container = GTK_WIDGET (object);
+
+ widget = e_paned_new (GTK_ORIENTATION_VERTICAL);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ priv->paned = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ g_object_bind_property (
+ object, "orientation",
+ widget, "orientation",
+ G_BINDING_SYNC_CREATE);
+
+ container = priv->paned;
+
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (
+ GTK_SCROLLED_WINDOW (widget),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (
+ GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+ gtk_paned_pack1 (GTK_PANED (container), widget, TRUE, FALSE);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = e_task_table_new (shell_view, priv->task_model);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ priv->task_table = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ container = priv->paned;
+
+ widget = e_cal_component_preview_new ();
+ gtk_widget_show (widget);
+
+ g_signal_connect_swapped (
+ widget, "status-message",
+ G_CALLBACK (e_shell_taskbar_set_message),
+ shell_taskbar);
+
+ widget = e_preview_pane_new (E_WEB_VIEW (widget));
+ gtk_paned_pack2 (GTK_PANED (container), widget, FALSE, FALSE);
+ priv->preview_pane = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ g_object_bind_property (
+ object, "preview-visible",
+ widget, "visible",
+ G_BINDING_SYNC_CREATE);
+
+ target_list = gtk_target_list_new (NULL, 0);
+ e_target_list_add_calendar_targets (target_list, 0);
+ targets = gtk_target_table_new_from_list (target_list, &n_targets);
+
+ e_table_drag_source_set (
+ E_TABLE (priv->task_table),
+ GDK_BUTTON1_MASK, targets, n_targets,
+ GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_ASK);
+
+ gtk_target_table_free (targets, n_targets);
+ gtk_target_list_unref (target_list);
+
+ g_signal_connect_swapped (
+ priv->task_table, "table-drag-data-get",
+ G_CALLBACK (task_shell_content_table_drag_data_get_cb),
+ object);
+
+ g_signal_connect_swapped (
+ priv->task_table, "table-drag-data-delete",
+ G_CALLBACK (task_shell_content_table_drag_data_delete_cb),
+ object);
+
+ g_signal_connect_swapped (
+ priv->task_table, "cursor-change",
+ G_CALLBACK (task_shell_content_cursor_change_cb),
+ object);
+
+ g_signal_connect_swapped (
+ priv->task_table, "selection-change",
+ G_CALLBACK (task_shell_content_selection_change_cb),
+ object);
+
+ g_signal_connect (
+ priv->task_table, "notify::is-editing",
+ G_CALLBACK (task_shell_content_is_editing_changed_cb), shell_view);
+
+ g_signal_connect_swapped (
+ priv->task_model, "model-row-changed",
+ G_CALLBACK (task_shell_content_model_row_changed_cb),
+ object);
+
+ /* Load the view instance. */
+
+ view_instance = e_shell_view_new_view_instance (shell_view, NULL);
+ g_signal_connect_swapped (
+ view_instance, "display-view",
+ G_CALLBACK (task_shell_content_display_view_cb),
+ object);
+ e_shell_view_set_view_instance (shell_view, view_instance);
+ gal_view_instance_load (view_instance);
+ g_object_unref (view_instance);
+
+ /* Restore pane positions from the last session once
+ * the shell view is fully initialized and visible. */
+ g_signal_connect (
+ shell_window, "shell-view-created::tasks",
+ G_CALLBACK (task_shell_content_restore_state_cb),
+ shell_content);
+}
+
+static guint32
+task_shell_content_check_state (EShellContent *shell_content)
+{
+ ETaskShellContent *task_shell_content;
+ ETaskTable *task_table;
+ GSList *list, *iter;
+ gboolean assignable = TRUE;
+ gboolean editable = TRUE;
+ gboolean has_url = FALSE;
+ gint n_selected;
+ gint n_complete = 0;
+ gint n_incomplete = 0;
+ guint32 state = 0;
+
+ task_shell_content = E_TASK_SHELL_CONTENT (shell_content);
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+
+ n_selected = e_table_selected_count (E_TABLE (task_table));
+
+ list = e_task_table_get_selected (task_table);
+ for (iter = list; iter != NULL; iter = iter->next) {
+ ECalModelComponent *comp_data = iter->data;
+ icalproperty *prop;
+ const gchar *cap;
+ gboolean read_only;
+
+ read_only = e_client_is_readonly (E_CLIENT (comp_data->client));
+ editable &= !read_only;
+
+ cap = CAL_STATIC_CAPABILITY_NO_TASK_ASSIGNMENT;
+ if (e_client_check_capability (E_CLIENT (comp_data->client), cap))
+ assignable = FALSE;
+
+ cap = CAL_STATIC_CAPABILITY_NO_CONV_TO_ASSIGN_TASK;
+ if (e_client_check_capability (E_CLIENT (comp_data->client), cap))
+ assignable = FALSE;
+
+ prop = icalcomponent_get_first_property (
+ comp_data->icalcomp, ICAL_URL_PROPERTY);
+ has_url |= (prop != NULL);
+
+ prop = icalcomponent_get_first_property (
+ comp_data->icalcomp, ICAL_COMPLETED_PROPERTY);
+ if (prop != NULL)
+ n_complete++;
+ else
+ n_incomplete++;
+ }
+ g_slist_free (list);
+
+ if (n_selected == 1)
+ state |= E_TASK_SHELL_CONTENT_SELECTION_SINGLE;
+ if (n_selected > 1)
+ state |= E_TASK_SHELL_CONTENT_SELECTION_MULTIPLE;
+ if (assignable)
+ state |= E_TASK_SHELL_CONTENT_SELECTION_CAN_ASSIGN;
+ if (editable)
+ state |= E_TASK_SHELL_CONTENT_SELECTION_CAN_EDIT;
+ if (n_complete > 0)
+ state |= E_TASK_SHELL_CONTENT_SELECTION_HAS_COMPLETE;
+ if (n_incomplete > 0)
+ state |= E_TASK_SHELL_CONTENT_SELECTION_HAS_INCOMPLETE;
+ if (has_url)
+ state |= E_TASK_SHELL_CONTENT_SELECTION_HAS_URL;
+
+ return state;
+}
+
+static void
+task_shell_content_focus_search_results (EShellContent *shell_content)
+{
+ ETaskShellContentPrivate *priv;
+
+ priv = E_TASK_SHELL_CONTENT_GET_PRIVATE (shell_content);
+
+ gtk_widget_grab_focus (priv->task_table);
+}
+
+static void
+e_task_shell_content_class_init (ETaskShellContentClass *class)
+{
+ GObjectClass *object_class;
+ EShellContentClass *shell_content_class;
+
+ g_type_class_add_private (class, sizeof (ETaskShellContentPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = task_shell_content_set_property;
+ object_class->get_property = task_shell_content_get_property;
+ object_class->dispose = task_shell_content_dispose;
+ object_class->finalize = task_shell_content_finalize;
+ object_class->constructed = task_shell_content_constructed;
+
+ shell_content_class = E_SHELL_CONTENT_CLASS (class);
+ shell_content_class->check_state = task_shell_content_check_state;
+ shell_content_class->focus_search_results =
+ task_shell_content_focus_search_results;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_MODEL,
+ g_param_spec_object (
+ "model",
+ "Model",
+ "The task table model",
+ E_TYPE_CAL_MODEL,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_PREVIEW_VISIBLE,
+ g_param_spec_boolean (
+ "preview-visible",
+ "Preview is Visible",
+ "Whether the preview pane is visible",
+ TRUE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_override_property (
+ object_class, PROP_ORIENTATION, "orientation");
+}
+
+static void
+e_task_shell_content_class_finalize (ETaskShellContentClass *class)
+{
+}
+
+static void
+e_task_shell_content_init (ETaskShellContent *task_shell_content)
+{
+ task_shell_content->priv =
+ E_TASK_SHELL_CONTENT_GET_PRIVATE (task_shell_content);
+
+ /* Postpone widget construction until we have a shell view. */
+}
+
+void
+e_task_shell_content_type_register (GTypeModule *type_module)
+{
+ /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
+ * function, so we have to wrap it with a public function in
+ * order to register types from a separate compilation unit. */
+ e_task_shell_content_register_type (type_module);
+}
+
+GtkWidget *
+e_task_shell_content_new (EShellView *shell_view)
+{
+ g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
+
+ return g_object_new (
+ E_TYPE_TASK_SHELL_CONTENT,
+ "shell-view", shell_view, NULL);
+}
+
+ECalModel *
+e_task_shell_content_get_task_model (ETaskShellContent *task_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_TASK_SHELL_CONTENT (task_shell_content), NULL);
+
+ return task_shell_content->priv->task_model;
+}
+
+ETaskTable *
+e_task_shell_content_get_task_table (ETaskShellContent *task_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_TASK_SHELL_CONTENT (task_shell_content), NULL);
+
+ return E_TASK_TABLE (task_shell_content->priv->task_table);
+}
+
+EPreviewPane *
+e_task_shell_content_get_preview_pane (ETaskShellContent *task_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_TASK_SHELL_CONTENT (task_shell_content), NULL);
+
+ return E_PREVIEW_PANE (task_shell_content->priv->preview_pane);
+}
+
+gboolean
+e_task_shell_content_get_preview_visible (ETaskShellContent *task_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_TASK_SHELL_CONTENT (task_shell_content), FALSE);
+
+ return task_shell_content->priv->preview_visible;
+}
+
+void
+e_task_shell_content_set_preview_visible (ETaskShellContent *task_shell_content,
+ gboolean preview_visible)
+{
+ g_return_if_fail (E_IS_TASK_SHELL_CONTENT (task_shell_content));
+
+ if (task_shell_content->priv->preview_visible == preview_visible)
+ return;
+
+ task_shell_content->priv->preview_visible = preview_visible;
+
+ if (preview_visible && task_shell_content->priv->preview_pane) {
+ task_shell_content_cursor_change_cb (
+ task_shell_content, 0,
+ E_TABLE (task_shell_content->priv->task_table));
+ }
+
+ g_object_notify (G_OBJECT (task_shell_content), "preview-visible");
+}
+
+EShellSearchbar *
+e_task_shell_content_get_searchbar (ETaskShellContent *task_shell_content)
+{
+ EShellView *shell_view;
+ EShellContent *shell_content;
+ GtkWidget *widget;
+
+ g_return_val_if_fail (
+ E_IS_TASK_SHELL_CONTENT (task_shell_content), NULL);
+
+ shell_content = E_SHELL_CONTENT (task_shell_content);
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ widget = e_shell_view_get_searchbar (shell_view);
+
+ return E_SHELL_SEARCHBAR (widget);
+}
+
diff --git a/modules/calendar/e-task-shell-content.h b/modules/calendar/e-task-shell-content.h
new file mode 100644
index 0000000000..7f5fac68b1
--- /dev/null
+++ b/modules/calendar/e-task-shell-content.h
@@ -0,0 +1,98 @@
+/*
+ * e-task-shell-content.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_TASK_SHELL_CONTENT_H
+#define E_TASK_SHELL_CONTENT_H
+
+#include <shell/e-shell-content.h>
+#include <shell/e-shell-searchbar.h>
+#include <shell/e-shell-view.h>
+
+#include <calendar/gui/e-cal-model.h>
+#include <calendar/gui/e-task-table.h>
+
+/* Standard GObject macros */
+#define E_TYPE_TASK_SHELL_CONTENT \
+ (e_task_shell_content_get_type ())
+#define E_TASK_SHELL_CONTENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_TASK_SHELL_CONTENT, ETaskShellContent))
+#define E_TASK_SHELL_CONTENT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_TASK_SHELL_CONTENT, ETaskShellContentClass))
+#define E_IS_TASK_SHELL_CONTENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_TASK_SHELL_CONTENT))
+#define E_IS_TASK_SHELL_CONTENT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_TASK_SHELL_CONTENT))
+#define E_TASK_SHELL_CONTENT_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_TASK_SHELL_CONTENT, ETaskShellContentClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ETaskShellContent ETaskShellContent;
+typedef struct _ETaskShellContentClass ETaskShellContentClass;
+typedef struct _ETaskShellContentPrivate ETaskShellContentPrivate;
+
+enum {
+ E_TASK_SHELL_CONTENT_SELECTION_SINGLE = 1 << 0,
+ E_TASK_SHELL_CONTENT_SELECTION_MULTIPLE = 1 << 1,
+ E_TASK_SHELL_CONTENT_SELECTION_CAN_ASSIGN = 1 << 2,
+ E_TASK_SHELL_CONTENT_SELECTION_CAN_EDIT = 1 << 3,
+ E_TASK_SHELL_CONTENT_SELECTION_HAS_COMPLETE = 1 << 4,
+ E_TASK_SHELL_CONTENT_SELECTION_HAS_INCOMPLETE = 1 << 5,
+ E_TASK_SHELL_CONTENT_SELECTION_HAS_URL = 1 << 6
+};
+
+struct _ETaskShellContent {
+ EShellContent parent;
+ ETaskShellContentPrivate *priv;
+};
+
+struct _ETaskShellContentClass {
+ EShellContentClass parent_class;
+};
+
+GType e_task_shell_content_get_type (void);
+void e_task_shell_content_type_register
+ (GTypeModule *type_module);
+GtkWidget * e_task_shell_content_new
+ (EShellView *shell_view);
+ECalModel * e_task_shell_content_get_task_model
+ (ETaskShellContent *task_shell_content);
+ETaskTable * e_task_shell_content_get_task_table
+ (ETaskShellContent *task_shell_content);
+EPreviewPane * e_task_shell_content_get_preview_pane
+ (ETaskShellContent *task_shell_content);
+gboolean e_task_shell_content_get_preview_visible
+ (ETaskShellContent *task_shell_content);
+void e_task_shell_content_set_preview_visible
+ (ETaskShellContent *task_shell_content,
+ gboolean preview_visible);
+EShellSearchbar *
+ e_task_shell_content_get_searchbar
+ (ETaskShellContent *task_shell_content);
+
+G_END_DECLS
+
+#endif /* E_TASK_SHELL_CONTENT_H */
diff --git a/modules/calendar/e-task-shell-migrate.c b/modules/calendar/e-task-shell-migrate.c
new file mode 100644
index 0000000000..40b731a0d0
--- /dev/null
+++ b/modules/calendar/e-task-shell-migrate.c
@@ -0,0 +1,38 @@
+/*
+ * e-task-shell-backend-migrate.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-task-shell-migrate.h"
+
+gboolean
+e_task_shell_backend_migrate (EShellBackend *shell_backend,
+ gint major,
+ gint minor,
+ gint micro,
+ GError **error)
+{
+ g_return_val_if_fail (E_IS_SHELL_BACKEND (shell_backend), FALSE);
+
+ return TRUE;
+}
diff --git a/modules/calendar/e-task-shell-migrate.h b/modules/calendar/e-task-shell-migrate.h
new file mode 100644
index 0000000000..f33aa82fcc
--- /dev/null
+++ b/modules/calendar/e-task-shell-migrate.h
@@ -0,0 +1,37 @@
+/*
+ * e-task-shell-backend-migrate.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_TASK_SHELL_BACKEND_MIGRATE_H
+#define E_TASK_SHELL_BACKEND_MIGRATE_H
+
+#include <shell/e-shell-backend.h>
+
+G_BEGIN_DECLS
+
+gboolean e_task_shell_backend_migrate (EShellBackend *shell_backend,
+ gint major,
+ gint minor,
+ gint micro,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* E_TASK_SHELL_BACKEND_MIGRATE_H */
diff --git a/modules/calendar/e-task-shell-sidebar.c b/modules/calendar/e-task-shell-sidebar.c
new file mode 100644
index 0000000000..c12bef75f5
--- /dev/null
+++ b/modules/calendar/e-task-shell-sidebar.c
@@ -0,0 +1,816 @@
+/*
+ * e-task-shell-sidebar.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-task-shell-sidebar.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+
+#include "e-util/e-util.h"
+#include "calendar/gui/e-task-list-selector.h"
+#include "calendar/gui/misc.h"
+
+#define E_TASK_SHELL_SIDEBAR_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_TASK_SHELL_SIDEBAR, ETaskShellSidebarPrivate))
+
+typedef struct _ConnectClosure ConnectClosure;
+
+struct _ETaskShellSidebarPrivate {
+ GtkWidget *selector;
+
+ /* The default client is for ECalModel. It follows the
+ * sidebar's primary selection, even if the highlighted
+ * source is not selected. The tricky part is we don't
+ * update the property until the client is successfully
+ * opened. So the user first highlights a source, then
+ * sometime later we update our default-client property
+ * which is bound by an EBinding to ECalModel. */
+ EClient *default_client;
+
+ /* Not referenced, only for pointer comparison. */
+ ESource *connecting_default_source_instance;
+
+ EActivity *connecting_default_client;
+};
+
+struct _ConnectClosure {
+ ETaskShellSidebar *task_shell_sidebar;
+ EActivity *activity;
+
+ /* For error messages. */
+ gchar *unique_display_name;
+};
+
+enum {
+ PROP_0,
+ PROP_DEFAULT_CLIENT,
+ PROP_SELECTOR
+};
+
+enum {
+ CLIENT_ADDED,
+ CLIENT_REMOVED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+G_DEFINE_DYNAMIC_TYPE (
+ ETaskShellSidebar,
+ e_task_shell_sidebar,
+ E_TYPE_SHELL_SIDEBAR)
+
+static ConnectClosure *
+connect_closure_new (ETaskShellSidebar *task_shell_sidebar,
+ ESource *source)
+{
+ ConnectClosure *closure;
+ EAlertSink *alert_sink;
+ GCancellable *cancellable;
+ ESourceRegistry *registry;
+ ESourceSelector *selector;
+ EShellView *shell_view;
+ EShellBackend *shell_backend;
+ EShellContent *shell_content;
+ EShellSidebar *shell_sidebar;
+ gchar *text;
+
+ shell_sidebar = E_SHELL_SIDEBAR (task_shell_sidebar);
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+ shell_content = e_shell_view_get_shell_content (shell_view);
+
+ selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
+ registry = e_source_selector_get_registry (selector);
+
+ closure = g_slice_new0 (ConnectClosure);
+ closure->task_shell_sidebar = g_object_ref (task_shell_sidebar);
+ closure->activity = e_activity_new ();
+ closure->unique_display_name =
+ e_source_registry_dup_unique_display_name (
+ registry, source, E_SOURCE_EXTENSION_TASK_LIST);
+
+ text = g_strdup_printf (
+ _("Opening task list '%s'"),
+ closure->unique_display_name);
+ e_activity_set_text (closure->activity, text);
+ g_free (text);
+
+ alert_sink = E_ALERT_SINK (shell_content);
+ e_activity_set_alert_sink (closure->activity, alert_sink);
+
+ cancellable = g_cancellable_new ();
+ e_activity_set_cancellable (closure->activity, cancellable);
+ g_object_unref (cancellable);
+
+ e_shell_backend_add_activity (shell_backend, closure->activity);
+
+ return closure;
+}
+
+static void
+connect_closure_free (ConnectClosure *closure)
+{
+ g_clear_object (&closure->task_shell_sidebar);
+ g_clear_object (&closure->activity);
+
+ g_free (closure->unique_display_name);
+
+ g_slice_free (ConnectClosure, closure);
+}
+
+static gboolean
+task_shell_sidebar_map_uid_to_source (GValue *value,
+ GVariant *variant,
+ gpointer user_data)
+{
+ ESourceRegistry *registry;
+ ESource *source;
+ const gchar *uid;
+
+ registry = E_SOURCE_REGISTRY (user_data);
+ uid = g_variant_get_string (variant, NULL);
+ if (uid != NULL && *uid != '\0')
+ source = e_source_registry_ref_source (registry, uid);
+ else
+ source = e_source_registry_ref_default_task_list (registry);
+ g_value_take_object (value, source);
+
+ return (source != NULL);
+}
+
+static GVariant *
+task_shell_sidebar_map_source_to_uid (const GValue *value,
+ const GVariantType *expected_type,
+ gpointer user_data)
+{
+ GVariant *variant = NULL;
+ ESource *source;
+
+ source = g_value_get_object (value);
+
+ if (source != NULL) {
+ const gchar *uid;
+
+ uid = e_source_get_uid (source);
+ variant = g_variant_new_string (uid);
+ }
+
+ return variant;
+}
+
+static void
+task_shell_sidebar_emit_client_added (ETaskShellSidebar *task_shell_sidebar,
+ EClient *client)
+{
+ guint signal_id = signals[CLIENT_ADDED];
+
+ g_signal_emit (task_shell_sidebar, signal_id, 0, client);
+}
+
+static void
+task_shell_sidebar_emit_client_removed (ETaskShellSidebar *task_shell_sidebar,
+ EClient *client)
+{
+ guint signal_id = signals[CLIENT_REMOVED];
+
+ g_signal_emit (task_shell_sidebar, signal_id, 0, client);
+}
+
+static void
+task_shell_sidebar_handle_connect_error (EActivity *activity,
+ const gchar *unique_display_name,
+ const GError *error)
+{
+ EAlertSink *alert_sink;
+ gboolean cancelled = FALSE;
+ gboolean offline_error;
+
+ alert_sink = e_activity_get_alert_sink (activity);
+
+ cancelled |= g_error_matches (
+ error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
+ cancelled |= g_error_matches (
+ error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED);
+
+ offline_error = g_error_matches (
+ error, E_CLIENT_ERROR, E_CLIENT_ERROR_REPOSITORY_OFFLINE);
+
+ if (e_activity_handle_cancellation (activity, error)) {
+ /* do nothing */
+ } else if (offline_error) {
+ e_alert_submit (
+ alert_sink,
+ "calendar:prompt-no-contents-offline-tasks",
+ unique_display_name,
+ NULL);
+ } else {
+ e_alert_submit (
+ alert_sink,
+ "calendar:failed-open-tasks",
+ unique_display_name,
+ error->message,
+ NULL);
+ }
+}
+
+static void
+task_shell_sidebar_client_connect_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EClient *client;
+ ConnectClosure *closure = user_data;
+ GError *error = NULL;
+
+ client = e_client_selector_get_client_finish (
+ E_CLIENT_SELECTOR (source_object), result, &error);
+
+ /* Sanity check. */
+ g_return_if_fail (
+ ((client != NULL) && (error == NULL)) ||
+ ((client == NULL) && (error != NULL)));
+
+ if (error != NULL) {
+ task_shell_sidebar_handle_connect_error (
+ closure->activity,
+ closure->unique_display_name,
+ error);
+ g_error_free (error);
+ goto exit;
+ }
+
+ e_activity_set_state (closure->activity, E_ACTIVITY_COMPLETED);
+
+ e_task_shell_sidebar_add_client (closure->task_shell_sidebar, client);
+
+ g_object_unref (client);
+
+exit:
+ connect_closure_free (closure);
+}
+
+static void
+task_shell_sidebar_default_connect_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EClient *client;
+ ESource *source;
+ ConnectClosure *closure = user_data;
+ ETaskShellSidebarPrivate *priv;
+ GError *error = NULL;
+
+ priv = E_TASK_SHELL_SIDEBAR_GET_PRIVATE (closure->task_shell_sidebar);
+
+ client = e_client_selector_get_client_finish (
+ E_CLIENT_SELECTOR (source_object), result, &error);
+
+ /* Sanity check. */
+ g_return_if_fail (
+ ((client != NULL) && (error == NULL)) ||
+ ((client == NULL) && (error != NULL)));
+
+ g_clear_object (&priv->connecting_default_client);
+
+ if (error != NULL) {
+ task_shell_sidebar_handle_connect_error (
+ closure->activity,
+ closure->unique_display_name,
+ error);
+ g_error_free (error);
+ goto exit;
+ }
+
+ e_activity_set_state (closure->activity, E_ACTIVITY_COMPLETED);
+
+ source = e_client_get_source (client);
+
+ if (source == priv->connecting_default_source_instance)
+ priv->connecting_default_source_instance = NULL;
+
+ if (priv->default_client != NULL)
+ g_object_unref (priv->default_client);
+
+ priv->default_client = g_object_ref (client);
+
+ g_object_notify (
+ G_OBJECT (closure->task_shell_sidebar), "default-client");
+
+ g_object_unref (client);
+
+exit:
+ connect_closure_free (closure);
+}
+
+static void
+task_shell_sidebar_set_default (ETaskShellSidebar *task_shell_sidebar,
+ ESource *source)
+{
+ ETaskShellSidebarPrivate *priv;
+ ESourceSelector *selector;
+ ConnectClosure *closure;
+
+ priv = task_shell_sidebar->priv;
+
+ selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
+
+ /* already loading that source as default source */
+ if (source == priv->connecting_default_source_instance)
+ return;
+
+ /* Cancel the previous request if unfinished. */
+ if (priv->connecting_default_client != NULL) {
+ e_activity_cancel (priv->connecting_default_client);
+ g_object_unref (priv->connecting_default_client);
+ priv->connecting_default_client = NULL;
+ }
+
+ closure = connect_closure_new (task_shell_sidebar, source);
+
+ /* it's only for pointer comparison, no need to ref it */
+ priv->connecting_default_source_instance = source;
+ priv->connecting_default_client = g_object_ref (closure->activity);
+
+ e_client_selector_get_client (
+ E_CLIENT_SELECTOR (selector), source,
+ e_activity_get_cancellable (closure->activity),
+ task_shell_sidebar_default_connect_cb, closure);
+}
+
+static void
+task_shell_sidebar_row_changed_cb (ETaskShellSidebar *task_shell_sidebar,
+ GtkTreePath *tree_path,
+ GtkTreeIter *tree_iter,
+ GtkTreeModel *tree_model)
+{
+ ESourceSelector *selector;
+ ESource *source;
+
+ selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
+ source = e_source_selector_ref_source_by_path (selector, tree_path);
+
+ /* XXX This signal gets emitted a lot while the model is being
+ * rebuilt, during which time we won't get a valid ESource.
+ * ESourceSelector should probably block this signal while
+ * rebuilding the model, but we'll be forgiving and not
+ * emit a warning. */
+ if (source == NULL)
+ return;
+
+ if (e_source_selector_source_is_selected (selector, source))
+ e_task_shell_sidebar_add_source (task_shell_sidebar, source);
+ else
+ e_task_shell_sidebar_remove_source (task_shell_sidebar, source);
+
+ g_object_unref (source);
+}
+
+static void
+task_shell_sidebar_primary_selection_changed_cb (ETaskShellSidebar *task_shell_sidebar,
+ ESourceSelector *selector)
+{
+ ESource *source;
+
+ source = e_source_selector_ref_primary_selection (selector);
+ if (source == NULL)
+ return;
+
+ task_shell_sidebar_set_default (task_shell_sidebar, source);
+
+ g_object_unref (source);
+}
+
+static void
+task_shell_sidebar_restore_state_cb (EShellWindow *shell_window,
+ EShellView *shell_view,
+ EShellSidebar *shell_sidebar)
+{
+ ETaskShellSidebarPrivate *priv;
+ ESourceRegistry *registry;
+ ESourceSelector *selector;
+ GSettings *settings;
+ GtkTreeModel *model;
+
+ priv = E_TASK_SHELL_SIDEBAR_GET_PRIVATE (shell_sidebar);
+
+ selector = E_SOURCE_SELECTOR (priv->selector);
+ registry = e_source_selector_get_registry (selector);
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector));
+
+ g_signal_connect_swapped (
+ registry, "source-removed",
+ G_CALLBACK (e_task_shell_sidebar_remove_source), shell_sidebar);
+
+ g_signal_connect_swapped (
+ model, "row-changed",
+ G_CALLBACK (task_shell_sidebar_row_changed_cb),
+ shell_sidebar);
+
+ g_signal_connect_swapped (
+ selector, "primary-selection-changed",
+ G_CALLBACK (task_shell_sidebar_primary_selection_changed_cb),
+ shell_sidebar);
+
+ /* This will trigger our "row-changed" signal handler for each
+ * task list source, so the appropriate ECalClients get added to
+ * the ECalModel, which will then create view objects to display
+ * the task list content. This all happens asynchronously. */
+ e_source_selector_update_all_rows (selector);
+
+ /* Bind GObject properties to settings keys. */
+
+ settings = g_settings_new ("org.gnome.evolution.calendar");
+
+ g_settings_bind_with_mapping (
+ settings, "primary-tasks",
+ selector, "primary-selection",
+ G_SETTINGS_BIND_DEFAULT,
+ task_shell_sidebar_map_uid_to_source,
+ task_shell_sidebar_map_source_to_uid,
+ g_object_ref (registry),
+ (GDestroyNotify) g_object_unref);
+
+ g_object_unref (settings);
+}
+
+static void
+task_shell_sidebar_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_DEFAULT_CLIENT:
+ g_value_set_object (
+ value,
+ e_task_shell_sidebar_get_default_client (
+ E_TASK_SHELL_SIDEBAR (object)));
+ return;
+
+ case PROP_SELECTOR:
+ g_value_set_object (
+ value,
+ e_task_shell_sidebar_get_selector (
+ E_TASK_SHELL_SIDEBAR (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+task_shell_sidebar_dispose (GObject *object)
+{
+ ETaskShellSidebarPrivate *priv;
+
+ priv = E_TASK_SHELL_SIDEBAR_GET_PRIVATE (object);
+
+ if (priv->selector != NULL) {
+ g_object_unref (priv->selector);
+ priv->selector = NULL;
+ }
+
+ if (priv->default_client != NULL) {
+ g_object_unref (priv->default_client);
+ priv->default_client = NULL;
+ }
+
+ if (priv->connecting_default_client != NULL) {
+ e_activity_cancel (priv->connecting_default_client);
+ g_object_unref (priv->connecting_default_client);
+ priv->connecting_default_client = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_task_shell_sidebar_parent_class)->dispose (object);
+}
+
+static void
+task_shell_sidebar_constructed (GObject *object)
+{
+ ETaskShellSidebarPrivate *priv;
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellSidebar *shell_sidebar;
+ EClientCache *client_cache;
+ GtkContainer *container;
+ GtkWidget *widget;
+ AtkObject *a11y;
+
+ priv = E_TASK_SHELL_SIDEBAR_GET_PRIVATE (object);
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_task_shell_sidebar_parent_class)->constructed (object);
+
+ shell_sidebar = E_SHELL_SIDEBAR (object);
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ container = GTK_CONTAINER (shell_sidebar);
+
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (
+ GTK_SCROLLED_WINDOW (widget),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (
+ GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+ gtk_container_add (container, widget);
+ gtk_widget_show (widget);
+
+ container = GTK_CONTAINER (widget);
+
+ client_cache = e_shell_get_client_cache (shell);
+ widget = e_task_list_selector_new (client_cache);
+ e_source_selector_set_select_new (E_SOURCE_SELECTOR (widget), TRUE);
+ gtk_container_add (container, widget);
+ a11y = gtk_widget_get_accessible (widget);
+ atk_object_set_name (a11y, _("Task List Selector"));
+ priv->selector = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ /* Restore widget state from the last session once
+ * the shell view is fully initialized and visible. */
+ g_signal_connect (
+ shell_window, "shell-view-created::tasks",
+ G_CALLBACK (task_shell_sidebar_restore_state_cb),
+ shell_sidebar);
+}
+
+static guint32
+task_shell_sidebar_check_state (EShellSidebar *shell_sidebar)
+{
+ ETaskShellSidebar *task_shell_sidebar;
+ ESourceSelector *selector;
+ ESourceRegistry *registry;
+ ESource *source;
+ gboolean is_writable = FALSE;
+ gboolean is_removable = FALSE;
+ gboolean is_remote_creatable = FALSE;
+ gboolean is_remote_deletable = FALSE;
+ gboolean in_collection = FALSE;
+ gboolean refresh_supported = FALSE;
+ gboolean has_primary_source = FALSE;
+ guint32 state = 0;
+
+ task_shell_sidebar = E_TASK_SHELL_SIDEBAR (shell_sidebar);
+ selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
+ source = e_source_selector_ref_primary_selection (selector);
+ registry = e_source_selector_get_registry (selector);
+
+ if (source != NULL) {
+ EClient *client;
+ ESource *collection;
+
+ has_primary_source = TRUE;
+ is_writable = e_source_get_writable (source);
+ is_removable = e_source_get_removable (source);
+ is_remote_creatable = e_source_get_remote_creatable (source);
+ is_remote_deletable = e_source_get_remote_deletable (source);
+
+ collection = e_source_registry_find_extension (
+ registry, source, E_SOURCE_EXTENSION_COLLECTION);
+ if (collection != NULL) {
+ in_collection = TRUE;
+ g_object_unref (collection);
+ }
+
+ client = e_client_selector_ref_cached_client (
+ E_CLIENT_SELECTOR (selector), source);
+
+ if (client != NULL) {
+ refresh_supported =
+ e_client_check_refresh_supported (client);
+ g_object_unref (client);
+ }
+
+ g_object_unref (source);
+ }
+
+ if (has_primary_source)
+ state |= E_TASK_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE;
+ if (is_writable)
+ state |= E_TASK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_WRITABLE;
+ if (is_removable)
+ state |= E_TASK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOVABLE;
+ if (is_remote_creatable)
+ state |= E_TASK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_CREATABLE;
+ if (is_remote_deletable)
+ state |= E_TASK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_DELETABLE;
+ if (in_collection)
+ state |= E_TASK_SHELL_SIDEBAR_PRIMARY_SOURCE_IN_COLLECTION;
+ if (refresh_supported)
+ state |= E_TASK_SHELL_SIDEBAR_SOURCE_SUPPORTS_REFRESH;
+
+ return state;
+}
+
+static void
+task_shell_sidebar_client_removed (ETaskShellSidebar *task_shell_sidebar,
+ ECalClient *client)
+{
+ ESourceSelector *selector;
+ ESource *source;
+
+ source = e_client_get_source (E_CLIENT (client));
+
+ selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
+ e_source_selector_unselect_source (selector, source);
+}
+
+static void
+e_task_shell_sidebar_class_init (ETaskShellSidebarClass *class)
+{
+ GObjectClass *object_class;
+ EShellSidebarClass *shell_sidebar_class;
+
+ g_type_class_add_private (class, sizeof (ETaskShellSidebarPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->get_property = task_shell_sidebar_get_property;
+ object_class->dispose = task_shell_sidebar_dispose;
+ object_class->constructed = task_shell_sidebar_constructed;
+
+ shell_sidebar_class = E_SHELL_SIDEBAR_CLASS (class);
+ shell_sidebar_class->check_state = task_shell_sidebar_check_state;
+
+ class->client_removed = task_shell_sidebar_client_removed;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_DEFAULT_CLIENT,
+ g_param_spec_object (
+ "default-client",
+ "Default Task ECalClient",
+ "Default client for task operations",
+ E_TYPE_CAL_CLIENT,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SELECTOR,
+ g_param_spec_object (
+ "selector",
+ "Source Selector Widget",
+ "This widget displays groups of task lists",
+ E_TYPE_SOURCE_SELECTOR,
+ G_PARAM_READABLE));
+
+ signals[CLIENT_ADDED] = g_signal_new (
+ "client-added",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ETaskShellSidebarClass, client_added),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ E_TYPE_CAL_CLIENT);
+
+ signals[CLIENT_REMOVED] = g_signal_new (
+ "client-removed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ETaskShellSidebarClass, client_removed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ E_TYPE_CAL_CLIENT);
+}
+
+static void
+e_task_shell_sidebar_class_finalize (ETaskShellSidebarClass *class)
+{
+}
+
+static void
+e_task_shell_sidebar_init (ETaskShellSidebar *task_shell_sidebar)
+{
+ task_shell_sidebar->priv =
+ E_TASK_SHELL_SIDEBAR_GET_PRIVATE (task_shell_sidebar);
+
+ /* Postpone widget construction until we have a shell view. */
+}
+
+void
+e_task_shell_sidebar_type_register (GTypeModule *type_module)
+{
+ /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
+ * function, so we have to wrap it with a public function in
+ * order to register types from a separate compilation unit. */
+ e_task_shell_sidebar_register_type (type_module);
+}
+
+GtkWidget *
+e_task_shell_sidebar_new (EShellView *shell_view)
+{
+ g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
+
+ return g_object_new (
+ E_TYPE_TASK_SHELL_SIDEBAR,
+ "shell-view", shell_view, NULL);
+}
+
+ECalClient *
+e_task_shell_sidebar_get_default_client (ETaskShellSidebar *task_shell_sidebar)
+{
+ g_return_val_if_fail (
+ E_IS_TASK_SHELL_SIDEBAR (task_shell_sidebar), NULL);
+
+ return (ECalClient *) task_shell_sidebar->priv->default_client;
+}
+
+ESourceSelector *
+e_task_shell_sidebar_get_selector (ETaskShellSidebar *task_shell_sidebar)
+{
+ g_return_val_if_fail (
+ E_IS_TASK_SHELL_SIDEBAR (task_shell_sidebar), NULL);
+
+ return E_SOURCE_SELECTOR (task_shell_sidebar->priv->selector);
+}
+
+void
+e_task_shell_sidebar_add_client (ETaskShellSidebar *task_shell_sidebar,
+ EClient *client)
+{
+ ESource *source;
+ ESourceSelector *selector;
+
+ g_return_if_fail (E_IS_TASK_SHELL_SIDEBAR (task_shell_sidebar));
+ g_return_if_fail (E_IS_CAL_CLIENT (client));
+
+ source = e_client_get_source (client);
+
+ selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
+ e_source_selector_select_source (selector, source);
+
+ task_shell_sidebar_emit_client_added (task_shell_sidebar, client);
+}
+
+void
+e_task_shell_sidebar_add_source (ETaskShellSidebar *task_shell_sidebar,
+ ESource *source)
+{
+ ESourceSelector *selector;
+ ConnectClosure *closure;
+
+ g_return_if_fail (E_IS_TASK_SHELL_SIDEBAR (task_shell_sidebar));
+ g_return_if_fail (E_IS_SOURCE (source));
+
+ selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
+
+ e_source_selector_select_source (selector, source);
+
+ closure = connect_closure_new (task_shell_sidebar, source);
+
+ e_client_selector_get_client (
+ E_CLIENT_SELECTOR (selector), source,
+ e_activity_get_cancellable (closure->activity),
+ task_shell_sidebar_client_connect_cb, closure);
+}
+
+void
+e_task_shell_sidebar_remove_source (ETaskShellSidebar *task_shell_sidebar,
+ ESource *source)
+{
+ ESourceSelector *selector;
+ EClient *client;
+
+ g_return_if_fail (E_IS_TASK_SHELL_SIDEBAR (task_shell_sidebar));
+ g_return_if_fail (E_IS_SOURCE (source));
+
+ selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
+
+ client = e_client_selector_ref_cached_client (
+ E_CLIENT_SELECTOR (selector), source);
+
+ if (client != NULL) {
+ task_shell_sidebar_emit_client_removed (
+ task_shell_sidebar, client);
+ g_object_unref (client);
+ }
+}
diff --git a/modules/calendar/e-task-shell-sidebar.h b/modules/calendar/e-task-shell-sidebar.h
new file mode 100644
index 0000000000..c92d21fd68
--- /dev/null
+++ b/modules/calendar/e-task-shell-sidebar.h
@@ -0,0 +1,103 @@
+/*
+ * e-task-shell-sidebar.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_TASK_SHELL_SIDEBAR_H
+#define E_TASK_SHELL_SIDEBAR_H
+
+#include <libecal/libecal.h>
+
+#include <shell/e-shell-sidebar.h>
+#include <shell/e-shell-view.h>
+
+/* Standard GObject macros */
+#define E_TYPE_TASK_SHELL_SIDEBAR \
+ (e_task_shell_sidebar_get_type ())
+#define E_TASK_SHELL_SIDEBAR(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_TASK_SHELL_SIDEBAR, ETaskShellSidebar))
+#define E_TASK_SHELL_SIDEBAR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_TASK_SHELL_SIDEBAR, ETaskShellSidebarClass))
+#define E_IS_TASK_SHELL_SIDEBAR(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_TASK_SHELL_SIDEBAR))
+#define E_IS_TASK_SHELL_SIDEBAR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_TASK_SHELL_SIDEBAR))
+#define E_TASK_SHELL_SIDEBAR_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_TASK_SHELL_SIDEBAR, ETaskShellSidebarClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ETaskShellSidebar ETaskShellSidebar;
+typedef struct _ETaskShellSidebarClass ETaskShellSidebarClass;
+typedef struct _ETaskShellSidebarPrivate ETaskShellSidebarPrivate;
+
+enum {
+ E_TASK_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE = 1 << 0,
+ E_TASK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_WRITABLE = 1 << 1,
+ E_TASK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOVABLE = 1 << 2,
+ E_TASK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_CREATABLE = 1 << 3,
+ E_TASK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_DELETABLE = 1 << 4,
+ E_TASK_SHELL_SIDEBAR_PRIMARY_SOURCE_IN_COLLECTION = 1 << 5,
+ E_TASK_SHELL_SIDEBAR_SOURCE_SUPPORTS_REFRESH = 1 << 6
+};
+
+struct _ETaskShellSidebar {
+ EShellSidebar parent;
+ ETaskShellSidebarPrivate *priv;
+};
+
+struct _ETaskShellSidebarClass {
+ EShellSidebarClass parent_class;
+
+ /* Signals */
+ void (*client_added) (ETaskShellSidebar *task_shell_sidebar,
+ ECalClient *client);
+ void (*client_removed)
+ (ETaskShellSidebar *task_shell_sidebar,
+ ECalClient *client);
+};
+
+GType e_task_shell_sidebar_get_type (void);
+void e_task_shell_sidebar_type_register
+ (GTypeModule *type_module);
+GtkWidget * e_task_shell_sidebar_new
+ (EShellView *shell_view);
+ECalClient * e_task_shell_sidebar_get_default_client
+ (ETaskShellSidebar *task_shell_sidebar);
+ESourceSelector *
+ e_task_shell_sidebar_get_selector
+ (ETaskShellSidebar *task_shell_sidebar);
+void e_task_shell_sidebar_add_client
+ (ETaskShellSidebar *task_shell_sidebar,
+ EClient *client);
+void e_task_shell_sidebar_add_source
+ (ETaskShellSidebar *task_shell_sidebar,
+ ESource *source);
+void e_task_shell_sidebar_remove_source
+ (ETaskShellSidebar *task_shell_sidebar,
+ ESource *source);
+
+G_END_DECLS
+
+#endif /* E_TASK_SHELL_SIDEBAR_H */
diff --git a/modules/calendar/e-task-shell-view-actions.c b/modules/calendar/e-task-shell-view-actions.c
new file mode 100644
index 0000000000..fe0dd051b2
--- /dev/null
+++ b/modules/calendar/e-task-shell-view-actions.c
@@ -0,0 +1,1251 @@
+/*
+ * e-task-shell-view-actions.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-task-shell-view-private.h"
+
+static void
+action_task_assign_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ ECalModelComponent *comp_data;
+ ETaskTable *task_table;
+ GSList *list;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+
+ list = e_task_table_get_selected (task_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only open the first selected task. */
+ e_task_shell_view_open_task (task_shell_view, comp_data);
+
+ /* FIXME Need to actually assign the task. */
+}
+
+static void
+action_task_delete_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ ETaskTable *task_table;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+
+ e_selectable_delete_selection (E_SELECTABLE (task_table));
+}
+
+static void
+action_task_find_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ EPreviewPane *preview_pane;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ preview_pane = e_task_shell_content_get_preview_pane (task_shell_content);
+
+ e_preview_pane_show_search_bar (preview_pane);
+}
+
+static void
+action_task_forward_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ESourceRegistry *registry;
+ ECalModelComponent *comp_data;
+ ETaskTable *task_table;
+ ECalComponent *comp;
+ icalcomponent *clone;
+ GSList *list;
+
+ shell_view = E_SHELL_VIEW (task_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ registry = e_shell_get_registry (shell);
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+
+ list = e_task_table_get_selected (task_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only forward the first selected task. */
+ comp = e_cal_component_new ();
+ clone = icalcomponent_new_clone (comp_data->icalcomp);
+ e_cal_component_set_icalcomponent (comp, clone);
+
+ itip_send_comp (
+ registry, E_CAL_COMPONENT_METHOD_PUBLISH, comp,
+ comp_data->client, NULL, NULL, NULL, TRUE, FALSE);
+
+ g_object_unref (comp);
+}
+
+static void
+action_task_list_copy_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellSidebar *task_shell_sidebar;
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ESourceRegistry *registry;
+ ESourceSelector *selector;
+ ESource *source;
+
+ shell_view = E_SHELL_VIEW (task_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ registry = e_shell_get_registry (shell);
+
+ task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
+ selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
+ source = e_source_selector_ref_primary_selection (selector);
+ g_return_if_fail (source != NULL);
+
+ copy_source_dialog (
+ GTK_WINDOW (shell_window), registry,
+ source, E_CAL_CLIENT_SOURCE_TYPE_TASKS);
+
+ g_object_unref (source);
+}
+
+static void
+action_task_list_delete_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellSidebar *task_shell_sidebar;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ ESource *source;
+ ESourceSelector *selector;
+ gint response;
+
+ shell_view = E_SHELL_VIEW (task_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
+ selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
+
+ source = e_source_selector_ref_primary_selection (selector);
+ g_return_if_fail (source != NULL);
+
+ if (e_source_get_remote_deletable (source)) {
+ response = e_alert_run_dialog_for_args (
+ GTK_WINDOW (shell_window),
+ "calendar:prompt-delete-remote-task-list",
+ e_source_get_display_name (source), NULL);
+
+ if (response == GTK_RESPONSE_YES)
+ e_shell_view_remote_delete_source (shell_view, source);
+
+ } else {
+ response = e_alert_run_dialog_for_args (
+ GTK_WINDOW (shell_window),
+ "calendar:prompt-delete-task-list",
+ e_source_get_display_name (source), NULL);
+
+ if (response == GTK_RESPONSE_YES)
+ e_shell_view_remove_source (shell_view, source);
+ }
+
+ g_object_unref (source);
+}
+
+static void
+action_task_list_new_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ESourceRegistry *registry;
+ ECalClientSourceType source_type;
+ GtkWidget *config;
+ GtkWidget *dialog;
+ const gchar *icon_name;
+
+ shell_view = E_SHELL_VIEW (task_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ registry = e_shell_get_registry (shell);
+ source_type = E_CAL_CLIENT_SOURCE_TYPE_TASKS;
+ config = e_cal_source_config_new (registry, NULL, source_type);
+
+ dialog = e_source_config_dialog_new (E_SOURCE_CONFIG (config));
+
+ gtk_window_set_transient_for (
+ GTK_WINDOW (dialog), GTK_WINDOW (shell_window));
+
+ icon_name = gtk_action_get_icon_name (action);
+ gtk_window_set_icon_name (GTK_WINDOW (dialog), icon_name);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), _("New Task List"));
+
+ gtk_widget_show (dialog);
+}
+
+static void
+action_task_list_print_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ ETaskTable *task_table;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+
+ print_table (
+ E_TABLE (task_table), _("Print Tasks"), _("Tasks"),
+ GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG);
+}
+
+static void
+action_task_list_print_preview_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ ETaskTable *task_table;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+
+ print_table (
+ E_TABLE (task_table), _("Print Tasks"), _("Tasks"),
+ GTK_PRINT_OPERATION_ACTION_PREVIEW);
+}
+
+static void
+action_task_list_properties_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ETaskShellSidebar *task_shell_sidebar;
+ ECalClientSourceType source_type;
+ ESource *source;
+ ESourceSelector *selector;
+ ESourceRegistry *registry;
+ GtkWidget *config;
+ GtkWidget *dialog;
+ const gchar *icon_name;
+
+ shell_view = E_SHELL_VIEW (task_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
+ selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
+ source = e_source_selector_ref_primary_selection (selector);
+ g_return_if_fail (source != NULL);
+
+ source_type = E_CAL_CLIENT_SOURCE_TYPE_TASKS;
+ registry = e_source_selector_get_registry (selector);
+ config = e_cal_source_config_new (registry, source, source_type);
+
+ g_object_unref (source);
+
+ dialog = e_source_config_dialog_new (E_SOURCE_CONFIG (config));
+
+ gtk_window_set_transient_for (
+ GTK_WINDOW (dialog), GTK_WINDOW (shell_window));
+
+ icon_name = gtk_action_get_icon_name (action);
+ gtk_window_set_icon_name (GTK_WINDOW (dialog), icon_name);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), _("Task List Properties"));
+
+ gtk_widget_show (dialog);
+}
+
+static void
+action_task_list_refresh_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellSidebar *task_shell_sidebar;
+ ESourceSelector *selector;
+ EClient *client = NULL;
+ ESource *source;
+ GError *error = NULL;
+
+ task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
+ selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
+
+ source = e_source_selector_ref_primary_selection (selector);
+
+ if (source != NULL) {
+ client = e_client_selector_ref_cached_client (
+ E_CLIENT_SELECTOR (selector), source);
+ g_object_unref (source);
+ }
+
+ if (client == NULL)
+ return;
+
+ g_return_if_fail (e_client_check_refresh_supported (client));
+
+ e_client_refresh_sync (client, NULL, &error);
+
+ if (error != NULL) {
+ g_warning (
+ "%s: Failed to refresh '%s', %s",
+ G_STRFUNC, e_source_get_display_name (source),
+ error->message);
+ g_error_free (error);
+ }
+
+ g_object_unref (client);
+}
+
+static void
+action_task_list_rename_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellSidebar *task_shell_sidebar;
+ ESourceSelector *selector;
+
+ task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
+ selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
+
+ e_source_selector_edit_primary_selection (selector);
+}
+
+static void
+action_task_list_select_one_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellSidebar *task_shell_sidebar;
+ ESourceSelector *selector;
+ ESource *primary;
+
+ task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
+ selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
+
+ primary = e_source_selector_ref_primary_selection (selector);
+ g_return_if_fail (primary != NULL);
+
+ e_source_selector_select_exclusive (selector, primary);
+
+ g_object_unref (primary);
+}
+
+static void
+action_task_mark_complete_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ ETaskTable *task_table;
+ ECalModel *model;
+ GSList *list, *iter;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+ list = e_task_table_get_selected (task_table);
+ model = e_task_table_get_model (task_table);
+
+ for (iter = list; iter != NULL; iter = iter->next) {
+ ECalModelComponent *comp_data = iter->data;
+ e_cal_model_tasks_mark_comp_complete (
+ E_CAL_MODEL_TASKS (model), comp_data);
+ }
+
+ g_slist_free (list);
+}
+
+static void
+action_task_mark_incomplete_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ ETaskTable *task_table;
+ ECalModel *model;
+ GSList *list, *iter;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+ list = e_task_table_get_selected (task_table);
+ model = e_task_table_get_model (task_table);
+
+ for (iter = list; iter != NULL; iter = iter->next) {
+ ECalModelComponent *comp_data = iter->data;
+ e_cal_model_tasks_mark_comp_incomplete (
+ E_CAL_MODEL_TASKS (model), comp_data);
+ }
+
+ g_slist_free (list);
+}
+
+static void
+action_task_new_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ETaskShellContent *task_shell_content;
+ ETaskTable *task_table;
+ ECalClient *client;
+ ECalComponent *comp;
+ CompEditor *editor;
+ GSList *list;
+
+ shell_view = E_SHELL_VIEW (task_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+
+ list = e_task_table_get_selected (task_table);
+ if (list == NULL) {
+ ECalModel *model;
+
+ model = e_task_table_get_model (task_table);
+ client = e_cal_model_ref_default_client (model);
+ } else {
+ ECalModelComponent *comp_data;
+
+ comp_data = list->data;
+ client = g_object_ref (comp_data->client);
+ g_slist_free (list);
+ }
+
+ g_return_if_fail (client != NULL);
+
+ editor = task_editor_new (client, shell, COMP_EDITOR_NEW_ITEM);
+ comp = cal_comp_task_new_with_defaults (client);
+ comp_editor_edit_comp (editor, comp);
+
+ gtk_window_present (GTK_WINDOW (editor));
+
+ g_object_unref (comp);
+
+ g_object_unref (client);
+}
+
+static void
+action_task_open_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ ECalModelComponent *comp_data;
+ ETaskTable *task_table;
+ GSList *list;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+
+ list = e_task_table_get_selected (task_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only open the first selected task. */
+ e_task_shell_view_open_task (task_shell_view, comp_data);
+}
+
+static void
+action_task_open_url_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ETaskShellContent *task_shell_content;
+ ECalModelComponent *comp_data;
+ ETaskTable *task_table;
+ icalproperty *prop;
+ const gchar *uri;
+ GSList *list;
+
+ shell_view = E_SHELL_VIEW (task_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+
+ list = e_task_table_get_selected (task_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+
+ /* XXX We only open the URI of the first selected task. */
+ prop = icalcomponent_get_first_property (
+ comp_data->icalcomp, ICAL_URL_PROPERTY);
+ g_return_if_fail (prop != NULL);
+
+ uri = icalproperty_get_url (prop);
+ e_show_uri (GTK_WINDOW (shell_window), uri);
+}
+
+static void
+action_task_preview_cb (GtkToggleAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ gboolean visible;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ visible = gtk_toggle_action_get_active (action);
+ e_task_shell_content_set_preview_visible (task_shell_content, visible);
+}
+
+static void
+action_task_print_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ ECalModelComponent *comp_data;
+ ECalComponent *comp;
+ ECalModel *model;
+ ETaskTable *task_table;
+ icalcomponent *clone;
+ GSList *list;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+ model = e_task_table_get_model (task_table);
+
+ list = e_task_table_get_selected (task_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only print the first selected task. */
+ comp = e_cal_component_new ();
+ clone = icalcomponent_new_clone (comp_data->icalcomp);
+ e_cal_component_set_icalcomponent (comp, clone);
+
+ print_comp (
+ comp, comp_data->client,
+ e_cal_model_get_timezone (model),
+ e_cal_model_get_use_24_hour_format (model),
+ GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG);
+
+ g_object_unref (comp);
+}
+
+static void
+action_task_purge_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ GtkWidget *content_area;
+ GtkWidget *dialog;
+ GtkWidget *widget;
+ gboolean active;
+ gint response;
+
+ shell_view = E_SHELL_VIEW (task_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ if (!e_task_shell_view_get_confirm_purge (task_shell_view))
+ goto purge;
+
+ /* XXX This needs reworked. The dialog looks like ass. */
+
+ dialog = gtk_message_dialog_new (
+ GTK_WINDOW (shell_window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_YES_NO,
+ "%s", _("This operation will permanently erase all tasks "
+ "marked as completed. If you continue, you will not be able "
+ "to recover these tasks.\n\nReally erase these tasks?"));
+
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_NO);
+
+ content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+ widget = gtk_check_button_new_with_label (_("Do not ask me again"));
+ gtk_box_pack_start (GTK_BOX (content_area), widget, TRUE, TRUE, 6);
+ gtk_widget_show (widget);
+
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+ active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+ gtk_widget_destroy (dialog);
+
+ if (response != GTK_RESPONSE_YES)
+ return;
+
+ if (active)
+ e_task_shell_view_set_confirm_purge (task_shell_view, FALSE);
+
+purge:
+ e_task_shell_view_delete_completed (task_shell_view);
+}
+
+static void
+action_task_save_as_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellBackend *shell_backend;
+ ETaskShellContent *task_shell_content;
+ ECalModelComponent *comp_data;
+ ETaskTable *task_table;
+ EActivity *activity;
+ GSList *list;
+ GFile *file;
+ gchar *string;
+
+ shell_view = E_SHELL_VIEW (task_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+
+ list = e_task_table_get_selected (task_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* Translators: Default filename part saving a task to a file when
+ * no summary is filed, the '.ics' extension is concatenated to it */
+ string = icalcomp_suggest_filename (comp_data->icalcomp, _("task"));
+ file = e_shell_run_save_dialog (
+ shell, _("Save as iCalendar"), string,
+ "*.ics:text/calendar", NULL, NULL);
+ g_free (string);
+ if (file == NULL)
+ return;
+
+ /* XXX We only save the first selected task. */
+ string = e_cal_client_get_component_as_string (
+ comp_data->client, comp_data->icalcomp);
+ if (string == NULL) {
+ g_warning ("Could not convert task to a string");
+ g_object_unref (file);
+ return;
+ }
+
+ /* XXX No callback means errors are discarded. */
+ activity = e_file_replace_contents_async (
+ file, string, strlen (string), NULL, FALSE,
+ G_FILE_CREATE_NONE, (GAsyncReadyCallback) NULL, NULL);
+ e_shell_backend_add_activity (shell_backend, activity);
+
+ /* Free the string when the activity is finalized. */
+ g_object_set_data_full (
+ G_OBJECT (activity),
+ "file-content", string,
+ (GDestroyNotify) g_free);
+
+ g_object_unref (file);
+}
+
+static void
+action_task_view_cb (GtkRadioAction *action,
+ GtkRadioAction *current,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ GtkOrientable *orientable;
+ GtkOrientation orientation;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ orientable = GTK_ORIENTABLE (task_shell_content);
+
+ switch (gtk_radio_action_get_current_value (action)) {
+ case 0:
+ orientation = GTK_ORIENTATION_VERTICAL;
+ break;
+ case 1:
+ orientation = GTK_ORIENTATION_HORIZONTAL;
+ break;
+ default:
+ g_return_if_reached ();
+ }
+
+ gtk_orientable_set_orientation (orientable, orientation);
+}
+
+static GtkActionEntry task_entries[] = {
+
+ { "task-assign",
+ NULL,
+ N_("_Assign Task"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_task_assign_cb) },
+
+ { "task-delete",
+ GTK_STOCK_DELETE,
+ N_("_Delete Task"),
+ NULL,
+ N_("Delete selected tasks"),
+ G_CALLBACK (action_task_delete_cb) },
+
+ { "task-find",
+ GTK_STOCK_FIND,
+ N_("_Find in Task..."),
+ "<Shift><Control>f",
+ N_("Search for text in the displayed task"),
+ G_CALLBACK (action_task_find_cb) },
+
+ { "task-forward",
+ "mail-forward",
+ N_("_Forward as iCalendar..."),
+ "<Control>f",
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_task_forward_cb) },
+
+ { "task-list-copy",
+ GTK_STOCK_COPY,
+ N_("Copy..."),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_task_list_copy_cb) },
+
+ { "task-list-delete",
+ GTK_STOCK_DELETE,
+ N_("D_elete Task List"),
+ NULL,
+ N_("Delete the selected task list"),
+ G_CALLBACK (action_task_list_delete_cb) },
+
+ { "task-list-new",
+ "stock_todo",
+ N_("_New Task List"),
+ NULL,
+ N_("Create a new task list"),
+ G_CALLBACK (action_task_list_new_cb) },
+
+ { "task-list-properties",
+ GTK_STOCK_PROPERTIES,
+ NULL,
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_task_list_properties_cb) },
+
+ { "task-list-refresh",
+ GTK_STOCK_REFRESH,
+ N_("Re_fresh"),
+ NULL,
+ N_("Refresh the selected task list"),
+ G_CALLBACK (action_task_list_refresh_cb) },
+
+ { "task-list-rename",
+ NULL,
+ N_("_Rename..."),
+ "F2",
+ N_("Rename the selected task list"),
+ G_CALLBACK (action_task_list_rename_cb) },
+
+ { "task-list-select-one",
+ "stock_check-filled",
+ N_("Show _Only This Task List"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_task_list_select_one_cb) },
+
+ { "task-mark-complete",
+ NULL,
+ N_("_Mark as Complete"),
+ "<Control>k",
+ N_("Mark selected tasks as complete"),
+ G_CALLBACK (action_task_mark_complete_cb) },
+
+ { "task-mark-incomplete",
+ NULL,
+ N_("Mar_k as Incomplete"),
+ NULL,
+ N_("Mark selected tasks as incomplete"),
+ G_CALLBACK (action_task_mark_incomplete_cb) },
+
+ { "task-new",
+ "stock_task",
+ N_("New _Task"),
+ NULL,
+ N_("Create a new task"),
+ G_CALLBACK (action_task_new_cb) },
+
+ { "task-open",
+ GTK_STOCK_OPEN,
+ N_("_Open Task"),
+ "<Control>o",
+ N_("View the selected task"),
+ G_CALLBACK (action_task_open_cb) },
+
+ { "task-open-url",
+ "applications-internet",
+ N_("Open _Web Page"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_task_open_url_cb) },
+
+ { "task-purge",
+ NULL,
+ N_("Purg_e"),
+ "<Control>e",
+ N_("Delete completed tasks"),
+ G_CALLBACK (action_task_purge_cb) },
+
+ /*** Menus ***/
+
+ { "task-actions-menu",
+ NULL,
+ N_("_Actions"),
+ NULL,
+ NULL,
+ NULL },
+
+ { "task-preview-menu",
+ NULL,
+ N_("_Preview"),
+ NULL,
+ NULL,
+ NULL }
+};
+
+static EPopupActionEntry task_popup_entries[] = {
+
+ { "task-list-popup-copy",
+ NULL,
+ "task-list-copy" },
+
+ { "task-list-popup-delete",
+ N_("_Delete"),
+ "task-list-delete" },
+
+ { "task-list-popup-properties",
+ NULL,
+ "task-list-properties" },
+
+ { "task-list-popup-refresh",
+ NULL,
+ "task-list-refresh" },
+
+ { "task-list-popup-rename",
+ NULL,
+ "task-list-rename" },
+
+ { "task-list-popup-select-one",
+ NULL,
+ "task-list-select-one" },
+
+ { "task-popup-assign",
+ NULL,
+ "task-assign" },
+
+ { "task-popup-forward",
+ NULL,
+ "task-forward" },
+
+ { "task-popup-mark-complete",
+ NULL,
+ "task-mark-complete" },
+
+ { "task-popup-mark-incomplete",
+ NULL,
+ "task-mark-incomplete" },
+
+ { "task-popup-open",
+ NULL,
+ "task-open" },
+
+ { "task-popup-open-url",
+ NULL,
+ "task-open-url" }
+};
+
+static GtkToggleActionEntry task_toggle_entries[] = {
+
+ { "task-preview",
+ NULL,
+ N_("Task _Preview"),
+ "<Control>m",
+ N_("Show task preview pane"),
+ G_CALLBACK (action_task_preview_cb),
+ TRUE }
+};
+
+static GtkRadioActionEntry task_view_entries[] = {
+
+ /* This action represents the inital active memo view.
+ * It should not be visible in the UI, nor should it be
+ * possible to switch to it from another shell view. */
+ { "task-view-initial",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ -1 },
+
+ { "task-view-classic",
+ NULL,
+ N_("_Classic View"),
+ NULL,
+ N_("Show task preview below the task list"),
+ 0 },
+
+ { "task-view-vertical",
+ NULL,
+ N_("_Vertical View"),
+ NULL,
+ N_("Show task preview alongside the task list"),
+ 1 }
+};
+
+static GtkRadioActionEntry task_filter_entries[] = {
+
+ { "task-filter-active-tasks",
+ NULL,
+ N_("Active Tasks"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ TASK_FILTER_ACTIVE_TASKS },
+
+ { "task-filter-any-category",
+ NULL,
+ N_("Any Category"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ TASK_FILTER_ANY_CATEGORY },
+
+ { "task-filter-completed-tasks",
+ NULL,
+ N_("Completed Tasks"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ TASK_FILTER_COMPLETED_TASKS },
+
+ { "task-filter-next-7-days-tasks",
+ NULL,
+ N_("Next 7 Days' Tasks"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ TASK_FILTER_NEXT_7_DAYS_TASKS },
+
+ { "task-filter-overdue-tasks",
+ NULL,
+ N_("Overdue Tasks"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ TASK_FILTER_OVERDUE_TASKS },
+
+ { "task-filter-tasks-with-attachments",
+ NULL,
+ N_("Tasks with Attachments"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ TASK_FILTER_TASKS_WITH_ATTACHMENTS },
+
+ { "task-filter-unmatched",
+ NULL,
+ N_("Unmatched"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ TASK_FILTER_UNMATCHED }
+};
+
+static GtkRadioActionEntry task_search_entries[] = {
+
+ { "task-search-advanced-hidden",
+ NULL,
+ N_("Advanced Search"),
+ NULL,
+ NULL,
+ TASK_SEARCH_ADVANCED },
+
+ { "task-search-any-field-contains",
+ NULL,
+ N_("Any field contains"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ TASK_SEARCH_ANY_FIELD_CONTAINS },
+
+ { "task-search-description-contains",
+ NULL,
+ N_("Description contains"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ TASK_SEARCH_DESCRIPTION_CONTAINS },
+
+ { "task-search-summary-contains",
+ NULL,
+ N_("Summary contains"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ TASK_SEARCH_SUMMARY_CONTAINS }
+};
+
+static GtkActionEntry lockdown_printing_entries[] = {
+
+ { "task-list-print",
+ GTK_STOCK_PRINT,
+ NULL,
+ "<Control>p",
+ N_("Print the list of tasks"),
+ G_CALLBACK (action_task_list_print_cb) },
+
+ { "task-list-print-preview",
+ GTK_STOCK_PRINT_PREVIEW,
+ NULL,
+ NULL,
+ N_("Preview the list of tasks to be printed"),
+ G_CALLBACK (action_task_list_print_preview_cb) },
+
+ { "task-print",
+ GTK_STOCK_PRINT,
+ NULL,
+ NULL,
+ N_("Print the selected task"),
+ G_CALLBACK (action_task_print_cb) }
+};
+
+static EPopupActionEntry lockdown_printing_popup_entries[] = {
+
+ { "task-popup-print",
+ NULL,
+ "task-print" }
+};
+
+static GtkActionEntry lockdown_save_to_disk_entries[] = {
+
+ { "task-save-as",
+ GTK_STOCK_SAVE_AS,
+ N_("_Save as iCalendar..."),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_task_save_as_cb) }
+};
+
+static EPopupActionEntry lockdown_save_to_disk_popup_entries[] = {
+
+ { "task-popup-save-as",
+ NULL,
+ "task-save-as" },
+};
+
+void
+e_task_shell_view_actions_init (ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellSearchbar *searchbar;
+ EPreviewPane *preview_pane;
+ EWebView *web_view;
+ GtkActionGroup *action_group;
+ GSettings *settings;
+ GtkAction *action;
+
+ shell_view = E_SHELL_VIEW (task_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ searchbar = e_task_shell_content_get_searchbar (task_shell_content);
+ preview_pane = e_task_shell_content_get_preview_pane (task_shell_content);
+ web_view = e_preview_pane_get_web_view (preview_pane);
+
+ /* Task Actions */
+ action_group = ACTION_GROUP (TASKS);
+ gtk_action_group_add_actions (
+ action_group, task_entries,
+ G_N_ELEMENTS (task_entries), task_shell_view);
+ e_action_group_add_popup_actions (
+ action_group, task_popup_entries,
+ G_N_ELEMENTS (task_popup_entries));
+ gtk_action_group_add_toggle_actions (
+ action_group, task_toggle_entries,
+ G_N_ELEMENTS (task_toggle_entries), task_shell_view);
+ gtk_action_group_add_radio_actions (
+ action_group, task_view_entries,
+ G_N_ELEMENTS (task_view_entries), -1,
+ G_CALLBACK (action_task_view_cb), task_shell_view);
+ gtk_action_group_add_radio_actions (
+ action_group, task_search_entries,
+ G_N_ELEMENTS (task_search_entries),
+ -1, NULL, NULL);
+
+ /* Advanced Search Action */
+ action = ACTION (TASK_SEARCH_ADVANCED_HIDDEN);
+ gtk_action_set_visible (action, FALSE);
+ e_shell_searchbar_set_search_option (
+ searchbar, GTK_RADIO_ACTION (action));
+
+ /* Lockdown Printing Actions */
+ action_group = ACTION_GROUP (LOCKDOWN_PRINTING);
+ gtk_action_group_add_actions (
+ action_group, lockdown_printing_entries,
+ G_N_ELEMENTS (lockdown_printing_entries),
+ task_shell_view);
+ e_action_group_add_popup_actions (
+ action_group, lockdown_printing_popup_entries,
+ G_N_ELEMENTS (lockdown_printing_popup_entries));
+
+ /* Lockdown Save-to-Disk Actions */
+ action_group = ACTION_GROUP (LOCKDOWN_SAVE_TO_DISK);
+ gtk_action_group_add_actions (
+ action_group, lockdown_save_to_disk_entries,
+ G_N_ELEMENTS (lockdown_save_to_disk_entries),
+ task_shell_view);
+ e_action_group_add_popup_actions (
+ action_group, lockdown_save_to_disk_popup_entries,
+ G_N_ELEMENTS (lockdown_save_to_disk_popup_entries));
+
+ /* Bind GObject properties to settings keys. */
+
+ settings = g_settings_new ("org.gnome.evolution.calendar");
+
+ g_settings_bind (
+ settings, "show-task-preview",
+ ACTION (TASK_PREVIEW), "active",
+ G_SETTINGS_BIND_DEFAULT);
+
+ g_settings_bind (
+ settings, "task-layout",
+ ACTION (TASK_VIEW_VERTICAL), "current-value",
+ G_SETTINGS_BIND_DEFAULT);
+
+ g_object_unref (settings);
+
+ /* Fine tuning. */
+
+ g_object_bind_property (
+ ACTION (TASK_PREVIEW), "active",
+ ACTION (TASK_VIEW_CLASSIC), "sensitive",
+ G_BINDING_SYNC_CREATE);
+
+ g_object_bind_property (
+ ACTION (TASK_PREVIEW), "active",
+ ACTION (TASK_VIEW_VERTICAL), "sensitive",
+ G_BINDING_SYNC_CREATE);
+
+ e_web_view_set_open_proxy (web_view, ACTION (TASK_OPEN));
+ e_web_view_set_print_proxy (web_view, ACTION (TASK_PRINT));
+ e_web_view_set_save_as_proxy (web_view, ACTION (TASK_SAVE_AS));
+}
+
+void
+e_task_shell_view_update_search_filter (ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellSearchbar *searchbar;
+ EActionComboBox *combo_box;
+ GtkActionGroup *action_group;
+ GtkRadioAction *radio_action;
+ GList *list, *iter;
+ GSList *group;
+ gint ii;
+
+ shell_view = E_SHELL_VIEW (task_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ action_group = ACTION_GROUP (TASKS_FILTER);
+ e_action_group_remove_all_actions (action_group);
+
+ /* Add the standard filter actions. No callback is needed
+ * because changes in the EActionComboBox are detected and
+ * handled by EShellSearchbar. */
+ gtk_action_group_add_radio_actions (
+ action_group, task_filter_entries,
+ G_N_ELEMENTS (task_filter_entries),
+ TASK_FILTER_ANY_CATEGORY, NULL, NULL);
+
+ /* Retrieve the radio group from an action we just added. */
+ list = gtk_action_group_list_actions (action_group);
+ radio_action = GTK_RADIO_ACTION (list->data);
+ group = gtk_radio_action_get_group (radio_action);
+ g_list_free (list);
+
+ /* Build the category actions. */
+
+ list = e_util_get_searchable_categories ();
+ for (iter = list, ii = 0; iter != NULL; iter = iter->next, ii++) {
+ const gchar *category_name = iter->data;
+ const gchar *filename;
+ GtkAction *action;
+ gchar *action_name;
+
+ action_name = g_strdup_printf (
+ "task-filter-category-%d", ii);
+ radio_action = gtk_radio_action_new (
+ action_name, category_name, NULL, NULL, ii);
+ g_free (action_name);
+
+ /* Convert the category icon file to a themed icon name. */
+ filename = e_categories_get_icon_file_for (category_name);
+ if (filename != NULL && *filename != '\0') {
+ gchar *basename;
+ gchar *cp;
+
+ basename = g_path_get_basename (filename);
+
+ /* Lose the file extension. */
+ if ((cp = strrchr (basename, '.')) != NULL)
+ *cp = '\0';
+
+ g_object_set (
+ radio_action, "icon-name", basename, NULL);
+
+ g_free (basename);
+ }
+
+ gtk_radio_action_set_group (radio_action, group);
+ group = gtk_radio_action_get_group (radio_action);
+
+ /* The action group takes ownership of the action. */
+ action = GTK_ACTION (radio_action);
+ gtk_action_group_add_action (action_group, action);
+ g_object_unref (radio_action);
+ }
+ g_list_free (list);
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ searchbar = e_task_shell_content_get_searchbar (task_shell_content);
+ combo_box = e_shell_searchbar_get_filter_combo_box (searchbar);
+
+ e_shell_view_block_execute_search (shell_view);
+
+ /* Use any action in the group; doesn't matter which. */
+ e_action_combo_box_set_action (combo_box, radio_action);
+
+ ii = TASK_FILTER_UNMATCHED;
+ e_action_combo_box_add_separator_after (combo_box, ii);
+
+ ii = TASK_FILTER_TASKS_WITH_ATTACHMENTS;
+ e_action_combo_box_add_separator_after (combo_box, ii);
+
+ e_shell_view_unblock_execute_search (shell_view);
+}
diff --git a/modules/calendar/e-task-shell-view-actions.h b/modules/calendar/e-task-shell-view-actions.h
new file mode 100644
index 0000000000..afa9fe3e1b
--- /dev/null
+++ b/modules/calendar/e-task-shell-view-actions.h
@@ -0,0 +1,109 @@
+/*
+ * e-task-shell-view-actions.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_TASK_SHELL_VIEW_ACTIONS_H
+#define E_TASK_SHELL_VIEW_ACTIONS_H
+
+#include <shell/e-shell-window-actions.h>
+
+/* Task Actions */
+#define E_SHELL_WINDOW_ACTION_TASK_ASSIGN(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-assign")
+#define E_SHELL_WINDOW_ACTION_TASK_DELETE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-delete")
+#define E_SHELL_WINDOW_ACTION_TASK_FIND(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-find")
+#define E_SHELL_WINDOW_ACTION_TASK_FORWARD(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-forward")
+#define E_SHELL_WINDOW_ACTION_TASK_MARK_COMPLETE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-mark-complete")
+#define E_SHELL_WINDOW_ACTION_TASK_MARK_INCOMPLETE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-mark-incomplete")
+#define E_SHELL_WINDOW_ACTION_TASK_NEW(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-new")
+#define E_SHELL_WINDOW_ACTION_TASK_OPEN(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-open")
+#define E_SHELL_WINDOW_ACTION_TASK_OPEN_URL(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-open-url")
+#define E_SHELL_WINDOW_ACTION_TASK_PREVIEW(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-preview")
+#define E_SHELL_WINDOW_ACTION_TASK_PRINT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-print")
+#define E_SHELL_WINDOW_ACTION_TASK_PURGE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-purge")
+#define E_SHELL_WINDOW_ACTION_TASK_SAVE_AS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-save-as")
+#define E_SHELL_WINDOW_ACTION_TASK_VIEW_CLASSIC(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-view-classic")
+#define E_SHELL_WINDOW_ACTION_TASK_VIEW_VERTICAL(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-view-vertical")
+
+/* Task List Actions */
+#define E_SHELL_WINDOW_ACTION_TASK_LIST_COPY(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-list-copy")
+#define E_SHELL_WINDOW_ACTION_TASK_LIST_DELETE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-list-delete")
+#define E_SHELL_WINDOW_ACTION_TASK_LIST_NEW(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-list-new")
+#define E_SHELL_WINDOW_ACTION_TASK_LIST_PRINT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-list-print")
+#define E_SHELL_WINDOW_ACTION_TASK_LIST_PRINT_PREVIEW(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-list-print-preview")
+#define E_SHELL_WINDOW_ACTION_TASK_LIST_PROPERTIES(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-list-properties")
+#define E_SHELL_WINDOW_ACTION_TASK_LIST_REFRESH(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-list-refresh")
+#define E_SHELL_WINDOW_ACTION_TASK_LIST_RENAME(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-list-rename")
+#define E_SHELL_WINDOW_ACTION_TASK_LIST_SELECT_ONE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-list-select-one")
+
+/* Task Query Actions */
+#define E_SHELL_WINDOW_ACTION_TASK_FILTER_ACTIVE_TASKS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-filter-active-tasks")
+#define E_SHELL_WINDOW_ACTION_TASK_FILTER_ANY_CATEGORY(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-filter-any-category")
+#define E_SHELL_WINDOW_ACTION_TASK_FILTER_COMPLETED_TASKS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-filter-completed-tasks")
+#define E_SHELL_WINDOW_ACTION_TASK_FILTER_NEXT_7_DAYS_TASKS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-filter-next-7-days-tasks")
+#define E_SHELL_WINDOW_ACTION_TASK_FILTER_OVERDUE_TASKS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-filter-overdue-tasks")
+#define E_SHELL_WINDOW_ACTION_TASK_FILTER_TASKS_WITH_ATTACHMENTS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-filter-tasks-with-attachments")
+#define E_SHELL_WINDOW_ACTION_TASK_FILTER_UNMATCHED(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-filter-unmatched")
+#define E_SHELL_WINDOW_ACTION_TASK_SEARCH_ADVANCED_HIDDEN(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-search-advanced-hidden")
+#define E_SHELL_WINDOW_ACTION_TASK_SEARCH_ANY_FIELD_CONTAINS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-search-any-field-contains")
+#define E_SHELL_WINDOW_ACTION_TASK_SEARCH_DESCRIPTION_CONTAINS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-search-description-contains")
+#define E_SHELL_WINDOW_ACTION_TASK_SEARCH_SUMMARY_CONTAINS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-search-summary-contains")
+
+/* Action Groups */
+#define E_SHELL_WINDOW_ACTION_GROUP_TASKS(window) \
+ E_SHELL_WINDOW_ACTION_GROUP ((window), "tasks")
+#define E_SHELL_WINDOW_ACTION_GROUP_TASKS_FILTER(window) \
+ E_SHELL_WINDOW_ACTION_GROUP ((window), "tasks-filter")
+
+#endif /* E_TASK_SHELL_VIEW_ACTIONS_H */
diff --git a/modules/calendar/e-task-shell-view-private.c b/modules/calendar/e-task-shell-view-private.c
new file mode 100644
index 0000000000..820339fa30
--- /dev/null
+++ b/modules/calendar/e-task-shell-view-private.c
@@ -0,0 +1,755 @@
+/*
+ * e-task-shell-view-private.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-task-shell-view-private.h"
+
+#include "e-util/e-util-private.h"
+
+static void
+task_shell_view_model_row_appended_cb (ETaskShellView *task_shell_view,
+ ECalModel *model)
+{
+ ETaskShellSidebar *task_shell_sidebar;
+ ECalClient *client;
+
+ /* This is the "Click to Add" handler. */
+
+ client = e_cal_model_ref_default_client (model);
+
+ task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
+ e_task_shell_sidebar_add_client (task_shell_sidebar, E_CLIENT (client));
+
+ g_object_unref (client);
+}
+
+static gboolean
+task_shell_view_process_completed_tasks_cb (gpointer user_data)
+{
+ ETaskShellContent *task_shell_content;
+ ETaskShellView *task_shell_view;
+ ETaskTable *task_table;
+
+ task_shell_view = E_TASK_SHELL_VIEW (user_data);
+
+ task_shell_view->priv->update_completed_timeout = 0;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+
+ e_task_table_process_completed_tasks (task_table, TRUE);
+
+ /* Search query takes whether to show completed tasks into account,
+ * so if the preference has changed we need to update the query. */
+ e_shell_view_execute_search (E_SHELL_VIEW (task_shell_view));
+
+ return FALSE;
+}
+
+static void
+task_shell_view_process_completed_tasks (ETaskShellView *task_shell_view)
+{
+ guint source_id;
+
+ source_id = task_shell_view->priv->update_completed_timeout;
+
+ if (source_id > 0)
+ g_source_remove (source_id);
+
+ source_id = g_timeout_add_seconds (
+ 1, task_shell_view_process_completed_tasks_cb,
+ task_shell_view);
+
+ task_shell_view->priv->update_completed_timeout = source_id;
+}
+
+static void
+task_shell_view_hide_completed_tasks_changed_cb (GSettings *settings,
+ const gchar *key,
+ ETaskShellView *task_shell_view)
+{
+ task_shell_view_process_completed_tasks (task_shell_view);
+}
+
+static void
+task_shell_view_table_popup_event_cb (EShellView *shell_view,
+ GdkEvent *button_event)
+{
+ const gchar *widget_path;
+
+ widget_path = "/task-popup";
+ e_shell_view_show_popup_menu (shell_view, widget_path, button_event);
+}
+
+static void
+task_shell_view_selector_client_added_cb (ETaskShellView *task_shell_view,
+ ECalClient *client)
+{
+ ETaskShellContent *task_shell_content;
+ ETaskTable *task_table;
+ ECalModel *model;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+ model = e_task_table_get_model (task_table);
+
+ e_cal_model_add_client (model, client);
+}
+
+static void
+task_shell_view_selector_client_removed_cb (ETaskShellView *task_shell_view,
+ ECalClient *client)
+{
+ ETaskShellContent *task_shell_content;
+ ETaskTable *task_table;
+ ECalModel *model;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+ model = e_task_table_get_model (task_table);
+
+ e_cal_model_remove_client (model, client);
+}
+
+static gboolean
+task_shell_view_selector_popup_event_cb (EShellView *shell_view,
+ ESource *primary_source,
+ GdkEvent *button_event)
+{
+ const gchar *widget_path;
+
+ widget_path = "/task-list-popup";
+ e_shell_view_show_popup_menu (shell_view, widget_path, button_event);
+
+ return TRUE;
+}
+
+static gboolean
+task_shell_view_update_timeout_cb (ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ ETaskTable *task_table;
+ ECalModel *model;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+ model = e_task_table_get_model (task_table);
+
+ e_task_table_process_completed_tasks (task_table, FALSE);
+ e_cal_model_tasks_update_due_tasks (E_CAL_MODEL_TASKS (model));
+
+ return TRUE;
+}
+
+static void
+task_shell_view_backend_error_cb (EClientCache *client_cache,
+ EClient *client,
+ EAlert *alert,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ ESource *source;
+ const gchar *extension_name;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+
+ source = e_client_get_source (client);
+ extension_name = E_SOURCE_EXTENSION_TASK_LIST;
+
+ /* Only submit alerts from task list backends. */
+ if (e_source_has_extension (source, extension_name)) {
+ EAlertSink *alert_sink;
+
+ alert_sink = E_ALERT_SINK (task_shell_content);
+ e_alert_sink_submit_alert (alert_sink, alert);
+ }
+}
+
+static void
+task_shell_view_notify_view_id_cb (EShellView *shell_view)
+{
+ GalViewInstance *view_instance;
+ const gchar *view_id;
+
+ view_id = e_shell_view_get_view_id (shell_view);
+ view_instance = e_shell_view_get_view_instance (shell_view);
+
+ /* A NULL view ID implies we're in a custom view. But you can
+ * only get to a custom view via the "Define Views" dialog, which
+ * would have already modified the view instance appropriately.
+ * Furthermore, there's no way to refer to a custom view by ID
+ * anyway, since custom views have no IDs. */
+ if (view_id == NULL)
+ return;
+
+ gal_view_instance_set_current_view_id (view_instance, view_id);
+}
+
+void
+e_task_shell_view_private_init (ETaskShellView *task_shell_view)
+{
+ g_signal_connect (
+ task_shell_view, "notify::view-id",
+ G_CALLBACK (task_shell_view_notify_view_id_cb), NULL);
+}
+
+void
+e_task_shell_view_private_constructed (ETaskShellView *task_shell_view)
+{
+ ETaskShellViewPrivate *priv = task_shell_view->priv;
+ EShellBackend *shell_backend;
+ EShellContent *shell_content;
+ EShellSidebar *shell_sidebar;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ EShell *shell;
+ gulong handler_id;
+
+ shell_view = E_SHELL_VIEW (task_shell_view);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+ shell_content = e_shell_view_get_shell_content (shell_view);
+ shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ e_shell_window_add_action_group (shell_window, "tasks");
+ e_shell_window_add_action_group (shell_window, "tasks-filter");
+
+ /* Cache these to avoid lots of awkward casting. */
+ priv->task_shell_backend = g_object_ref (shell_backend);
+ priv->task_shell_content = g_object_ref (shell_content);
+ priv->task_shell_sidebar = g_object_ref (shell_sidebar);
+
+ priv->settings = g_settings_new ("org.gnome.evolution.calendar");
+
+ handler_id = g_signal_connect_object (
+ priv->task_shell_sidebar, "client-added",
+ G_CALLBACK (task_shell_view_selector_client_added_cb),
+ task_shell_view, G_CONNECT_SWAPPED);
+ priv->client_added_handler_id = handler_id;
+
+ handler_id = g_signal_connect_object (
+ priv->task_shell_sidebar, "client-removed",
+ G_CALLBACK (task_shell_view_selector_client_removed_cb),
+ task_shell_view, G_CONNECT_SWAPPED);
+ priv->client_removed_handler_id = handler_id;
+
+ /* Keep our own reference to this so we can
+ * disconnect our signal handlers in dispose(). */
+ priv->client_cache = e_shell_get_client_cache (shell);
+ g_object_ref (priv->client_cache);
+
+ handler_id = g_signal_connect (
+ priv->client_cache, "backend-error",
+ G_CALLBACK (task_shell_view_backend_error_cb),
+ task_shell_view);
+ priv->backend_error_handler_id = handler_id;
+
+ /* Keep our own reference to this so we can
+ * disconnect our signal handlers in dispose(). */
+ priv->task_table = e_task_shell_content_get_task_table (
+ E_TASK_SHELL_CONTENT (shell_content));
+ g_object_ref (priv->task_table);
+
+ handler_id = g_signal_connect_swapped (
+ priv->task_table, "open-component",
+ G_CALLBACK (e_task_shell_view_open_task),
+ task_shell_view);
+ priv->open_component_handler_id = handler_id;
+
+ handler_id = g_signal_connect_swapped (
+ priv->task_table, "popup-event",
+ G_CALLBACK (task_shell_view_table_popup_event_cb),
+ task_shell_view);
+ priv->popup_event_handler_id = handler_id;
+
+ handler_id = g_signal_connect_swapped (
+ priv->task_table, "selection-change",
+ G_CALLBACK (e_task_shell_view_update_sidebar),
+ task_shell_view);
+ priv->selection_change_1_handler_id = handler_id;
+
+ handler_id = g_signal_connect_swapped (
+ priv->task_table, "selection-change",
+ G_CALLBACK (e_shell_view_update_actions),
+ task_shell_view);
+ priv->selection_change_2_handler_id = handler_id;
+
+ handler_id = g_signal_connect_swapped (
+ priv->task_table, "status-message",
+ G_CALLBACK (e_task_shell_view_set_status_message),
+ task_shell_view);
+ priv->status_message_handler_id = handler_id;
+
+ /* Keep our own reference to this so we can
+ * disconnect our signal handlers in dispose(). */
+ priv->model = e_task_table_get_model (priv->task_table);
+ g_object_ref (priv->model);
+
+ handler_id = g_signal_connect_swapped (
+ priv->model, "model-changed",
+ G_CALLBACK (e_task_shell_view_update_sidebar),
+ task_shell_view);
+ priv->model_changed_handler_id = handler_id;
+
+ handler_id = g_signal_connect_swapped (
+ priv->model, "model-rows-deleted",
+ G_CALLBACK (e_task_shell_view_update_sidebar),
+ task_shell_view);
+ priv->model_rows_deleted_handler_id = handler_id;
+
+ handler_id = g_signal_connect_swapped (
+ priv->model, "model-rows-inserted",
+ G_CALLBACK (e_task_shell_view_update_sidebar),
+ task_shell_view);
+ priv->model_rows_inserted_handler_id = handler_id;
+
+ handler_id = g_signal_connect_swapped (
+ priv->model, "row-appended",
+ G_CALLBACK (task_shell_view_model_row_appended_cb),
+ task_shell_view);
+ priv->rows_appended_handler_id = handler_id;
+
+ /* Keep our own reference to this so we can
+ * disconnect our signal handlers in dispose(). */
+ priv->selector = e_task_shell_sidebar_get_selector (
+ E_TASK_SHELL_SIDEBAR (shell_sidebar));
+ g_object_ref (priv->selector);
+
+ handler_id = g_signal_connect_swapped (
+ priv->selector, "popup-event",
+ G_CALLBACK (task_shell_view_selector_popup_event_cb),
+ task_shell_view);
+ priv->selector_popup_event_handler_id = handler_id;
+
+ handler_id = g_signal_connect_swapped (
+ priv->selector, "primary-selection-changed",
+ G_CALLBACK (e_shell_view_update_actions),
+ task_shell_view);
+ priv->primary_selection_changed_handler_id = handler_id;
+
+ e_categories_add_change_hook (
+ (GHookFunc) e_task_shell_view_update_search_filter,
+ task_shell_view);
+
+ /* Listen for configuration changes. */
+ g_settings_bind (
+ priv->settings, "confirm-purge",
+ shell_view, "confirm-purge",
+ G_SETTINGS_BIND_DEFAULT);
+
+ /* Keep the ECalModel in sync with the sidebar. */
+ g_object_bind_property (
+ shell_sidebar, "default-client",
+ priv->model, "default-client",
+ G_BINDING_SYNC_CREATE);
+
+ /* Hide Completed Tasks (enable/units/value) */
+ handler_id = g_signal_connect (
+ priv->settings, "changed::hide-completed-tasks",
+ G_CALLBACK (task_shell_view_hide_completed_tasks_changed_cb),
+ task_shell_view);
+ priv->settings_hide_completed_tasks_handler_id = handler_id;
+ handler_id = g_signal_connect (
+ priv->settings, "changed::hide-completed-tasks-units",
+ G_CALLBACK (task_shell_view_hide_completed_tasks_changed_cb),
+ task_shell_view);
+ priv->settings_hide_completed_tasks_units_handler_id = handler_id;
+ handler_id = g_signal_connect (
+ priv->settings, "changed::hide-completed-tasks-value",
+ G_CALLBACK (task_shell_view_hide_completed_tasks_changed_cb),
+ task_shell_view);
+ priv->settings_hide_completed_tasks_value_handler_id = handler_id;
+
+ e_task_shell_view_actions_init (task_shell_view);
+ e_task_shell_view_update_sidebar (task_shell_view);
+ e_task_shell_view_update_search_filter (task_shell_view);
+
+ /* Call this when everything is ready, like actions in
+ * action groups and such. */
+ task_shell_view_update_timeout_cb (task_shell_view);
+ priv->update_timeout = g_timeout_add_full (
+ G_PRIORITY_LOW, 60000, (GSourceFunc)
+ task_shell_view_update_timeout_cb,
+ task_shell_view, NULL);
+}
+
+void
+e_task_shell_view_private_dispose (ETaskShellView *task_shell_view)
+{
+ ETaskShellViewPrivate *priv = task_shell_view->priv;
+
+ if (priv->client_added_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->task_shell_sidebar,
+ priv->client_added_handler_id);
+ priv->client_added_handler_id = 0;
+ }
+
+ if (priv->client_removed_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->task_shell_sidebar,
+ priv->client_removed_handler_id);
+ priv->client_removed_handler_id = 0;
+ }
+
+ if (priv->backend_error_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->client_cache,
+ priv->backend_error_handler_id);
+ priv->backend_error_handler_id = 0;
+ }
+
+ if (priv->open_component_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->task_table,
+ priv->open_component_handler_id);
+ priv->open_component_handler_id = 0;
+ }
+
+ if (priv->popup_event_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->task_table,
+ priv->popup_event_handler_id);
+ priv->popup_event_handler_id = 0;
+ }
+
+ if (priv->selection_change_1_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->task_table,
+ priv->selection_change_1_handler_id);
+ priv->selection_change_1_handler_id = 0;
+ }
+
+ if (priv->selection_change_2_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->task_table,
+ priv->selection_change_2_handler_id);
+ priv->selection_change_2_handler_id = 0;
+ }
+
+ if (priv->status_message_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->task_table,
+ priv->status_message_handler_id);
+ priv->status_message_handler_id = 0;
+ }
+
+ if (priv->model_changed_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->model,
+ priv->model_changed_handler_id);
+ priv->model_changed_handler_id = 0;
+ }
+
+ if (priv->model_rows_deleted_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->model,
+ priv->model_rows_deleted_handler_id);
+ priv->model_rows_deleted_handler_id = 0;
+ }
+
+ if (priv->model_rows_inserted_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->model,
+ priv->model_rows_inserted_handler_id);
+ priv->model_rows_inserted_handler_id = 0;
+ }
+
+ if (priv->rows_appended_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->model,
+ priv->rows_appended_handler_id);
+ priv->rows_appended_handler_id = 0;
+ }
+
+ if (priv->selector_popup_event_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->selector,
+ priv->selector_popup_event_handler_id);
+ priv->selector_popup_event_handler_id = 0;
+ }
+
+ if (priv->primary_selection_changed_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->selector,
+ priv->primary_selection_changed_handler_id);
+ priv->primary_selection_changed_handler_id = 0;
+ }
+
+ if (priv->settings_hide_completed_tasks_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->settings,
+ priv->settings_hide_completed_tasks_handler_id);
+ priv->settings_hide_completed_tasks_handler_id = 0;
+ }
+
+ if (priv->settings_hide_completed_tasks_units_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->settings,
+ priv->settings_hide_completed_tasks_units_handler_id);
+ priv->settings_hide_completed_tasks_units_handler_id = 0;
+ }
+
+ if (priv->settings_hide_completed_tasks_value_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->settings,
+ priv->settings_hide_completed_tasks_value_handler_id);
+ priv->settings_hide_completed_tasks_units_handler_id = 0;
+ }
+
+ g_clear_object (&priv->task_shell_backend);
+ g_clear_object (&priv->task_shell_content);
+ g_clear_object (&priv->task_shell_sidebar);
+
+ g_clear_object (&priv->client_cache);
+ g_clear_object (&priv->task_table);
+ g_clear_object (&priv->model);
+ g_clear_object (&priv->selector);
+ g_clear_object (&priv->settings);
+
+ if (task_shell_view->priv->activity != NULL) {
+ /* XXX Activity is not cancellable. */
+ e_activity_set_state (
+ task_shell_view->priv->activity,
+ E_ACTIVITY_COMPLETED);
+ g_object_unref (task_shell_view->priv->activity);
+ task_shell_view->priv->activity = NULL;
+ }
+
+ if (priv->update_timeout > 0) {
+ g_source_remove (priv->update_timeout);
+ priv->update_timeout = 0;
+ }
+
+ if (priv->update_completed_timeout > 0) {
+ g_source_remove (priv->update_completed_timeout);
+ priv->update_completed_timeout = 0;
+ }
+}
+
+void
+e_task_shell_view_private_finalize (ETaskShellView *task_shell_view)
+{
+ /* XXX Nothing to do? */
+}
+
+void
+e_task_shell_view_open_task (ETaskShellView *task_shell_view,
+ ECalModelComponent *comp_data)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ESourceRegistry *registry;
+ CompEditor *editor;
+ CompEditorFlags flags = 0;
+ ECalComponent *comp;
+ icalcomponent *clone;
+ icalproperty *prop;
+ const gchar *uid;
+
+ g_return_if_fail (E_IS_TASK_SHELL_VIEW (task_shell_view));
+ g_return_if_fail (E_IS_CAL_MODEL_COMPONENT (comp_data));
+
+ shell_view = E_SHELL_VIEW (task_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ registry = e_shell_get_registry (shell);
+
+ uid = icalcomponent_get_uid (comp_data->icalcomp);
+ editor = comp_editor_find_instance (uid);
+
+ if (editor != NULL)
+ goto exit;
+
+ comp = e_cal_component_new ();
+ clone = icalcomponent_new_clone (comp_data->icalcomp);
+ e_cal_component_set_icalcomponent (comp, clone);
+
+ prop = icalcomponent_get_first_property (
+ comp_data->icalcomp, ICAL_ATTENDEE_PROPERTY);
+ if (prop != NULL)
+ flags |= COMP_EDITOR_IS_ASSIGNED;
+
+ if (itip_organizer_is_user (registry, comp, comp_data->client))
+ flags |= COMP_EDITOR_USER_ORG;
+
+ if (!e_cal_component_has_attendees (comp))
+ flags |= COMP_EDITOR_USER_ORG;
+
+ editor = task_editor_new (comp_data->client, shell, flags);
+ comp_editor_edit_comp (editor, comp);
+
+ g_object_unref (comp);
+
+ if (flags & COMP_EDITOR_IS_ASSIGNED)
+ task_editor_show_assignment (TASK_EDITOR (editor));
+
+exit:
+ gtk_window_present (GTK_WINDOW (editor));
+}
+
+void
+e_task_shell_view_delete_completed (ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ ECalModel *model;
+ GList *list, *link;
+ const gchar *sexp;
+
+ g_return_if_fail (E_IS_TASK_SHELL_VIEW (task_shell_view));
+
+ sexp = "(is-completed?)";
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ model = e_task_shell_content_get_task_model (task_shell_content);
+
+ e_task_shell_view_set_status_message (
+ task_shell_view, _("Expunging"), -1.0);
+
+ list = e_cal_model_list_clients (model);
+
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ ECalClient *client = E_CAL_CLIENT (link->data);
+ GSList *objects, *obj;
+ GError *error = NULL;
+
+ if (e_client_is_readonly (E_CLIENT (client)))
+ continue;
+
+ e_cal_client_get_object_list_sync (
+ client, sexp, &objects, NULL, &error);
+
+ if (error != NULL) {
+ g_warning (
+ "%s: Failed to get object list: %s",
+ G_STRFUNC, error->message);
+ g_clear_error (&error);
+ continue;
+ }
+
+ for (obj = objects; obj != NULL; obj = obj->next) {
+ icalcomponent *component = obj->data;
+ const gchar *uid;
+
+ uid = icalcomponent_get_uid (component);
+
+ e_cal_client_remove_object_sync (
+ client, uid, NULL,
+ CALOBJ_MOD_THIS, NULL, &error);
+
+ if (error != NULL) {
+ g_warning (
+ "%s: Failed to remove object: %s",
+ G_STRFUNC, error->message);
+ g_clear_error (&error);
+ }
+ }
+
+ e_cal_client_free_icalcomp_slist (objects);
+ }
+
+ g_list_free_full (list, (GDestroyNotify) g_object_unref);
+
+ e_task_shell_view_set_status_message (task_shell_view, NULL, -1.0);
+}
+
+void
+e_task_shell_view_set_status_message (ETaskShellView *task_shell_view,
+ const gchar *status_message,
+ gdouble percent)
+{
+ EActivity *activity;
+ EShellView *shell_view;
+ EShellBackend *shell_backend;
+
+ g_return_if_fail (E_IS_TASK_SHELL_VIEW (task_shell_view));
+
+ activity = task_shell_view->priv->activity;
+ shell_view = E_SHELL_VIEW (task_shell_view);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+
+ if (status_message == NULL || *status_message == '\0') {
+ if (activity != NULL) {
+ e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
+ g_object_unref (activity);
+ activity = NULL;
+ }
+
+ } else if (activity == NULL) {
+ activity = e_activity_new ();
+ e_activity_set_percent (activity, percent);
+ e_activity_set_text (activity, status_message);
+ e_shell_backend_add_activity (shell_backend, activity);
+
+ } else {
+ e_activity_set_percent (activity, percent);
+ e_activity_set_text (activity, status_message);
+ }
+
+ task_shell_view->priv->activity = activity;
+}
+
+void
+e_task_shell_view_update_sidebar (ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ EShellView *shell_view;
+ EShellSidebar *shell_sidebar;
+ ETaskTable *task_table;
+ ECalModel *model;
+ GString *string;
+ const gchar *format;
+ gint n_rows;
+ gint n_selected;
+
+ shell_view = E_SHELL_VIEW (task_shell_view);
+ shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+
+ model = e_task_table_get_model (task_table);
+
+ n_rows = e_table_model_row_count (E_TABLE_MODEL (model));
+ n_selected = e_table_selected_count (E_TABLE (task_table));
+
+ string = g_string_sized_new (64);
+
+ format = ngettext ("%d task", "%d tasks", n_rows);
+ g_string_append_printf (string, format, n_rows);
+
+ if (n_selected > 0) {
+ format = _("%d selected");
+ g_string_append_len (string, ", ", 2);
+ g_string_append_printf (string, format, n_selected);
+ }
+
+ e_shell_sidebar_set_secondary_text (shell_sidebar, string->str);
+
+ g_string_free (string, TRUE);
+}
+
diff --git a/modules/calendar/e-task-shell-view-private.h b/modules/calendar/e-task-shell-view-private.h
new file mode 100644
index 0000000000..71772f55bb
--- /dev/null
+++ b/modules/calendar/e-task-shell-view-private.h
@@ -0,0 +1,155 @@
+/*
+ * e-task-shell-view-private.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_TASK_SHELL_VIEW_PRIVATE_H
+#define E_TASK_SHELL_VIEW_PRIVATE_H
+
+#include "e-task-shell-view.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <libecal/libecal.h>
+
+#include "shell/e-shell-utils.h"
+
+#include "calendar/gui/calendar-config.h"
+#include "calendar/gui/comp-util.h"
+#include "calendar/gui/e-cal-component-preview.h"
+#include "calendar/gui/e-cal-model-tasks.h"
+#include "calendar/gui/e-calendar-selector.h"
+#include "calendar/gui/print.h"
+#include "calendar/gui/dialogs/copy-source-dialog.h"
+#include "calendar/gui/dialogs/task-editor.h"
+
+#include "e-task-shell-backend.h"
+#include "e-task-shell-content.h"
+#include "e-task-shell-sidebar.h"
+#include "e-task-shell-view-actions.h"
+
+#define E_TASK_SHELL_VIEW_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_TASK_SHELL_VIEW, ETaskShellViewPrivate))
+
+/* Shorthand, requires a variable named "shell_window". */
+#define ACTION(name) \
+ (E_SHELL_WINDOW_ACTION_##name (shell_window))
+#define ACTION_GROUP(name) \
+ (E_SHELL_WINDOW_ACTION_GROUP_##name (shell_window))
+
+/* ETable Specifications */
+#define ETSPEC_FILENAME "e-calendar-table.etspec"
+
+G_BEGIN_DECLS
+
+/* Filter items are displayed in ascending order.
+ * Non-negative values are reserved for categories. */
+enum {
+ TASK_FILTER_ANY_CATEGORY = -7,
+ TASK_FILTER_UNMATCHED = -6,
+ TASK_FILTER_NEXT_7_DAYS_TASKS = -5,
+ TASK_FILTER_ACTIVE_TASKS = -4,
+ TASK_FILTER_OVERDUE_TASKS = -3,
+ TASK_FILTER_COMPLETED_TASKS = -2,
+ TASK_FILTER_TASKS_WITH_ATTACHMENTS = -1
+};
+
+/* Search items are displayed in ascending order. */
+enum {
+ TASK_SEARCH_ADVANCED = -1,
+ TASK_SEARCH_SUMMARY_CONTAINS,
+ TASK_SEARCH_DESCRIPTION_CONTAINS,
+ TASK_SEARCH_ANY_FIELD_CONTAINS
+};
+
+struct _ETaskShellViewPrivate {
+
+ /* These are just for convenience. */
+ ETaskShellBackend *task_shell_backend;
+ ETaskShellContent *task_shell_content;
+ ETaskShellSidebar *task_shell_sidebar;
+
+ /* sidebar signal handlers */
+ gulong client_added_handler_id;
+ gulong client_removed_handler_id;
+
+ EClientCache *client_cache;
+ gulong backend_error_handler_id;
+
+ ETaskTable *task_table;
+ gulong open_component_handler_id;
+ gulong popup_event_handler_id;
+ gulong selection_change_1_handler_id;
+ gulong selection_change_2_handler_id;
+ gulong status_message_handler_id;
+
+ ECalModel *model;
+ gulong model_changed_handler_id;
+ gulong model_rows_deleted_handler_id;
+ gulong model_rows_inserted_handler_id;
+ gulong rows_appended_handler_id;
+
+ ESourceSelector *selector;
+ gulong selector_popup_event_handler_id;
+ gulong primary_selection_changed_handler_id;
+
+ /* org.gnome.evolution.calendar */
+ GSettings *settings;
+ gulong settings_hide_completed_tasks_handler_id;
+ gulong settings_hide_completed_tasks_units_handler_id;
+ gulong settings_hide_completed_tasks_value_handler_id;
+
+ EActivity *activity;
+ guint update_timeout;
+ guint update_completed_timeout;
+
+ guint confirm_purge : 1;
+};
+
+void e_task_shell_view_private_init
+ (ETaskShellView *task_shell_view);
+void e_task_shell_view_private_constructed
+ (ETaskShellView *task_shell_view);
+void e_task_shell_view_private_dispose
+ (ETaskShellView *task_shell_view);
+void e_task_shell_view_private_finalize
+ (ETaskShellView *task_shell_view);
+
+/* Private Utilities */
+
+void e_task_shell_view_actions_init
+ (ETaskShellView *task_shell_view);
+void e_task_shell_view_open_task
+ (ETaskShellView *task_shell_view,
+ ECalModelComponent *comp_data);
+void e_task_shell_view_delete_completed
+ (ETaskShellView *task_shell_view);
+void e_task_shell_view_set_status_message
+ (ETaskShellView *task_shell_view,
+ const gchar *status_message,
+ gdouble percent);
+void e_task_shell_view_update_sidebar
+ (ETaskShellView *task_shell_view);
+void e_task_shell_view_update_search_filter
+ (ETaskShellView *task_shell_view);
+
+G_END_DECLS
+
+#endif /* E_TASK_SHELL_VIEW_PRIVATE_H */
diff --git a/modules/calendar/e-task-shell-view.c b/modules/calendar/e-task-shell-view.c
new file mode 100644
index 0000000000..14dbfd5b24
--- /dev/null
+++ b/modules/calendar/e-task-shell-view.c
@@ -0,0 +1,530 @@
+/*
+ * e-task-shell-view.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-task-shell-view-private.h"
+
+enum {
+ PROP_0,
+ PROP_CONFIRM_PURGE
+};
+
+G_DEFINE_DYNAMIC_TYPE (
+ ETaskShellView,
+ e_task_shell_view,
+ E_TYPE_SHELL_VIEW)
+
+static void
+task_shell_view_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CONFIRM_PURGE:
+ e_task_shell_view_set_confirm_purge (
+ E_TASK_SHELL_VIEW (object),
+ g_value_get_boolean (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+task_shell_view_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CONFIRM_PURGE:
+ g_value_set_boolean (
+ value, e_task_shell_view_get_confirm_purge (
+ E_TASK_SHELL_VIEW (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+task_shell_view_dispose (GObject *object)
+{
+ e_task_shell_view_private_dispose (E_TASK_SHELL_VIEW (object));
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_task_shell_view_parent_class)->dispose (object);
+}
+
+static void
+task_shell_view_finalize (GObject *object)
+{
+ e_task_shell_view_private_finalize (E_TASK_SHELL_VIEW (object));
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_task_shell_view_parent_class)->finalize (object);
+}
+
+static void
+task_shell_view_constructed (GObject *object)
+{
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_task_shell_view_parent_class)->constructed (object);
+
+ e_task_shell_view_private_constructed (E_TASK_SHELL_VIEW (object));
+}
+
+static void
+task_shell_view_execute_search (EShellView *shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ EShellWindow *shell_window;
+ EShellContent *shell_content;
+ EShellSearchbar *searchbar;
+ EActionComboBox *combo_box;
+ GtkRadioAction *action;
+ ECalComponentPreview *task_preview;
+ EPreviewPane *preview_pane;
+ ETaskTable *task_table;
+ EWebView *web_view;
+ ECalModel *model;
+ icaltimezone *timezone;
+ struct icaltimetype current_time;
+ time_t start_range;
+ time_t end_range;
+ time_t now_time;
+ gchar *start, *end;
+ gchar *query;
+ gchar *temp;
+ gint value;
+
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell_content = e_shell_view_get_shell_content (shell_view);
+
+ task_shell_content = E_TASK_SHELL_CONTENT (shell_content);
+ searchbar = e_task_shell_content_get_searchbar (task_shell_content);
+
+ task_shell_content = E_TASK_SHELL_CONTENT (shell_content);
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+ model = e_task_table_get_model (task_table);
+ timezone = e_cal_model_get_timezone (model);
+ current_time = icaltime_current_time_with_zone (timezone);
+ now_time = time_day_begin (icaltime_as_timet (current_time));
+
+ action = GTK_RADIO_ACTION (ACTION (TASK_SEARCH_ANY_FIELD_CONTAINS));
+ value = gtk_radio_action_get_current_value (action);
+
+ if (value == TASK_SEARCH_ADVANCED) {
+ query = e_shell_view_get_search_query (shell_view);
+
+ if (!query)
+ query = g_strdup ("");
+ } else {
+ const gchar *format;
+ const gchar *text;
+ GString *string;
+
+ text = e_shell_searchbar_get_search_text (searchbar);
+
+ if (text == NULL || *text == '\0') {
+ text = "";
+ value = TASK_SEARCH_SUMMARY_CONTAINS;
+ }
+
+ switch (value) {
+ default:
+ text = "";
+ /* fall through */
+
+ case TASK_SEARCH_SUMMARY_CONTAINS:
+ format = "(contains? \"summary\" %s)";
+ break;
+
+ case TASK_SEARCH_DESCRIPTION_CONTAINS:
+ format = "(contains? \"description\" %s)";
+ break;
+
+ case TASK_SEARCH_ANY_FIELD_CONTAINS:
+ format = "(contains? \"any\" %s)";
+ break;
+ }
+
+ /* Build the query. */
+ string = g_string_new ("");
+ e_sexp_encode_string (string, text);
+ query = g_strdup_printf (format, string->str);
+ g_string_free (string, TRUE);
+ }
+
+ /* Apply selected filter. */
+ combo_box = e_shell_searchbar_get_filter_combo_box (searchbar);
+ value = e_action_combo_box_get_current_value (combo_box);
+ switch (value) {
+ case TASK_FILTER_ANY_CATEGORY:
+ break;
+
+ case TASK_FILTER_UNMATCHED:
+ temp = g_strdup_printf (
+ "(and (has-categories? #f) %s)", query);
+ g_free (query);
+ query = temp;
+ break;
+
+ case TASK_FILTER_NEXT_7_DAYS_TASKS:
+ start_range = now_time;
+ end_range = time_day_end (time_add_day (start_range, 7));
+ start = isodate_from_time_t (start_range);
+ end = isodate_from_time_t (end_range);
+
+ temp = g_strdup_printf (
+ "(and %s (due-in-time-range? "
+ "(make-time \"%s\") (make-time \"%s\")))",
+ query, start, end);
+ g_free (query);
+ query = temp;
+ break;
+
+ case TASK_FILTER_ACTIVE_TASKS:
+ start_range = now_time;
+ end_range = time_day_end (time_add_day (start_range, 365));
+ start = isodate_from_time_t (start_range);
+ end = isodate_from_time_t (end_range);
+
+ temp = g_strdup_printf (
+ "(and %s (due-in-time-range? "
+ "(make-time \"%s\") (make-time \"%s\")) "
+ "(not (is-completed?)))",
+ query, start, end);
+ g_free (query);
+ query = temp;
+ break;
+
+ case TASK_FILTER_OVERDUE_TASKS:
+ start_range = 0;
+ end_range = time_day_end (now_time);
+ start = isodate_from_time_t (start_range);
+ end = isodate_from_time_t (end_range);
+
+ temp = g_strdup_printf (
+ "(and %s (due-in-time-range? "
+ "(make-time \"%s\") (make-time \"%s\")) "
+ "(not (is-completed?)))",
+ query, start, end);
+ g_free (query);
+ query = temp;
+ break;
+
+ case TASK_FILTER_COMPLETED_TASKS:
+ temp = g_strdup_printf (
+ "(and (is-completed?) %s)", query);
+ g_free (query);
+ query = temp;
+ break;
+
+ case TASK_FILTER_TASKS_WITH_ATTACHMENTS:
+ temp = g_strdup_printf (
+ "(and (has-attachments?) %s)", query);
+ g_free (query);
+ query = temp;
+ break;
+
+ default:
+ {
+ GList *categories;
+ const gchar *category_name;
+
+ categories = e_util_get_searchable_categories ();
+ category_name = g_list_nth_data (categories, value);
+ g_list_free (categories);
+
+ temp = g_strdup_printf (
+ "(and (has-categories? \"%s\") %s)",
+ category_name, query);
+ g_free (query);
+ query = temp;
+ break;
+ }
+ }
+
+ /* Honor the user's preference to hide completed tasks. */
+ temp = calendar_config_get_hide_completed_tasks_sexp (FALSE);
+ if (temp != NULL) {
+ gchar *temp2;
+
+ temp2 = g_strdup_printf ("(and %s %s)", temp, query);
+ g_free (query);
+ g_free (temp);
+ query = temp2;
+ }
+
+ /* Submit the query. */
+ e_cal_model_set_search_query (model, query);
+ g_free (query);
+
+ preview_pane =
+ e_task_shell_content_get_preview_pane (task_shell_content);
+
+ web_view = e_preview_pane_get_web_view (preview_pane);
+ task_preview = E_CAL_COMPONENT_PREVIEW (web_view);
+ e_cal_component_preview_clear (task_preview);
+}
+
+static void
+task_shell_view_update_actions (EShellView *shell_view)
+{
+ EShellContent *shell_content;
+ EShellSidebar *shell_sidebar;
+ EShellWindow *shell_window;
+ GtkAction *action;
+ const gchar *label;
+ gboolean sensitive;
+ guint32 state;
+
+ /* Be descriptive. */
+ gboolean any_tasks_selected;
+ gboolean has_primary_source;
+ gboolean multiple_tasks_selected;
+ gboolean primary_source_is_writable;
+ gboolean primary_source_is_removable;
+ gboolean primary_source_is_remote_deletable;
+ gboolean primary_source_in_collection;
+ gboolean selection_has_url;
+ gboolean selection_is_assignable;
+ gboolean single_task_selected;
+ gboolean some_tasks_complete;
+ gboolean some_tasks_incomplete;
+ gboolean sources_are_editable;
+ gboolean refresh_supported;
+
+ /* Chain up to parent's update_actions() method. */
+ E_SHELL_VIEW_CLASS (e_task_shell_view_parent_class)->
+ update_actions (shell_view);
+
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ shell_content = e_shell_view_get_shell_content (shell_view);
+ state = e_shell_content_check_state (shell_content);
+
+ single_task_selected =
+ (state & E_TASK_SHELL_CONTENT_SELECTION_SINGLE);
+ multiple_tasks_selected =
+ (state & E_TASK_SHELL_CONTENT_SELECTION_MULTIPLE);
+ selection_is_assignable =
+ (state & E_TASK_SHELL_CONTENT_SELECTION_CAN_ASSIGN);
+ sources_are_editable =
+ (state & E_TASK_SHELL_CONTENT_SELECTION_CAN_EDIT);
+ some_tasks_complete =
+ (state & E_TASK_SHELL_CONTENT_SELECTION_HAS_COMPLETE);
+ some_tasks_incomplete =
+ (state & E_TASK_SHELL_CONTENT_SELECTION_HAS_INCOMPLETE);
+ selection_has_url =
+ (state & E_TASK_SHELL_CONTENT_SELECTION_HAS_URL);
+
+ shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+ state = e_shell_sidebar_check_state (shell_sidebar);
+
+ has_primary_source =
+ (state & E_TASK_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE);
+ primary_source_is_writable =
+ (state & E_TASK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_WRITABLE);
+ primary_source_is_removable =
+ (state & E_TASK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOVABLE);
+ primary_source_is_remote_deletable =
+ (state & E_TASK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_DELETABLE);
+ primary_source_in_collection =
+ (state & E_TASK_SHELL_SIDEBAR_PRIMARY_SOURCE_IN_COLLECTION);
+ refresh_supported =
+ (state & E_TASK_SHELL_SIDEBAR_SOURCE_SUPPORTS_REFRESH);
+
+ any_tasks_selected =
+ (single_task_selected || multiple_tasks_selected);
+
+ action = ACTION (TASK_ASSIGN);
+ sensitive =
+ single_task_selected && sources_are_editable &&
+ selection_is_assignable;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (TASK_DELETE);
+ sensitive = any_tasks_selected && sources_are_editable;
+ gtk_action_set_sensitive (action, sensitive);
+ if (multiple_tasks_selected)
+ label = _("Delete Tasks");
+ else
+ label = _("Delete Task");
+ gtk_action_set_label (action, label);
+
+ action = ACTION (TASK_FIND);
+ sensitive = single_task_selected;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (TASK_FORWARD);
+ sensitive = single_task_selected;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (TASK_LIST_COPY);
+ sensitive = has_primary_source;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (TASK_LIST_DELETE);
+ sensitive =
+ primary_source_is_removable ||
+ primary_source_is_remote_deletable;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (TASK_LIST_PROPERTIES);
+ sensitive = primary_source_is_writable;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (TASK_LIST_REFRESH);
+ sensitive = refresh_supported;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (TASK_LIST_RENAME);
+ sensitive =
+ primary_source_is_writable &&
+ !primary_source_in_collection;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (TASK_MARK_COMPLETE);
+ sensitive =
+ any_tasks_selected &&
+ sources_are_editable &&
+ some_tasks_incomplete;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (TASK_MARK_INCOMPLETE);
+ sensitive =
+ any_tasks_selected &&
+ sources_are_editable &&
+ some_tasks_complete;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (TASK_OPEN);
+ sensitive = single_task_selected;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (TASK_OPEN_URL);
+ sensitive = single_task_selected && selection_has_url;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (TASK_PRINT);
+ sensitive = single_task_selected;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (TASK_PURGE);
+ sensitive = sources_are_editable;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (TASK_SAVE_AS);
+ sensitive = single_task_selected;
+ gtk_action_set_sensitive (action, sensitive);
+}
+
+static void
+e_task_shell_view_class_init (ETaskShellViewClass *class)
+{
+ GObjectClass *object_class;
+ EShellViewClass *shell_view_class;
+
+ g_type_class_add_private (class, sizeof (ETaskShellViewPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = task_shell_view_set_property;
+ object_class->get_property = task_shell_view_get_property;
+ object_class->dispose = task_shell_view_dispose;
+ object_class->finalize = task_shell_view_finalize;
+ object_class->constructed = task_shell_view_constructed;
+
+ shell_view_class = E_SHELL_VIEW_CLASS (class);
+ shell_view_class->label = _("Tasks");
+ shell_view_class->icon_name = "evolution-tasks";
+ shell_view_class->ui_definition = "evolution-tasks.ui";
+ shell_view_class->ui_manager_id = "org.gnome.evolution.tasks";
+ shell_view_class->search_options = "/task-search-options";
+ shell_view_class->search_rules = "tasktypes.xml";
+ shell_view_class->new_shell_content = e_task_shell_content_new;
+ shell_view_class->new_shell_sidebar = e_task_shell_sidebar_new;
+ shell_view_class->execute_search = task_shell_view_execute_search;
+ shell_view_class->update_actions = task_shell_view_update_actions;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_CONFIRM_PURGE,
+ g_param_spec_boolean (
+ "confirm-purge",
+ "Confirm Purge",
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE));
+
+ /* Ensure the GalView types we need are registered. */
+ g_type_ensure (GAL_TYPE_VIEW_ETABLE);
+}
+
+static void
+e_task_shell_view_class_finalize (ETaskShellViewClass *class)
+{
+}
+
+static void
+e_task_shell_view_init (ETaskShellView *task_shell_view)
+{
+ task_shell_view->priv =
+ E_TASK_SHELL_VIEW_GET_PRIVATE (task_shell_view);
+
+ e_task_shell_view_private_init (task_shell_view);
+}
+
+void
+e_task_shell_view_type_register (GTypeModule *type_module)
+{
+ /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
+ * function, so we have to wrap it with a public function in
+ * order to register types from a separate compilation unit. */
+ e_task_shell_view_register_type (type_module);
+}
+
+gboolean
+e_task_shell_view_get_confirm_purge (ETaskShellView *task_shell_view)
+{
+ g_return_val_if_fail (E_IS_TASK_SHELL_VIEW (task_shell_view), FALSE);
+
+ return task_shell_view->priv->confirm_purge;
+}
+
+void
+e_task_shell_view_set_confirm_purge (ETaskShellView *task_shell_view,
+ gboolean confirm_purge)
+{
+ g_return_if_fail (E_IS_TASK_SHELL_VIEW (task_shell_view));
+
+ if (task_shell_view->priv->confirm_purge == confirm_purge)
+ return;
+
+ task_shell_view->priv->confirm_purge = confirm_purge;
+
+ g_object_notify (G_OBJECT (task_shell_view), "confirm-purge");
+}
diff --git a/modules/calendar/e-task-shell-view.h b/modules/calendar/e-task-shell-view.h
new file mode 100644
index 0000000000..97f07edff7
--- /dev/null
+++ b/modules/calendar/e-task-shell-view.h
@@ -0,0 +1,71 @@
+/*
+ * e-task-shell-view.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_TASK_SHELL_VIEW_H
+#define E_TASK_SHELL_VIEW_H
+
+#include <shell/e-shell-view.h>
+
+/* Standard GObject macros */
+#define E_TYPE_TASK_SHELL_VIEW \
+ (e_task_shell_view_get_type ())
+#define E_TASK_SHELL_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_TASK_SHELL_VIEW, ETaskShellView))
+#define E_TASK_SHELL_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_TASK_SHELL_VIEW, ETaskShellViewClass))
+#define E_IS_TASK_SHELL_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_TASK_SHELL_VIEW))
+#define E_IS_TASK_SHELL_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_TASK_SHELL_VIEW))
+#define E_TASK_SHELL_VIEW_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_TASK_SHELL_VIEW, ETaskShellViewClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ETaskShellView ETaskShellView;
+typedef struct _ETaskShellViewClass ETaskShellViewClass;
+typedef struct _ETaskShellViewPrivate ETaskShellViewPrivate;
+
+struct _ETaskShellView {
+ EShellView parent;
+ ETaskShellViewPrivate *priv;
+};
+
+struct _ETaskShellViewClass {
+ EShellViewClass parent_class;
+};
+
+GType e_task_shell_view_get_type (void);
+void e_task_shell_view_type_register (GTypeModule *type_module);
+gboolean e_task_shell_view_get_confirm_purge
+ (ETaskShellView *task_shell_view);
+void e_task_shell_view_set_confirm_purge
+ (ETaskShellView *task_shell_view,
+ gboolean confirm_purge);
+
+G_END_DECLS
+
+#endif /* E_TASK_SHELL_VIEW_H */
diff --git a/modules/calendar/evolution-module-calendar.c b/modules/calendar/evolution-module-calendar.c
new file mode 100644
index 0000000000..fabe410271
--- /dev/null
+++ b/modules/calendar/evolution-module-calendar.c
@@ -0,0 +1,83 @@
+/*
+ * evolution-module-calendar.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-cal-attachment-handler.h"
+
+#include "e-cal-config-hook.h"
+#include "e-cal-event-hook.h"
+
+#include "e-cal-shell-backend.h"
+#include "e-cal-shell-content.h"
+#include "e-cal-shell-sidebar.h"
+#include "e-cal-shell-view.h"
+
+#include "e-memo-shell-backend.h"
+#include "e-memo-shell-content.h"
+#include "e-memo-shell-sidebar.h"
+#include "e-memo-shell-view.h"
+
+#include "e-task-shell-backend.h"
+#include "e-task-shell-content.h"
+#include "e-task-shell-sidebar.h"
+#include "e-task-shell-view.h"
+
+#include "e-calendar-preferences.h"
+
+/* Module Entry Points */
+void e_module_load (GTypeModule *type_module);
+void e_module_unload (GTypeModule *type_module);
+
+G_MODULE_EXPORT void
+e_module_load (GTypeModule *type_module)
+{
+ /* Register dynamically loaded types. */
+
+ e_cal_attachment_handler_register_type (type_module);
+
+ e_cal_config_hook_register_type (type_module);
+ e_cal_event_hook_register_type (type_module);
+
+ e_cal_shell_view_type_register (type_module);
+ e_cal_shell_backend_type_register (type_module);
+ e_cal_shell_content_type_register (type_module);
+ e_cal_shell_sidebar_type_register (type_module);
+
+ e_memo_shell_view_type_register (type_module);
+ e_memo_shell_backend_type_register (type_module);
+ e_memo_shell_content_type_register (type_module);
+ e_memo_shell_sidebar_type_register (type_module);
+
+ e_task_shell_view_type_register (type_module);
+ e_task_shell_backend_type_register (type_module);
+ e_task_shell_content_type_register (type_module);
+ e_task_shell_sidebar_type_register (type_module);
+
+ e_calendar_preferences_type_register (type_module);
+}
+
+G_MODULE_EXPORT void
+e_module_unload (GTypeModule *type_module)
+{
+}