From 3d4ae9b06558e060ac54da959c19af2b3a4ba352 Mon Sep 17 00:00:00 2001 From: Packit Date: Sep 25 2020 09:30:56 +0000 Subject: Apply patch evolution-3.28.5-deselect-task-memo-list.patch patch_name: evolution-3.28.5-deselect-task-memo-list.patch present_in_specfile: true --- 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); +}