aboutsummaryrefslogtreecommitdiffstats
path: root/calendar/modules/e-cal-shell-sidebar.c
diff options
context:
space:
mode:
authorMatthew Barnes <mbarnes@src.gnome.org>2008-10-07 01:41:31 +0800
committerMatthew Barnes <mbarnes@src.gnome.org>2008-10-07 01:41:31 +0800
commit1bed00795bf092ad6e9e076eccf7cc2a8c20cb27 (patch)
tree1479219994e81557af0c8041fa170f95064e541f /calendar/modules/e-cal-shell-sidebar.c
parent3c9c7a2ac1864cd7cf3b72737e0577612e672b01 (diff)
downloadgsoc2013-evolution-1bed00795bf092ad6e9e076eccf7cc2a8c20cb27.tar
gsoc2013-evolution-1bed00795bf092ad6e9e076eccf7cc2a8c20cb27.tar.gz
gsoc2013-evolution-1bed00795bf092ad6e9e076eccf7cc2a8c20cb27.tar.bz2
gsoc2013-evolution-1bed00795bf092ad6e9e076eccf7cc2a8c20cb27.tar.lz
gsoc2013-evolution-1bed00795bf092ad6e9e076eccf7cc2a8c20cb27.tar.xz
gsoc2013-evolution-1bed00795bf092ad6e9e076eccf7cc2a8c20cb27.tar.zst
gsoc2013-evolution-1bed00795bf092ad6e9e076eccf7cc2a8c20cb27.zip
Baseline cut at the Calendar sidebar and module. Pretty much identical
to Tasks and Memos so far. Now for the interesting part... svn path=/branches/kill-bonobo/; revision=36573
Diffstat (limited to 'calendar/modules/e-cal-shell-sidebar.c')
-rw-r--r--calendar/modules/e-cal-shell-sidebar.c483
1 files changed, 476 insertions, 7 deletions
diff --git a/calendar/modules/e-cal-shell-sidebar.c b/calendar/modules/e-cal-shell-sidebar.c
index b60d1660d1..bbe0c15caf 100644
--- a/calendar/modules/e-cal-shell-sidebar.c
+++ b/calendar/modules/e-cal-shell-sidebar.c
@@ -24,9 +24,11 @@
#include <string.h>
#include <glib/gi18n.h>
-#include "e-util/e-util.h"
-#include "calendar/gui/gnome-cal.h"
+#include "e-util/e-error.h"
+#include "calendar/common/authentication.h"
+#include "calendar/gui/calendar-config.h"
#include "calendar/gui/e-calendar-selector.h"
+#include "calendar/gui/misc.h"
#include "e-cal-shell-view.h"
@@ -36,6 +38,9 @@
struct _ECalShellSidebarPrivate {
GtkWidget *selector;
+
+ /* UID -> Client */
+ GHashTable *client_table;
};
enum {
@@ -43,13 +48,261 @@ enum {
PROP_SELECTOR
};
+enum {
+ CLIENT_ADDED,
+ CLIENT_REMOVED,
+ STATUS_MESSAGE,
+ LAST_SIGNAL
+};
+
static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
+
+static void
+cal_shell_sidebar_emit_client_added (ECalShellSidebar *cal_shell_sidebar,
+ ECal *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,
+ ECal *client)
+{
+ guint signal_id = signals[CLIENT_REMOVED];
+
+ g_signal_emit (cal_shell_sidebar, signal_id, 0, client);
+}
+
+static void
+cal_shell_sidebar_emit_status_message (ECalShellSidebar *cal_shell_sidebar,
+ const gchar *status_message)
+{
+ guint signal_id = signals[STATUS_MESSAGE];
+
+ g_signal_emit (cal_shell_sidebar, signal_id, 0, status_message);
+}
+
+static void
+cal_shell_sidebar_update_timezone (ECalShellSidebar *cal_shell_sidebar)
+{
+ GHashTable *client_table;
+ icaltimezone *zone;
+ GList *values;
+
+ zone = calendar_config_get_icaltimezone ();
+ client_table = cal_shell_sidebar->priv->client_table;
+ values = g_hash_table_get_values (client_table);
+
+ while (values != NULL) {
+ ECal *client = values->data;
+
+ if (e_cal_get_load_state (client) == E_CAL_LOAD_LOADED)
+ e_cal_set_default_timezone (client, zone, NULL);
+
+ values = g_list_delete_link (values, values);
+ }
+
+ /* XXX Need to call e_calendar_view_set_timezone() here but the
+ * sidebar is not really supposed to access content stuff.
+ * I guess we could emit an "update-timezone" signal here,
+ * but that feels wrong. Maybe this whole thing should be
+ * in ECalShellView instead. */
+}
+
+static void
+cal_shell_sidebar_backend_died_cb (ECalShellSidebar *cal_shell_sidebar,
+ ECal *client)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellSidebar *shell_sidebar;
+ GHashTable *client_table;
+ ESource *source;
+ const gchar *uid;
+
+ client_table = cal_shell_sidebar->priv->client_table;
+
+ shell_sidebar = E_SHELL_SIDEBAR (cal_shell_sidebar);
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ source = e_cal_get_source (client);
+ uid = e_source_peek_uid (source);
+
+ g_object_ref (source);
+
+ g_hash_table_remove (client_table, uid);
+ cal_shell_sidebar_emit_status_message (cal_shell_sidebar, NULL);
+
+ e_error_run (
+ GTK_WINDOW (shell_window),
+ "calendar:calendar-crashed", NULL);
+
+ g_object_unref (source);
+}
+
+static void
+cal_shell_sidebar_backend_error_cb (ECalShellSidebar *cal_shell_sidebar,
+ const gchar *message,
+ ECal *client)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellSidebar *shell_sidebar;
+ GtkWidget *dialog;
+ const gchar *uri;
+ gchar *uri_no_passwd;
+
+ shell_sidebar = E_SHELL_SIDEBAR (cal_shell_sidebar);
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ uri = e_cal_get_uri (client);
+ uri_no_passwd = get_uri_without_password (uri);
+
+ dialog = gtk_message_dialog_new (
+ GTK_WINDOW (shell_window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
+ _("Error on %s\n%s"),
+ uri_no_passwd, message);
+
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+
+ g_free (uri_no_passwd);
+}
+
+static void
+cal_shell_sidebar_client_opened_cb (ECalShellSidebar *cal_shell_sidebar,
+ ECalendarStatus status,
+ ECal *client)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellSidebar *shell_sidebar;
+ ESource *source;
+
+ source = e_cal_get_source (client);
+
+ shell_sidebar = E_SHELL_SIDEBAR (cal_shell_sidebar);
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ switch (status) {
+ case E_CALENDAR_STATUS_OK:
+ g_signal_handlers_disconnect_matched (
+ client, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
+ cal_shell_sidebar_client_opened_cb, NULL);
+
+ cal_shell_sidebar_emit_status_message (
+ cal_shell_sidebar, _("Loading calendars"));
+ cal_shell_sidebar_emit_client_added (
+ cal_shell_sidebar, client);
+ cal_shell_sidebar_emit_status_message (
+ cal_shell_sidebar, NULL);
+ break;
+
+ case E_CALENDAR_STATUS_BUSY:
+ break;
+
+ case E_CALENDAR_STATUS_REPOSITORY_OFFLINE:
+ e_error_run (
+ GTK_WINDOW (shell_window),
+ "calendar:prompt-no-contents-offline-calendar",
+ NULL);
+ break;
+
+ default:
+ cal_shell_sidebar_emit_client_removed (
+ cal_shell_sidebar, client);
+ break;
+ }
+}
+
+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;
+
+ /* XXX ESourceSelector's underlying tree store has only one
+ * column: ESource objects. While we're not supposed to
+ * know this, listening for "row-changed" signals from
+ * the model is easier to deal with than the selector's
+ * "selection-changed" signal, which doesn't tell you
+ * _which_ row changed. */
+
+ selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+ gtk_tree_model_get (tree_model, tree_iter, 0, &source, -1);
+
+ /* 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 (!E_IS_SOURCE (source))
+ 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);
+}
+
+static void
+cal_shell_sidebar_selection_changed_cb (ECalShellSidebar *cal_shell_sidebar,
+ ESourceSelector *selector)
+{
+ GSList *list, *iter;
+
+ /* This signal is emitted less frequently than "row-changed",
+ * especially when the model is being rebuilt. So we'll take
+ * it easy on poor GConf. */
+
+ list = e_source_selector_get_selection (selector);
+
+ for (iter = list; iter != NULL; iter = iter->next) {
+ ESource *source = iter->data;
+
+ iter->data = (gpointer) e_source_peek_uid (source);
+ g_object_unref (source);
+ }
+
+ calendar_config_set_calendars_selected (list);
+
+ g_slist_free (list);
+}
+
+static void
+cal_shell_sidebar_primary_selection_changed_cb (ECalShellSidebar *cal_shell_sidebar,
+ ESourceSelector *selector)
+{
+ ESource *source;
+ const gchar *uid;
+
+ /* XXX ESourceSelector needs a "primary-selection-uid" property
+ * so we can just bind the property with GConfBridge. */
+
+ source = e_source_selector_peek_primary_selection (selector);
+ if (source == NULL)
+ return;
+
+ uid = e_source_peek_uid (source);
+ calendar_config_set_primary_calendar (uid);
+}
static void
cal_shell_sidebar_get_property (GObject *object,
- guint property_id,
- GValue *value,
- GParamSpec *pspec)
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
{
switch (property_id) {
case PROP_SELECTOR:
@@ -74,20 +327,40 @@ cal_shell_sidebar_dispose (GObject *object)
priv->selector = NULL;
}
+ g_hash_table_remove_all (priv->client_table);
+
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
+cal_shell_sidebar_finalize (GObject *object)
+{
+ ECalShellSidebarPrivate *priv;
+
+ priv = E_CAL_SHELL_SIDEBAR_GET_PRIVATE (object);
+
+ g_hash_table_destroy (priv->client_table);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
cal_shell_sidebar_constructed (GObject *object)
{
ECalShellSidebarPrivate *priv;
EShellView *shell_view;
EShellSidebar *shell_sidebar;
ECalShellView *cal_shell_view;
+ ESourceSelector *selector;
ESourceList *source_list;
+ ESource *source;
GtkContainer *container;
+ GtkTreeModel *model;
GtkWidget *widget;
+ GSList *list, *iter;
+ gchar *uid;
priv = E_CAL_SHELL_SIDEBAR_GET_PRIVATE (object);
@@ -117,6 +390,83 @@ cal_shell_sidebar_constructed (GObject *object)
gtk_container_add (container, widget);
priv->selector = g_object_ref (widget);
gtk_widget_show (widget);
+
+ /* Restore the selector state from the last session. */
+
+ selector = E_SOURCE_SELECTOR (priv->selector);
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
+
+ g_signal_connect_swapped (
+ model, "row-changed",
+ G_CALLBACK (cal_shell_sidebar_row_changed_cb),
+ object);
+
+ source = NULL;
+ uid = calendar_config_get_primary_calendar ();
+ if (uid != NULL)
+ source = e_source_list_peek_source_by_uid (source_list, uid);
+ if (source == NULL)
+ source = e_source_list_peek_source_any (source_list);
+ if (source != NULL)
+ e_source_selector_set_primary_selection (selector, source);
+ g_free (uid);
+
+ list = calendar_config_get_tasks_selected ();
+ for (iter = list; iter != NULL; iter = iter->next) {
+ uid = iter->data;
+ source = e_source_list_peek_source_by_uid (source_list, uid);
+ g_free (uid);
+
+ if (source == NULL)
+ continue;
+
+ e_source_selector_select_source (selector, source);
+ }
+ g_slist_free (list);
+
+ /* Listen for subsequent changes to the selector. */
+
+ g_signal_connect_swapped (
+ widget, "selection-changed",
+ G_CALLBACK (cal_shell_sidebar_selection_changed_cb),
+ object);
+
+ g_signal_connect_swapped (
+ widget, "primary-selection-changed",
+ G_CALLBACK (cal_shell_sidebar_primary_selection_changed_cb),
+ object);
+}
+
+static void
+cal_shell_sidebar_client_added (ECalShellSidebar *cal_shell_sidebar,
+ ECal *client)
+{
+ cal_shell_sidebar_update_timezone (cal_shell_sidebar);
+}
+
+static void
+cal_shell_sidebar_client_removed (ECalShellSidebar *cal_shell_sidebar,
+ ECal *client)
+{
+ ESourceSelector *selector;
+ GHashTable *client_table;
+ ESource *source;
+ const gchar *uid;
+
+ client_table = cal_shell_sidebar->priv->client_table;
+ selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+
+ g_signal_handlers_disconnect_matched (
+ client, G_SIGNAL_MATCH_DATA, 0, 0,
+ NULL, NULL, cal_shell_sidebar);
+
+ source = e_cal_get_source (client);
+ e_source_selector_unselect_source (selector, source);
+
+ uid = e_source_peek_uid (source);
+ g_hash_table_remove (client_table, uid);
+
+ cal_shell_sidebar_emit_status_message (cal_shell_sidebar, NULL);
}
static void
@@ -130,8 +480,12 @@ cal_shell_sidebar_class_init (ECalShellSidebarClass *class)
object_class = G_OBJECT_CLASS (class);
object_class->get_property = cal_shell_sidebar_get_property;
object_class->dispose = cal_shell_sidebar_dispose;
+ object_class->finalize = cal_shell_sidebar_finalize;
object_class->constructed = cal_shell_sidebar_constructed;
+ class->client_added = cal_shell_sidebar_client_added;
+ class->client_removed = cal_shell_sidebar_client_removed;
+
g_object_class_install_property (
object_class,
PROP_SELECTOR,
@@ -141,14 +495,53 @@ cal_shell_sidebar_class_init (ECalShellSidebarClass *class)
_("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);
+
+ 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);
+
+ signals[STATUS_MESSAGE] = g_signal_new (
+ "status-message",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (ECalShellSidebarClass, status_message),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1,
+ G_TYPE_STRING);
}
static void
cal_shell_sidebar_init (ECalShellSidebar *cal_shell_sidebar)
{
+ GHashTable *client_table;
+
+ client_table = g_hash_table_new_full (
+ g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_object_unref);
+
cal_shell_sidebar->priv =
E_CAL_SHELL_SIDEBAR_GET_PRIVATE (cal_shell_sidebar);
+ cal_shell_sidebar->priv->client_table = client_table;
+
/* Postpone widget construction until we have a shell view. */
}
@@ -189,11 +582,87 @@ e_cal_shell_sidebar_new (EShellView *shell_view)
"shell-view", shell_view, NULL);
}
-GtkWidget *
+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 cal_shell_sidebar->priv->selector;
+ return E_SOURCE_SELECTOR (cal_shell_sidebar->priv->selector);
+}
+
+void
+e_cal_shell_sidebar_add_source (ECalShellSidebar *cal_shell_sidebar,
+ ESource *source)
+{
+ ESourceSelector *selector;
+ GHashTable *client_table;
+ ECal *client;
+ const gchar *uid;
+ const gchar *uri;
+ gchar *message;
+
+ g_return_if_fail (E_IS_CAL_SHELL_SIDEBAR (cal_shell_sidebar));
+ g_return_if_fail (E_IS_SOURCE (source));
+
+ client_table = cal_shell_sidebar->priv->client_table;
+ selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+
+ uid = e_source_peek_uid (source);
+ client = g_hash_table_lookup (client_table, uid);
+
+ if (client != NULL)
+ return;
+
+ client = auth_new_cal_from_source (source, E_CAL_SOURCE_TYPE_EVENT);
+ g_return_if_fail (client != NULL);
+
+ g_signal_connect_swapped (
+ client, "backend-died",
+ G_CALLBACK (cal_shell_sidebar_backend_died_cb),
+ cal_shell_sidebar);
+
+ g_signal_connect_swapped (
+ client, "backend-error",
+ G_CALLBACK (cal_shell_sidebar_backend_error_cb),
+ cal_shell_sidebar);
+
+ g_hash_table_insert (client_table, g_strdup (uid), client);
+ e_source_selector_select_source (selector, source);
+
+ uri = e_cal_get_uri (client);
+ message = g_strdup_printf (_("Opening calendar at %s"), uri);
+ cal_shell_sidebar_emit_status_message (cal_shell_sidebar, message);
+ g_free (message);
+
+ g_signal_connect_swapped (
+ client, "cal-opened",
+ G_CALLBACK (cal_shell_sidebar_client_opened_cb),
+ cal_shell_sidebar);
+
+ e_cal_open_async (client, FALSE);
+}
+
+void
+e_cal_shell_sidebar_remove_source (ECalShellSidebar *cal_shell_sidebar,
+ ESource *source)
+{
+ ESourceSelector *selector;
+ GHashTable *client_table;
+ ECal *client;
+ const gchar *uid;
+
+ g_return_if_fail (E_IS_CAL_SHELL_SIDEBAR (cal_shell_sidebar));
+ g_return_if_fail (E_IS_SOURCE (source));
+
+ client_table = cal_shell_sidebar->priv->client_table;
+ selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+
+ uid = e_source_peek_uid (source);
+ client = g_hash_table_lookup (client_table, uid);
+
+ if (client == NULL)
+ return;
+
+ cal_shell_sidebar_emit_client_removed (cal_shell_sidebar, client);
}