diff options
-rw-r--r-- | calendar/common/authentication.c | 273 | ||||
-rw-r--r-- | calendar/common/authentication.h | 18 | ||||
-rw-r--r-- | modules/addressbook/e-book-shell-backend.c | 7 | ||||
-rw-r--r-- | modules/calendar/e-cal-shell-backend.c | 128 | ||||
-rw-r--r-- | modules/calendar/e-cal-shell-sidebar.c | 126 | ||||
-rw-r--r-- | modules/calendar/e-memo-shell-backend.c | 102 | ||||
-rw-r--r-- | modules/calendar/e-memo-shell-sidebar.c | 126 | ||||
-rw-r--r-- | modules/calendar/e-task-shell-backend.c | 99 | ||||
-rw-r--r-- | modules/calendar/e-task-shell-sidebar.c | 126 |
9 files changed, 665 insertions, 340 deletions
diff --git a/calendar/common/authentication.c b/calendar/common/authentication.c index 675754c5f0..b36e10a244 100644 --- a/calendar/common/authentication.c +++ b/calendar/common/authentication.c @@ -32,8 +32,6 @@ #include "authentication.h" #include <libedataserver/e-url.h> -static GHashTable *source_lists_hash = NULL; - static gchar * auth_func_cb (ECal *ecal, const gchar *prompt, @@ -124,3 +122,274 @@ e_auth_new_cal_from_source (ESource *source, ECalSourceType type) return cal; } + +typedef struct { + ECal *cal; + GtkWindow *parent; + GCancellable *cancellable; + ECalSourceType source_type; + icaltimezone *default_zone; + + /* Authentication Details */ + gchar *auth_uri; + gchar *auth_component; +} LoadContext; + +static void +load_cal_source_context_free (LoadContext *context) +{ + if (context->cal != NULL) + g_object_unref (context->cal); + + if (context->parent != NULL) + g_object_unref (context->parent); + + if (context->cancellable != NULL) + g_object_unref (context->cancellable); + + g_free (context->auth_uri); + g_free (context->auth_component); + + g_slice_free (LoadContext, context); +} + +static void +load_cal_source_get_auth_details (ESource *source, + LoadContext *context) +{ + const gchar *property; + + /* ECal figures out most of the details before invoking the + * authentication callback, but we still need a component name + * for e_passwords_ask_password(). */ + + /* auth_component */ + + property = e_source_get_property (source, "auth-domain"); + + if (property == NULL) + property = "Calendar"; + + context->auth_component = g_strdup (property); +} + +static gchar * +load_cal_source_authenticate (ECal *cal, + const gchar *prompt, + const gchar *uri, + LoadContext *context) +{ + const gchar *title; + gboolean remember; /* not used */ + gchar *password; + + /* Remember the URI so we don't have to reconstruct it if + * authentication fails and we have to forget the password. */ + g_free (context->auth_uri); + context->auth_uri = g_strdup (uri); + + /* XXX Dialog windows should not have titles. */ + title = ""; + + password = e_passwords_get_password (context->auth_component, uri); + + if (password == NULL) + password = e_passwords_ask_password ( + title, context->auth_component, uri, + prompt, E_PASSWORDS_REMEMBER_FOREVER | + E_PASSWORDS_SECRET | E_PASSWORDS_ONLINE, + &remember, context->parent); + + return password; +} + +static void +load_cal_source_thread (GSimpleAsyncResult *simple, + ESource *source, + GCancellable *cancellable) +{ + ECal *cal; + LoadContext *context; + GError *error = NULL; + + context = g_simple_async_result_get_op_res_gpointer (simple); + + /* XXX This doesn't take a GError, it just dumps + * error messages to the terminal... so broken. */ + cal = e_cal_new (source, context->source_type); + g_return_if_fail (cal != NULL); + + if (g_cancellable_set_error_if_cancelled (cancellable, &error)) { + g_simple_async_result_set_from_error (simple, error); + g_object_unref (cal); + g_error_free (error); + return; + } + + if (!e_cal_set_default_timezone (cal, context->default_zone, &error)) { + g_simple_async_result_set_from_error (simple, error); + g_object_unref (cal); + g_error_free (error); + return; + } + + /* XXX Why doesn't EBook have something like this? */ + e_cal_set_auth_func ( + cal, (ECalAuthFunc) + load_cal_source_authenticate, context); + +try_again: + if (!e_cal_open (cal, FALSE, &error)) + goto fail; + + /* We should be authenticated now if we're going to be, + * so remove the authentication callback so it doesn't + * get triggered after we free the load context. */ + e_cal_set_auth_func (cal, NULL, NULL); + + if (g_cancellable_set_error_if_cancelled (cancellable, &error)) { + g_simple_async_result_set_from_error (simple, error); + g_object_unref (cal); + g_error_free (error); + return; + } + + context->cal = cal; + + return; + +fail: + g_return_if_fail (error != NULL); + + /* If authentication failed, forget the password and reprompt. */ + if (g_error_matches ( + error, E_CALENDAR_ERROR, + E_CALENDAR_STATUS_AUTHENTICATION_FAILED)) { + e_passwords_forget_password ( + context->auth_component, context->auth_uri); + g_clear_error (&error); + goto try_again; + + /* XXX Might this cause a busy loop? */ + } else if (g_error_matches ( + error, E_CALENDAR_ERROR, E_CALENDAR_STATUS_BUSY)) { + g_clear_error (&error); + goto try_again; + + } else { + g_simple_async_result_set_from_error (simple, error); + g_object_unref (cal); + g_error_free (error); + } +} + +/** + * e_load_cal_source_async: + * @source: an #ESource + * @source_type: the type of #ECal to load + * @default_zone: default time zone, or %NULL to use UTC + * @parent: parent window for password dialogs, or %NULL + * @cancellable: optional #GCancellable object, %NULL to ignore + * @callback: a #GAsyncReadyCallback to call when the request is satisfied + * @user_data: the data to pass to @callback + * + * Creates a new #ECal specified by @source and opens it, prompting the + * user for authentication if necessary. + * + * When the operation is finished, @callback will be called. You can + * then call e_load_cal_source_finish() to obtain the resulting #ECal. + **/ +void +e_load_cal_source_async (ESource *source, + ECalSourceType source_type, + icaltimezone *default_zone, + GtkWindow *parent, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + LoadContext *context; + + g_return_if_fail (E_IS_SOURCE (source)); + + /* Source must have a group so we can obtain its URI. */ + g_return_if_fail (e_source_peek_group (source) != NULL); + + if (parent != NULL) { + g_return_if_fail (GTK_IS_WINDOW (parent)); + g_object_ref (parent); + } + + if (cancellable != NULL) { + g_return_if_fail (G_IS_CANCELLABLE (cancellable)); + g_object_ref (cancellable); + } + + if (default_zone == NULL) + default_zone = icaltimezone_get_utc_timezone (); + + context = g_slice_new0 (LoadContext); + context->parent = parent; + context->cancellable = cancellable; + context->source_type = source_type; + context->default_zone = default_zone; + + /* Extract authentication details from the ESource before + * spawning the thread, since ESource is not thread-safe. */ + load_cal_source_get_auth_details (source, context); + + simple = g_simple_async_result_new ( + G_OBJECT (source), callback, + user_data, e_load_cal_source_async); + + g_simple_async_result_set_op_res_gpointer ( + simple, context, (GDestroyNotify) + load_cal_source_context_free); + + g_simple_async_result_run_in_thread ( + simple, (GSimpleAsyncThreadFunc) load_cal_source_thread, + G_PRIORITY_DEFAULT, context->cancellable); + + g_object_unref (simple); +} + +/** + * e_load_cal_source_finish: + * @source: an #ESource + * @result: a #GAsyncResult + * @error: return location for a #GError, or %NULL + * + * Finishes an asynchronous #ECal open operation started with + * e_load_cal_source_async(). If an error occurred, or the user + * declined to authenticate, the function will return %NULL and + * set @error. + * + * Returns: a ready-to-use #ECal, or %NULL on error + **/ +ECal * +e_load_cal_source_finish (ESource *source, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + LoadContext *context; + + g_return_val_if_fail (E_IS_SOURCE (source), NULL); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL); + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (source), + e_load_cal_source_async), NULL); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + if (g_simple_async_result_propagate_error (simple, error)) + return NULL; + + context = g_simple_async_result_get_op_res_gpointer (simple); + g_return_val_if_fail (context != NULL, NULL); + + return g_object_ref (context->cal); +} diff --git a/calendar/common/authentication.h b/calendar/common/authentication.h index d48ca3edc2..11b2dc1dfc 100644 --- a/calendar/common/authentication.h +++ b/calendar/common/authentication.h @@ -21,9 +21,10 @@ * */ -#ifndef _AUTHENTICATION_H_ -#define _AUTHENTICATION_H_ +#ifndef AUTHENTICATION_H +#define AUTHENTICATION_H +#include <gtk/gtk.h> #include <libedataserver/e-source.h> #include <libecal/e-cal.h> @@ -31,4 +32,15 @@ ECal *e_auth_new_cal_from_default (ECalSourceType type); ECal *e_auth_new_cal_from_source (ESource *source, ECalSourceType type); void e_auth_cal_forget_password (ECal *ecal); -#endif +void e_load_cal_source_async (ESource *source, + ECalSourceType source_type, + icaltimezone *default_zone, + GtkWindow *parent, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +ECal * e_load_cal_source_finish (ESource *source, + GAsyncResult *result, + GError **error); + +#endif /* AUTHENTICATION_H */ diff --git a/modules/addressbook/e-book-shell-backend.c b/modules/addressbook/e-book-shell-backend.c index 5036796c93..aecc93efb7 100644 --- a/modules/addressbook/e-book-shell-backend.c +++ b/modules/addressbook/e-book-shell-backend.c @@ -228,15 +228,13 @@ action_contact_new_cb (GtkAction *action, /* This callback is used for both contacts and contact lists. */ - /* Dig out the EBookShellBackend's source list. */ shell = e_shell_window_get_shell (shell_window); shell_backend = e_shell_get_backend_by_name (shell, "addressbook"); + g_object_get (shell_backend, "source-list", &source_list, NULL); g_return_if_fail (E_IS_SOURCE_LIST (source_list)); client = e_shell_get_gconf_client (shell); - action_name = gtk_action_get_name (action); - key = "/apps/evolution/addressbook/display/primary_addressbook"; uid = gconf_client_get_string (client, key, NULL); @@ -250,13 +248,14 @@ action_contact_new_cb (GtkAction *action, g_return_if_fail (E_IS_SOURCE (source)); + /* Use a callback function appropriate for the action. */ + action_name = gtk_action_get_name (action); if (strcmp (action_name, "contact-new") == 0) e_load_book_source_async ( source, GTK_WINDOW (shell_window), NULL, (GAsyncReadyCallback) book_shell_backend_new_contact_cb, g_object_ref (shell)); - if (strcmp (action_name, "contact-new-list") == 0) e_load_book_source_async ( source, GTK_WINDOW (shell_window), diff --git a/modules/calendar/e-cal-shell-backend.c b/modules/calendar/e-cal-shell-backend.c index 8861a82cf3..e72626304e 100644 --- a/modules/calendar/e-cal-shell-backend.c +++ b/modules/calendar/e-cal-shell-backend.c @@ -221,20 +221,19 @@ cal_shell_backend_ensure_sources (EShellBackend *shell_backend) } static void -cal_shell_backend_new_event (ECal *cal, - const GError *error, +cal_shell_backend_new_event (ESource *source, + GAsyncResult *result, EShell *shell, CompEditorFlags flags, gboolean all_day) { + ECal *cal; ECalComponent *comp; CompEditor *editor; /* XXX Handle errors better. */ - if (error) - return; - - flags |= COMP_EDITOR_NEW_ITEM; + cal = e_load_cal_source_finish (source, result, NULL); + g_return_if_fail (E_IS_CAL (cal)); editor = event_editor_new (cal, shell, flags); comp = cal_comp_event_new_with_current_time (cal, all_day); @@ -244,68 +243,77 @@ cal_shell_backend_new_event (ECal *cal, gtk_window_present (GTK_WINDOW (editor)); g_object_unref (comp); + g_object_unref (cal); } static void -cal_shell_backend_event_new_cb (ECal *cal, - const GError *error, +cal_shell_backend_event_new_cb (ESource *source, + GAsyncResult *result, EShell *shell) { - CompEditorFlags flags; + CompEditorFlags flags = 0; + gboolean all_day = FALSE; - flags = COMP_EDITOR_USER_ORG; - cal_shell_backend_new_event (cal, error, shell, flags, FALSE); + flags |= COMP_EDITOR_NEW_ITEM; + flags |= COMP_EDITOR_USER_ORG; - g_object_unref (cal); + cal_shell_backend_new_event (source, result, shell, flags, all_day); + + g_object_unref (shell); } static void -cal_shell_backend_event_all_day_new_cb (ECal *cal, - const GError *error, +cal_shell_backend_event_all_day_new_cb (ESource *source, + GAsyncResult *result, EShell *shell) { - CompEditorFlags flags; + CompEditorFlags flags = 0; + gboolean all_day = TRUE; - flags = COMP_EDITOR_USER_ORG; - cal_shell_backend_new_event (cal, error, shell, flags, TRUE); + flags |= COMP_EDITOR_NEW_ITEM; + flags |= COMP_EDITOR_USER_ORG; - g_object_unref (cal); + cal_shell_backend_new_event (source, result, shell, flags, all_day); + + g_object_unref (shell); } static void -cal_shell_backend_event_meeting_new_cb (ECal *cal, - const GError *error, +cal_shell_backend_event_meeting_new_cb (ESource *source, + GAsyncResult *result, EShell *shell) { - CompEditorFlags flags; + CompEditorFlags flags = 0; + gboolean all_day = FALSE; - flags = COMP_EDITOR_USER_ORG | COMP_EDITOR_MEETING; - cal_shell_backend_new_event (cal, error, shell, flags, FALSE); + flags |= COMP_EDITOR_NEW_ITEM; + flags |= COMP_EDITOR_USER_ORG; + flags |= COMP_EDITOR_MEETING; - g_object_unref (cal); + cal_shell_backend_new_event (source, result, shell, flags, all_day); + + g_object_unref (shell); } static void action_event_new_cb (GtkAction *action, EShellWindow *shell_window) { - ECal *cal = NULL; - ECalSourceType source_type; - ESourceList *source_list; - EShellSettings *shell_settings; - EShellView *shell_view; EShell *shell; - const gchar *view_name; + EShellView *shell_view; + EShellBackend *shell_backend; + EShellSettings *shell_settings; + ESource *source = NULL; + ESourceList *source_list; + ECalSourceType source_type; const gchar *action_name; gchar *uid; /* With a 'calendar' active shell view pass the new appointment * request to it, thus the event will inherit selected time from * the view. */ - view_name = e_shell_window_get_active_view (shell_window); - shell_view = e_shell_window_get_shell_view (shell_window, view_name); - - if (shell_view && g_ascii_strcasecmp (view_name, "calendar") == 0) { + shell_view = e_shell_window_peek_shell_view (shell_window, "calendar"); + if (shell_view != NULL) { EShellContent *shell_content; GnomeCalendar *gcal; GnomeCalendarViewType view_type; @@ -338,48 +346,50 @@ action_event_new_cb (GtkAction *action, shell = e_shell_window_get_shell (shell_window); shell_settings = e_shell_get_shell_settings (shell); + shell_backend = e_shell_get_backend_by_name (shell, "calendar"); - if (!e_cal_get_sources (&source_list, source_type, NULL)) { - g_warning ("Could not get calendar sources from GConf!"); - return; - } + g_object_get (shell_backend, "source-list", &source_list, NULL); + g_return_if_fail (E_IS_SOURCE_LIST (source_list)); uid = e_shell_settings_get_string ( shell_settings, "cal-primary-calendar"); if (uid != NULL) { - ESource *source; - source = e_source_list_peek_source_by_uid (source_list, uid); - if (source != NULL) - cal = e_auth_new_cal_from_source (source, source_type); g_free (uid); } - if (cal == NULL) - cal = e_auth_new_cal_from_default (source_type); + if (source == NULL) + source = e_source_list_peek_default_source (source_list); - g_return_if_fail (cal != NULL); + g_return_if_fail (E_IS_SOURCE (source)); - /* Connect the appropriate signal handler. */ + /* Use a callback function appropriate for the action. + * FIXME Need to obtain a better default time zone. */ action_name = gtk_action_get_name (action); if (strcmp (action_name, "event-all-day-new") == 0) - g_signal_connect ( - cal, "cal-opened-ex", - G_CALLBACK (cal_shell_backend_event_all_day_new_cb), - shell); + e_load_cal_source_async ( + source, source_type, NULL, + GTK_WINDOW (shell_window), + NULL, (GAsyncReadyCallback) + cal_shell_backend_event_all_day_new_cb, + g_object_ref (shell)); else if (strcmp (action_name, "event-meeting-new") == 0) - g_signal_connect ( - cal, "cal-opened-ex", - G_CALLBACK (cal_shell_backend_event_meeting_new_cb), - shell); + e_load_cal_source_async ( + source, source_type, NULL, + GTK_WINDOW (shell_window), + NULL, (GAsyncReadyCallback) + cal_shell_backend_event_meeting_new_cb, + g_object_ref (shell)); else - g_signal_connect ( - cal, "cal-opened-ex", - G_CALLBACK (cal_shell_backend_event_new_cb), - shell); + e_load_cal_source_async ( + source, source_type, NULL, + GTK_WINDOW (shell_window), + NULL, (GAsyncReadyCallback) + cal_shell_backend_event_new_cb, + g_object_ref (shell)); - e_cal_open_async (cal, FALSE); + g_object_unref (source_list); } static void diff --git a/modules/calendar/e-cal-shell-sidebar.c b/modules/calendar/e-cal-shell-sidebar.c index 1cd4ba9619..a819d88473 100644 --- a/modules/calendar/e-cal-shell-sidebar.c +++ b/modules/calendar/e-cal-shell-sidebar.c @@ -59,6 +59,8 @@ struct _ECalShellSidebarPrivate { * sometime later we update our default-client property * which is bound by an EBinding to ECalModel. */ ECal *default_client; + + GCancellable *loading_default_client; }; enum { @@ -241,104 +243,106 @@ cal_shell_sidebar_client_opened_cb (ECalShellSidebar *cal_shell_sidebar, } static void -cal_shell_sidebar_default_opened_cb (ECalShellSidebar *cal_shell_sidebar, - const GError *error, - ECal *client) +cal_shell_sidebar_default_loaded_cb (ESource *source, + GAsyncResult *result, + EShellSidebar *shell_sidebar) { + ECalShellSidebarPrivate *priv; + EShellWindow *shell_window; EShellView *shell_view; - EShellSidebar *shell_sidebar; + ECal *client; + GError *error = NULL; + + priv = E_CAL_SHELL_SIDEBAR_GET_PRIVATE (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 (g_error_matches (error, E_CALENDAR_ERROR, - E_CALENDAR_STATUS_AUTHENTICATION_FAILED) || - g_error_matches (error, E_CALENDAR_ERROR, - E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED)) - e_auth_cal_forget_password (client); + client = e_load_cal_source_finish (source, result, &error); - /* Handle errors. */ - switch (error ? error->code : E_CALENDAR_STATUS_OK) { - case E_CALENDAR_STATUS_OK: - break; + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + g_error_free (error); + goto exit; - case E_CALENDAR_STATUS_AUTHENTICATION_FAILED: - e_cal_open_async (client, FALSE); - return; + } else if (error != NULL) { + e_alert_run_dialog_for_args ( + GTK_WINDOW (shell_window), + "calendar:failed-open-calendar", + error->message, NULL); + g_error_free (error); + goto exit; + } - case E_CALENDAR_STATUS_BUSY: - return; + g_return_if_fail (E_IS_CAL (client)); - default: - e_alert_run_dialog_for_args ( - GTK_WINDOW (e_shell_view_get_shell_window (shell_view)), - "calendar:failed-open-calendar", - error->message, NULL); + if (priv->default_client != NULL) + g_object_unref (priv->default_client); - e_cal_shell_sidebar_remove_source ( - cal_shell_sidebar, - e_cal_get_source (client)); - return; - } + priv->default_client = client; - g_assert (error == NULL); + g_object_notify (G_OBJECT (shell_sidebar), "default-client"); - 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"); +exit: + g_object_unref (shell_sidebar); } static void cal_shell_sidebar_set_default (ECalShellSidebar *cal_shell_sidebar, ESource *source) { + ECalShellSidebarPrivate *priv; EShellView *shell_view; + EShellWindow *shell_window; EShellContent *shell_content; EShellSidebar *shell_sidebar; ECalShellContent *cal_shell_content; ECalSourceType source_type; - GHashTable *client_table; ECalModel *model; ECal *client; icaltimezone *timezone; const gchar *uid; + priv = cal_shell_sidebar->priv; 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-ex", - G_CALLBACK (cal_shell_sidebar_default_opened_cb), - cal_shell_sidebar); /* FIXME Sidebar should not be accessing the EShellContent. * This probably needs to be moved to ECalShellView. */ shell_sidebar = E_SHELL_SIDEBAR (cal_shell_sidebar); shell_view = e_shell_sidebar_get_shell_view (shell_sidebar); shell_content = e_shell_view_get_shell_content (shell_view); + shell_window = e_shell_view_get_shell_window (shell_view); cal_shell_content = E_CAL_SHELL_CONTENT (shell_content); model = e_cal_shell_content_get_model (cal_shell_content); timezone = e_cal_model_get_timezone (model); - e_cal_set_default_timezone (client, timezone, NULL); - e_cal_open_async (client, FALSE); + /* Cancel any unfinished previous request. */ + if (priv->loading_default_client != NULL) { + g_cancellable_cancel (priv->loading_default_client); + g_object_unref (priv->loading_default_client); + priv->loading_default_client = NULL; + } + + uid = e_source_peek_uid (source); + client = g_hash_table_lookup (priv->client_table, uid); + + /* If we already have an open connection for + * this UID, we can finish immediately. */ + if (client != NULL) { + if (priv->default_client != NULL) + g_object_unref (priv->default_client); + priv->default_client = g_object_ref (client); + g_object_notify (G_OBJECT (shell_sidebar), "default-client"); + return; + } + + priv->loading_default_client = g_cancellable_new (); + + e_load_cal_source_async ( + source, source_type, timezone, + GTK_WINDOW (shell_window), priv->loading_default_client, + (GAsyncReadyCallback) cal_shell_sidebar_default_loaded_cb, + g_object_ref (shell_sidebar)); } static void @@ -572,6 +576,12 @@ cal_shell_sidebar_dispose (GObject *object) priv->default_client = NULL; } + if (priv->loading_default_client != NULL) { + g_cancellable_cancel (priv->loading_default_client); + g_object_unref (priv->loading_default_client); + priv->loading_default_client = NULL; + } + g_hash_table_remove_all (priv->client_table); /* Chain up to parent's dispose() method. */ diff --git a/modules/calendar/e-memo-shell-backend.c b/modules/calendar/e-memo-shell-backend.c index 8f5bf40825..d54c32f98e 100644 --- a/modules/calendar/e-memo-shell-backend.c +++ b/modules/calendar/e-memo-shell-backend.c @@ -153,19 +153,18 @@ memo_shell_backend_ensure_sources (EShellBackend *shell_backend) } static void -memo_shell_backend_memo_new_cb (ECal *cal, - const GError *error, - EShell *shell) +memo_shell_backend_new_memo (ESource *source, + GAsyncResult *result, + EShell *shell, + CompEditorFlags flags) { + ECal *cal; ECalComponent *comp; CompEditor *editor; - CompEditorFlags flags = 0; /* XXX Handle errors better. */ - if (error) - return; - - flags |= COMP_EDITOR_NEW_ITEM; + cal = e_load_cal_source_finish (source, result, NULL); + g_return_if_fail (E_IS_CAL (cal)); comp = cal_comp_memo_new_with_defaults (cal); cal_comp_update_time_by_active_window (comp, shell); @@ -179,42 +178,45 @@ memo_shell_backend_memo_new_cb (ECal *cal, } static void -memo_shell_backend_memo_shared_new_cb (ECal *cal, - const GError *error, - EShell *shell) +memo_shell_backend_memo_new_cb (ESource *source, + GAsyncResult *result, + EShell *shell) { - ECalComponent *comp; - CompEditor *editor; CompEditorFlags flags = 0; - /* XXX Handle errors better. */ - if (error) - return; + flags |= COMP_EDITOR_NEW_ITEM; + + memo_shell_backend_new_memo (source, result, shell, flags); + + g_object_unref (shell); +} + +static void +memo_shell_backend_memo_shared_new_cb (ESource *source, + GAsyncResult *result, + EShell *shell) +{ + CompEditorFlags flags = 0; flags |= COMP_EDITOR_NEW_ITEM; flags |= COMP_EDITOR_IS_SHARED; flags |= COMP_EDITOR_USER_ORG; - comp = cal_comp_memo_new_with_defaults (cal); - cal_comp_update_time_by_active_window (comp, shell); - editor = memo_editor_new (cal, shell, flags); - comp_editor_edit_comp (editor, comp); - - gtk_window_present (GTK_WINDOW (editor)); + memo_shell_backend_new_memo (source, result, shell, flags); - g_object_unref (comp); - g_object_unref (cal); + g_object_unref (shell); } static void action_memo_new_cb (GtkAction *action, EShellWindow *shell_window) { - ECal *cal = NULL; - ECalSourceType source_type; - ESourceList *source_list; - EShellSettings *shell_settings; EShell *shell; + EShellBackend *shell_backend; + EShellSettings *shell_settings; + ESource *source = NULL; + ESourceList *source_list; + ECalSourceType source_type; const gchar *action_name; gchar *uid; @@ -224,43 +226,43 @@ action_memo_new_cb (GtkAction *action, shell = e_shell_window_get_shell (shell_window); shell_settings = e_shell_get_shell_settings (shell); + shell_backend = e_shell_get_backend_by_name (shell, "memos"); - if (!e_cal_get_sources (&source_list, source_type, NULL)) { - g_warning ("Could not get memo sources from GConf!"); - return; - } + g_object_get (shell_backend, "source-list", &source_list, NULL); + g_return_if_fail (E_IS_SOURCE_LIST (source_list)); uid = e_shell_settings_get_string ( shell_settings, "cal-primary-memo-list"); if (uid != NULL) { - ESource *source; - source = e_source_list_peek_source_by_uid (source_list, uid); - if (source != NULL) - cal = e_auth_new_cal_from_source (source, source_type); g_free (uid); } - if (cal == NULL) - cal = e_auth_new_cal_from_default (source_type); + if (source == NULL) + source = e_source_list_peek_default_source (source_list); - g_return_if_fail (cal != NULL); + g_return_if_fail (E_IS_SOURCE (source)); - /* Connect the appropriate signal handler. */ + /* Use a callback function appropriate for the action. + * FIXME Need to obtain a better default time zone. */ action_name = gtk_action_get_name (action); - if (strcmp (action_name, "memo-shared-new") == 0) - g_signal_connect ( - cal, "cal-opened-ex", - G_CALLBACK (memo_shell_backend_memo_shared_new_cb), - shell); + if (g_strcmp0 (action_name, "memo-shared-new") == 0) + e_load_cal_source_async ( + source, source_type, NULL, + GTK_WINDOW (shell_window), + NULL, (GAsyncReadyCallback) + memo_shell_backend_memo_shared_new_cb, + g_object_ref (shell)); else - g_signal_connect ( - cal, "cal-opened-ex", - G_CALLBACK (memo_shell_backend_memo_new_cb), - shell); + e_load_cal_source_async ( + source, source_type, NULL, + GTK_WINDOW (shell_window), + NULL, (GAsyncReadyCallback) + memo_shell_backend_memo_new_cb, + g_object_ref (shell)); - e_cal_open_async (cal, FALSE); + g_object_unref (source_list); } static void diff --git a/modules/calendar/e-memo-shell-sidebar.c b/modules/calendar/e-memo-shell-sidebar.c index 7b4b8f71b6..f463394fbd 100644 --- a/modules/calendar/e-memo-shell-sidebar.c +++ b/modules/calendar/e-memo-shell-sidebar.c @@ -54,6 +54,8 @@ struct _EMemoShellSidebarPrivate { * sometime later we update our default-client property * which is bound by an EBinding to ECalModel. */ ECal *default_client; + + GCancellable *loading_default_client; }; enum { @@ -235,104 +237,106 @@ memo_shell_sidebar_client_opened_cb (EMemoShellSidebar *memo_shell_sidebar, } static void -memo_shell_sidebar_default_opened_cb (EMemoShellSidebar *memo_shell_sidebar, - const GError *error, - ECal *client) +memo_shell_sidebar_default_loaded_cb (ESource *source, + GAsyncResult *result, + EShellSidebar *shell_sidebar) { + EMemoShellSidebarPrivate *priv; + EShellWindow *shell_window; EShellView *shell_view; - EShellSidebar *shell_sidebar; + ECal *client; + GError *error = NULL; + + priv = E_MEMO_SHELL_SIDEBAR_GET_PRIVATE (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 (g_error_matches (error, E_CALENDAR_ERROR, - E_CALENDAR_STATUS_AUTHENTICATION_FAILED) || - g_error_matches (error, E_CALENDAR_ERROR, - E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED)) - e_auth_cal_forget_password (client); + client = e_load_cal_source_finish (source, result, &error); - /* Handle errors. */ - switch (error ? error->code : E_CALENDAR_STATUS_OK) { - case E_CALENDAR_STATUS_OK: - break; + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + g_error_free (error); + goto exit; - case E_CALENDAR_STATUS_AUTHENTICATION_FAILED: - e_cal_open_async (client, FALSE); - return; + } else if (error != NULL) { + e_alert_run_dialog_for_args ( + GTK_WINDOW (shell_window), + "calendar:failed-open-memos", + error->message, NULL); + g_error_free (error); + goto exit; + } - case E_CALENDAR_STATUS_BUSY: - return; + g_return_if_fail (E_IS_CAL (client)); - default: - e_alert_run_dialog_for_args ( - GTK_WINDOW (e_shell_view_get_shell_window (shell_view)), - "calendar:failed-open-memos", - error->message, NULL); + if (priv->default_client != NULL) + g_object_unref (priv->default_client); - e_memo_shell_sidebar_remove_source ( - memo_shell_sidebar, - e_cal_get_source (client)); - return; - } + priv->default_client = client; - g_assert (error == NULL); + g_object_notify (G_OBJECT (shell_sidebar), "default-client"); - 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"); +exit: + g_object_unref (shell_sidebar); } static void memo_shell_sidebar_set_default (EMemoShellSidebar *memo_shell_sidebar, ESource *source) { + EMemoShellSidebarPrivate *priv; EShellView *shell_view; + EShellWindow *shell_window; EShellContent *shell_content; EShellSidebar *shell_sidebar; EMemoShellContent *memo_shell_content; ECalSourceType source_type; - GHashTable *client_table; ECalModel *model; ECal *client; icaltimezone *timezone; const gchar *uid; + priv = memo_shell_sidebar->priv; 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-ex", - G_CALLBACK (memo_shell_sidebar_default_opened_cb), - memo_shell_sidebar); /* FIXME Sidebar should not be accessing the EShellContent. * This probably needs to be moved to EMemoShellView. */ shell_sidebar = E_SHELL_SIDEBAR (memo_shell_sidebar); shell_view = e_shell_sidebar_get_shell_view (shell_sidebar); shell_content = e_shell_view_get_shell_content (shell_view); + shell_window = e_shell_view_get_shell_window (shell_view); memo_shell_content = E_MEMO_SHELL_CONTENT (shell_content); model = e_memo_shell_content_get_memo_model (memo_shell_content); timezone = e_cal_model_get_timezone (model); - e_cal_set_default_timezone (client, timezone, NULL); - e_cal_open_async (client, FALSE); + /* Cancel any unfinished previous request. */ + if (priv->loading_default_client != NULL) { + g_cancellable_cancel (priv->loading_default_client); + g_object_unref (priv->loading_default_client); + priv->loading_default_client = NULL; + } + + uid = e_source_peek_uid (source); + client = g_hash_table_lookup (priv->client_table, uid); + + /* If we already have an open connection for + * this UID, we can finish immediately. */ + if (client != NULL) { + if (priv->default_client != NULL) + g_object_unref (priv->default_client); + priv->default_client = g_object_ref (client); + g_object_notify (G_OBJECT (shell_sidebar), "default-client"); + return; + } + + priv->loading_default_client = g_cancellable_new (); + + e_load_cal_source_async ( + source, source_type, timezone, + GTK_WINDOW (shell_window), priv->loading_default_client, + (GAsyncReadyCallback) memo_shell_sidebar_default_loaded_cb, + g_object_ref (shell_sidebar)); } static void @@ -538,6 +542,12 @@ memo_shell_sidebar_dispose (GObject *object) priv->default_client = NULL; } + if (priv->loading_default_client != NULL) { + g_cancellable_cancel (priv->loading_default_client); + g_object_unref (priv->loading_default_client); + priv->loading_default_client = NULL; + } + g_hash_table_remove_all (priv->client_table); /* Chain up to parent's dispose() method. */ diff --git a/modules/calendar/e-task-shell-backend.c b/modules/calendar/e-task-shell-backend.c index cdd4dcc608..be085afa8d 100644 --- a/modules/calendar/e-task-shell-backend.c +++ b/modules/calendar/e-task-shell-backend.c @@ -153,19 +153,18 @@ task_shell_backend_ensure_sources (EShellBackend *shell_backend) } static void -task_shell_backend_task_new_cb (ECal *cal, - const GError *error, - EShell *shell) +task_shell_backend_new_task (ESource *source, + GAsyncResult *result, + EShell *shell, + CompEditorFlags flags) { + ECal *cal; ECalComponent *comp; CompEditor *editor; - CompEditorFlags flags = 0; /* XXX Handle errors better. */ - if (error) - return; - - flags |= COMP_EDITOR_NEW_ITEM; + cal = e_load_cal_source_finish (source, result, NULL); + g_return_if_fail (E_IS_CAL (cal)); editor = task_editor_new (cal, shell, flags); comp = cal_comp_task_new_with_defaults (cal); @@ -178,41 +177,45 @@ task_shell_backend_task_new_cb (ECal *cal, } static void -task_shell_backend_task_assigned_new_cb (ECal *cal, - const GError *error, - EShell *shell) +task_shell_backend_task_new_cb (ESource *source, + GAsyncResult *result, + EShell *shell) { - ECalComponent *comp; - CompEditor *editor; CompEditorFlags flags = 0; - /* XXX Handle errors better. */ - if (error) - return; + flags |= COMP_EDITOR_NEW_ITEM; + + task_shell_backend_new_task (source, result, shell, flags); + + g_object_unref (shell); +} + +static void +task_shell_backend_task_assigned_new_cb (ESource *source, + GAsyncResult *result, + EShell *shell) +{ + CompEditorFlags flags = 0; flags |= COMP_EDITOR_NEW_ITEM; flags |= COMP_EDITOR_IS_ASSIGNED; flags |= COMP_EDITOR_USER_ORG; - editor = task_editor_new (cal, shell, flags); - comp = cal_comp_task_new_with_defaults (cal); - comp_editor_edit_comp (editor, comp); + task_shell_backend_new_task (source, result, shell, flags); - gtk_window_present (GTK_WINDOW (editor)); - - g_object_unref (comp); - g_object_unref (cal); + g_object_unref (shell); } static void action_task_new_cb (GtkAction *action, EShellWindow *shell_window) { - ECal *cal = NULL; - ECalSourceType source_type; - ESourceList *source_list; - EShellSettings *shell_settings; EShell *shell; + EShellBackend *shell_backend; + EShellSettings *shell_settings; + ESource *source = NULL; + ESourceList *source_list; + ECalSourceType source_type; const gchar *action_name; gchar *uid; @@ -222,43 +225,43 @@ action_task_new_cb (GtkAction *action, shell = e_shell_window_get_shell (shell_window); shell_settings = e_shell_get_shell_settings (shell); + shell_backend = e_shell_get_backend_by_name (shell, "tasks"); - if (!e_cal_get_sources (&source_list, source_type, NULL)) { - g_warning ("Could not get task sources from GConf!"); - return; - } + g_object_get (shell_backend, "source-list", &source_list, NULL); + g_return_if_fail (E_IS_SOURCE_LIST (source_list)); uid = e_shell_settings_get_string ( shell_settings, "cal-primary-task-list"); if (uid != NULL) { - ESource *source; - source = e_source_list_peek_source_by_uid (source_list, uid); - if (source != NULL) - cal = e_auth_new_cal_from_source (source, source_type); g_free (uid); } - if (cal == NULL) - cal = e_auth_new_cal_from_default (source_type); + if (source == NULL) + source = e_source_list_peek_default_source (source_list); - g_return_if_fail (cal != NULL); + g_return_if_fail (E_IS_SOURCE (source)); - /* Connect the appropriate signal handler. */ + /* Use a callback function appropriate for the action. + * FIXME Need to obtain a better default time zone. */ action_name = gtk_action_get_name (action); if (strcmp (action_name, "task-assigned-new") == 0) - g_signal_connect ( - cal, "cal-opened-ex", - G_CALLBACK (task_shell_backend_task_assigned_new_cb), - shell); + e_load_cal_source_async ( + source, source_type, NULL, + GTK_WINDOW (shell_window), + NULL, (GAsyncReadyCallback) + task_shell_backend_task_assigned_new_cb, + g_object_ref (shell)); else - g_signal_connect ( - cal, "cal-opened-ex", - G_CALLBACK (task_shell_backend_task_new_cb), - shell); + e_load_cal_source_async ( + source, source_type, NULL, + GTK_WINDOW (shell_window), + NULL, (GAsyncReadyCallback) + task_shell_backend_task_new_cb, + g_object_ref (shell)); - e_cal_open_async (cal, FALSE); + g_object_unref (source_list); } static void diff --git a/modules/calendar/e-task-shell-sidebar.c b/modules/calendar/e-task-shell-sidebar.c index 8613b4eb0f..b50e463e8a 100644 --- a/modules/calendar/e-task-shell-sidebar.c +++ b/modules/calendar/e-task-shell-sidebar.c @@ -54,6 +54,8 @@ struct _ETaskShellSidebarPrivate { * sometime later we update our default-client property * which is bound by an EBinding to ECalModel. */ ECal *default_client; + + GCancellable *loading_default_client; }; enum { @@ -235,104 +237,106 @@ task_shell_sidebar_client_opened_cb (ETaskShellSidebar *task_shell_sidebar, } static void -task_shell_sidebar_default_opened_cb (ETaskShellSidebar *task_shell_sidebar, - const GError *error, - ECal *client) +task_shell_sidebar_default_loaded_cb (ESource *source, + GAsyncResult *result, + EShellSidebar *shell_sidebar) { + ETaskShellSidebarPrivate *priv; + EShellWindow *shell_window; EShellView *shell_view; - EShellSidebar *shell_sidebar; + ECal *client; + GError *error = NULL; + + priv = E_TASK_SHELL_SIDEBAR_GET_PRIVATE (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 (g_error_matches (error, E_CALENDAR_ERROR, - E_CALENDAR_STATUS_AUTHENTICATION_FAILED) || - g_error_matches (error, E_CALENDAR_ERROR, - E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED)) - e_auth_cal_forget_password (client); + client = e_load_cal_source_finish (source, result, &error); - /* Handle errors. */ - switch (error ? error->code : E_CALENDAR_STATUS_OK) { - case E_CALENDAR_STATUS_OK: - break; + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + g_error_free (error); + goto exit; - case E_CALENDAR_STATUS_AUTHENTICATION_FAILED: - e_cal_open_async (client, FALSE); - return; + } else if (error != NULL) { + e_alert_run_dialog_for_args ( + GTK_WINDOW (shell_window), + "calendar:failed-open-tasks", + error->message, NULL); + g_error_free (error); + goto exit; + } - case E_CALENDAR_STATUS_BUSY: - return; + g_return_if_fail (E_IS_CAL (client)); - default: - e_alert_run_dialog_for_args ( - GTK_WINDOW (e_shell_view_get_shell_window (shell_view)), - "calendar:failed-open-tasks", - error->message, NULL); + if (priv->default_client != NULL) + g_object_unref (priv->default_client); - e_task_shell_sidebar_remove_source ( - task_shell_sidebar, - e_cal_get_source (client)); - return; - } + priv->default_client = client; - g_assert (error == NULL); + g_object_notify (G_OBJECT (shell_sidebar), "default-client"); - 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"); +exit: + g_object_unref (shell_sidebar); } static void task_shell_sidebar_set_default (ETaskShellSidebar *task_shell_sidebar, ESource *source) { + ETaskShellSidebarPrivate *priv; EShellView *shell_view; + EShellWindow *shell_window; EShellContent *shell_content; EShellSidebar *shell_sidebar; ETaskShellContent *task_shell_content; ECalSourceType source_type; - GHashTable *client_table; ECalModel *model; ECal *client; icaltimezone *timezone; const gchar *uid; + priv = task_shell_sidebar->priv; 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-ex", - G_CALLBACK (task_shell_sidebar_default_opened_cb), - task_shell_sidebar); /* FIXME Sidebar should not be accessing the EShellContent. * This probably needs to be moved to ETaskShellView. */ shell_sidebar = E_SHELL_SIDEBAR (task_shell_sidebar); shell_view = e_shell_sidebar_get_shell_view (shell_sidebar); shell_content = e_shell_view_get_shell_content (shell_view); + shell_window = e_shell_view_get_shell_window (shell_view); task_shell_content = E_TASK_SHELL_CONTENT (shell_content); model = e_task_shell_content_get_task_model (task_shell_content); timezone = e_cal_model_get_timezone (model); - e_cal_set_default_timezone (client, timezone, NULL); - e_cal_open_async (client, FALSE); + /* Cancel any unfinished previous request. */ + if (priv->loading_default_client != NULL) { + g_cancellable_cancel (priv->loading_default_client); + g_object_unref (priv->loading_default_client); + priv->loading_default_client = NULL; + } + + uid = e_source_peek_uid (source); + client = g_hash_table_lookup (priv->client_table, uid); + + /* If we already have an open connection for + * this UID, we can finish immediately. */ + if (client != NULL) { + if (priv->default_client != NULL) + g_object_unref (priv->default_client); + priv->default_client = g_object_ref (client); + g_object_notify (G_OBJECT (shell_sidebar), "default-client"); + return; + } + + priv->loading_default_client = g_cancellable_new (); + + e_load_cal_source_async ( + source, source_type, timezone, + GTK_WINDOW (shell_window), priv->loading_default_client, + (GAsyncReadyCallback) task_shell_sidebar_default_loaded_cb, + g_object_ref (shell_sidebar)); } static void @@ -538,6 +542,12 @@ task_shell_sidebar_dispose (GObject *object) priv->default_client = NULL; } + if (priv->loading_default_client != NULL) { + g_cancellable_cancel (priv->loading_default_client); + g_object_unref (priv->loading_default_client); + priv->loading_default_client = NULL; + } + g_hash_table_remove_all (priv->client_table); /* Chain up to parent's dispose() method. */ |