diff --git a/src/modules/calendar/e-cal-base-shell-sidebar.c b/src/modules/calendar/e-cal-base-shell-sidebar.c
index f574b18..749d589 100644
--- a/src/modules/calendar/e-cal-base-shell-sidebar.c
+++ b/src/modules/calendar/e-cal-base-shell-sidebar.c
@@ -296,6 +296,7 @@ typedef struct _OpenClientData {
ECalBaseShellSidebar *sidebar;
ESource *source;
EClient *client;
+ gboolean was_cancelled;
} OpenClientData;
static void
@@ -304,9 +305,14 @@ open_client_data_free (gpointer pdata)
OpenClientData *data = pdata;
if (data) {
+ /* To free the cancellable in the 'value' pair, which is useless now */
+ g_hash_table_insert (data->sidebar->priv->selected_uids,
+ g_strdup (e_source_get_uid (data->source)),
+ NULL);
+
if (data->client) {
g_signal_emit (data->sidebar, signals[CLIENT_OPENED], 0, data->client);
- } else {
+ } else if (!data->was_cancelled) {
ESourceSelector *selector = e_cal_base_shell_sidebar_get_selector (data->sidebar);
e_source_selector_unselect_source (selector, data->source);
}
@@ -333,6 +339,7 @@ e_cal_base_shell_sidebar_open_client_thread (EAlertSinkThreadJobData *job_data,
selector = E_CLIENT_SELECTOR (e_cal_base_shell_sidebar_get_selector (data->sidebar));
data->client = e_client_selector_get_client_sync (
selector, data->source, TRUE, (guint32) -1, cancellable, &local_error);
+ data->was_cancelled = g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
e_util_propagate_open_source_job_error (job_data, data->extension_name, local_error, error);
}
@@ -350,6 +357,10 @@ e_cal_base_shell_sidebar_ensure_source_opened (ECalBaseShellSidebar *sidebar,
g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (sidebar));
g_return_if_fail (E_IS_SOURCE (source));
+ /* Skip it when it's already opening or opened */
+ if (g_hash_table_contains (sidebar->priv->selected_uids, e_source_get_uid (source)))
+ return;
+
shell_view = e_shell_sidebar_get_shell_view (E_SHELL_SIDEBAR (sidebar));
switch (e_cal_base_shell_view_get_source_type (shell_view)) {
diff --git a/src/modules/calendar/e-cal-base-shell-sidebar.c.deselect-task-memo-list b/src/modules/calendar/e-cal-base-shell-sidebar.c.deselect-task-memo-list
new file mode 100644
index 0000000..f574b18
--- /dev/null
+++ b/src/modules/calendar/e-cal-base-shell-sidebar.c.deselect-task-memo-list
@@ -0,0 +1,957 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
+ *
+ * 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.
+ *
+ * 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 this program; if not, see .
+ *
+ * Authors: Milan Crha
+ */
+
+#include "evolution-config.h"
+
+#include
+#include
+
+#include "e-util/e-util.h"
+#include "calendar/gui/comp-util.h"
+
+#include "e-cal-base-shell-view.h"
+#include "e-cal-base-shell-sidebar.h"
+
+#define E_CAL_BASE_SHELL_SIDEBAR_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_CAL_BASE_SHELL_SIDEBAR, ECalBaseShellSidebarPrivate))
+
+struct _ECalBaseShellSidebarPrivate {
+ ECalendar *date_navigator; /* not referenced, is inside itself */
+ GtkWidget *paned; /* not referenced, is inside itself */
+ ESourceSelector *selector; /* not referenced, is inside itself */
+
+ gulong date_navigator_scroll_event_handler_id;
+
+ GHashTable *selected_uids; /* source UID -> cancellable */
+};
+
+enum {
+ PROP_0,
+ PROP_DATE_NAVIGATOR,
+ PROP_SELECTOR
+};
+
+enum {
+ CLIENT_OPENED,
+ CLIENT_CLOSED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+G_DEFINE_DYNAMIC_TYPE (ECalBaseShellSidebar, e_cal_base_shell_sidebar, E_TYPE_SHELL_SIDEBAR)
+
+static gboolean
+cal_base_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_base_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_base_shell_sidebar_restore_state_cb (EShellWindow *shell_window,
+ EShellView *shell_view,
+ EShellSidebar *shell_sidebar)
+{
+ ECalBaseShellSidebarPrivate *priv;
+ ESourceRegistry *registry;
+ ESourceSelector *selector;
+ GSettings *settings;
+ const gchar *primary_source_key = NULL;
+
+ priv = E_CAL_BASE_SHELL_SIDEBAR (shell_sidebar)->priv;
+
+ g_signal_handlers_disconnect_by_func (
+ shell_window,
+ cal_base_shell_sidebar_restore_state_cb, shell_sidebar);
+
+ switch (e_cal_base_shell_view_get_source_type (shell_view)) {
+ case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+ primary_source_key = "primary-calendar";
+ break;
+ case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+ primary_source_key = "primary-memos";
+ break;
+ case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+ primary_source_key = "primary-tasks";
+ break;
+ case E_CAL_CLIENT_SOURCE_TYPE_LAST:
+ g_warn_if_reached ();
+ return;
+ }
+
+ selector = E_SOURCE_SELECTOR (priv->selector);
+ registry = e_source_selector_get_registry (selector);
+
+ /* Bind GObject properties to settings keys. */
+
+ settings = e_util_ref_settings ("org.gnome.evolution.calendar");
+
+ g_settings_bind_with_mapping (
+ settings, primary_source_key,
+ selector, "primary-selection",
+ G_SETTINGS_BIND_DEFAULT,
+ cal_base_shell_sidebar_map_uid_to_source,
+ cal_base_shell_sidebar_map_source_to_uid,
+ g_object_ref (registry),
+ (GDestroyNotify) g_object_unref);
+
+ if (priv->date_navigator) {
+ if (e_shell_window_is_main_instance (shell_window)) {
+ g_settings_bind (
+ settings, "date-navigator-pane-position",
+ priv->paned, "vposition",
+ G_SETTINGS_BIND_DEFAULT);
+ } else {
+ g_settings_bind (
+ settings, "date-navigator-pane-position-sub",
+ priv->paned, "vposition",
+ G_SETTINGS_BIND_DEFAULT |
+ G_SETTINGS_BIND_GET_NO_CHANGES);
+ }
+ }
+
+ g_object_unref (settings);
+}
+
+static guint32
+cal_base_shell_sidebar_check_state (EShellSidebar *shell_sidebar)
+{
+ ECalBaseShellSidebar *cal_base_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_base_shell_sidebar = E_CAL_BASE_SHELL_SIDEBAR (shell_sidebar);
+ selector = e_cal_base_shell_sidebar_get_selector (cal_base_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 (e_source_selector_count_total (selector) == e_source_selector_count_selected (selector))
+ state |= E_CAL_BASE_SHELL_SIDEBAR_ALL_SOURCES_SELECTED;
+ if (has_primary_source)
+ state |= E_CAL_BASE_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE;
+ if (is_writable)
+ state |= E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_WRITABLE;
+ if (is_removable)
+ state |= E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOVABLE;
+ if (is_remote_creatable)
+ state |= E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_CREATABLE;
+ if (is_remote_deletable)
+ state |= E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_DELETABLE;
+ if (in_collection)
+ state |= E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IN_COLLECTION;
+ if (refresh_supported)
+ state |= E_CAL_BASE_SHELL_SIDEBAR_SOURCE_SUPPORTS_REFRESH;
+
+ return state;
+}
+
+static gboolean
+cal_base_shell_sidebar_date_navigator_scroll_event_cb (ECalBaseShellSidebar *cal_base_shell_sidebar,
+ GdkEventScroll *event,
+ ECalendar *date_navigator)
+{
+ ECalendarItem *calitem;
+ gint year = -1, month = -1;
+ GdkScrollDirection direction;
+
+ calitem = e_calendar_get_item (date_navigator);
+ e_calendar_item_get_first_month (calitem, &year, &month);
+ if (year == -1 || month == -1)
+ 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:
+ month--;
+ if (month < 0) {
+ year--;
+ month += 12;
+ }
+ break;
+
+ case GDK_SCROLL_DOWN:
+ month++;
+ if (month >= 12) {
+ year++;
+ month -= 12;
+ }
+ break;
+
+ default:
+ g_return_val_if_reached (FALSE);
+ }
+
+ e_calendar_item_set_first_month (calitem, year, month);
+
+ return TRUE;
+}
+
+typedef struct _OpenClientData {
+ const gchar *extension_name;
+ ECalBaseShellSidebar *sidebar;
+ ESource *source;
+ EClient *client;
+} OpenClientData;
+
+static void
+open_client_data_free (gpointer pdata)
+{
+ OpenClientData *data = pdata;
+
+ if (data) {
+ if (data->client) {
+ g_signal_emit (data->sidebar, signals[CLIENT_OPENED], 0, data->client);
+ } else {
+ ESourceSelector *selector = e_cal_base_shell_sidebar_get_selector (data->sidebar);
+ e_source_selector_unselect_source (selector, data->source);
+ }
+
+ g_clear_object (&data->sidebar);
+ g_clear_object (&data->source);
+ g_clear_object (&data->client);
+ g_free (data);
+ }
+}
+
+static void
+e_cal_base_shell_sidebar_open_client_thread (EAlertSinkThreadJobData *job_data,
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EClientSelector *selector;
+ OpenClientData *data = user_data;
+ GError *local_error = NULL;
+
+ g_return_if_fail (data != NULL);
+
+ selector = E_CLIENT_SELECTOR (e_cal_base_shell_sidebar_get_selector (data->sidebar));
+ data->client = e_client_selector_get_client_sync (
+ selector, data->source, TRUE, (guint32) -1, cancellable, &local_error);
+
+ e_util_propagate_open_source_job_error (job_data, data->extension_name, local_error, error);
+}
+
+static void
+e_cal_base_shell_sidebar_ensure_source_opened (ECalBaseShellSidebar *sidebar,
+ ESource *source)
+{
+ OpenClientData *data;
+ EShellView *shell_view;
+ EActivity *activity;
+ gchar *description = NULL, *alert_ident = NULL, *alert_arg_0 = NULL, *display_name;
+ const gchar *extension_name = NULL;
+
+ g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (sidebar));
+ g_return_if_fail (E_IS_SOURCE (source));
+
+ shell_view = e_shell_sidebar_get_shell_view (E_SHELL_SIDEBAR (sidebar));
+
+ switch (e_cal_base_shell_view_get_source_type (shell_view)) {
+ case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+ extension_name = E_SOURCE_EXTENSION_CALENDAR;
+ break;
+ case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+ extension_name = E_SOURCE_EXTENSION_MEMO_LIST;
+ break;
+ case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+ extension_name = E_SOURCE_EXTENSION_TASK_LIST;
+ break;
+ case E_CAL_CLIENT_SOURCE_TYPE_LAST:
+ g_warn_if_reached ();
+ return;
+ }
+
+ display_name = e_util_get_source_full_name (e_shell_get_registry (e_shell_backend_get_shell (e_shell_view_get_shell_backend (shell_view))), source);
+
+ if (!e_util_get_open_source_job_info (extension_name, display_name,
+ &description, &alert_ident, &alert_arg_0)) {
+ g_free (display_name);
+ g_warn_if_reached ();
+ return;
+ }
+
+ g_free (display_name);
+
+ data = g_new0 (OpenClientData, 1);
+ data->extension_name = extension_name; /* no need to copy, it's a static string */
+ data->sidebar = g_object_ref (sidebar);
+ data->source = g_object_ref (source);
+
+ activity = e_shell_view_submit_thread_job (
+ shell_view, description, alert_ident, alert_arg_0,
+ e_cal_base_shell_sidebar_open_client_thread, data,
+ open_client_data_free);
+
+ if (activity) {
+ GCancellable *cancellable;
+
+ cancellable = e_activity_get_cancellable (activity);
+
+ g_hash_table_insert (sidebar->priv->selected_uids,
+ g_strdup (e_source_get_uid (source)),
+ g_object_ref (cancellable));
+
+ g_object_unref (activity);
+ }
+
+ g_free (description);
+ g_free (alert_ident);
+ g_free (alert_arg_0);
+}
+
+static void
+e_cal_base_shell_sidebar_primary_selection_changed_cb (ESourceSelector *selector,
+ EShellSidebar *sidebar)
+{
+ g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (sidebar));
+
+ e_shell_view_update_actions (e_shell_sidebar_get_shell_view (sidebar));
+}
+
+static void
+e_cal_base_shell_sidebar_source_selected (ESourceSelector *selector,
+ ESource *source,
+ ECalBaseShellSidebar *sidebar)
+{
+ g_return_if_fail (E_IS_SOURCE_SELECTOR (selector));
+ g_return_if_fail (E_IS_SOURCE (source));
+ g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (sidebar));
+
+ if (!g_hash_table_contains (sidebar->priv->selected_uids, e_source_get_uid (source))) {
+ e_cal_base_shell_sidebar_ensure_source_opened (sidebar, source);
+ }
+}
+
+static void
+e_cal_base_shell_sidebar_source_unselected (ESourceSelector *selector,
+ ESource *source,
+ ECalBaseShellSidebar *sidebar)
+{
+ g_return_if_fail (E_IS_SOURCE_SELECTOR (selector));
+ g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (sidebar));
+
+ if (g_hash_table_remove (sidebar->priv->selected_uids, e_source_get_uid (source)))
+ g_signal_emit (sidebar, signals[CLIENT_CLOSED], 0, source);
+}
+
+typedef struct {
+ ESource *source;
+ ESource *destination;
+ gboolean do_copy;
+ icalcomponent *icalcomp;
+ EClientSelector *selector;
+} TransferItemToData;
+
+static void
+transfer_item_to_data_free (gpointer ptr)
+{
+ TransferItemToData *titd = ptr;
+
+ if (titd) {
+ g_clear_object (&titd->source);
+ g_clear_object (&titd->destination);
+ g_clear_object (&titd->selector);
+
+ if (titd->icalcomp)
+ icalcomponent_free (titd->icalcomp);
+
+ g_free (titd);
+ }
+}
+
+static void
+cal_base_shell_sidebar_transfer_thread (EAlertSinkThreadJobData *job_data,
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **error)
+{
+ TransferItemToData *titd = user_data;
+ EClient *source_client, *destination_client;
+
+ g_return_if_fail (titd != NULL);
+ g_return_if_fail (E_IS_SOURCE (titd->source));
+ g_return_if_fail (E_IS_SOURCE (titd->destination));
+ g_return_if_fail (E_IS_CLIENT_SELECTOR (titd->selector));
+ g_return_if_fail (titd->icalcomp != NULL);
+
+ source_client = e_client_selector_get_client_sync (
+ titd->selector, titd->source, FALSE, 30, cancellable, error);
+ if (!source_client)
+ return;
+
+ destination_client = e_client_selector_get_client_sync (
+ titd->selector, titd->destination, FALSE, 30, cancellable, error);
+ if (!destination_client) {
+ g_object_unref (source_client);
+ return;
+ }
+
+ cal_comp_transfer_item_to_sync (E_CAL_CLIENT (source_client), E_CAL_CLIENT (destination_client),
+ titd->icalcomp, titd->do_copy, cancellable, error);
+
+ g_clear_object (&source_client);
+ g_clear_object (&destination_client);
+}
+
+static gboolean
+e_cal_base_shell_sidebar_selector_data_dropped (ESourceSelector *selector,
+ GtkSelectionData *selection_data,
+ ESource *destination,
+ GdkDragAction action,
+ guint info,
+ ECalBaseShellSidebar *sidebar)
+{
+ icalcomponent *icalcomp = NULL;
+ EActivity *activity;
+ EShellView *shell_view;
+ ESource *source = NULL;
+ ESourceRegistry *registry;
+ gchar **segments;
+ gchar *source_uid = NULL;
+ gchar *message = NULL;
+ gchar *display_name = NULL;
+ const gchar *alert_ident = NULL;
+ const guchar *data;
+ gboolean do_copy;
+ TransferItemToData *titd;
+
+ g_return_val_if_fail (E_IS_SOURCE_SELECTOR (selector), FALSE);
+ g_return_val_if_fail (E_IS_SOURCE (destination), FALSE);
+ g_return_val_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (sidebar), FALSE);
+
+ data = gtk_selection_data_get_data (selection_data);
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ segments = g_strsplit ((const gchar *) data, "\n", 2);
+ if (g_strv_length (segments) != 2)
+ goto exit;
+
+ source_uid = g_strdup (segments[0]);
+ icalcomp = icalparser_parse_string (segments[1]);
+
+ if (!icalcomp)
+ goto exit;
+
+ registry = e_source_selector_get_registry (selector);
+ source = e_source_registry_ref_source (registry, source_uid);
+ if (!source)
+ goto exit;
+
+ display_name = e_util_get_source_full_name (registry, destination);
+ do_copy = action == GDK_ACTION_COPY ? TRUE : FALSE;
+ shell_view = e_shell_sidebar_get_shell_view (E_SHELL_SIDEBAR (sidebar));
+
+ switch (e_cal_base_shell_view_get_source_type (shell_view)) {
+ case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+ message = do_copy ?
+ g_strdup_printf (_("Copying an event into the calendar “%s”"), display_name) :
+ g_strdup_printf (_("Moving an event into the calendar “%s”"), display_name);
+ alert_ident = do_copy ? "calendar:failed-copy-event" : "calendar:failed-move-event";
+ break;
+ case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+ message = do_copy ?
+ g_strdup_printf (_("Copying a memo into the memo list “%s”"), display_name) :
+ g_strdup_printf (_("Moving a memo into the memo list “%s”"), display_name);
+ alert_ident = do_copy ? "calendar:failed-copy-memo" : "calendar:failed-move-memo";
+ break;
+ case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+ message = do_copy ?
+ g_strdup_printf (_("Copying a task into the task list “%s”"), display_name) :
+ g_strdup_printf (_("Moving a task into the task list “%s”"), display_name);
+ alert_ident = do_copy ? "calendar:failed-copy-task" : "calendar:failed-move-task";
+ break;
+ case E_CAL_CLIENT_SOURCE_TYPE_LAST:
+ g_warn_if_reached ();
+ goto exit;
+ }
+
+ titd = g_new0 (TransferItemToData, 1);
+ titd->source = g_object_ref (source);
+ titd->destination = g_object_ref (destination);
+ titd->do_copy = do_copy;
+ titd->icalcomp = icalcomp;
+ titd->selector = g_object_ref (selector);
+
+ icalcomp = NULL;
+
+ activity = e_shell_view_submit_thread_job (shell_view, message,
+ alert_ident, display_name, cal_base_shell_sidebar_transfer_thread,
+ titd, transfer_item_to_data_free);
+
+ g_clear_object (&activity);
+
+ exit:
+ if (icalcomp)
+ icalcomponent_free (icalcomp);
+
+ g_clear_object (&source);
+ g_free (message);
+ g_free (source_uid);
+ g_free (display_name);
+ g_strfreev (segments);
+
+ return TRUE;
+}
+
+static void
+cancel_and_unref (gpointer data)
+{
+ GCancellable *cancellable = data;
+
+ if (cancellable) {
+ g_cancellable_cancel (cancellable);
+ g_object_unref (cancellable);
+ }
+}
+
+static void
+cal_base_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_base_shell_sidebar_get_date_navigator (
+ E_CAL_BASE_SHELL_SIDEBAR (object)));
+ return;
+
+ case PROP_SELECTOR:
+ g_value_set_object (
+ value,
+ e_cal_base_shell_sidebar_get_selector (
+ E_CAL_BASE_SHELL_SIDEBAR (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_cal_base_shell_sidebar_update_calendar_margin_cb (GObject *object,
+ GParamSpec *pspec,
+ gpointer *user_data)
+{
+ EShellWindow *shell_window;
+ GtkWidget *calendar;
+ gboolean switcher_visible;
+
+ shell_window = E_SHELL_WINDOW (object);
+ calendar = GTK_WIDGET (user_data);
+ switcher_visible = e_shell_window_get_switcher_visible (shell_window);
+
+ if (switcher_visible)
+ gtk_widget_set_margin_bottom (calendar, 0);
+ else
+ gtk_widget_set_margin_bottom (calendar, 6);
+}
+
+static void
+cal_base_shell_sidebar_constructed (GObject *object)
+{
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ EShellBackend *shell_backend;
+ EShell *shell;
+ EClientCache *client_cache;
+ const gchar *source_extension = NULL, *selector_name = NULL, *restore_state_signal = NULL;
+ ECalBaseShellSidebar *cal_base_shell_sidebar;
+ GtkWidget *container, *widget;
+ AtkObject *a11y;
+ gboolean add_navigator = FALSE;
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_cal_base_shell_sidebar_parent_class)->constructed (object);
+
+ cal_base_shell_sidebar = E_CAL_BASE_SHELL_SIDEBAR (object);
+ shell_view = e_shell_sidebar_get_shell_view (E_SHELL_SIDEBAR (object));
+ 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);
+
+ switch (e_cal_base_shell_view_get_source_type (shell_view)) {
+ case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+ source_extension = E_SOURCE_EXTENSION_CALENDAR;
+ selector_name = _("Calendar Selector");
+ restore_state_signal = "shell-view-created::calendar";
+ add_navigator = TRUE;
+ break;
+ case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+ source_extension = E_SOURCE_EXTENSION_MEMO_LIST;
+ selector_name = _("Memo List Selector");
+ restore_state_signal = "shell-view-created::memos";
+ break;
+ case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+ source_extension = E_SOURCE_EXTENSION_TASK_LIST;
+ selector_name = _("Task List Selector");
+ restore_state_signal = "shell-view-created::tasks";
+ break;
+ case E_CAL_CLIENT_SOURCE_TYPE_LAST:
+ g_warn_if_reached ();
+ return;
+ }
+
+ client_cache = e_shell_get_client_cache (shell);
+
+ container = GTK_WIDGET (object);
+
+ widget = e_paned_new (GTK_ORIENTATION_VERTICAL);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ cal_base_shell_sidebar->priv->paned = widget;
+
+ container = widget;
+
+ widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+ gtk_paned_pack1 (GTK_PANED (container), widget, TRUE, TRUE);
+
+ 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_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+
+ container = widget;
+
+ widget = e_client_selector_new (client_cache, source_extension);
+ a11y = gtk_widget_get_accessible (widget);
+ atk_object_set_name (a11y, selector_name);
+ cal_base_shell_sidebar->priv->selector = E_SOURCE_SELECTOR (widget);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+
+ e_source_selector_load_groups_setup (cal_base_shell_sidebar->priv->selector,
+ e_shell_view_get_state_key_file (shell_view));
+
+ if (add_navigator) {
+ ECalendarItem *calitem;
+
+ container = cal_base_shell_sidebar->priv->paned;
+
+ widget = e_calendar_new ();
+ gtk_widget_set_margin_top (widget, 6);
+ gtk_widget_set_margin_start (widget, 6);
+ gtk_widget_set_margin_end (widget, 6);
+ calitem = e_calendar_get_item (E_CALENDAR (widget));
+ 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);
+ cal_base_shell_sidebar->priv->date_navigator = E_CALENDAR (widget);
+ gtk_widget_show (widget);
+
+ gnome_canvas_item_set (
+ GNOME_CANVAS_ITEM (e_calendar_get_item (cal_base_shell_sidebar->priv->date_navigator)),
+ "move-selection-when-moving", FALSE,
+ NULL);
+
+ cal_base_shell_sidebar->priv->date_navigator_scroll_event_handler_id = g_signal_connect_swapped (
+ cal_base_shell_sidebar->priv->date_navigator, "scroll-event",
+ G_CALLBACK (cal_base_shell_sidebar_date_navigator_scroll_event_cb), cal_base_shell_sidebar);
+ }
+
+ gtk_widget_show_all (GTK_WIDGET (object));
+
+ gtk_drag_dest_set (
+ GTK_WIDGET (cal_base_shell_sidebar->priv->selector), GTK_DEST_DEFAULT_ALL,
+ NULL, 0, GDK_ACTION_COPY | GDK_ACTION_MOVE);
+
+ e_drag_dest_add_calendar_targets (GTK_WIDGET (cal_base_shell_sidebar->priv->selector));
+
+ g_signal_connect (shell_window,
+ "notify::switcher-visible", G_CALLBACK (e_cal_base_shell_sidebar_update_calendar_margin_cb),
+ widget);
+
+ g_signal_connect (cal_base_shell_sidebar->priv->selector,
+ "data-dropped", G_CALLBACK (e_cal_base_shell_sidebar_selector_data_dropped),
+ cal_base_shell_sidebar);
+
+ g_signal_connect (cal_base_shell_sidebar->priv->selector,
+ "primary-selection-changed", G_CALLBACK (e_cal_base_shell_sidebar_primary_selection_changed_cb),
+ cal_base_shell_sidebar);
+
+ g_signal_connect (cal_base_shell_sidebar->priv->selector,
+ "source-selected", G_CALLBACK (e_cal_base_shell_sidebar_source_selected),
+ cal_base_shell_sidebar);
+
+ g_signal_connect (cal_base_shell_sidebar->priv->selector,
+ "source-unselected", G_CALLBACK (e_cal_base_shell_sidebar_source_unselected),
+ cal_base_shell_sidebar);
+
+ /* Restore widget state from the last session once
+ * the shell view is fully initialized and visible. */
+ g_signal_connect (
+ shell_window, restore_state_signal,
+ G_CALLBACK (cal_base_shell_sidebar_restore_state_cb),
+ cal_base_shell_sidebar);
+}
+
+static void
+cal_base_shell_sidebar_dispose (GObject *object)
+{
+ ECalBaseShellSidebar *cal_base_shell_sidebar;
+
+ cal_base_shell_sidebar = E_CAL_BASE_SHELL_SIDEBAR (object);
+
+ if (cal_base_shell_sidebar->priv->date_navigator_scroll_event_handler_id > 0 &&
+ cal_base_shell_sidebar->priv->date_navigator) {
+ g_signal_handler_disconnect (cal_base_shell_sidebar->priv->date_navigator,
+ cal_base_shell_sidebar->priv->date_navigator_scroll_event_handler_id);
+ cal_base_shell_sidebar->priv->date_navigator_scroll_event_handler_id = 0;
+ }
+
+ cal_base_shell_sidebar->priv->date_navigator = NULL;
+ cal_base_shell_sidebar->priv->selector = NULL;
+ cal_base_shell_sidebar->priv->paned = NULL;
+
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (e_cal_base_shell_sidebar_parent_class)->dispose (object);
+}
+
+static void
+cal_base_shell_sidebar_finalize (GObject *object)
+{
+ ECalBaseShellSidebar *cal_base_shell_sidebar;
+
+ cal_base_shell_sidebar = E_CAL_BASE_SHELL_SIDEBAR (object);
+
+ g_hash_table_destroy (cal_base_shell_sidebar->priv->selected_uids);
+ cal_base_shell_sidebar->priv->selected_uids = NULL;
+
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (e_cal_base_shell_sidebar_parent_class)->finalize (object);
+}
+
+static void
+e_cal_base_shell_sidebar_class_init (ECalBaseShellSidebarClass *class)
+{
+ GObjectClass *object_class;
+ EShellSidebarClass *shell_sidebar_class;
+
+ g_type_class_add_private (class, sizeof (ECalBaseShellSidebarPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->get_property = cal_base_shell_sidebar_get_property;
+ object_class->constructed = cal_base_shell_sidebar_constructed;
+ object_class->dispose = cal_base_shell_sidebar_dispose;
+ object_class->finalize = cal_base_shell_sidebar_finalize;
+
+ shell_sidebar_class = E_SHELL_SIDEBAR_CLASS (class);
+ shell_sidebar_class->check_state = cal_base_shell_sidebar_check_state;
+
+ 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));
+
+ 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));
+
+ signals[CLIENT_OPENED] = g_signal_new (
+ "client-opened",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ECalBaseShellSidebarClass, client_opened),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ E_TYPE_CAL_CLIENT);
+
+ signals[CLIENT_CLOSED] = g_signal_new (
+ "client-closed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ECalBaseShellSidebarClass, client_closed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ E_TYPE_SOURCE);
+}
+
+static void
+e_cal_base_shell_sidebar_class_finalize (ECalBaseShellSidebarClass *class)
+{
+}
+
+static void
+e_cal_base_shell_sidebar_init (ECalBaseShellSidebar *cal_base_shell_sidebar)
+{
+ cal_base_shell_sidebar->priv = E_CAL_BASE_SHELL_SIDEBAR_GET_PRIVATE (cal_base_shell_sidebar);
+ cal_base_shell_sidebar->priv->selected_uids =
+ g_hash_table_new_full (g_str_hash, g_str_equal, g_free, cancel_and_unref);
+}
+
+void
+e_cal_base_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_base_shell_sidebar_register_type (type_module);
+}
+
+GtkWidget *
+e_cal_base_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_BASE_SHELL_SIDEBAR,
+ "shell-view", shell_view, NULL);
+}
+
+ECalendar *
+e_cal_base_shell_sidebar_get_date_navigator (ECalBaseShellSidebar *cal_base_shell_sidebar)
+{
+ g_return_val_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (cal_base_shell_sidebar), NULL);
+
+ return cal_base_shell_sidebar->priv->date_navigator;
+}
+
+ESourceSelector *
+e_cal_base_shell_sidebar_get_selector (ECalBaseShellSidebar *cal_base_shell_sidebar)
+{
+ g_return_val_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (cal_base_shell_sidebar), NULL);
+
+ return cal_base_shell_sidebar->priv->selector;
+}
+
+void
+e_cal_base_shell_sidebar_ensure_sources_open (ECalBaseShellSidebar *cal_base_shell_sidebar)
+{
+ GList *selected, *link;
+ ESourceSelector *selector;
+
+ g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (cal_base_shell_sidebar));
+
+ selector = cal_base_shell_sidebar->priv->selector;
+ g_return_if_fail (E_IS_SOURCE_SELECTOR (selector));
+
+ selected = e_source_selector_get_selection (selector);
+ for (link = selected; link; link = g_list_next (link)) {
+ ESource *source = link->data;
+
+ e_cal_base_shell_sidebar_ensure_source_opened (cal_base_shell_sidebar, source);
+ }
+
+ g_list_free_full (selected, g_object_unref);
+}