[evolution] Improve sidebar and ECalModel interaction.



commit ab794abcd3fa23969a1f8b04d0236838f721180a
Author: Matthew Barnes <mbarnes redhat com>
Date:   Fri Jan 29 14:02:53 2010 -0500

    Improve sidebar and ECalModel interaction.
    
    Restores the "default client" behavior from 2.28, so that "Click to Add"
    task and memo fields work properly.

 calendar/gui/e-cal-model.c                   |   48 ++++--
 modules/calendar/e-cal-shell-sidebar.c       |  251 ++++++++++++++++++++++----
 modules/calendar/e-cal-shell-sidebar.h       |    2 +
 modules/calendar/e-cal-shell-view-private.c  |    5 +
 modules/calendar/e-memo-shell-sidebar.c      |  250 +++++++++++++++++++++----
 modules/calendar/e-memo-shell-sidebar.h      |    2 +
 modules/calendar/e-memo-shell-view-private.c |    7 +-
 modules/calendar/e-task-shell-sidebar.c      |  250 ++++++++++++++++++++++----
 modules/calendar/e-task-shell-sidebar.h      |    2 +
 modules/calendar/e-task-shell-view-private.c |    8 +-
 10 files changed, 693 insertions(+), 132 deletions(-)
---
diff --git a/calendar/gui/e-cal-model.c b/calendar/gui/e-cal-model.c
index 58ca63e..7533e56 100644
--- a/calendar/gui/e-cal-model.c
+++ b/calendar/gui/e-cal-model.c
@@ -127,6 +127,7 @@ static void remove_client (ECalModel *model, ECalModelClient *client_data);
 
 enum {
 	PROP_0,
+	PROP_DEFAULT_CLIENT,
 	PROP_SHELL_SETTINGS,
 	PROP_TIMEZONE,
 	PROP_USE_24_HOUR_FORMAT,
@@ -165,6 +166,12 @@ cal_model_set_property (GObject *object,
                         GParamSpec *pspec)
 {
 	switch (property_id) {
+		case PROP_DEFAULT_CLIENT:
+			e_cal_model_set_default_client (
+				E_CAL_MODEL (object),
+				g_value_get_object (value));
+			return;
+
 		case PROP_SHELL_SETTINGS:
 			cal_model_set_shell_settings (
 				E_CAL_MODEL (object),
@@ -200,6 +207,13 @@ cal_model_get_property (GObject *object,
                         GParamSpec *pspec)
 {
 	switch (property_id) {
+		case PROP_DEFAULT_CLIENT:
+			g_value_set_object (
+				value,
+				e_cal_model_get_default_client (
+				E_CAL_MODEL (object)));
+			return;
+
 		case PROP_SHELL_SETTINGS:
 			g_value_set_object (
 				value,
@@ -357,6 +371,16 @@ e_cal_model_class_init (ECalModelClass *class)
 
 	g_object_class_install_property (
 		object_class,
+		PROP_DEFAULT_CLIENT,
+		g_param_spec_object (
+			"default-client",
+			_("Default Client"),
+			NULL,
+			E_TYPE_CAL,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
 		PROP_SHELL_SETTINGS,
 		g_param_spec_object (
 			"shell-settings",
@@ -1516,10 +1540,10 @@ e_cal_model_set_default_client (ECalModel *model, ECal *client)
 	ECalModelPrivate *priv;
 	ECalModelClient *client_data;
 
-	g_return_if_fail (model != NULL);
 	g_return_if_fail (E_IS_CAL_MODEL (model));
-	g_return_if_fail (client != NULL);
-	g_return_if_fail (E_IS_CAL (client));
+
+	if (client != NULL)
+		g_return_if_fail (E_IS_CAL (client));
 
 	priv = model->priv;
 
@@ -1533,11 +1557,16 @@ e_cal_model_set_default_client (ECalModel *model, ECal *client)
 		}
 	}
 
-	/* Make sure its in the model */
-	client_data = add_new_client (model, client, FALSE);
+	if (client != NULL) {
+		/* Make sure its in the model */
+		client_data = add_new_client (model, client, FALSE);
 
-	/* Store the default client */
-	priv->default_client = client_data->client;
+		/* Store the default client */
+		priv->default_client = client_data->client;
+	} else
+		priv->default_client = NULL;
+
+	g_object_notify (G_OBJECT (model), "default-client");
 }
 
 GList *
@@ -2147,11 +2176,6 @@ add_new_client (ECalModel *model, ECal *client, gboolean do_query)
 	/* Look to see if we already have this client */
 	client_data = find_client_data (model, client);
 	if (client_data) {
-		if (do_query && client_data->client == priv->default_client) {
-			g_warning ("%s: %s: You shouldn't request a query on a default client", G_STRLOC, G_STRFUNC);
-			return client_data;
-		}
-
 		if (client_data->do_query)
 			return client_data;
 		else
diff --git a/modules/calendar/e-cal-shell-sidebar.c b/modules/calendar/e-cal-shell-sidebar.c
index 390be5e..3b78afa 100644
--- a/modules/calendar/e-cal-shell-sidebar.c
+++ b/modules/calendar/e-cal-shell-sidebar.c
@@ -34,8 +34,8 @@
 #include "calendar/gui/e-calendar-selector.h"
 #include "calendar/gui/misc.h"
 
-#include "e-cal-shell-backend.h"
 #include "e-cal-shell-view.h"
+#include "e-cal-shell-backend.h"
 
 #define E_CAL_SHELL_SIDEBAR_GET_PRIVATE(obj) \
 	(G_TYPE_INSTANCE_GET_PRIVATE \
@@ -48,11 +48,21 @@ struct _ECalShellSidebarPrivate {
 
 	/* UID -> Client */
 	GHashTable *client_table;
+
+	/* 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. */
+	ECal *default_client;
 };
 
 enum {
 	PROP_0,
 	PROP_DATE_NAVIGATOR,
+	PROP_DEFAULT_CLIENT,
 	PROP_SELECTOR
 };
 
@@ -166,6 +176,7 @@ cal_shell_sidebar_client_opened_cb (ECalShellSidebar *cal_shell_sidebar,
 	EShellView *shell_view;
 	EShellWindow *shell_window;
 	EShellSidebar *shell_sidebar;
+	const gchar *message;
 
 	shell_sidebar = E_SHELL_SIDEBAR (cal_shell_sidebar);
 	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
@@ -175,39 +186,121 @@ cal_shell_sidebar_client_opened_cb (ECalShellSidebar *cal_shell_sidebar,
 		status == E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED)
 		e_auth_cal_forget_password (client);
 
+	/* Handle errors. */
 	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_AUTHENTICATION_FAILED:
 			e_cal_open_async (client, FALSE);
-			break;
+			return;
 
 		case E_CALENDAR_STATUS_BUSY:
-			break;
+			return;
 
 		case E_CALENDAR_STATUS_REPOSITORY_OFFLINE:
 			e_alert_run_dialog_for_args (
 				GTK_WINDOW (shell_window),
 				"calendar:prompt-no-contents-offline-calendar",
 				NULL);
-			break;
+			/* fall through */
 
 		default:
-			cal_shell_sidebar_emit_client_removed (
-				cal_shell_sidebar, client);
+			e_cal_shell_sidebar_remove_source (
+				cal_shell_sidebar,
+				e_cal_get_source (client));
+			return;
+	}
+
+	g_assert (status == E_CALENDAR_STATUS_OK);
+
+	g_signal_handlers_disconnect_matched (
+		client, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
+		cal_shell_sidebar_client_opened_cb, NULL);
+
+	message = _("Loading calendars");
+	cal_shell_sidebar_emit_status_message (cal_shell_sidebar, message);
+	cal_shell_sidebar_emit_client_added (cal_shell_sidebar, client);
+	cal_shell_sidebar_emit_status_message (cal_shell_sidebar, NULL);
+}
+
+static void
+cal_shell_sidebar_default_opened_cb (ECalShellSidebar *cal_shell_sidebar,
+                                     ECalendarStatus status,
+                                     ECal *client)
+{
+	EShellView *shell_view;
+	EShellWindow *shell_window;
+	EShellSidebar *shell_sidebar;
+
+	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);
+
+	if (status == E_CALENDAR_STATUS_AUTHENTICATION_FAILED ||
+		status == E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED)
+		e_auth_cal_forget_password (client);
+
+	/* Handle errors. */
+	switch (status) {
+		case E_CALENDAR_STATUS_OK:
 			break;
+
+		case E_CALENDAR_STATUS_AUTHENTICATION_FAILED:
+			e_cal_open_async (client, FALSE);
+			return;
+
+		case E_CALENDAR_STATUS_BUSY:
+			return;
+
+		default:
+			e_cal_shell_sidebar_remove_source (
+				cal_shell_sidebar,
+				e_cal_get_source (client));
+			return;
 	}
+
+	g_assert (status == E_CALENDAR_STATUS_OK);
+
+	g_signal_handlers_disconnect_matched (
+		client, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
+		cal_shell_sidebar_default_opened_cb, NULL);
+
+	g_object_notify (G_OBJECT (cal_shell_sidebar), "default-client");
+}
+
+static void
+cal_shell_sidebar_set_default (ECalShellSidebar *cal_shell_sidebar,
+                               ESource *source)
+{
+	ECalSourceType source_type;
+	GHashTable *client_table;
+	ECal *client;
+	const gchar *uid;
+
+	source_type = E_CAL_SOURCE_TYPE_EVENT;
+	client_table = cal_shell_sidebar->priv->client_table;
+
+	uid = e_source_peek_uid (source);
+	client = g_hash_table_lookup (client_table, uid);
+
+	if (cal_shell_sidebar->priv->default_client != NULL)
+		g_object_unref (cal_shell_sidebar->priv->default_client);
+
+	if (client != NULL)
+		g_object_ref (client);
+	else
+		client = e_auth_new_cal_from_source (source, source_type);
+
+	cal_shell_sidebar->priv->default_client = client;
+	g_return_if_fail (client != NULL);
+
+	g_signal_connect_swapped (
+		client, "cal-opened",
+		G_CALLBACK (cal_shell_sidebar_default_opened_cb),
+		cal_shell_sidebar);
+
+	e_cal_open_async (client, FALSE);
 }
 
 static void
@@ -295,6 +388,8 @@ cal_shell_sidebar_primary_selection_changed_cb (ECalShellSidebar *cal_shell_side
 	e_shell_settings_set_string (
 		shell_settings, "cal-primary-calendar",
 		e_source_peek_uid (source));
+
+	cal_shell_sidebar_set_default (cal_shell_sidebar, source);
 }
 
 static void
@@ -306,13 +401,22 @@ cal_shell_sidebar_get_property (GObject *object,
 	switch (property_id) {
 		case PROP_DATE_NAVIGATOR:
 			g_value_set_object (
-				value, e_cal_shell_sidebar_get_date_navigator (
+				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 (
+				value,
+				e_cal_shell_sidebar_get_selector (
 				E_CAL_SHELL_SIDEBAR (object)));
 			return;
 	}
@@ -342,6 +446,11 @@ cal_shell_sidebar_dispose (GObject *object)
 		priv->date_navigator = NULL;
 	}
 
+	if (priv->default_client != NULL) {
+		g_object_unref (priv->default_client);
+		priv->default_client = NULL;
+	}
+
 	g_hash_table_remove_all (priv->client_table);
 
 	/* Chain up to parent's dispose() method. */
@@ -370,18 +479,11 @@ cal_shell_sidebar_constructed (GObject *object)
 	EShellBackend *shell_backend;
 	EShellSidebar *shell_sidebar;
 	EShellSettings *shell_settings;
-	ESourceSelector *selector;
 	ESourceList *source_list;
-	ESource *source;
 	ECalendarItem *calitem;
-	GConfBridge *bridge;
-	GtkTreeModel *model;
 	GtkWidget *container;
 	GtkWidget *widget;
 	AtkObject *a11y;
-	GSList *list, *iter;
-	const gchar *key;
-	gchar *uid;
 
 	priv = E_CAL_SHELL_SIDEBAR_GET_PRIVATE (object);
 
@@ -443,16 +545,55 @@ cal_shell_sidebar_constructed (GObject *object)
 	e_binding_new (
 		shell_settings, "cal-week-start-day",
 		calitem, "week-start-day");
+}
 
-	/* Restore the selector state from the last session. */
+static void
+cal_shell_sidebar_realize (GtkWidget *widget)
+{
+	ECalShellSidebarPrivate *priv;
+	EShell *shell;
+	EShellView *shell_view;
+	EShellBackend *shell_backend;
+	EShellSidebar *shell_sidebar;
+	EShellSettings *shell_settings;
+	ESourceSelector *selector;
+	ESourceList *source_list;
+	ESource *source;
+	GConfBridge *bridge;
+	GtkTreeModel *model;
+	GSList *list, *iter;
+	GObject *object;
+	const gchar *key;
+	gchar *uid;
+
+	priv = E_CAL_SHELL_SIDEBAR_GET_PRIVATE (widget);
+
+	/* Restore the selector state from the last session.  We do this
+	 * in realize() instead of constructed() so the shell view has a
+	 * chance to connect handlers to our signals. */
+
+	shell_sidebar = E_SHELL_SIDEBAR (widget);
+	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+	shell_backend = e_shell_view_get_shell_backend (shell_view);
+
+	shell = e_shell_backend_get_shell (shell_backend);
+	shell_settings = e_shell_get_shell_settings (shell);
 
 	selector = E_SOURCE_SELECTOR (priv->selector);
 	model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector));
 
+	source_list = e_cal_shell_backend_get_source_list (
+		E_CAL_SHELL_BACKEND (shell_backend));
+
 	g_signal_connect_swapped (
 		model, "row-changed",
 		G_CALLBACK (cal_shell_sidebar_row_changed_cb),
-		object);
+		shell_sidebar);
+
+	g_signal_connect_swapped (
+		selector, "primary-selection-changed",
+		G_CALLBACK (cal_shell_sidebar_primary_selection_changed_cb),
+		shell_sidebar);
 
 	source = NULL;
 	uid = e_shell_settings_get_string (
@@ -483,12 +624,7 @@ cal_shell_sidebar_constructed (GObject *object)
 	g_signal_connect_swapped (
 		selector, "selection-changed",
 		G_CALLBACK (cal_shell_sidebar_selection_changed_cb),
-		object);
-
-	g_signal_connect_swapped (
-		selector, "primary-selection-changed",
-		G_CALLBACK (cal_shell_sidebar_primary_selection_changed_cb),
-		object);
+		shell_sidebar);
 
 	/* Bind GObject properties to GConf keys. */
 
@@ -497,6 +633,9 @@ cal_shell_sidebar_constructed (GObject *object)
 	object = G_OBJECT (priv->paned);
 	key = "/apps/evolution/calendar/display/date_navigator_vpane_position";
 	gconf_bridge_bind_property_delayed (bridge, key, object, "vposition");
+
+	/* Chain up to parent's realize() method. */
+	GTK_WIDGET_CLASS (parent_class)->realize (widget);
 }
 
 static guint32
@@ -562,10 +701,10 @@ cal_shell_sidebar_client_removed (ECalShellSidebar *cal_shell_sidebar,
 		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);
+	e_source_selector_unselect_source (selector, source);
 
 	cal_shell_sidebar_emit_status_message (cal_shell_sidebar, NULL);
 }
@@ -574,6 +713,7 @@ static void
 cal_shell_sidebar_class_init (ECalShellSidebarClass *class)
 {
 	GObjectClass *object_class;
+	GtkWidgetClass *widget_class;
 	EShellSidebarClass *shell_sidebar_class;
 
 	parent_class = g_type_class_peek_parent (class);
@@ -585,6 +725,9 @@ cal_shell_sidebar_class_init (ECalShellSidebarClass *class)
 	object_class->finalize = cal_shell_sidebar_finalize;
 	object_class->constructed = cal_shell_sidebar_constructed;
 
+	widget_class = GTK_WIDGET_CLASS (class);
+	widget_class->realize = cal_shell_sidebar_realize;
+
 	shell_sidebar_class = E_SHELL_SIDEBAR_CLASS (class);
 	shell_sidebar_class->check_state = cal_shell_sidebar_check_state;
 
@@ -602,6 +745,16 @@ cal_shell_sidebar_class_init (ECalShellSidebarClass *class)
 
 	g_object_class_install_property (
 		object_class,
+		PROP_DEFAULT_CLIENT,
+		g_param_spec_object (
+			"default-client",
+			_("Default Calendar Client"),
+			_("Default client for calendar operations"),
+			E_TYPE_CAL,
+			G_PARAM_READABLE));
+
+	g_object_class_install_property (
+		object_class,
 		PROP_SELECTOR,
 		g_param_spec_object (
 			"selector",
@@ -718,6 +871,15 @@ e_cal_shell_sidebar_get_date_navigator (ECalShellSidebar *cal_shell_sidebar)
 	return E_CALENDAR (cal_shell_sidebar->priv->date_navigator);
 }
 
+ECal *
+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 cal_shell_sidebar->priv->default_client;
+}
+
 ESourceSelector *
 e_cal_shell_sidebar_get_selector (ECalShellSidebar *cal_shell_sidebar)
 {
@@ -731,8 +893,10 @@ void
 e_cal_shell_sidebar_add_source (ECalShellSidebar *cal_shell_sidebar,
                                 ESource *source)
 {
+	ECalSourceType source_type;
 	ESourceSelector *selector;
 	GHashTable *client_table;
+	ECal *default_client;
 	ECal *client;
 	const gchar *uid;
 	const gchar *uri;
@@ -741,7 +905,9 @@ e_cal_shell_sidebar_add_source (ECalShellSidebar *cal_shell_sidebar,
 	g_return_if_fail (E_IS_CAL_SHELL_SIDEBAR (cal_shell_sidebar));
 	g_return_if_fail (E_IS_SOURCE (source));
 
+	source_type = E_CAL_SOURCE_TYPE_EVENT;
 	client_table = cal_shell_sidebar->priv->client_table;
+	default_client = cal_shell_sidebar->priv->default_client;
 	selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
 
 	uid = e_source_peek_uid (source);
@@ -750,7 +916,20 @@ e_cal_shell_sidebar_add_source (ECalShellSidebar *cal_shell_sidebar,
 	if (client != NULL)
 		return;
 
-	client = e_auth_new_cal_from_source (source, E_CAL_SOURCE_TYPE_EVENT);
+	if (default_client != NULL) {
+		ESource *default_source;
+		const gchar *default_uid;
+
+		default_source = e_cal_get_source (default_client);
+		default_uid = e_source_peek_uid (default_source);
+
+		if (g_strcmp0 (uid, default_uid) == 0)
+			client = g_object_ref (default_client);
+	}
+
+	if (client == NULL)
+		client = e_auth_new_cal_from_source (source, source_type);
+
 	g_return_if_fail (client != NULL);
 
 	g_signal_connect_swapped (
diff --git a/modules/calendar/e-cal-shell-sidebar.h b/modules/calendar/e-cal-shell-sidebar.h
index 6169d30..6919d7a 100644
--- a/modules/calendar/e-cal-shell-sidebar.h
+++ b/modules/calendar/e-cal-shell-sidebar.h
@@ -86,6 +86,8 @@ GList *		e_cal_shell_sidebar_get_clients
 					(ECalShellSidebar *cal_shell_sidebar);
 ECalendar *	e_cal_shell_sidebar_get_date_navigator
 					(ECalShellSidebar *cal_shell_sidebar);
+ECal *		e_cal_shell_sidebar_get_default_client
+					(ECalShellSidebar *cal_shell_sidebar);
 ESourceSelector *
 		e_cal_shell_sidebar_get_selector
 					(ECalShellSidebar *cal_shell_sidebar);
diff --git a/modules/calendar/e-cal-shell-view-private.c b/modules/calendar/e-cal-shell-view-private.c
index 74a2bbc..b5f9ba5 100644
--- a/modules/calendar/e-cal-shell-view-private.c
+++ b/modules/calendar/e-cal-shell-view-private.c
@@ -566,6 +566,11 @@ e_cal_shell_view_private_constructed (ECalShellView *cal_shell_view)
         e_cal_shell_view_update_search_filter (cal_shell_view);
 	e_cal_shell_view_update_timezone (cal_shell_view);
 
+	/* Keep the ECalModel in sync with the sidebar. */
+	e_binding_new (
+		shell_sidebar, "default-client",
+		model, "default-client");
+
 	/* Keep the toolbar view buttons in sync with the calendar. */
 	e_mutual_binding_new (
 		calendar, "view",
diff --git a/modules/calendar/e-memo-shell-sidebar.c b/modules/calendar/e-memo-shell-sidebar.c
index e76341c..7ce7441 100644
--- a/modules/calendar/e-memo-shell-sidebar.c
+++ b/modules/calendar/e-memo-shell-sidebar.c
@@ -25,7 +25,6 @@
 #include <glib/gi18n.h>
 #include <libecal/e-cal.h>
 
-#include "e-util/e-binding.h"
 #include "e-util/e-alert-dialog.h"
 #include "e-util/e-util.h"
 #include "calendar/common/authentication.h"
@@ -42,14 +41,23 @@
 
 struct _EMemoShellSidebarPrivate {
 	GtkWidget *selector;
-	icaltimezone *timezone;
 
 	/* UID -> Client */
 	GHashTable *client_table;
+
+	/* 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. */
+	ECal *default_client;
 };
 
 enum {
 	PROP_0,
+	PROP_DEFAULT_CLIENT,
 	PROP_SELECTOR
 };
 
@@ -163,6 +171,7 @@ memo_shell_sidebar_client_opened_cb (EMemoShellSidebar *memo_shell_sidebar,
 	EShellView *shell_view;
 	EShellWindow *shell_window;
 	EShellSidebar *shell_sidebar;
+	const gchar *message;
 
 	shell_sidebar = E_SHELL_SIDEBAR (memo_shell_sidebar);
 	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
@@ -172,39 +181,121 @@ memo_shell_sidebar_client_opened_cb (EMemoShellSidebar *memo_shell_sidebar,
 		status == E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED)
 		e_auth_cal_forget_password (client);
 
+	/* Handle errors. */
 	switch (status) {
 		case E_CALENDAR_STATUS_OK:
-			g_signal_handlers_disconnect_matched (
-				client, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
-				memo_shell_sidebar_client_opened_cb, NULL);
-
-			memo_shell_sidebar_emit_status_message (
-				memo_shell_sidebar, _("Loading memos"));
-			memo_shell_sidebar_emit_client_added (
-				memo_shell_sidebar, client);
-			memo_shell_sidebar_emit_status_message (
-				memo_shell_sidebar, NULL);
 			break;
 
 		case E_CALENDAR_STATUS_AUTHENTICATION_FAILED:
 			e_cal_open_async (client, FALSE);
-			break;
+			return;
 
 		case E_CALENDAR_STATUS_BUSY:
-			break;
+			return;
 
 		case E_CALENDAR_STATUS_REPOSITORY_OFFLINE:
 			e_alert_run_dialog_for_args (
 				GTK_WINDOW (shell_window),
 				"calendar:prompt-no-contents-offline-memos",
 				NULL);
-			break;
+			/* fall through */
 
 		default:
-			memo_shell_sidebar_emit_client_removed (
-				memo_shell_sidebar, client);
+			e_memo_shell_sidebar_remove_source (
+				memo_shell_sidebar,
+				e_cal_get_source (client));
+			return;
+	}
+
+	g_assert (status == E_CALENDAR_STATUS_OK);
+
+	g_signal_handlers_disconnect_matched (
+		client, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
+		memo_shell_sidebar_client_opened_cb, NULL);
+
+	message = _("Loading memos");
+	memo_shell_sidebar_emit_status_message (memo_shell_sidebar, message);
+	memo_shell_sidebar_emit_client_added (memo_shell_sidebar, client);
+	memo_shell_sidebar_emit_status_message (memo_shell_sidebar, NULL);
+}
+
+static void
+memo_shell_sidebar_default_opened_cb (EMemoShellSidebar *memo_shell_sidebar,
+                                      ECalendarStatus status,
+                                      ECal *client)
+{
+	EShellView *shell_view;
+	EShellWindow *shell_window;
+	EShellSidebar *shell_sidebar;
+
+	shell_sidebar = E_SHELL_SIDEBAR (memo_shell_sidebar);
+	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+	shell_window = e_shell_view_get_shell_window (shell_view);
+
+	if (status == E_CALENDAR_STATUS_AUTHENTICATION_FAILED ||
+		status == E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED)
+		e_auth_cal_forget_password (client);
+
+	/* Handle errors. */
+	switch (status) {
+		case E_CALENDAR_STATUS_OK:
 			break;
+
+		case E_CALENDAR_STATUS_AUTHENTICATION_FAILED:
+			e_cal_open_async (client, FALSE);
+			return;
+
+		case E_CALENDAR_STATUS_BUSY:
+			return;
+
+		default:
+			e_memo_shell_sidebar_remove_source (
+				memo_shell_sidebar,
+				e_cal_get_source (client));
+			return;
 	}
+
+	g_assert (status == E_CALENDAR_STATUS_OK);
+
+	g_signal_handlers_disconnect_matched (
+		client, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
+		memo_shell_sidebar_default_opened_cb, NULL);
+
+	g_object_notify (G_OBJECT (memo_shell_sidebar), "default-client");
+}
+
+static void
+memo_shell_sidebar_set_default (EMemoShellSidebar *memo_shell_sidebar,
+                                ESource *source)
+{
+	ECalSourceType source_type;
+	GHashTable *client_table;
+	ECal *client;
+	const gchar *uid;
+
+	source_type = E_CAL_SOURCE_TYPE_JOURNAL;
+	client_table = memo_shell_sidebar->priv->client_table;
+
+	uid = e_source_peek_uid (source);
+	client = g_hash_table_lookup (client_table, uid);
+
+	if (memo_shell_sidebar->priv->default_client != NULL)
+		g_object_unref (memo_shell_sidebar->priv->default_client);
+
+	if (client != NULL)
+		g_object_ref (client);
+	else
+		client = e_auth_new_cal_from_source (source, source_type);
+
+	memo_shell_sidebar->priv->default_client = client;
+	g_return_if_fail (client != NULL);
+
+	g_signal_connect_swapped (
+		client, "cal-opened",
+		G_CALLBACK (memo_shell_sidebar_default_opened_cb),
+		memo_shell_sidebar);
+
+	e_cal_open_async (client, FALSE);
 }
 
 static void
@@ -292,6 +383,8 @@ memo_shell_sidebar_primary_selection_changed_cb (EMemoShellSidebar *memo_shell_s
 	e_shell_settings_set_string (
 		shell_settings, "cal-primary-memo-list",
 		e_source_peek_uid (source));
+
+	memo_shell_sidebar_set_default (memo_shell_sidebar, source);
 }
 
 static void
@@ -301,9 +394,17 @@ memo_shell_sidebar_get_property (GObject *object,
                                  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 (
+				value,
+				e_memo_shell_sidebar_get_selector (
 				E_MEMO_SHELL_SIDEBAR (object)));
 			return;
 	}
@@ -323,6 +424,11 @@ memo_shell_sidebar_dispose (GObject *object)
 		priv->selector = NULL;
 	}
 
+	if (priv->default_client != NULL) {
+		g_object_unref (priv->default_client);
+		priv->default_client = NULL;
+	}
+
 	g_hash_table_remove_all (priv->client_table);
 
 	/* Chain up to parent's dispose() method. */
@@ -346,20 +452,13 @@ static void
 memo_shell_sidebar_constructed (GObject *object)
 {
 	EMemoShellSidebarPrivate *priv;
-	EShell *shell;
 	EShellView *shell_view;
 	EShellBackend *shell_backend;
 	EShellSidebar *shell_sidebar;
-	EShellSettings *shell_settings;
-	ESourceSelector *selector;
 	ESourceList *source_list;
-	ESource *source;
 	GtkContainer *container;
-	GtkTreeModel *model;
 	GtkWidget *widget;
 	AtkObject *a11y;
-	GSList *list, *iter;
-	gchar *uid;
 
 	priv = E_MEMO_SHELL_SIDEBAR_GET_PRIVATE (object);
 
@@ -370,9 +469,6 @@ memo_shell_sidebar_constructed (GObject *object)
 	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
 	shell_backend = e_shell_view_get_shell_backend (shell_view);
 
-	shell = e_shell_backend_get_shell (shell_backend);
-	shell_settings = e_shell_get_shell_settings (shell);
-
 	source_list = e_memo_shell_backend_get_source_list (
 		E_MEMO_SHELL_BACKEND (shell_backend));
 
@@ -396,16 +492,52 @@ memo_shell_sidebar_constructed (GObject *object)
 	atk_object_set_name (a11y, _("Memo List Selector"));
 	priv->selector = g_object_ref (widget);
 	gtk_widget_show (widget);
+}
+
+static void
+memo_shell_sidebar_realize (GtkWidget *widget)
+{
+	EMemoShellSidebarPrivate *priv;
+	EShell *shell;
+	EShellView *shell_view;
+	EShellBackend *shell_backend;
+	EShellSidebar *shell_sidebar;
+	EShellSettings *shell_settings;
+	ESourceSelector *selector;
+	ESourceList *source_list;
+	ESource *source;
+	GtkTreeModel *model;
+	GSList *list, *iter;
+	gchar *uid;
+
+	priv = E_MEMO_SHELL_SIDEBAR_GET_PRIVATE (widget);
+
+	/* Restore the selector state from the last session.  We do this
+	 * in realize() instead of constructed() so the shell view has a
+	 * chance to connect handlers to our signals. */
 
-	/* Restore the selector state from the last session. */
+	shell_sidebar = E_SHELL_SIDEBAR (widget);
+	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+	shell_backend = e_shell_view_get_shell_backend (shell_view);
+
+	shell = e_shell_backend_get_shell (shell_backend);
+	shell_settings = e_shell_get_shell_settings (shell);
 
 	selector = E_SOURCE_SELECTOR (priv->selector);
-	model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
+	model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector));
+
+	source_list = e_memo_shell_backend_get_source_list (
+		E_MEMO_SHELL_BACKEND (shell_backend));
 
 	g_signal_connect_swapped (
 		model, "row-changed",
 		G_CALLBACK (memo_shell_sidebar_row_changed_cb),
-		object);
+		shell_sidebar);
+
+	g_signal_connect_swapped (
+		selector, "primary-selection-changed",
+		G_CALLBACK (memo_shell_sidebar_primary_selection_changed_cb),
+		shell_sidebar);
 
 	source = NULL;
 	uid = e_shell_settings_get_string (
@@ -434,14 +566,12 @@ memo_shell_sidebar_constructed (GObject *object)
 	/* Listen for subsequent changes to the selector. */
 
 	g_signal_connect_swapped (
-		widget, "selection-changed",
+		selector, "selection-changed",
 		G_CALLBACK (memo_shell_sidebar_selection_changed_cb),
-		object);
+		shell_sidebar);
 
-	g_signal_connect_swapped (
-		widget, "primary-selection-changed",
-		G_CALLBACK (memo_shell_sidebar_primary_selection_changed_cb),
-		object);
+	/* Chain up to parent's realize() method. */
+	GTK_WIDGET_CLASS (parent_class)->realize (widget);
 }
 
 static guint32
@@ -507,10 +637,10 @@ memo_shell_sidebar_client_removed (EMemoShellSidebar *memo_shell_sidebar,
 		NULL, NULL, memo_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);
+	e_source_selector_unselect_source (selector, source);
 
 	memo_shell_sidebar_emit_status_message (memo_shell_sidebar, NULL);
 }
@@ -519,6 +649,7 @@ static void
 memo_shell_sidebar_class_init (EMemoShellSidebarClass *class)
 {
 	GObjectClass *object_class;
+	GtkWidgetClass *widget_class;
 	EShellSidebarClass *shell_sidebar_class;
 
 	parent_class = g_type_class_peek_parent (class);
@@ -530,6 +661,9 @@ memo_shell_sidebar_class_init (EMemoShellSidebarClass *class)
 	object_class->finalize = memo_shell_sidebar_finalize;
 	object_class->constructed = memo_shell_sidebar_constructed;
 
+	widget_class = GTK_WIDGET_CLASS (class);
+	widget_class->realize = memo_shell_sidebar_realize;
+
 	shell_sidebar_class = E_SHELL_SIDEBAR_CLASS (class);
 	shell_sidebar_class->check_state = memo_shell_sidebar_check_state;
 
@@ -537,6 +671,16 @@ memo_shell_sidebar_class_init (EMemoShellSidebarClass *class)
 
 	g_object_class_install_property (
 		object_class,
+		PROP_DEFAULT_CLIENT,
+		g_param_spec_object (
+			"default-client",
+			_("Default Memo Client"),
+			_("Default client for memo operations"),
+			E_TYPE_CAL,
+			G_PARAM_READABLE));
+
+	g_object_class_install_property (
+		object_class,
 		PROP_SELECTOR,
 		g_param_spec_object (
 			"selector",
@@ -645,6 +789,15 @@ e_memo_shell_sidebar_get_clients (EMemoShellSidebar *memo_shell_sidebar)
 	return g_hash_table_get_values (client_table);
 }
 
+ECal *
+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 memo_shell_sidebar->priv->default_client;
+}
+
 ESourceSelector *
 e_memo_shell_sidebar_get_selector (EMemoShellSidebar *memo_shell_sidebar)
 {
@@ -658,8 +811,10 @@ void
 e_memo_shell_sidebar_add_source (EMemoShellSidebar *memo_shell_sidebar,
                                  ESource *source)
 {
+	ECalSourceType source_type;
 	ESourceSelector *selector;
 	GHashTable *client_table;
+	ECal *default_client;
 	ECal *client;
 	const gchar *uid;
 	const gchar *uri;
@@ -668,7 +823,9 @@ e_memo_shell_sidebar_add_source (EMemoShellSidebar *memo_shell_sidebar,
 	g_return_if_fail (E_IS_MEMO_SHELL_SIDEBAR (memo_shell_sidebar));
 	g_return_if_fail (E_IS_SOURCE (source));
 
+	source_type = E_CAL_SOURCE_TYPE_JOURNAL;
 	client_table = memo_shell_sidebar->priv->client_table;
+	default_client = memo_shell_sidebar->priv->default_client;
 	selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
 
 	uid = e_source_peek_uid (source);
@@ -677,7 +834,20 @@ e_memo_shell_sidebar_add_source (EMemoShellSidebar *memo_shell_sidebar,
 	if (client != NULL)
 		return;
 
-	client = e_auth_new_cal_from_source (source, E_CAL_SOURCE_TYPE_JOURNAL);
+	if (default_client != NULL) {
+		ESource *default_source;
+		const gchar *default_uid;
+
+		default_source = e_cal_get_source (default_client);
+		default_uid = e_source_peek_uid (default_source);
+
+		if (g_strcmp0 (uid, default_uid) == 0)
+			client = g_object_ref (default_client);
+	}
+
+	if (client == NULL)
+		client = e_auth_new_cal_from_source (source, source_type);
+
 	g_return_if_fail (client != NULL);
 
 	g_signal_connect_swapped (
diff --git a/modules/calendar/e-memo-shell-sidebar.h b/modules/calendar/e-memo-shell-sidebar.h
index 8eabee1..0d32c7b 100644
--- a/modules/calendar/e-memo-shell-sidebar.h
+++ b/modules/calendar/e-memo-shell-sidebar.h
@@ -84,6 +84,8 @@ void		e_memo_shell_sidebar_register_type
 GtkWidget *	e_memo_shell_sidebar_new(EShellView *shell_view);
 GList *		e_memo_shell_sidebar_get_clients
 					(EMemoShellSidebar *memo_shell_sidebar);
+ECal *		e_memo_shell_sidebar_get_default_client
+					(EMemoShellSidebar *memo_shell_sidebar);
 ESourceSelector *
 		e_memo_shell_sidebar_get_selector
 					(EMemoShellSidebar *memo_shell_sidebar);
diff --git a/modules/calendar/e-memo-shell-view-private.c b/modules/calendar/e-memo-shell-view-private.c
index 2caa6ec..decd900 100644
--- a/modules/calendar/e-memo-shell-view-private.c
+++ b/modules/calendar/e-memo-shell-view-private.c
@@ -38,8 +38,6 @@ memo_shell_view_model_row_appended_cb (EMemoShellView *memo_shell_view,
 
 	memo_shell_sidebar = memo_shell_view->priv->memo_shell_sidebar;
 	e_memo_shell_sidebar_add_source (memo_shell_sidebar, source);
-
-	e_cal_model_add_client (model, client);
 }
 
 static void
@@ -273,6 +271,11 @@ e_memo_shell_view_private_constructed (EMemoShellView *memo_shell_view)
 		(GHookFunc) e_memo_shell_view_update_search_filter,
 		memo_shell_view);
 
+	/* Keep the ECalModel in sync with the sidebar. */
+	e_binding_new (
+		shell_sidebar, "default-client",
+		model, "default-client");
+
 	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);
diff --git a/modules/calendar/e-task-shell-sidebar.c b/modules/calendar/e-task-shell-sidebar.c
index 7708f72..347c64b 100644
--- a/modules/calendar/e-task-shell-sidebar.c
+++ b/modules/calendar/e-task-shell-sidebar.c
@@ -32,8 +32,8 @@
 #include "calendar/gui/e-task-list-selector.h"
 #include "calendar/gui/misc.h"
 
-#include "e-task-shell-backend.h"
 #include "e-task-shell-view.h"
+#include "e-task-shell-backend.h"
 
 #define E_TASK_SHELL_SIDEBAR_GET_PRIVATE(obj) \
 	(G_TYPE_INSTANCE_GET_PRIVATE \
@@ -44,10 +44,20 @@ struct _ETaskShellSidebarPrivate {
 
 	/* UID -> Client */
 	GHashTable *client_table;
+
+	/* 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. */
+	ECal *default_client;
 };
 
 enum {
 	PROP_0,
+	PROP_DEFAULT_CLIENT,
 	PROP_SELECTOR
 };
 
@@ -161,6 +171,7 @@ task_shell_sidebar_client_opened_cb (ETaskShellSidebar *task_shell_sidebar,
 	EShellView *shell_view;
 	EShellWindow *shell_window;
 	EShellSidebar *shell_sidebar;
+	const gchar *message;
 
 	shell_sidebar = E_SHELL_SIDEBAR (task_shell_sidebar);
 	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
@@ -170,39 +181,121 @@ task_shell_sidebar_client_opened_cb (ETaskShellSidebar *task_shell_sidebar,
 		status == E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED)
 		e_auth_cal_forget_password (client);
 
+	/* Handle errors. */
 	switch (status) {
 		case E_CALENDAR_STATUS_OK:
-			g_signal_handlers_disconnect_matched (
-				client, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
-				task_shell_sidebar_client_opened_cb, NULL);
-
-			task_shell_sidebar_emit_status_message (
-				task_shell_sidebar, _("Loading tasks"));
-			task_shell_sidebar_emit_client_added (
-				task_shell_sidebar, client);
-			task_shell_sidebar_emit_status_message (
-				task_shell_sidebar, NULL);
 			break;
 
 		case E_CALENDAR_STATUS_AUTHENTICATION_FAILED:
 			e_cal_open_async (client, FALSE);
-			break;
+			return;
 
 		case E_CALENDAR_STATUS_BUSY:
-			break;
+			return;
 
 		case E_CALENDAR_STATUS_REPOSITORY_OFFLINE:
 			e_alert_run_dialog_for_args (
 				GTK_WINDOW (shell_window),
 				"calendar:prompt-no-contents-offline-tasks",
 				NULL);
-			break;
+			/* fall through */
 
 		default:
-			task_shell_sidebar_emit_client_removed (
-				task_shell_sidebar, client);
+			e_task_shell_sidebar_remove_source (
+				task_shell_sidebar,
+				e_cal_get_source (client));
+			return;
+	}
+
+	g_assert (status == E_CALENDAR_STATUS_OK);
+
+	g_signal_handlers_disconnect_matched (
+		client, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
+		task_shell_sidebar_client_opened_cb, NULL);
+
+	message = _("Loading tasks");
+	task_shell_sidebar_emit_status_message (task_shell_sidebar, message);
+	task_shell_sidebar_emit_client_added (task_shell_sidebar, client);
+	task_shell_sidebar_emit_status_message (task_shell_sidebar, NULL);
+}
+
+static void
+task_shell_sidebar_default_opened_cb (ETaskShellSidebar *task_shell_sidebar,
+                                      ECalendarStatus status,
+                                      ECal *client)
+{
+	EShellView *shell_view;
+	EShellWindow *shell_window;
+	EShellSidebar *shell_sidebar;
+
+	shell_sidebar = E_SHELL_SIDEBAR (task_shell_sidebar);
+	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+	shell_window = e_shell_view_get_shell_window (shell_view);
+
+	if (status == E_CALENDAR_STATUS_AUTHENTICATION_FAILED ||
+		status == E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED)
+		e_auth_cal_forget_password (client);
+
+	/* Handle errors. */
+	switch (status) {
+		case E_CALENDAR_STATUS_OK:
 			break;
+
+		case E_CALENDAR_STATUS_AUTHENTICATION_FAILED:
+			e_cal_open_async (client, FALSE);
+			return;
+
+		case E_CALENDAR_STATUS_BUSY:
+			return;
+
+		default:
+			e_task_shell_sidebar_remove_source (
+				task_shell_sidebar,
+				e_cal_get_source (client));
+			return;
 	}
+
+	g_assert (status == E_CALENDAR_STATUS_OK);
+
+	g_signal_handlers_disconnect_matched (
+		client, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
+		task_shell_sidebar_default_opened_cb, NULL);
+
+	g_object_notify (G_OBJECT (task_shell_sidebar), "default-client");
+}
+
+static void
+task_shell_sidebar_set_default (ETaskShellSidebar *task_shell_sidebar,
+                                ESource *source)
+{
+	ECalSourceType source_type;
+	GHashTable *client_table;
+	ECal *client;
+	const gchar *uid;
+
+	source_type = E_CAL_SOURCE_TYPE_TODO;
+	client_table = task_shell_sidebar->priv->client_table;
+
+	uid = e_source_peek_uid (source);
+	client = g_hash_table_lookup (client_table, uid);
+
+	if (task_shell_sidebar->priv->default_client != NULL)
+		g_object_unref (task_shell_sidebar->priv->default_client);
+
+	if (client != NULL)
+		g_object_ref (client);
+	else
+		client = e_auth_new_cal_from_source (source, source_type);
+
+	task_shell_sidebar->priv->default_client = client;
+	g_return_if_fail (client != NULL);
+
+	g_signal_connect_swapped (
+		client, "cal-opened",
+		G_CALLBACK (task_shell_sidebar_default_opened_cb),
+		task_shell_sidebar);
+
+	e_cal_open_async (client, FALSE);
 }
 
 static void
@@ -290,6 +383,8 @@ task_shell_sidebar_primary_selection_changed_cb (ETaskShellSidebar *task_shell_s
 	e_shell_settings_set_string (
 		shell_settings, "cal-primary-task-list",
 		e_source_peek_uid (source));
+
+	task_shell_sidebar_set_default (task_shell_sidebar, source);
 }
 
 static void
@@ -299,9 +394,17 @@ task_shell_sidebar_get_property (GObject *object,
                                  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 (
+				value,
+				e_task_shell_sidebar_get_selector (
 				E_TASK_SHELL_SIDEBAR (object)));
 			return;
 	}
@@ -321,6 +424,11 @@ task_shell_sidebar_dispose (GObject *object)
 		priv->selector = NULL;
 	}
 
+	if (priv->default_client != NULL) {
+		g_object_unref (priv->default_client);
+		priv->default_client = NULL;
+	}
+
 	g_hash_table_remove_all (priv->client_table);
 
 	/* Chain up to parent's dispose() method. */
@@ -344,20 +452,13 @@ static void
 task_shell_sidebar_constructed (GObject *object)
 {
 	ETaskShellSidebarPrivate *priv;
-	EShell *shell;
 	EShellView *shell_view;
 	EShellBackend *shell_backend;
 	EShellSidebar *shell_sidebar;
-	EShellSettings *shell_settings;
-	ESourceSelector *selector;
 	ESourceList *source_list;
-	ESource *source;
 	GtkContainer *container;
-	GtkTreeModel *model;
 	GtkWidget *widget;
 	AtkObject *a11y;
-	GSList *list, *iter;
-	gchar *uid;
 
 	priv = E_TASK_SHELL_SIDEBAR_GET_PRIVATE (object);
 
@@ -368,9 +469,6 @@ task_shell_sidebar_constructed (GObject *object)
 	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
 	shell_backend = e_shell_view_get_shell_backend (shell_view);
 
-	shell = e_shell_backend_get_shell (shell_backend);
-	shell_settings = e_shell_get_shell_settings (shell);
-
 	source_list = e_task_shell_backend_get_source_list (
 		E_TASK_SHELL_BACKEND (shell_backend));
 
@@ -394,16 +492,52 @@ task_shell_sidebar_constructed (GObject *object)
 	atk_object_set_name (a11y, _("Task List Selector"));
 	priv->selector = g_object_ref (widget);
 	gtk_widget_show (widget);
+}
+
+static void
+task_shell_sidebar_realize (GtkWidget *widget)
+{
+	ETaskShellSidebarPrivate *priv;
+	EShell *shell;
+	EShellView *shell_view;
+	EShellBackend *shell_backend;
+	EShellSidebar *shell_sidebar;
+	EShellSettings *shell_settings;
+	ESourceSelector *selector;
+	ESourceList *source_list;
+	ESource *source;
+	GtkTreeModel *model;
+	GSList *list, *iter;
+	gchar *uid;
 
-	/* Restore the selector state from the last session. */
+	priv = E_TASK_SHELL_SIDEBAR_GET_PRIVATE (widget);
+
+	/* Restore the selector state from the last session.  We do this
+	 * in realize() instead of constructed() so the shell view has a
+	 * chance to connect handlers to our signals. */
+
+	shell_sidebar = E_SHELL_SIDEBAR (widget);
+	shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+	shell_backend = e_shell_view_get_shell_backend (shell_view);
+
+	shell = e_shell_backend_get_shell (shell_backend);
+	shell_settings = e_shell_get_shell_settings (shell);
 
 	selector = E_SOURCE_SELECTOR (priv->selector);
-	model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
+	model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector));
+
+	source_list = e_task_shell_backend_get_source_list (
+		E_TASK_SHELL_BACKEND (shell_backend));
 
 	g_signal_connect_swapped (
 		model, "row-changed",
 		G_CALLBACK (task_shell_sidebar_row_changed_cb),
-		object);
+		shell_sidebar);
+
+	g_signal_connect_swapped (
+		selector, "primary-selection-changed",
+		G_CALLBACK (task_shell_sidebar_primary_selection_changed_cb),
+		shell_sidebar);
 
 	source = NULL;
 	uid = e_shell_settings_get_string (
@@ -432,14 +566,12 @@ task_shell_sidebar_constructed (GObject *object)
 	/* Listen for subsequent changes to the selector. */
 
 	g_signal_connect_swapped (
-		widget, "selection-changed",
+		selector, "selection-changed",
 		G_CALLBACK (task_shell_sidebar_selection_changed_cb),
-		object);
+		shell_sidebar);
 
-	g_signal_connect_swapped (
-		widget, "primary-selection-changed",
-		G_CALLBACK (task_shell_sidebar_primary_selection_changed_cb),
-		object);
+	/* Chain up to parent's realize() method. */
+	GTK_WIDGET_CLASS (parent_class)->realize (widget);
 }
 
 static guint32
@@ -505,10 +637,10 @@ task_shell_sidebar_client_removed (ETaskShellSidebar *task_shell_sidebar,
 		NULL, NULL, task_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);
+	e_source_selector_unselect_source (selector, source);
 
 	task_shell_sidebar_emit_status_message (task_shell_sidebar, NULL);
 }
@@ -517,6 +649,7 @@ static void
 task_shell_sidebar_class_init (ETaskShellSidebarClass *class)
 {
 	GObjectClass *object_class;
+	GtkWidgetClass *widget_class;
 	EShellSidebarClass *shell_sidebar_class;
 
 	parent_class = g_type_class_peek_parent (class);
@@ -528,6 +661,9 @@ task_shell_sidebar_class_init (ETaskShellSidebarClass *class)
 	object_class->finalize = task_shell_sidebar_finalize;
 	object_class->constructed = task_shell_sidebar_constructed;
 
+	widget_class = GTK_WIDGET_CLASS (class);
+	widget_class->realize = task_shell_sidebar_realize;
+
 	shell_sidebar_class = E_SHELL_SIDEBAR_CLASS (class);
 	shell_sidebar_class->check_state = task_shell_sidebar_check_state;
 
@@ -535,6 +671,16 @@ task_shell_sidebar_class_init (ETaskShellSidebarClass *class)
 
 	g_object_class_install_property (
 		object_class,
+		PROP_DEFAULT_CLIENT,
+		g_param_spec_object (
+			"default-client",
+			_("Default Task Client"),
+			_("Default client for task operations"),
+			E_TYPE_CAL,
+			G_PARAM_READABLE));
+
+	g_object_class_install_property (
+		object_class,
 		PROP_SELECTOR,
 		g_param_spec_object (
 			"selector",
@@ -643,6 +789,15 @@ e_task_shell_sidebar_get_clients (ETaskShellSidebar *task_shell_sidebar)
 	return g_hash_table_get_values (client_table);
 }
 
+ECal *
+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 task_shell_sidebar->priv->default_client;
+}
+
 ESourceSelector *
 e_task_shell_sidebar_get_selector (ETaskShellSidebar *task_shell_sidebar)
 {
@@ -656,8 +811,10 @@ void
 e_task_shell_sidebar_add_source (ETaskShellSidebar *task_shell_sidebar,
                                  ESource *source)
 {
+	ECalSourceType source_type;
 	ESourceSelector *selector;
 	GHashTable *client_table;
+	ECal *default_client;
 	ECal *client;
 	const gchar *uid;
 	const gchar *uri;
@@ -666,7 +823,9 @@ e_task_shell_sidebar_add_source (ETaskShellSidebar *task_shell_sidebar,
 	g_return_if_fail (E_IS_TASK_SHELL_SIDEBAR (task_shell_sidebar));
 	g_return_if_fail (E_IS_SOURCE (source));
 
+	source_type = E_CAL_SOURCE_TYPE_TODO;
 	client_table = task_shell_sidebar->priv->client_table;
+	default_client = task_shell_sidebar->priv->default_client;
 	selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
 
 	uid = e_source_peek_uid (source);
@@ -675,7 +834,20 @@ e_task_shell_sidebar_add_source (ETaskShellSidebar *task_shell_sidebar,
 	if (client != NULL)
 		return;
 
-	client = e_auth_new_cal_from_source (source, E_CAL_SOURCE_TYPE_TODO);
+	if (default_client != NULL) {
+		ESource *default_source;
+		const gchar *default_uid;
+
+		default_source = e_cal_get_source (default_client);
+		default_uid = e_source_peek_uid (default_source);
+
+		if (g_strcmp0 (uid, default_uid) == 0)
+			client = g_object_ref (default_client);
+	}
+
+	if (client == NULL)
+		client = e_auth_new_cal_from_source (source, source_type);
+
 	g_return_if_fail (client != NULL);
 
 	g_signal_connect_swapped (
diff --git a/modules/calendar/e-task-shell-sidebar.h b/modules/calendar/e-task-shell-sidebar.h
index 6a18279..152c7ca 100644
--- a/modules/calendar/e-task-shell-sidebar.h
+++ b/modules/calendar/e-task-shell-sidebar.h
@@ -84,6 +84,8 @@ void		e_task_shell_sidebar_register_type
 GtkWidget *	e_task_shell_sidebar_new(EShellView *shell_view);
 GList *		e_task_shell_sidebar_get_clients
 					(ETaskShellSidebar *task_shell_sidebar);
+ECal *		e_task_shell_sidebar_get_default_client
+					(ETaskShellSidebar *task_shell_sidebar);
 ESourceSelector *
 		e_task_shell_sidebar_get_selector
 					(ETaskShellSidebar *task_shell_sidebar);
diff --git a/modules/calendar/e-task-shell-view-private.c b/modules/calendar/e-task-shell-view-private.c
index 1cdf669..ada67c7 100644
--- a/modules/calendar/e-task-shell-view-private.c
+++ b/modules/calendar/e-task-shell-view-private.c
@@ -38,8 +38,6 @@ task_shell_view_model_row_appended_cb (ETaskShellView *task_shell_view,
 
 	task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
 	e_task_shell_sidebar_add_source (task_shell_sidebar, source);
-
-	e_cal_model_add_client (model, client);
 }
 
 static void
@@ -326,11 +324,15 @@ e_task_shell_view_private_constructed (ETaskShellView *task_shell_view)
 		task_shell_view);
 
 	/* Listen for configuration changes. */
-
 	e_mutual_binding_new (
 		shell_settings, "cal-confirm-purge",
 		task_shell_view, "confirm-purge");
 
+	/* Keep the ECalModel in sync with the sidebar. */
+	e_binding_new (
+		shell_sidebar, "default-client",
+		model, "default-client");
+
 	/* Hide Completed Tasks (enable/units/value) */
 	g_signal_connect_swapped (
 		shell_settings, "notify::cal-hide-completed-tasks",



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]