[evolution] Bug 795870 - Add a way to initiate refresh of account sources



commit 1a05ba089e9b3dd6dde675f25f11a295c5ad043f
Author: Milan Crha <mcrha redhat com>
Date:   Fri Jun 8 10:36:16 2018 +0200

    Bug 795870 - Add a way to initiate refresh of account sources

 data/ui/evolution-calendars.ui                     |   1 +
 data/ui/evolution-contacts.ui                      |   1 +
 data/ui/evolution-memos.ui                         |   1 +
 data/ui/evolution-tasks.ui                         |   1 +
 src/addressbook/addressbook.error.xml              |   5 +
 src/e-util/e-accounts-window.c                     |  45 ++++++
 src/e-util/e-system.error.xml                      |   5 +
 src/modules/addressbook/e-book-shell-sidebar.c     |   7 +-
 src/modules/addressbook/e-book-shell-sidebar.h     |   4 +-
 .../addressbook/e-book-shell-view-actions.c        |  82 ++++++++++
 .../addressbook/e-book-shell-view-actions.h        |   2 +
 .../addressbook/e-book-shell-view-private.c        | 115 +++++++------
 .../addressbook/e-book-shell-view-private.h        |   2 +
 src/modules/addressbook/e-book-shell-view.c        |  81 ++++++++--
 src/modules/addressbook/e-book-shell-view.h        |   1 +
 src/modules/calendar/e-cal-base-shell-sidebar.c    |   7 +-
 src/modules/calendar/e-cal-base-shell-sidebar.h    |   4 +-
 src/modules/calendar/e-cal-base-shell-view.c       | 179 ++++++++++++++++++++-
 src/modules/calendar/e-cal-base-shell-view.h       |   8 +
 src/modules/calendar/e-cal-shell-view-actions.c    |  25 +++
 src/modules/calendar/e-cal-shell-view-actions.h    |   2 +
 src/modules/calendar/e-cal-shell-view-private.c    |  21 +--
 src/modules/calendar/e-cal-shell-view.c            |  36 ++++-
 src/modules/calendar/e-memo-shell-view-actions.c   |  25 +++
 src/modules/calendar/e-memo-shell-view-actions.h   |   2 +
 src/modules/calendar/e-memo-shell-view-private.c   |  12 +-
 src/modules/calendar/e-memo-shell-view.c           |  38 ++++-
 src/modules/calendar/e-task-shell-view-actions.c   |  25 +++
 src/modules/calendar/e-task-shell-view-actions.h   |   2 +
 src/modules/calendar/e-task-shell-view-private.c   |  12 +-
 src/modules/calendar/e-task-shell-view.c           |  36 ++++-
 src/plugins/save-calendar/save-calendar.c          |  30 +++-
 32 files changed, 698 insertions(+), 119 deletions(-)
---
diff --git a/data/ui/evolution-calendars.ui b/data/ui/evolution-calendars.ui
index 20dbe465fd..fbb97982dc 100644
--- a/data/ui/evolution-calendars.ui
+++ b/data/ui/evolution-calendars.ui
@@ -65,6 +65,7 @@
     <menuitem action='calendar-popup-copy'/>
     <menuitem action='calendar-popup-rename'/>
     <menuitem action='calendar-popup-refresh'/>
+    <menuitem action='calendar-popup-refresh-backend'/>
     <separator/>
     <menuitem action='calendar-popup-delete'/>
     <menuitem action='calendar-popup-select-one'/>
diff --git a/data/ui/evolution-contacts.ui b/data/ui/evolution-contacts.ui
index 1e2679c7be..233a388de6 100644
--- a/data/ui/evolution-contacts.ui
+++ b/data/ui/evolution-contacts.ui
@@ -61,6 +61,7 @@
     <menuitem action='address-book-new'/>
     <menuitem action='address-book-popup-rename'/>
     <menuitem action='address-book-popup-refresh'/>
+    <menuitem action='address-book-popup-refresh-backend'/>
     <menuitem action='address-book-popup-save-as'/>
     <separator/>
     <menuitem action='address-book-popup-delete'/>
diff --git a/data/ui/evolution-memos.ui b/data/ui/evolution-memos.ui
index 6ad5399a3e..1e8fc428ad 100644
--- a/data/ui/evolution-memos.ui
+++ b/data/ui/evolution-memos.ui
@@ -62,6 +62,7 @@
     <menuitem action='memo-list-popup-copy'/>
     <menuitem action='memo-list-popup-rename'/>
     <menuitem action='memo-list-popup-refresh'/>
+    <menuitem action='memo-list-popup-refresh-backend'/>
     <separator/>
     <menuitem action='memo-list-popup-delete'/>
     <menuitem action='memo-list-popup-select-one'/>
diff --git a/data/ui/evolution-tasks.ui b/data/ui/evolution-tasks.ui
index 494f271d65..4d10964f8f 100644
--- a/data/ui/evolution-tasks.ui
+++ b/data/ui/evolution-tasks.ui
@@ -75,6 +75,7 @@
     <menuitem action='task-list-popup-copy'/>
     <menuitem action='task-list-popup-rename'/>
     <menuitem action='task-list-popup-refresh'/>
+    <menuitem action='task-list-popup-refresh-backend'/>
     <separator/>
     <menuitem action='task-list-popup-delete'/>
     <menuitem action='task-list-popup-select-one'/>
diff --git a/src/addressbook/addressbook.error.xml b/src/addressbook/addressbook.error.xml
index 753072b103..73af31e4f1 100644
--- a/src/addressbook/addressbook.error.xml
+++ b/src/addressbook/addressbook.error.xml
@@ -141,4 +141,9 @@
     <_secondary>A WebKitWebProcess crashed when displaying the contact. You can try again by moving to 
another contact and back. If the issue persists, please file a bug report in the GNOME bugzilla.</_secondary>
   </error>
 
+  <error id="refresh-backend-failed" type="error">
+    <_primary>Failed to refresh list of account address books</_primary>
+    <secondary>{1}</secondary>
+  </error>
+
 </error-list>
diff --git a/src/e-util/e-accounts-window.c b/src/e-util/e-accounts-window.c
index de99e1b525..e57c49b4db 100644
--- a/src/e-util/e-accounts-window.c
+++ b/src/e-util/e-accounts-window.c
@@ -59,6 +59,7 @@ struct _EAccountsWindowPrivate {
        GtkWidget *add_box;             /* not referenced */
        GtkWidget *edit_button;         /* not referenced */
        GtkWidget *delete_button;       /* not referenced */
+       GtkWidget *refresh_backend_button;      /* not referenced */
 
        GHashTable *references; /* gchar *UID ~> GtkTreeRowReference * */
        gchar *select_source_uid; /* Which source to select, or NULL */
@@ -177,6 +178,39 @@ accounts_window_emit_delete_source (EAccountsWindow *accounts_window)
        }
 }
 
+static void
+accounts_window_refresh_backend_done_cb (GObject *source_object,
+                                        GAsyncResult *result,
+                                        gpointer user_data)
+{
+       GError *error = NULL;
+
+       if (!e_source_registry_refresh_backend_finish (E_SOURCE_REGISTRY (source_object), result, &error)) {
+               g_warning ("%s: Failed to refresh backend: %s", G_STRFUNC, error ? error->message : "Unknown 
error");
+       }
+
+       g_clear_error (&error);
+}
+
+static void
+accounts_window_refresh_backend_cb (EAccountsWindow *accounts_window)
+{
+       ESource *source;
+
+       source = e_accounts_window_ref_selected_source (accounts_window);
+
+       if (source) {
+               ESourceRegistry *registry;
+
+               registry = e_accounts_window_get_registry (accounts_window);
+
+               e_source_registry_refresh_backend (registry, e_source_get_uid (source), NULL,
+                       accounts_window_refresh_backend_done_cb, accounts_window);
+
+               g_object_unref (source);
+       }
+}
+
 static gboolean
 accounts_window_find_source_uid_iter (EAccountsWindow *accounts_window,
                                      const gchar *uid,
@@ -1048,6 +1082,8 @@ accounts_window_selection_changed_cb (GtkTreeSelection *selection,
 
        gtk_widget_set_sensitive (accounts_window->priv->edit_button, (editing_flags & 
E_SOURCE_EDITING_FLAG_CAN_EDIT) != 0);
        gtk_widget_set_sensitive (accounts_window->priv->delete_button, (editing_flags & 
E_SOURCE_EDITING_FLAG_CAN_DELETE) != 0);
+       gtk_widget_set_sensitive (accounts_window->priv->refresh_backend_button,
+               source && e_source_has_extension (source, E_SOURCE_EXTENSION_COLLECTION));
 
        g_signal_emit (accounts_window, signals[SELECTION_CHANGED], 0, source);
 
@@ -1719,6 +1755,15 @@ accounts_window_constructed (GObject *object)
                widget, "clicked",
                G_CALLBACK (accounts_window_emit_delete_source), accounts_window);
 
+       widget = e_dialog_button_new_with_icon ("view-refresh", _("_Refresh"));
+       gtk_widget_set_tooltip_text (widget, _("Initiates refresh of account sources"));
+       gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+       accounts_window->priv->refresh_backend_button = widget;
+
+       g_signal_connect_swapped (
+               widget, "clicked",
+               G_CALLBACK (accounts_window_refresh_backend_cb), accounts_window);
+
        widget = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
        gtk_button_box_set_layout (GTK_BUTTON_BOX (widget), GTK_BUTTONBOX_END);
        gtk_box_set_spacing (GTK_BOX (widget), 6);
diff --git a/src/e-util/e-system.error.xml b/src/e-util/e-system.error.xml
index 5e104941d8..135bfc462b 100644
--- a/src/e-util/e-system.error.xml
+++ b/src/e-util/e-system.error.xml
@@ -101,4 +101,9 @@
    <button _label="_Delete From Server" response="GTK_RESPONSE_YES"/>
  </error>
 
+  <error id="refresh-backend-failed" type="error">
+    <_primary>Failed to refresh list of account sources</_primary>
+    <secondary>{1}</secondary>
+  </error>
+
 </error-list>
diff --git a/src/modules/addressbook/e-book-shell-sidebar.c b/src/modules/addressbook/e-book-shell-sidebar.c
index ee3fc908c5..060672a4d9 100644
--- a/src/modules/addressbook/e-book-shell-sidebar.c
+++ b/src/modules/addressbook/e-book-shell-sidebar.c
@@ -185,7 +185,7 @@ book_shell_sidebar_check_state (EShellSidebar *shell_sidebar)
        EBookShellSidebar *book_shell_sidebar;
        ESourceSelector *selector;
        ESourceRegistry *registry;
-       ESource *source;
+       ESource *source, *clicked_source;
        gboolean is_writable = FALSE;
        gboolean is_removable = FALSE;
        gboolean is_remote_creatable = FALSE;
@@ -232,6 +232,11 @@ book_shell_sidebar_check_state (EShellSidebar *shell_sidebar)
                g_object_unref (source);
        }
 
+       clicked_source = e_book_shell_view_get_clicked_source (e_shell_sidebar_get_shell_view 
(shell_sidebar));
+       if (clicked_source && clicked_source == source)
+               state |= E_BOOK_SHELL_SIDEBAR_CLICKED_SOURCE_IS_PRIMARY;
+       if (clicked_source && e_source_has_extension (clicked_source, E_SOURCE_EXTENSION_COLLECTION))
+               state |= E_BOOK_SHELL_SIDEBAR_CLICKED_SOURCE_IS_COLLECTION;
        if (has_primary_source)
                state |= E_BOOK_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE;
        if (is_writable)
diff --git a/src/modules/addressbook/e-book-shell-sidebar.h b/src/modules/addressbook/e-book-shell-sidebar.h
index 75f999cff7..e6609fbcea 100644
--- a/src/modules/addressbook/e-book-shell-sidebar.h
+++ b/src/modules/addressbook/e-book-shell-sidebar.h
@@ -56,7 +56,9 @@ enum {
        E_BOOK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_CREATABLE = 1 << 3,
        E_BOOK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_DELETABLE = 1 << 4,
        E_BOOK_SHELL_SIDEBAR_PRIMARY_SOURCE_IN_COLLECTION = 1 << 5,
-       E_BOOK_SHELL_SIDEBAR_SOURCE_SUPPORTS_REFRESH = 1 << 6
+       E_BOOK_SHELL_SIDEBAR_SOURCE_SUPPORTS_REFRESH = 1 << 6,
+       E_BOOK_SHELL_SIDEBAR_CLICKED_SOURCE_IS_PRIMARY = 1 << 7,
+       E_BOOK_SHELL_SIDEBAR_CLICKED_SOURCE_IS_COLLECTION = 1 << 8
 };
 
 struct _EBookShellSidebar {
diff --git a/src/modules/addressbook/e-book-shell-view-actions.c 
b/src/modules/addressbook/e-book-shell-view-actions.c
index fabfbc9cc9..5b98a38a92 100644
--- a/src/modules/addressbook/e-book-shell-view-actions.c
+++ b/src/modules/addressbook/e-book-shell-view-actions.c
@@ -318,6 +318,77 @@ action_address_book_refresh_cb (GtkAction *action,
        g_object_unref (client);
 }
 
+static void
+book_shell_view_refresh_backend_done_cb (GObject *source_object,
+                                        GAsyncResult *result,
+                                        gpointer user_data)
+{
+       ESourceRegistry *registry;
+       EActivity *activity = user_data;
+       EAlertSink *alert_sink;
+       GError *local_error = NULL;
+
+       g_return_if_fail (E_IS_SOURCE_REGISTRY (source_object));
+
+       registry = E_SOURCE_REGISTRY (source_object);
+       alert_sink = e_activity_get_alert_sink (activity);
+
+       e_source_registry_refresh_backend_finish (registry, result, &local_error);
+
+       if (e_activity_handle_cancellation (activity, local_error)) {
+               g_error_free (local_error);
+
+       } else if (local_error != NULL) {
+               e_alert_submit (alert_sink, "addressbook:refresh-backend-failed", local_error->message, NULL);
+               g_error_free (local_error);
+
+       } else {
+               e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
+       }
+
+       g_clear_object (&activity);
+}
+
+static void
+action_address_book_refresh_backend_cb (GtkAction *action,
+                                       EShellView *shell_view)
+{
+       EShellBackend *shell_backend;
+       EShellContent *shell_content;
+       EShell *shell;
+       ESource *source;
+       EActivity *activity;
+       EAlertSink *alert_sink;
+       ESourceRegistry *registry;
+       GCancellable *cancellable;
+
+       g_return_if_fail (E_IS_BOOK_SHELL_VIEW (shell_view));
+
+       source = e_book_shell_view_get_clicked_source (shell_view);
+       if (!source || !e_source_has_extension (source, E_SOURCE_EXTENSION_COLLECTION))
+               return;
+
+       shell_backend = e_shell_view_get_shell_backend (shell_view);
+       shell_content = e_shell_view_get_shell_content (shell_view);
+       shell = e_shell_backend_get_shell (shell_backend);
+
+       alert_sink = E_ALERT_SINK (shell_content);
+       activity = e_activity_new ();
+       cancellable = g_cancellable_new ();
+
+       e_activity_set_alert_sink (activity, alert_sink);
+       e_activity_set_cancellable (activity, cancellable);
+
+       registry = e_shell_get_registry (shell);
+
+       e_source_registry_refresh_backend (registry, e_source_get_uid (source), cancellable,
+               book_shell_view_refresh_backend_done_cb, activity);
+
+       e_shell_backend_add_activity (shell_backend, activity);
+
+       g_object_unref (cancellable);
+}
+
 #ifdef ENABLE_CONTACT_MAPS
 static void
 contact_editor_contact_modified_cb (EABEditor *editor,
@@ -986,6 +1057,13 @@ static GtkActionEntry contact_entries[] = {
          N_("Refresh the selected address book"),
          G_CALLBACK (action_address_book_refresh_cb) },
 
+       { "address-book-refresh-backend",
+         "view-refresh",
+         N_("Re_fresh list of account address books"),
+         NULL,
+         NULL,
+         G_CALLBACK (action_address_book_refresh_backend_cb) },
+
        { "address-book-map",
          NULL,
          N_("Address Book _Map"),
@@ -1105,6 +1183,10 @@ static EPopupActionEntry contact_popup_entries[] = {
          NULL,
          "address-book-refresh" },
 
+       { "address-book-popup-refresh-backend",
+         NULL,
+         "address-book-refresh-backend" },
+
        { "address-book-popup-map",
          N_("Address Book Map"),
          "address-book-map" },
diff --git a/src/modules/addressbook/e-book-shell-view-actions.h 
b/src/modules/addressbook/e-book-shell-view-actions.h
index dc839628fc..75650aeed4 100644
--- a/src/modules/addressbook/e-book-shell-view-actions.h
+++ b/src/modules/addressbook/e-book-shell-view-actions.h
@@ -38,6 +38,8 @@
        E_SHELL_WINDOW_ACTION ((window), "address-book-properties")
 #define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_REFRESH(window) \
        E_SHELL_WINDOW_ACTION ((window), "address-book-refresh")
+#define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_REFRESH_BACKEND(window) \
+       E_SHELL_WINDOW_ACTION ((window), "address-book-refresh-backend")
 #define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_RENAME(window) \
        E_SHELL_WINDOW_ACTION ((window), "address-book-rename")
 #define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_SAVE_AS(window) \
diff --git a/src/modules/addressbook/e-book-shell-view-private.c 
b/src/modules/addressbook/e-book-shell-view-private.c
index 41df95a261..284b6f7b06 100644
--- a/src/modules/addressbook/e-book-shell-view-private.c
+++ b/src/modules/addressbook/e-book-shell-view-private.c
@@ -24,6 +24,67 @@
 
 #include "e-book-shell-view-private.h"
 
+static gboolean
+book_shell_view_cleanup_clicked_source_idle_cb (gpointer user_data)
+{
+       EBookShellView *book_shell_view = user_data;
+
+       g_return_val_if_fail (E_IS_BOOK_SHELL_VIEW (book_shell_view), FALSE);
+
+       g_clear_object (&book_shell_view->priv->clicked_source);
+       g_clear_object (&book_shell_view);
+
+       return FALSE;
+}
+
+static void
+book_shell_view_popup_menu_hidden_cb (GObject *object,
+                                     GParamSpec *param,
+                                     gpointer user_data)
+{
+       EBookShellView *book_shell_view = user_data;
+
+       g_return_if_fail (E_IS_BOOK_SHELL_VIEW (book_shell_view));
+
+       /* Cannot do the clean up immediately, because the menu is hidden before
+          the action is executed. */
+       g_idle_add (book_shell_view_cleanup_clicked_source_idle_cb, book_shell_view);
+
+       g_signal_handlers_disconnect_by_func (object, book_shell_view_popup_menu_hidden_cb, user_data);
+}
+
+static GtkWidget *
+e_book_shell_view_show_popup_menu (EShellView *shell_view,
+                                  const gchar *widget_path,
+                                  GdkEvent *button_event,
+                                  ESource *clicked_source)
+{
+       EBookShellView *book_shell_view;
+       GtkWidget *menu;
+
+       g_return_val_if_fail (E_IS_BOOK_SHELL_VIEW (shell_view), NULL);
+       g_return_val_if_fail (widget_path != NULL, NULL);
+       if (clicked_source)
+               g_return_val_if_fail (E_IS_SOURCE (clicked_source), NULL);
+
+       book_shell_view = E_BOOK_SHELL_VIEW (shell_view);
+
+       g_clear_object (&book_shell_view->priv->clicked_source);
+       if (clicked_source)
+               book_shell_view->priv->clicked_source = g_object_ref (clicked_source);
+
+       menu = e_shell_view_show_popup_menu (shell_view, widget_path, button_event);
+
+       if (menu) {
+               g_signal_connect (menu, "notify::visible",
+                       G_CALLBACK (book_shell_view_popup_menu_hidden_cb), g_object_ref (shell_view));
+       } else {
+               g_clear_object (&book_shell_view->priv->clicked_source);
+       }
+
+       return menu;
+}
+
 static void
 open_contact (EBookShellView *book_shell_view,
               EContact *contact,
@@ -59,16 +120,10 @@ open_contact (EBookShellView *book_shell_view,
 }
 
 static void
-popup_event (EBookShellView *book_shell_view,
+popup_event (EShellView *shell_view,
              GdkEvent *button_event)
 {
-       EShellView *shell_view;
-       const gchar *widget_path;
-
-       widget_path = "/contact-popup";
-       shell_view = E_SHELL_VIEW (book_shell_view);
-
-       e_shell_view_show_popup_menu (shell_view, widget_path, button_event);
+       e_book_shell_view_show_popup_menu (shell_view, "/contact-popup", button_event, NULL);
 }
 
 static void
@@ -369,41 +424,15 @@ book_shell_view_activate_selected_source (EBookShellView *book_shell_view,
 }
 
 static gboolean
-book_shell_view_show_popup_menu (GdkEvent *button_event,
-                                 EShellView *shell_view)
+book_shell_view_selector_popup_event_cb (EShellView *shell_view,
+                                         ESource *clicked_source,
+                                         GdkEvent *button_event)
 {
-       const gchar *widget_path;
-
-       widget_path = "/address-book-popup";
-       e_shell_view_show_popup_menu (shell_view, widget_path, button_event);
+       e_book_shell_view_show_popup_menu (shell_view, "/address-book-popup", button_event, clicked_source);
 
        return TRUE;
 }
 
-static gboolean
-book_shell_view_selector_button_press_event_cb (EShellView *shell_view,
-                                                GdkEvent *button_event)
-{
-       guint event_button = 0;
-
-       /* XXX Use ESourceSelector's "popup-event" signal instead. */
-
-       gdk_event_get_button (button_event, &event_button);
-
-       if (button_event->type != GDK_BUTTON_PRESS || event_button != 3)
-               return FALSE;
-
-       return book_shell_view_show_popup_menu (button_event, shell_view);
-}
-
-static gboolean
-book_shell_view_selector_popup_menu_cb (EShellView *shell_view)
-{
-       /* XXX Use ESourceSelector's "popup-event" signal instead. */
-
-       return book_shell_view_show_popup_menu (NULL, shell_view);
-}
-
 static void
 book_shell_view_backend_error_cb (EClientCache *client_cache,
                                   EClient *client,
@@ -547,13 +576,8 @@ e_book_shell_view_private_constructed (EBookShellView *book_shell_view)
        priv->source_removed_handler_id = handler_id;
 
        g_signal_connect_object (
-               selector, "button-press-event",
-               G_CALLBACK (book_shell_view_selector_button_press_event_cb),
-               book_shell_view, G_CONNECT_SWAPPED);
-
-       g_signal_connect_object (
-               selector, "popup-menu",
-               G_CALLBACK (book_shell_view_selector_popup_menu_cb),
+               selector, "popup-event",
+               G_CALLBACK (book_shell_view_selector_popup_event_cb),
                book_shell_view, G_CONNECT_SWAPPED);
 
        g_signal_connect_object (
@@ -593,6 +617,7 @@ e_book_shell_view_private_dispose (EBookShellView *book_shell_view)
        g_clear_object (&priv->book_shell_content);
        g_clear_object (&priv->book_shell_sidebar);
 
+       g_clear_object (&priv->clicked_source);
        g_clear_object (&priv->client_cache);
        g_clear_object (&priv->registry);
 
diff --git a/src/modules/addressbook/e-book-shell-view-private.h 
b/src/modules/addressbook/e-book-shell-view-private.h
index a7d943b868..df39beb95a 100644
--- a/src/modules/addressbook/e-book-shell-view-private.h
+++ b/src/modules/addressbook/e-book-shell-view-private.h
@@ -96,6 +96,8 @@ struct _EBookShellViewPrivate {
        /* Can track whether search changed while locked,
         * but it is not usable at the moment. */
        gint search_locked;
+
+       ESource *clicked_source;
 };
 
 void           e_book_shell_view_private_init
diff --git a/src/modules/addressbook/e-book-shell-view.c b/src/modules/addressbook/e-book-shell-view.c
index 8f2da6b0fb..9eb898aaa5 100644
--- a/src/modules/addressbook/e-book-shell-view.c
+++ b/src/modules/addressbook/e-book-shell-view.c
@@ -24,11 +24,33 @@
 
 #include "addressbook/gui/widgets/gal-view-minicard.h"
 
+enum {
+       PROP_0,
+       PROP_CLICKED_SOURCE
+};
+
 G_DEFINE_DYNAMIC_TYPE (
        EBookShellView,
        e_book_shell_view,
        E_TYPE_SHELL_VIEW);
 
+static void
+book_shell_view_get_property (GObject *object,
+                             guint property_id,
+                             GValue *value,
+                             GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_CLICKED_SOURCE:
+                       g_value_set_object (
+                               value, e_book_shell_view_get_clicked_source (
+                               E_SHELL_VIEW (object)));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
 static void
 book_shell_view_dispose (GObject *object)
 {
@@ -214,6 +236,8 @@ book_shell_view_update_actions (EShellView *shell_view)
        gboolean selection_has_email;
        gboolean source_is_busy;
        gboolean source_is_editable;
+       gboolean clicked_source_is_primary;
+       gboolean clicked_source_is_collection;
 
        /* Chain up to parent's update_actions() method. */
        E_SHELL_VIEW_CLASS (e_book_shell_view_parent_class)->
@@ -252,40 +276,56 @@ book_shell_view_update_actions (EShellView *shell_view)
                (state & E_BOOK_SHELL_SIDEBAR_PRIMARY_SOURCE_IN_COLLECTION);
        refresh_supported =
                (state & E_BOOK_SHELL_SIDEBAR_SOURCE_SUPPORTS_REFRESH);
+       clicked_source_is_primary =
+               (state & E_BOOK_SHELL_SIDEBAR_CLICKED_SOURCE_IS_PRIMARY) != 0;
+       clicked_source_is_collection =
+               (state & E_BOOK_SHELL_SIDEBAR_CLICKED_SOURCE_IS_COLLECTION) != 0;
 
        any_contacts_selected =
                (single_contact_selected || multiple_contacts_selected);
 
        action = ACTION (ADDRESS_BOOK_MOVE);
-       sensitive = source_is_editable;
+       sensitive = clicked_source_is_primary && source_is_editable;
        gtk_action_set_sensitive (action, sensitive);
 
        action = ACTION (ADDRESS_BOOK_DELETE);
-       sensitive =
+       sensitive = clicked_source_is_primary && (
                primary_source_is_removable ||
-               primary_source_is_remote_deletable;
+               primary_source_is_remote_deletable);
        gtk_action_set_sensitive (action, sensitive);
 
        action = ACTION (ADDRESS_BOOK_PRINT);
-       sensitive = has_primary_source;
+       sensitive = clicked_source_is_primary && has_primary_source;
        gtk_action_set_sensitive (action, sensitive);
 
        action = ACTION (ADDRESS_BOOK_PRINT_PREVIEW);
-       sensitive = has_primary_source;
+       sensitive = clicked_source_is_primary && has_primary_source;
        gtk_action_set_sensitive (action, sensitive);
 
        action = ACTION (ADDRESS_BOOK_PROPERTIES);
-       sensitive = primary_source_is_writable;
+       sensitive = clicked_source_is_primary && primary_source_is_writable;
        gtk_action_set_sensitive (action, sensitive);
 
        action = ACTION (ADDRESS_BOOK_REFRESH);
-       sensitive = refresh_supported;
+       sensitive = clicked_source_is_primary && refresh_supported;
+       gtk_action_set_sensitive (action, sensitive);
+
+       action = ACTION (ADDRESS_BOOK_REFRESH_BACKEND);
+       sensitive = clicked_source_is_collection;
        gtk_action_set_sensitive (action, sensitive);
 
        action = ACTION (ADDRESS_BOOK_RENAME);
-       sensitive =
+       sensitive = clicked_source_is_primary && (
                primary_source_is_writable &&
-               !primary_source_in_collection;
+               !primary_source_in_collection);
+       gtk_action_set_sensitive (action, sensitive);
+
+       action = ACTION (ADDRESS_BOOK_SAVE_AS);
+       sensitive = clicked_source_is_primary && has_primary_source;
+       gtk_action_set_sensitive (action, sensitive);
+
+       action = ACTION (ADDRESS_BOOK_POPUP_MAP);
+       sensitive = clicked_source_is_primary;
        gtk_action_set_sensitive (action, sensitive);
 
        action = ACTION (ADDRESS_BOOK_STOP);
@@ -363,6 +403,7 @@ e_book_shell_view_class_init (EBookShellViewClass *class)
        g_type_class_add_private (class, sizeof (EBookShellViewPrivate));
 
        object_class = G_OBJECT_CLASS (class);
+       object_class->get_property = book_shell_view_get_property;
        object_class->dispose = book_shell_view_dispose;
        object_class->finalize = book_shell_view_finalize;
        object_class->constructed = book_shell_view_constructed;
@@ -379,6 +420,16 @@ e_book_shell_view_class_init (EBookShellViewClass *class)
        shell_view_class->execute_search = book_shell_view_execute_search;
        shell_view_class->update_actions = book_shell_view_update_actions;
 
+       g_object_class_install_property (
+               object_class,
+               PROP_CLICKED_SOURCE,
+               g_param_spec_object (
+                       "clicked-source",
+                       "Clicked Source",
+                       "An ESource which had been clicked in the source selector before showing context 
menu",
+                       E_TYPE_SOURCE,
+                       G_PARAM_READABLE));
+
        /* Ensure the GalView types we need are registered. */
        g_type_ensure (GAL_TYPE_VIEW_ETABLE);
        g_type_ensure (GAL_TYPE_VIEW_MINICARD);
@@ -529,3 +580,15 @@ e_book_shell_view_maybe_prefill_list_with_selection (EShellView *shell_view,
                        e_contact_set (contact, E_CONTACT_IS_LIST, GINT_TO_POINTER (TRUE));
        }
 }
+
+ESource *
+e_book_shell_view_get_clicked_source (EShellView *shell_view)
+{
+       EBookShellView *book_shell_view;
+
+       g_return_val_if_fail (E_IS_BOOK_SHELL_VIEW (shell_view), NULL);
+
+       book_shell_view = E_BOOK_SHELL_VIEW (shell_view);
+
+       return book_shell_view->priv->clicked_source;
+}
diff --git a/src/modules/addressbook/e-book-shell-view.h b/src/modules/addressbook/e-book-shell-view.h
index 587cf9d374..7fadff305f 100644
--- a/src/modules/addressbook/e-book-shell-view.h
+++ b/src/modules/addressbook/e-book-shell-view.h
@@ -65,6 +65,7 @@ void          e_book_shell_view_enable_searching (EBookShellView *book_shell_view);
 void           e_book_shell_view_maybe_prefill_list_with_selection
                                                (EShellView *shell_view,
                                                 EContact *contact);
+ESource *      e_book_shell_view_get_clicked_source    (EShellView *shell_view);
 
 G_END_DECLS
 
diff --git a/src/modules/calendar/e-cal-base-shell-sidebar.c b/src/modules/calendar/e-cal-base-shell-sidebar.c
index ae9b34f34e..6cde762b91 100644
--- a/src/modules/calendar/e-cal-base-shell-sidebar.c
+++ b/src/modules/calendar/e-cal-base-shell-sidebar.c
@@ -169,7 +169,7 @@ cal_base_shell_sidebar_check_state (EShellSidebar *shell_sidebar)
        ECalBaseShellSidebar *cal_base_shell_sidebar;
        ESourceSelector *selector;
        ESourceRegistry *registry;
-       ESource *source;
+       ESource *source, *clicked_source;
        gboolean is_writable = FALSE;
        gboolean is_removable = FALSE;
        gboolean is_remote_creatable = FALSE;
@@ -213,6 +213,11 @@ cal_base_shell_sidebar_check_state (EShellSidebar *shell_sidebar)
                g_object_unref (source);
        }
 
+       clicked_source = e_cal_base_shell_view_get_clicked_source (e_shell_sidebar_get_shell_view 
(shell_sidebar));
+       if (clicked_source && clicked_source == source)
+               state |= E_CAL_BASE_SHELL_SIDEBAR_CLICKED_SOURCE_IS_PRIMARY;
+       if (clicked_source && e_source_has_extension (clicked_source, E_SOURCE_EXTENSION_COLLECTION))
+               state |= E_CAL_BASE_SHELL_SIDEBAR_CLICKED_SOURCE_IS_COLLECTION;
        if (e_source_selector_count_total (selector) == e_source_selector_count_selected (selector))
                state |= E_CAL_BASE_SHELL_SIDEBAR_ALL_SOURCES_SELECTED;
        if (has_primary_source)
diff --git a/src/modules/calendar/e-cal-base-shell-sidebar.h b/src/modules/calendar/e-cal-base-shell-sidebar.h
index e33746f0e2..ee86ad2b38 100644
--- a/src/modules/calendar/e-cal-base-shell-sidebar.h
+++ b/src/modules/calendar/e-cal-base-shell-sidebar.h
@@ -57,7 +57,9 @@ enum {
        E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_DELETABLE = 1 << 4,
        E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IN_COLLECTION = 1 << 5,
        E_CAL_BASE_SHELL_SIDEBAR_SOURCE_SUPPORTS_REFRESH = 1 << 6,
-       E_CAL_BASE_SHELL_SIDEBAR_ALL_SOURCES_SELECTED = 1 << 7
+       E_CAL_BASE_SHELL_SIDEBAR_ALL_SOURCES_SELECTED = 1 << 7,
+       E_CAL_BASE_SHELL_SIDEBAR_CLICKED_SOURCE_IS_PRIMARY = 1 << 8,
+       E_CAL_BASE_SHELL_SIDEBAR_CLICKED_SOURCE_IS_COLLECTION = 1 << 9
 };
 
 struct _ECalBaseShellSidebar {
diff --git a/src/modules/calendar/e-cal-base-shell-view.c b/src/modules/calendar/e-cal-base-shell-view.c
index 28335425a0..eb98d0d8ec 100644
--- a/src/modules/calendar/e-cal-base-shell-view.c
+++ b/src/modules/calendar/e-cal-base-shell-view.c
@@ -34,13 +34,19 @@
        (G_TYPE_INSTANCE_GET_PRIVATE \
        ((obj), E_TYPE_CAL_BASE_SHELL_VIEW, ECalBaseShellViewPrivate))
 
-G_DEFINE_ABSTRACT_TYPE (ECalBaseShellView, e_cal_base_shell_view, E_TYPE_SHELL_VIEW)
-
 struct _ECalBaseShellViewPrivate {
        EShell *shell;
        guint prepare_for_quit_handler_id;
+       ESource *clicked_source;
+};
+
+enum {
+       PROP_0,
+       PROP_CLICKED_SOURCE
 };
 
+G_DEFINE_ABSTRACT_TYPE (ECalBaseShellView, e_cal_base_shell_view, E_TYPE_SHELL_VIEW)
+
 static void
 cal_base_shell_view_prepare_for_quit_cb (EShell *shell,
                                         EActivity *activity,
@@ -58,6 +64,23 @@ cal_base_shell_view_prepare_for_quit_cb (EShell *shell,
        e_cal_base_shell_content_prepare_for_quit (E_CAL_BASE_SHELL_CONTENT (shell_content), activity);
 }
 
+static void
+cal_base_shell_view_get_property (GObject *object,
+                                 guint property_id,
+                                 GValue *value,
+                                 GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_CLICKED_SOURCE:
+                       g_value_set_object (
+                               value, e_cal_base_shell_view_get_clicked_source (
+                               E_SHELL_VIEW (object)));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
 static void
 cal_base_shell_view_dispose (GObject *object)
 {
@@ -70,6 +93,7 @@ cal_base_shell_view_dispose (GObject *object)
        }
 
        g_clear_object (&cal_base_shell_view->priv->shell);
+       g_clear_object (&cal_base_shell_view->priv->clicked_source);
 
        /* Chain up to parent's dispose() method. */
        G_OBJECT_CLASS (e_cal_base_shell_view_parent_class)->dispose (object);
@@ -105,10 +129,21 @@ e_cal_base_shell_view_class_init (ECalBaseShellViewClass *class)
        g_type_class_add_private (class, sizeof (ECalBaseShellViewPrivate));
 
        object_class = G_OBJECT_CLASS (class);
+       object_class->get_property = cal_base_shell_view_get_property;
        object_class->dispose = cal_base_shell_view_dispose;
        object_class->constructed = cal_base_shell_view_constructed;
 
        class->source_type = E_CAL_CLIENT_SOURCE_TYPE_LAST;
+
+       g_object_class_install_property (
+               object_class,
+               PROP_CLICKED_SOURCE,
+               g_param_spec_object (
+                       "clicked-source",
+                       "Clicked Source",
+                       "An ESource which had been clicked in the source selector before showing context 
menu",
+                       E_TYPE_SOURCE,
+                       G_PARAM_READABLE));
 }
 
 static void
@@ -279,3 +314,143 @@ e_cal_base_shell_view_copy_calendar (EShellView *shell_view)
 
        g_clear_object (&from_source);
 }
+
+static gboolean
+cal_base_shell_view_cleanup_clicked_source_idle_cb (gpointer user_data)
+{
+       ECalBaseShellView *cal_base_shell_view = user_data;
+
+       g_return_val_if_fail (E_IS_CAL_BASE_SHELL_VIEW (cal_base_shell_view), FALSE);
+
+       g_clear_object (&cal_base_shell_view->priv->clicked_source);
+       g_clear_object (&cal_base_shell_view);
+
+       return FALSE;
+}
+
+static void
+cal_base_shell_view_popup_menu_hidden_cb (GObject *object,
+                                         GParamSpec *param,
+                                         gpointer user_data)
+{
+       ECalBaseShellView *cal_base_shell_view = user_data;
+
+       g_return_if_fail (E_IS_CAL_BASE_SHELL_VIEW (cal_base_shell_view));
+
+       /* Cannot do the clean up immediately, because the menu is hidden before
+          the action is executed. */
+       g_idle_add (cal_base_shell_view_cleanup_clicked_source_idle_cb, cal_base_shell_view);
+
+       g_signal_handlers_disconnect_by_func (object, cal_base_shell_view_popup_menu_hidden_cb, user_data);
+}
+
+GtkWidget *
+e_cal_base_shell_view_show_popup_menu (EShellView *shell_view,
+                                      const gchar *widget_path,
+                                      GdkEvent *button_event,
+                                      ESource *clicked_source)
+{
+       ECalBaseShellView *cal_base_shell_view;
+       GtkWidget *menu;
+
+       g_return_val_if_fail (E_IS_CAL_BASE_SHELL_VIEW (shell_view), NULL);
+       g_return_val_if_fail (widget_path != NULL, NULL);
+       if (clicked_source)
+               g_return_val_if_fail (E_IS_SOURCE (clicked_source), NULL);
+
+       cal_base_shell_view = E_CAL_BASE_SHELL_VIEW (shell_view);
+
+       g_clear_object (&cal_base_shell_view->priv->clicked_source);
+       if (clicked_source)
+               cal_base_shell_view->priv->clicked_source = g_object_ref (clicked_source);
+
+       menu = e_shell_view_show_popup_menu (shell_view, widget_path, button_event);
+
+       if (menu) {
+               g_signal_connect (menu, "notify::visible",
+                       G_CALLBACK (cal_base_shell_view_popup_menu_hidden_cb), g_object_ref (shell_view));
+       } else {
+               g_clear_object (&cal_base_shell_view->priv->clicked_source);
+       }
+
+       return menu;
+}
+
+ESource *
+e_cal_base_shell_view_get_clicked_source (EShellView *shell_view)
+{
+       ECalBaseShellView *cal_base_shell_view;
+
+       g_return_val_if_fail (E_IS_CAL_BASE_SHELL_VIEW (shell_view), NULL);
+
+       cal_base_shell_view = E_CAL_BASE_SHELL_VIEW (shell_view);
+
+       return cal_base_shell_view->priv->clicked_source;
+}
+
+static void
+cal_base_shell_view_refresh_backend_done_cb (GObject *source_object,
+                                            GAsyncResult *result,
+                                            gpointer user_data)
+{
+       ESourceRegistry *registry;
+       EActivity *activity = user_data;
+       EAlertSink *alert_sink;
+       GError *local_error = NULL;
+
+       g_return_if_fail (E_IS_SOURCE_REGISTRY (source_object));
+
+       registry = E_SOURCE_REGISTRY (source_object);
+       alert_sink = e_activity_get_alert_sink (activity);
+
+       e_source_registry_refresh_backend_finish (registry, result, &local_error);
+
+       if (e_activity_handle_cancellation (activity, local_error)) {
+               g_error_free (local_error);
+
+       } else if (local_error != NULL) {
+               e_alert_submit (alert_sink, "system:refresh-backend-failed", local_error->message, NULL);
+               g_error_free (local_error);
+
+       } else {
+               e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
+       }
+
+       g_clear_object (&activity);
+}
+
+void
+e_cal_base_shell_view_refresh_backend (EShellView *shell_view,
+                                      ESource *source)
+{
+       EShellBackend *shell_backend;
+       EShellContent *shell_content;
+       EShell *shell;
+       EActivity *activity;
+       EAlertSink *alert_sink;
+       ESourceRegistry *registry;
+       GCancellable *cancellable;
+
+       g_return_if_fail (E_IS_CAL_BASE_SHELL_VIEW (shell_view));
+       g_return_if_fail (E_IS_SOURCE (source));
+
+       shell_backend = e_shell_view_get_shell_backend (shell_view);
+       shell_content = e_shell_view_get_shell_content (shell_view);
+       shell = e_shell_backend_get_shell (shell_backend);
+
+       alert_sink = E_ALERT_SINK (shell_content);
+       activity = e_activity_new ();
+       cancellable = g_cancellable_new ();
+
+       e_activity_set_alert_sink (activity, alert_sink);
+       e_activity_set_cancellable (activity, cancellable);
+
+       registry = e_shell_get_registry (shell);
+
+       e_source_registry_refresh_backend (registry, e_source_get_uid (source), cancellable,
+               cal_base_shell_view_refresh_backend_done_cb, activity);
+
+       e_shell_backend_add_activity (shell_backend, activity);
+
+       g_object_unref (cancellable);
+}
diff --git a/src/modules/calendar/e-cal-base-shell-view.h b/src/modules/calendar/e-cal-base-shell-view.h
index 8cdcf5d0e5..8ea5246cf5 100644
--- a/src/modules/calendar/e-cal-base-shell-view.h
+++ b/src/modules/calendar/e-cal-base-shell-view.h
@@ -71,6 +71,14 @@ void         e_cal_base_shell_view_model_row_appended
                                                        (EShellView *shell_view,
                                                         ECalModel *model);
 void           e_cal_base_shell_view_copy_calendar     (EShellView *shell_view);
+GtkWidget *    e_cal_base_shell_view_show_popup_menu   (EShellView *shell_view,
+                                                        const gchar *widget_path,
+                                                        GdkEvent *button_event,
+                                                        ESource *clicked_source);
+ESource *      e_cal_base_shell_view_get_clicked_source
+                                                       (EShellView *shell_view);
+void           e_cal_base_shell_view_refresh_backend   (EShellView *shell_view,
+                                                        ESource *collection_source);
 
 G_END_DECLS
 
diff --git a/src/modules/calendar/e-cal-shell-view-actions.c b/src/modules/calendar/e-cal-shell-view-actions.c
index 50a5c7d03d..835d32d40b 100644
--- a/src/modules/calendar/e-cal-shell-view-actions.c
+++ b/src/modules/calendar/e-cal-shell-view-actions.c
@@ -387,6 +387,20 @@ action_calendar_refresh_cb (GtkAction *action,
        g_object_unref (client);
 }
 
+static void
+action_calendar_refresh_backend_cb (GtkAction *action,
+                                   EShellView *shell_view)
+{
+       ESource *source;
+
+       g_return_if_fail (E_IS_CAL_SHELL_VIEW (shell_view));
+
+       source = e_cal_base_shell_view_get_clicked_source (shell_view);
+
+       if (source && e_source_has_extension (source, E_SOURCE_EXTENSION_COLLECTION))
+               e_cal_base_shell_view_refresh_backend (shell_view, source);
+}
+
 static void
 action_calendar_rename_cb (GtkAction *action,
                            ECalShellView *cal_shell_view)
@@ -1332,6 +1346,13 @@ static GtkActionEntry calendar_entries[] = {
          N_("Refresh the selected calendar"),
          G_CALLBACK (action_calendar_refresh_cb) },
 
+       { "calendar-refresh-backend",
+         "view-refresh",
+         N_("Re_fresh list of account calendars"),
+         NULL,
+         NULL,
+         G_CALLBACK (action_calendar_refresh_backend_cb) },
+
        { "calendar-rename",
          NULL,
          N_("_Rename..."),
@@ -1544,6 +1565,10 @@ static EPopupActionEntry calendar_popup_entries[] = {
          NULL,
          "calendar-refresh" },
 
+       { "calendar-popup-refresh-backend",
+         NULL,
+         "calendar-refresh-backend" },
+
        { "calendar-popup-rename",
          NULL,
          "calendar-rename" },
diff --git a/src/modules/calendar/e-cal-shell-view-actions.h b/src/modules/calendar/e-cal-shell-view-actions.h
index 834d86da4e..26a4d8b398 100644
--- a/src/modules/calendar/e-cal-shell-view-actions.h
+++ b/src/modules/calendar/e-cal-shell-view-actions.h
@@ -48,6 +48,8 @@
        E_SHELL_WINDOW_ACTION ((window), "calendar-purge")
 #define E_SHELL_WINDOW_ACTION_CALENDAR_REFRESH(window) \
        E_SHELL_WINDOW_ACTION ((window), "calendar-refresh")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_REFRESH_BACKEND(window) \
+       E_SHELL_WINDOW_ACTION ((window), "calendar-refresh-backend")
 #define E_SHELL_WINDOW_ACTION_CALENDAR_RENAME(window) \
        E_SHELL_WINDOW_ACTION ((window), "calendar-rename")
 #define E_SHELL_WINDOW_ACTION_CALENDAR_SEARCH_PREV(window) \
diff --git a/src/modules/calendar/e-cal-shell-view-private.c b/src/modules/calendar/e-cal-shell-view-private.c
index 4f418b2821..58f5bf3122 100644
--- a/src/modules/calendar/e-cal-shell-view-private.c
+++ b/src/modules/calendar/e-cal-shell-view-private.c
@@ -86,18 +86,15 @@ cal_shell_view_popup_event_cb (EShellView *shell_view,
        else
                widget_path = "/calendar-event-popup";
 
-       e_shell_view_show_popup_menu (shell_view, widget_path, button_event);
+       e_cal_base_shell_view_show_popup_menu (shell_view, widget_path, button_event, NULL);
 }
 
 static gboolean
 cal_shell_view_selector_popup_event_cb (EShellView *shell_view,
-                                        ESource *primary_source,
+                                        ESource *clicked_source,
                                         GdkEvent *button_event)
 {
-       const gchar *widget_path;
-
-       widget_path = "/calendar-popup";
-       e_shell_view_show_popup_menu (shell_view, widget_path, button_event);
+       e_cal_base_shell_view_show_popup_menu (shell_view, "/calendar-popup", button_event, clicked_source);
 
        return TRUE;
 }
@@ -106,26 +103,18 @@ static void
 cal_shell_view_memopad_popup_event_cb (EShellView *shell_view,
                                        GdkEvent *button_event)
 {
-       const gchar *widget_path;
-
-       widget_path = "/calendar-memopad-popup";
-
        e_cal_shell_view_memopad_actions_update (E_CAL_SHELL_VIEW (shell_view));
 
-       e_shell_view_show_popup_menu (shell_view, widget_path, button_event);
+       e_cal_base_shell_view_show_popup_menu (shell_view, "/calendar-memopad-popup", button_event, NULL);
 }
 
 static void
 cal_shell_view_taskpad_popup_event_cb (EShellView *shell_view,
                                        GdkEvent *button_event)
 {
-       const gchar *widget_path;
-
-       widget_path = "/calendar-taskpad-popup";
-
        e_cal_shell_view_taskpad_actions_update (E_CAL_SHELL_VIEW (shell_view));
 
-       e_shell_view_show_popup_menu (shell_view, widget_path, button_event);
+       e_cal_base_shell_view_show_popup_menu (shell_view, "/calendar-taskpad-popup", button_event, NULL);
 }
 
 static void
diff --git a/src/modules/calendar/e-cal-shell-view.c b/src/modules/calendar/e-cal-shell-view.c
index fbff988379..de9e874411 100644
--- a/src/modules/calendar/e-cal-shell-view.c
+++ b/src/modules/calendar/e-cal-shell-view.c
@@ -284,6 +284,8 @@ cal_shell_view_update_actions (EShellView *shell_view)
        gboolean single_event_selected;
        gboolean refresh_supported;
        gboolean all_sources_selected;
+       gboolean clicked_source_is_primary;
+       gboolean clicked_source_is_collection;
 
        /* Chain up to parent's update_actions() method. */
        E_SHELL_VIEW_CLASS (e_cal_shell_view_parent_class)->
@@ -348,33 +350,53 @@ cal_shell_view_update_actions (EShellView *shell_view)
                (state & E_CAL_BASE_SHELL_SIDEBAR_SOURCE_SUPPORTS_REFRESH);
        all_sources_selected =
                (state & E_CAL_BASE_SHELL_SIDEBAR_ALL_SOURCES_SELECTED) != 0;
+       clicked_source_is_primary =
+               (state & E_CAL_BASE_SHELL_SIDEBAR_CLICKED_SOURCE_IS_PRIMARY) != 0;
+       clicked_source_is_collection =
+               (state & E_CAL_BASE_SHELL_SIDEBAR_CLICKED_SOURCE_IS_COLLECTION) != 0;
 
        any_events_selected = (single_event_selected || multiple_events_selected);
 
        action = ACTION (CALENDAR_SELECT_ALL);
-       sensitive = !all_sources_selected;
+       sensitive = clicked_source_is_primary && !all_sources_selected;
+       gtk_action_set_sensitive (action, sensitive);
+
+       action = ACTION (CALENDAR_SELECT_ONE);
+       sensitive = clicked_source_is_primary;
        gtk_action_set_sensitive (action, sensitive);
 
        action = ACTION (CALENDAR_COPY);
-       sensitive = has_primary_source;
+       sensitive = clicked_source_is_primary && has_primary_source;
        gtk_action_set_sensitive (action, sensitive);
 
        action = ACTION (CALENDAR_DELETE);
-       sensitive =
+       sensitive = clicked_source_is_primary && (
                primary_source_is_removable ||
-               primary_source_is_remote_deletable;
+               primary_source_is_remote_deletable);
+       gtk_action_set_sensitive (action, sensitive);
+
+       action = ACTION (CALENDAR_PRINT);
+       sensitive = clicked_source_is_primary;
+       gtk_action_set_sensitive (action, sensitive);
+
+       action = ACTION (CALENDAR_PRINT_PREVIEW);
+       sensitive = clicked_source_is_primary;
        gtk_action_set_sensitive (action, sensitive);
 
        action = ACTION (CALENDAR_PROPERTIES);
-       sensitive = primary_source_is_writable;
+       sensitive = clicked_source_is_primary && primary_source_is_writable;
        gtk_action_set_sensitive (action, sensitive);
 
        action = ACTION (CALENDAR_REFRESH);
-       sensitive = refresh_supported;
+       sensitive = clicked_source_is_primary && refresh_supported;
+       gtk_action_set_sensitive (action, sensitive);
+
+       action = ACTION (CALENDAR_REFRESH_BACKEND);
+       sensitive = clicked_source_is_collection;
        gtk_action_set_sensitive (action, sensitive);
 
        action = ACTION (CALENDAR_RENAME);
-       sensitive =
+       sensitive = clicked_source_is_primary &&
                primary_source_is_writable &&
                !primary_source_in_collection;
        gtk_action_set_sensitive (action, sensitive);
diff --git a/src/modules/calendar/e-memo-shell-view-actions.c 
b/src/modules/calendar/e-memo-shell-view-actions.c
index 5c2c0a8dac..50e13781ca 100644
--- a/src/modules/calendar/e-memo-shell-view-actions.c
+++ b/src/modules/calendar/e-memo-shell-view-actions.c
@@ -282,6 +282,20 @@ action_memo_list_refresh_cb (GtkAction *action,
        g_object_unref (client);
 }
 
+static void
+action_memo_list_refresh_backend_cb (GtkAction *action,
+                                    EShellView *shell_view)
+{
+       ESource *source;
+
+       g_return_if_fail (E_IS_MEMO_SHELL_VIEW (shell_view));
+
+       source = e_cal_base_shell_view_get_clicked_source (shell_view);
+
+       if (source && e_source_has_extension (source, E_SOURCE_EXTENSION_COLLECTION))
+               e_cal_base_shell_view_refresh_backend (shell_view, source);
+}
+
 static void
 action_memo_list_rename_cb (GtkAction *action,
                             EMemoShellView *memo_shell_view)
@@ -614,6 +628,13 @@ static GtkActionEntry memo_entries[] = {
          N_("Refresh the selected memo list"),
          G_CALLBACK (action_memo_list_refresh_cb) },
 
+       { "memo-list-refresh-backend",
+         "view-refresh",
+         N_("Re_fresh list of account memo lists"),
+         NULL,
+         NULL,
+         G_CALLBACK (action_memo_list_refresh_backend_cb) },
+
        { "memo-list-rename",
          NULL,
          N_("_Rename..."),
@@ -688,6 +709,10 @@ static EPopupActionEntry memo_popup_entries[] = {
          NULL,
          "memo-list-refresh" },
 
+       { "memo-list-popup-refresh-backend",
+         NULL,
+         "memo-list-refresh-backend" },
+
        { "memo-list-popup-rename",
          NULL,
          "memo-list-rename" },
diff --git a/src/modules/calendar/e-memo-shell-view-actions.h 
b/src/modules/calendar/e-memo-shell-view-actions.h
index e71a81c574..8128c86577 100644
--- a/src/modules/calendar/e-memo-shell-view-actions.h
+++ b/src/modules/calendar/e-memo-shell-view-actions.h
@@ -62,6 +62,8 @@
        E_SHELL_WINDOW_ACTION ((window), "memo-list-properties")
 #define E_SHELL_WINDOW_ACTION_MEMO_LIST_REFRESH(window) \
        E_SHELL_WINDOW_ACTION ((window), "memo-list-refresh")
+#define E_SHELL_WINDOW_ACTION_MEMO_LIST_REFRESH_BACKEND(window) \
+       E_SHELL_WINDOW_ACTION ((window), "memo-list-refresh-backend")
 #define E_SHELL_WINDOW_ACTION_MEMO_LIST_RENAME(window) \
        E_SHELL_WINDOW_ACTION ((window), "memo-list-rename")
 #define E_SHELL_WINDOW_ACTION_MEMO_LIST_SELECT_ALL(window) \
diff --git a/src/modules/calendar/e-memo-shell-view-private.c 
b/src/modules/calendar/e-memo-shell-view-private.c
index 393d2992c2..8ac5946208 100644
--- a/src/modules/calendar/e-memo-shell-view-private.c
+++ b/src/modules/calendar/e-memo-shell-view-private.c
@@ -29,21 +29,15 @@ static void
 memo_shell_view_table_popup_event_cb (EShellView *shell_view,
                                       GdkEvent *button_event)
 {
-       const gchar *widget_path;
-
-       widget_path = "/memo-popup";
-       e_shell_view_show_popup_menu (shell_view, widget_path, button_event);
+       e_cal_base_shell_view_show_popup_menu (shell_view, "/memo-popup", button_event, NULL);
 }
 
 static gboolean
 memo_shell_view_selector_popup_event_cb (EShellView *shell_view,
-                                         ESource *primary_source,
+                                         ESource *clicked_source,
                                          GdkEvent *button_event)
 {
-       const gchar *widget_path;
-
-       widget_path = "/memo-list-popup";
-       e_shell_view_show_popup_menu (shell_view, widget_path, button_event);
+       e_cal_base_shell_view_show_popup_menu (shell_view, "/memo-list-popup", button_event, clicked_source);
 
        return TRUE;
 }
diff --git a/src/modules/calendar/e-memo-shell-view.c b/src/modules/calendar/e-memo-shell-view.c
index 21dcca19dd..1e27533d0f 100644
--- a/src/modules/calendar/e-memo-shell-view.c
+++ b/src/modules/calendar/e-memo-shell-view.c
@@ -167,6 +167,8 @@ memo_shell_view_update_actions (EShellView *shell_view)
        gboolean sources_are_editable;
        gboolean refresh_supported;
        gboolean all_sources_selected;
+       gboolean clicked_source_is_primary;
+       gboolean clicked_source_is_collection;
 
        /* Chain up to parent's update_actions() method. */
        E_SHELL_VIEW_CLASS (e_memo_shell_view_parent_class)->
@@ -203,11 +205,19 @@ memo_shell_view_update_actions (EShellView *shell_view)
                (state & E_CAL_BASE_SHELL_SIDEBAR_SOURCE_SUPPORTS_REFRESH);
        all_sources_selected =
                (state & E_CAL_BASE_SHELL_SIDEBAR_ALL_SOURCES_SELECTED) != 0;
+       clicked_source_is_primary =
+               (state & E_CAL_BASE_SHELL_SIDEBAR_CLICKED_SOURCE_IS_PRIMARY) != 0;
+       clicked_source_is_collection =
+               (state & E_CAL_BASE_SHELL_SIDEBAR_CLICKED_SOURCE_IS_COLLECTION) != 0;
 
        any_memos_selected = (single_memo_selected || multiple_memos_selected);
 
        action = ACTION (MEMO_LIST_SELECT_ALL);
-       sensitive = !all_sources_selected;
+       sensitive = clicked_source_is_primary && !all_sources_selected;
+       gtk_action_set_sensitive (action, sensitive);
+
+       action = ACTION (MEMO_LIST_SELECT_ONE);
+       sensitive = clicked_source_is_primary;
        gtk_action_set_sensitive (action, sensitive);
 
        action = ACTION (MEMO_DELETE);
@@ -228,27 +238,39 @@ memo_shell_view_update_actions (EShellView *shell_view)
        gtk_action_set_sensitive (action, sensitive);
 
        action = ACTION (MEMO_LIST_COPY);
-       sensitive = has_primary_source;
+       sensitive = clicked_source_is_primary && has_primary_source;
        gtk_action_set_sensitive (action, sensitive);
 
        action = ACTION (MEMO_LIST_DELETE);
-       sensitive =
+       sensitive = clicked_source_is_primary && (
                primary_source_is_removable ||
-               primary_source_is_remote_deletable;
+               primary_source_is_remote_deletable);
+       gtk_action_set_sensitive (action, sensitive);
+
+       action = ACTION (MEMO_LIST_PRINT);
+       sensitive = clicked_source_is_primary;
+       gtk_action_set_sensitive (action, sensitive);
+
+       action = ACTION (MEMO_LIST_PRINT_PREVIEW);
+       sensitive = clicked_source_is_primary;
        gtk_action_set_sensitive (action, sensitive);
 
        action = ACTION (MEMO_LIST_PROPERTIES);
-       sensitive = primary_source_is_writable;
+       sensitive = clicked_source_is_primary && primary_source_is_writable;
        gtk_action_set_sensitive (action, sensitive);
 
        action = ACTION (MEMO_LIST_REFRESH);
-       sensitive = refresh_supported;
+       sensitive = clicked_source_is_primary && refresh_supported;
+       gtk_action_set_sensitive (action, sensitive);
+
+       action = ACTION (MEMO_LIST_REFRESH_BACKEND);
+       sensitive = clicked_source_is_collection;
        gtk_action_set_sensitive (action, sensitive);
 
        action = ACTION (MEMO_LIST_RENAME);
-       sensitive =
+       sensitive = clicked_source_is_primary && (
                primary_source_is_writable &&
-               !primary_source_in_collection;
+               !primary_source_in_collection);
        gtk_action_set_sensitive (action, sensitive);
 
        action = ACTION (MEMO_OPEN);
diff --git a/src/modules/calendar/e-task-shell-view-actions.c 
b/src/modules/calendar/e-task-shell-view-actions.c
index 1034b518fd..fb62f59f17 100644
--- a/src/modules/calendar/e-task-shell-view-actions.c
+++ b/src/modules/calendar/e-task-shell-view-actions.c
@@ -306,6 +306,20 @@ action_task_list_refresh_cb (GtkAction *action,
        g_object_unref (client);
 }
 
+static void
+action_task_list_refresh_backend_cb (GtkAction *action,
+                                    EShellView *shell_view)
+{
+       ESource *source;
+
+       g_return_if_fail (E_IS_TASK_SHELL_VIEW (shell_view));
+
+       source = e_cal_base_shell_view_get_clicked_source (shell_view);
+
+       if (source && e_source_has_extension (source, E_SOURCE_EXTENSION_COLLECTION))
+               e_cal_base_shell_view_refresh_backend (shell_view, source);
+}
+
 static void
 action_task_list_rename_cb (GtkAction *action,
                             ETaskShellView *task_shell_view)
@@ -740,6 +754,13 @@ static GtkActionEntry task_entries[] = {
          N_("Refresh the selected task list"),
          G_CALLBACK (action_task_list_refresh_cb) },
 
+       { "task-list-refresh-backend",
+         "view-refresh",
+         N_("Re_fresh list of account task lists"),
+         NULL,
+         NULL,
+         G_CALLBACK (action_task_list_refresh_backend_cb) },
+
        { "task-list-rename",
          NULL,
          N_("_Rename..."),
@@ -842,6 +863,10 @@ static EPopupActionEntry task_popup_entries[] = {
          NULL,
          "task-list-refresh" },
 
+       { "task-list-popup-refresh-backend",
+         NULL,
+         "task-list-refresh-backend" },
+
        { "task-list-popup-rename",
          NULL,
          "task-list-rename" },
diff --git a/src/modules/calendar/e-task-shell-view-actions.h 
b/src/modules/calendar/e-task-shell-view-actions.h
index f8097e8f7f..b6cba843a6 100644
--- a/src/modules/calendar/e-task-shell-view-actions.h
+++ b/src/modules/calendar/e-task-shell-view-actions.h
@@ -70,6 +70,8 @@
        E_SHELL_WINDOW_ACTION ((window), "task-list-properties")
 #define E_SHELL_WINDOW_ACTION_TASK_LIST_REFRESH(window) \
        E_SHELL_WINDOW_ACTION ((window), "task-list-refresh")
+#define E_SHELL_WINDOW_ACTION_TASK_LIST_REFRESH_BACKEND(window) \
+       E_SHELL_WINDOW_ACTION ((window), "task-list-refresh-backend")
 #define E_SHELL_WINDOW_ACTION_TASK_LIST_RENAME(window) \
        E_SHELL_WINDOW_ACTION ((window), "task-list-rename")
 #define E_SHELL_WINDOW_ACTION_TASK_LIST_SELECT_ALL(window) \
diff --git a/src/modules/calendar/e-task-shell-view-private.c 
b/src/modules/calendar/e-task-shell-view-private.c
index 17611dfe23..2447c806aa 100644
--- a/src/modules/calendar/e-task-shell-view-private.c
+++ b/src/modules/calendar/e-task-shell-view-private.c
@@ -101,21 +101,15 @@ static void
 task_shell_view_table_popup_event_cb (EShellView *shell_view,
                                       GdkEvent *button_event)
 {
-       const gchar *widget_path;
-
-       widget_path = "/task-popup";
-       e_shell_view_show_popup_menu (shell_view, widget_path, button_event);
+       e_cal_base_shell_view_show_popup_menu (shell_view, "/task-popup", button_event, NULL);
 }
 
 static gboolean
 task_shell_view_selector_popup_event_cb (EShellView *shell_view,
-                                         ESource *primary_source,
+                                         ESource *clicked_source,
                                          GdkEvent *button_event)
 {
-       const gchar *widget_path;
-
-       widget_path = "/task-list-popup";
-       e_shell_view_show_popup_menu (shell_view, widget_path, button_event);
+       e_cal_base_shell_view_show_popup_menu (shell_view, "/task-list-popup", button_event, clicked_source);
 
        return TRUE;
 }
diff --git a/src/modules/calendar/e-task-shell-view.c b/src/modules/calendar/e-task-shell-view.c
index 21193f9b7d..e39fdc180a 100644
--- a/src/modules/calendar/e-task-shell-view.c
+++ b/src/modules/calendar/e-task-shell-view.c
@@ -260,6 +260,8 @@ task_shell_view_update_actions (EShellView *shell_view)
        gboolean sources_are_editable;
        gboolean refresh_supported;
        gboolean all_sources_selected;
+       gboolean clicked_source_is_primary;
+       gboolean clicked_source_is_collection;
 
        /* Chain up to parent's update_actions() method. */
        E_SHELL_VIEW_CLASS (e_task_shell_view_parent_class)->update_actions (shell_view);
@@ -301,11 +303,19 @@ task_shell_view_update_actions (EShellView *shell_view)
                (state & E_CAL_BASE_SHELL_SIDEBAR_SOURCE_SUPPORTS_REFRESH);
        all_sources_selected =
                (state & E_CAL_BASE_SHELL_SIDEBAR_ALL_SOURCES_SELECTED) != 0;
+       clicked_source_is_primary =
+               (state & E_CAL_BASE_SHELL_SIDEBAR_CLICKED_SOURCE_IS_PRIMARY) != 0;
+       clicked_source_is_collection =
+               (state & E_CAL_BASE_SHELL_SIDEBAR_CLICKED_SOURCE_IS_COLLECTION) != 0;
 
        any_tasks_selected = (single_task_selected || multiple_tasks_selected);
 
        action = ACTION (TASK_LIST_SELECT_ALL);
-       sensitive = !all_sources_selected;
+       sensitive = clicked_source_is_primary && !all_sources_selected;
+       gtk_action_set_sensitive (action, sensitive);
+
+       action = ACTION (TASK_LIST_SELECT_ONE);
+       sensitive = clicked_source_is_primary;
        gtk_action_set_sensitive (action, sensitive);
 
        action = ACTION (TASK_ASSIGN);
@@ -332,25 +342,37 @@ task_shell_view_update_actions (EShellView *shell_view)
        gtk_action_set_sensitive (action, sensitive);
 
        action = ACTION (TASK_LIST_COPY);
-       sensitive = has_primary_source;
+       sensitive = clicked_source_is_primary && has_primary_source;
        gtk_action_set_sensitive (action, sensitive);
 
        action = ACTION (TASK_LIST_DELETE);
-       sensitive =
+       sensitive = clicked_source_is_primary && (
                primary_source_is_removable ||
-               primary_source_is_remote_deletable;
+               primary_source_is_remote_deletable);
+       gtk_action_set_sensitive (action, sensitive);
+
+       action = ACTION (TASK_LIST_PRINT);
+       sensitive = clicked_source_is_primary;
+       gtk_action_set_sensitive (action, sensitive);
+
+       action = ACTION (TASK_LIST_PRINT_PREVIEW);
+       sensitive = clicked_source_is_primary;
        gtk_action_set_sensitive (action, sensitive);
 
        action = ACTION (TASK_LIST_PROPERTIES);
-       sensitive = primary_source_is_writable;
+       sensitive = clicked_source_is_primary && primary_source_is_writable;
        gtk_action_set_sensitive (action, sensitive);
 
        action = ACTION (TASK_LIST_REFRESH);
-       sensitive = refresh_supported;
+       sensitive = clicked_source_is_primary && refresh_supported;
+       gtk_action_set_sensitive (action, sensitive);
+
+       action = ACTION (TASK_LIST_REFRESH_BACKEND);
+       sensitive = clicked_source_is_collection;
        gtk_action_set_sensitive (action, sensitive);
 
        action = ACTION (TASK_LIST_RENAME);
-       sensitive =
+       sensitive = clicked_source_is_primary &&
                primary_source_is_writable &&
                !primary_source_in_collection;
        gtk_action_set_sensitive (action, sensitive);
diff --git a/src/plugins/save-calendar/save-calendar.c b/src/plugins/save-calendar/save-calendar.c
index 9f2915205b..7ffd4975de 100644
--- a/src/plugins/save-calendar/save-calendar.c
+++ b/src/plugins/save-calendar/save-calendar.c
@@ -338,7 +338,7 @@ calendar_save_as_init (GtkUIManager *ui_manager,
 {
        EShellWindow *shell_window;
        GtkActionGroup *action_group;
-       GtkAction *action;
+       GtkAction *action, *select_one_action;
        const gchar *tooltip;
        const gchar *icon_name;
        const gchar *name;
@@ -358,6 +358,14 @@ calendar_save_as_init (GtkUIManager *ui_manager,
                action, "activate",
                G_CALLBACK (action_calendar_save_as_cb), shell_view);
 
+       /* select-one is always sensitive, except when the clicked and the primary source differ */
+       select_one_action = e_shell_window_get_action (shell_window, "calendar-select-one");
+
+       e_binding_bind_property (
+               select_one_action, "sensitive",
+               action, "visible",
+               G_BINDING_SYNC_CREATE);
+
        g_object_unref (action);
 
        return TRUE;
@@ -369,7 +377,7 @@ memo_list_save_as_init (GtkUIManager *ui_manager,
 {
        EShellWindow *shell_window;
        GtkActionGroup *action_group;
-       GtkAction *action;
+       GtkAction *action, *select_one_action;
        const gchar *tooltip;
        const gchar *icon_name;
        const gchar *name;
@@ -389,6 +397,14 @@ memo_list_save_as_init (GtkUIManager *ui_manager,
                action, "activate",
                G_CALLBACK (action_memo_list_save_as_cb), shell_view);
 
+       /* select-one is always sensitive, except when the clicked and the primary source differ */
+       select_one_action = e_shell_window_get_action (shell_window, "memo-list-select-one");
+
+       e_binding_bind_property (
+               select_one_action, "sensitive",
+               action, "visible",
+               G_BINDING_SYNC_CREATE);
+
        g_object_unref (action);
 
        return TRUE;
@@ -400,7 +416,7 @@ task_list_save_as_init (GtkUIManager *ui_manager,
 {
        EShellWindow *shell_window;
        GtkActionGroup *action_group;
-       GtkAction *action;
+       GtkAction *action, *select_one_action;
        const gchar *tooltip;
        const gchar *icon_name;
        const gchar *name;
@@ -420,6 +436,14 @@ task_list_save_as_init (GtkUIManager *ui_manager,
                action, "activate",
                G_CALLBACK (action_task_list_save_as_cb), shell_view);
 
+       /* select-one is always sensitive, except when the clicked and the primary source differ */
+       select_one_action = e_shell_window_get_action (shell_window, "task-list-select-one");
+
+       e_binding_bind_property (
+               select_one_action, "sensitive",
+               action, "visible",
+               G_BINDING_SYNC_CREATE);
+
        g_object_unref (action);
 
        return TRUE;


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