[evolution] Make Calendar, Memos and Tasks views non-UI-blocking



commit 8752647ecabea0767cc9d72f3a10ac81538066e6
Author: Milan Crha <mcrha redhat com>
Date:   Mon Oct 6 12:33:03 2014 +0200

    Make Calendar, Memos and Tasks views non-UI-blocking
    
    The Calendar, Memos and Tasks views use to do D-Bus calls to
    the backends on the main (UI) thread, which could result in UI
    freezes, until the operation was done on the backend (and server)
    side. This commit fixes that by invoking the operations in
    a dedicated thread. It has few additional advantages too:
    - operations can be cancelled
    - proper error reporting to a user
    - less code duplication between the views for common operations
    
    There had been fixed some performance issues when selecting/unselecting
    sources in the source selector as well.

 calendar/calendar.error.xml                        |  121 +-
 calendar/gui/Makefile.am                           |   27 +-
 calendar/gui/comp-util.c                           |  278 ++-
 calendar/gui/comp-util.h                           |   52 +-
 calendar/gui/dialogs/Makefile.am                   |    3 -
 calendar/gui/dialogs/comp-editor.c                 |   19 +-
 calendar/gui/dialogs/copy-source-dialog.c          |  338 ++--
 calendar/gui/dialogs/copy-source-dialog.h          |    6 +-
 calendar/gui/dialogs/delete-error.c                |  125 -
 calendar/gui/dialogs/delete-error.h                |   32 -
 calendar/gui/dialogs/event-editor.c                |    4 +-
 calendar/gui/dialogs/goto-dialog.c                 |  124 +-
 calendar/gui/dialogs/goto-dialog.h                 |    9 +-
 calendar/gui/dialogs/goto-dialog.ui                |    2 +-
 calendar/gui/dialogs/recur-comp.c                  |   41 +-
 calendar/gui/dialogs/recur-comp.h                  |    8 +-
 calendar/gui/dialogs/task-editor.c                 |    4 +-
 calendar/gui/dialogs/task-page.c                   |    2 +
 calendar/gui/e-cal-data-model-subscriber.c         |  161 ++
 calendar/gui/e-cal-data-model-subscriber.h         |   81 +
 calendar/gui/e-cal-data-model.c                    | 2785 ++++++++++++++++++++
 calendar/gui/e-cal-data-model.h                    |  142 +
 calendar/gui/e-cal-list-view.c                     |    1 -
 calendar/gui/e-cal-list-view.h                     |    1 -
 calendar/gui/e-cal-model-calendar.c                |  124 +-
 calendar/gui/e-cal-model-calendar.h                |    4 +-
 calendar/gui/e-cal-model-memos.c                   |   52 +-
 calendar/gui/e-cal-model-memos.h                   |    4 +-
 calendar/gui/e-cal-model-tasks.c                   |   98 +-
 calendar/gui/e-cal-model-tasks.h                   |    4 +-
 calendar/gui/e-cal-model.c                         | 2548 ++++++-------------
 calendar/gui/e-cal-model.h                         |   91 +-
 calendar/gui/e-cal-ops.c                           | 2090 +++++++++++++++
 calendar/gui/e-cal-ops.h                           |  109 +
 calendar/gui/e-calendar-selector.c                 |  467 ----
 calendar/gui/e-calendar-selector.h                 |   67 -
 calendar/gui/e-calendar-view.c                     | 1239 ++++-----
 calendar/gui/e-calendar-view.h                     |   76 +-
 calendar/gui/e-day-view.c                          |  498 ++--
 calendar/gui/e-day-view.h                          |    1 -
 calendar/gui/e-memo-list-selector.c                |  469 ----
 calendar/gui/e-memo-list-selector.h                |   72 -
 calendar/gui/e-memo-table.c                        |  196 +--
 calendar/gui/e-memo-table.h                        |    3 -
 calendar/gui/e-task-list-selector.c                |  466 ----
 calendar/gui/e-task-list-selector.h                |   72 -
 calendar/gui/e-task-table.c                        |  232 +--
 calendar/gui/e-task-table.h                        |    3 -
 calendar/gui/e-week-view-event-item.c              |    5 +-
 calendar/gui/e-week-view.c                         |  308 ++-
 calendar/gui/e-week-view.h                         |    1 -
 calendar/gui/ea-cal-view.c                         |   71 +-
 calendar/gui/ea-calendar.c                         |    6 +-
 calendar/gui/ea-calendar.h                         |    2 +-
 calendar/gui/ea-day-view-main-item.c               |   22 +-
 calendar/gui/ea-day-view.c                         |   20 +-
 calendar/gui/ea-gnome-calendar.c                   |  344 ---
 calendar/gui/ea-gnome-calendar.h                   |   58 -
 calendar/gui/ea-week-view-main-item.c              |   24 +-
 calendar/gui/ea-week-view.c                        |   38 +-
 calendar/gui/gnome-cal.c                           | 2464 -----------------
 calendar/gui/gnome-cal.h                           |  190 --
 calendar/gui/itip-utils.c                          |  360 ++-
 calendar/gui/itip-utils.h                          |   19 +-
 calendar/gui/print.c                               |  143 +-
 calendar/gui/print.h                               |   18 +-
 calendar/gui/tag-calendar.c                        |  879 ++++++-
 calendar/gui/tag-calendar.h                        |   65 +-
 e-util/e-alarm-selector.c                          |   10 +-
 e-util/e-alert-sink.c                              |  213 ++
 e-util/e-alert-sink.h                              |   25 +
 e-util/e-autocomplete-selector.c                   |   10 +-
 e-util/e-calendar-item.c                           |  103 +-
 e-util/e-calendar-item.h                           |    6 +
 e-util/e-misc-utils.c                              |  142 +
 e-util/e-misc-utils.h                              |   19 +
 e-util/e-proxy-link-selector.c                     |   10 +-
 e-util/e-source-selector.c                         |   66 +-
 e-util/e-source-selector.h                         |    6 +-
 e-util/e-table-one.c                               |    8 +-
 e-util/e-table-sorter.c                            |   28 +
 e-util/e-table-sorting-utils.c                     |   18 +
 modules/cal-config-contacts/e-contacts-selector.c  |   10 +-
 modules/calendar/Makefile.am                       |  103 +-
 modules/calendar/e-cal-attachment-handler.c        |  340 ++--
 modules/calendar/e-cal-base-shell-backend.c        |  598 +++++
 modules/calendar/e-cal-base-shell-backend.h        |   86 +
 modules/calendar/e-cal-base-shell-content.c        |  378 +++
 modules/calendar/e-cal-base-shell-content.h        |  108 +
 modules/calendar/e-cal-base-shell-sidebar.c        |  916 +++++++
 modules/calendar/e-cal-base-shell-sidebar.h        |   90 +
 modules/calendar/e-cal-base-shell-view.c           |  279 ++
 modules/calendar/e-cal-base-shell-view.h           |   77 +
 modules/calendar/e-cal-shell-backend.c             |  616 +----
 modules/calendar/e-cal-shell-backend.h             |   27 +-
 modules/calendar/e-cal-shell-content.c             | 2120 ++++++++++++----
 modules/calendar/e-cal-shell-content.h             |   84 +-
 modules/calendar/e-cal-shell-sidebar.c             |  881 -------
 modules/calendar/e-cal-shell-sidebar.h             |  103 -
 modules/calendar/e-cal-shell-view-actions.c        |  573 ++---
 modules/calendar/e-cal-shell-view-memopad.c        |  119 +-
 modules/calendar/e-cal-shell-view-private.c        |  893 +------
 modules/calendar/e-cal-shell-view-private.h        |   53 +-
 modules/calendar/e-cal-shell-view-taskpad.c        |  127 +-
 modules/calendar/e-cal-shell-view.c                |  342 +--
 modules/calendar/e-cal-shell-view.h                |   23 +-
 modules/calendar/e-memo-shell-backend.c            |  399 +---
 modules/calendar/e-memo-shell-backend.h            |   20 +-
 modules/calendar/e-memo-shell-content.c            |  344 +--
 modules/calendar/e-memo-shell-content.h            |   50 +-
 modules/calendar/e-memo-shell-sidebar.c            |  808 ------
 modules/calendar/e-memo-shell-sidebar.h            |  102 -
 modules/calendar/e-memo-shell-view-actions.c       |  101 +-
 modules/calendar/e-memo-shell-view-private.c       |  187 +--
 modules/calendar/e-memo-shell-view-private.h       |   20 +-
 modules/calendar/e-memo-shell-view.c               |  111 +-
 modules/calendar/e-memo-shell-view.h               |   20 +-
 modules/calendar/e-task-shell-backend.c            |  402 +---
 modules/calendar/e-task-shell-backend.h            |   20 +-
 modules/calendar/e-task-shell-content.c            |  400 ++--
 modules/calendar/e-task-shell-content.h            |   51 +-
 modules/calendar/e-task-shell-sidebar.c            |  808 ------
 modules/calendar/e-task-shell-sidebar.h            |  102 -
 modules/calendar/e-task-shell-view-actions.c       |  100 +-
 modules/calendar/e-task-shell-view-private.c       |  253 +--
 modules/calendar/e-task-shell-view-private.h       |   19 +-
 modules/calendar/e-task-shell-view.c               |  196 +-
 modules/calendar/e-task-shell-view.h               |   28 +-
 modules/calendar/evolution-module-calendar.c       |   35 +-
 .../itip-formatter/e-conflict-search-selector.c    |   10 +-
 modules/itip-formatter/itip-view.c                 |   16 +-
 po/POTFILES.in                                     |   12 +-
 shell/e-shell-view.c                               |   66 +
 shell/e-shell-view.h                               |    8 +
 shell/e-shell-window.c                             |  116 +
 shell/e-shell-window.h                             |   14 +
 136 files changed, 15833 insertions(+), 16983 deletions(-)
---
diff --git a/calendar/calendar.error.xml b/calendar/calendar.error.xml
index 0fecc1c..b59a33e 100644
--- a/calendar/calendar.error.xml
+++ b/calendar/calendar.error.xml
@@ -287,19 +287,127 @@
 
   <error id="failed-open-calendar" type="error" default="GTK_RESPONSE_YES">
     <!-- Translators: {0} is the name of the calendar. -->
-    <_primary>Error loading calendar '{0}'</_primary>
+    <_primary>Failed to open calendar '{0}'</_primary>
+    <secondary>{1}</secondary>
+  </error>
+
+  <error id="failed-open-memos" type="error" default="GTK_RESPONSE_YES">
+    <!-- Translators: {0} is the name of the memo list. -->
+    <_primary>Failed to open memo list '{0}'</_primary>
     <secondary>{1}</secondary>
   </error>
 
   <error id="failed-open-tasks" type="error" default="GTK_RESPONSE_YES">
     <!-- Translators: {0} is the name of the task list. -->
-    <_primary>Error loading task list '{0}'</_primary>
+    <_primary>Failed to open task list '{0}'</_primary>
     <secondary>{1}</secondary>
   </error>
 
-  <error id="failed-open-memos" type="error" default="GTK_RESPONSE_YES">
+  <error id="failed-create-event" type="error" default="GTK_RESPONSE_YES">
+    <!-- Translators: {0} is the name of the calendar. -->
+    <_primary>Failed to create an event in a calendar '{0}'</_primary>
+    <secondary>{1}</secondary>
+  </error>
+
+  <error id="failed-create-memo" type="error" default="GTK_RESPONSE_YES">
     <!-- Translators: {0} is the name of the memo list. -->
-    <_primary>Error loading memo list '{0}'</_primary>
+    <_primary>Failed to create a memo in a memo list '{0}'</_primary>
+    <secondary>{1}</secondary>
+  </error>
+
+  <error id="failed-create-task" type="error" default="GTK_RESPONSE_YES">
+    <!-- Translators: {0} is the name of the task list. -->
+    <_primary>Failed to create a task in a task list '{0}'</_primary>
+    <secondary>{1}</secondary>
+  </error>
+
+  <error id="failed-modify-event" type="error" default="GTK_RESPONSE_YES">
+    <!-- Translators: {0} is the name of the calendar. -->
+    <_primary>Failed to modify an event in a calendar '{0}'</_primary>
+    <secondary>{1}</secondary>
+  </error>
+
+  <error id="failed-modify-memo" type="error" default="GTK_RESPONSE_YES">
+    <!-- Translators: {0} is the name of the memo list. -->
+    <_primary>Failed to modify a memo in a memo list '{0}'</_primary>
+    <secondary>{1}</secondary>
+  </error>
+
+  <error id="failed-modify-task" type="error" default="GTK_RESPONSE_YES">
+    <!-- Translators: {0} is the name of the task list. -->
+    <_primary>Failed to modify a task in a task list '{0}'</_primary>
+    <secondary>{1}</secondary>
+  </error>
+
+  <error id="failed-remove-event" type="error" default="GTK_RESPONSE_YES">
+    <!-- Translators: {0} is the name of the calendar. -->
+    <_primary>Failed to delete an event in a calendar '{0}'</_primary>
+    <secondary>{1}</secondary>
+  </error>
+
+  <error id="failed-remove-memo" type="error" default="GTK_RESPONSE_YES">
+    <!-- Translators: {0} is the name of the memo list. -->
+    <_primary>Failed to delete a memo in a memo list '{0}'</_primary>
+    <secondary>{1}</secondary>
+  </error>
+
+  <error id="failed-remove-task" type="error" default="GTK_RESPONSE_YES">
+    <!-- Translators: {0} is the name of the task list. -->
+    <_primary>Failed to delete a task in a task list '{0}'</_primary>
+    <secondary>{1}</secondary>
+  </error>
+
+  <error id="failed-update-event" type="error" default="GTK_RESPONSE_YES">
+    <!-- Translators: {0} is the name of the calendar. -->
+    <_primary>Failed to update an event in a calendar '{0}'</_primary>
+    <secondary>{1}</secondary>
+  </error>
+
+  <error id="failed-update-memo" type="error" default="GTK_RESPONSE_YES">
+    <!-- Translators: {0} is the name of the memo list. -->
+    <_primary>Failed to update a memo in a memo list '{0}'</_primary>
+    <secondary>{1}</secondary>
+  </error>
+
+  <error id="failed-update-task" type="error" default="GTK_RESPONSE_YES">
+    <!-- Translators: {0} is the name of the task list. -->
+    <_primary>Failed to update a task in a task list '{0}'</_primary>
+    <secondary>{1}</secondary>
+  </error>
+
+  <error id="failed-send-event" type="error" default="GTK_RESPONSE_YES">
+    <!-- Translators: {0} is the name of the calendar. -->
+    <_primary>Failed to send an event to a calendar '{0}'</_primary>
+    <secondary>{1}</secondary>
+  </error>
+
+  <error id="failed-send-memo" type="error" default="GTK_RESPONSE_YES">
+    <!-- Translators: {0} is the name of the memo list. -->
+    <_primary>Failed to send a memo to a memo list '{0}'</_primary>
+    <secondary>{1}</secondary>
+  </error>
+
+  <error id="failed-send-task" type="error" default="GTK_RESPONSE_YES">
+    <!-- Translators: {0} is the name of the task list. -->
+    <_primary>Failed to send a task to a task list '{0}'</_primary>
+    <secondary>{1}</secondary>
+  </error>
+
+  <error id="failed-create-view-calendar" type="error" default="GTK_RESPONSE_YES">
+    <!-- Translators: {0} is the name of the calendar. -->
+    <_primary>Error creating view for a calendar '{0}'</_primary>
+    <secondary>{1}</secondary>
+  </error>
+
+  <error id="failed-create-view-tasks" type="error" default="GTK_RESPONSE_YES">
+    <!-- Translators: {0} is the name of the task list. -->
+    <_primary>Error creating view for a task list '{0}'</_primary>
+    <secondary>{1}</secondary>
+  </error>
+
+  <error id="failed-create-view-memos" type="error" default="GTK_RESPONSE_YES">
+    <!-- Translators: {0} is the name of the memo list. -->
+    <_primary>Error creating view for a memo list '{0}'</_primary>
     <secondary>{1}</secondary>
   </error>
 
@@ -391,4 +499,9 @@
     <secondary>{1}</secondary>
   </error>
 
+  <error id="failed-make-movable" type="error">
+    <_primary>Failed to make an occurrence movable</_primary>
+    <secondary>{1}</secondary>
+  </error>
+
 </error-list>
diff --git a/calendar/gui/Makefile.am b/calendar/gui/Makefile.am
index 2dca7d5..bbf8e10 100644
--- a/calendar/gui/Makefile.am
+++ b/calendar/gui/Makefile.am
@@ -11,11 +11,13 @@ ecalendarinclude_HEADERS =                  \
        comp-util.h                             \
        e-alarm-list.h                          \
        e-cal-config.h                          \
+       e-cal-data-model.h                      \
+       e-cal-data-model-subscriber.h           \
        e-cal-event.h                           \
        e-cal-list-view.h                       \
        e-cal-model-calendar.h                  \
        e-cal-model.h                           \
-       e-calendar-selector.h                   \
+       e-cal-ops.h                             \
        e-calendar-view.h                       \
        e-cell-date-edit-text.h                 \
        e-date-time-list.h                      \
@@ -40,7 +42,6 @@ ecalendarinclude_HEADERS =                    \
        e-week-view.h                           \
        e-weekday-chooser.h                     \
        e-timezone-entry.h                      \
-       gnome-cal.h                             \
        itip-utils.h                            \
        misc.h                                  \
        tag-calendar.h
@@ -91,20 +92,24 @@ libevolution_calendar_la_SOURCES = \
        e-cal-component-preview.h               \
        e-cal-config.c                          \
        e-cal-config.h                          \
+       e-cal-data-model.c                      \
+       e-cal-data-model.h                      \
+       e-cal-data-model-subscriber.c           \
+       e-cal-data-model-subscriber.h           \
        e-cal-event.c                           \
        e-cal-event.h                           \
+       e-cal-list-view.c                       \
+       e-cal-list-view.h                       \
        e-cal-model-calendar.c                  \
        e-cal-model-calendar.h                  \
        e-cal-model.c                           \
        e-cal-model.h                           \
-       e-cal-list-view.c                       \
-       e-cal-list-view.h                       \
        e-cal-model-memos.c                     \
        e-cal-model-memos.h                     \
        e-cal-model-tasks.c                     \
        e-cal-model-tasks.h                     \
-       e-calendar-selector.c                   \
-       e-calendar-selector.h                   \
+       e-cal-ops.h                             \
+       e-cal-ops.c                             \
        e-calendar-view.c                       \
        e-calendar-view.h                       \
        e-cell-date-edit-text.h                 \
@@ -134,8 +139,6 @@ libevolution_calendar_la_SOURCES = \
        e-meeting-types.h                       \
        e-meeting-utils.c                       \
        e-meeting-utils.h                       \
-       e-memo-list-selector.c                  \
-       e-memo-list-selector.h                  \
        e-memo-table.c                          \
        e-memo-table.h                          \
        e-month-view.c                          \
@@ -144,8 +147,6 @@ libevolution_calendar_la_SOURCES = \
        e-select-names-editable.h               \
        e-select-names-renderer.c               \
        e-select-names-renderer.h               \
-       e-task-list-selector.c                  \
-       e-task-list-selector.h                  \
        e-task-table.c                          \
        e-task-table.h                          \
        e-week-view-event-item.c                \
@@ -162,8 +163,6 @@ libevolution_calendar_la_SOURCES = \
        e-weekday-chooser.h                     \
        e-timezone-entry.c                      \
        e-timezone-entry.h                      \
-       gnome-cal.c                             \
-       gnome-cal.h                             \
        itip-utils.c                            \
        itip-utils.h                            \
        misc.c                                  \
@@ -193,9 +192,7 @@ libevolution_calendar_la_SOURCES = \
        ea-week-view-cell.c                     \
        ea-week-view-cell.h                     \
        ea-jump-button.c                        \
-       ea-jump-button.h                        \
-       ea-gnome-calendar.c                     \
-       ea-gnome-calendar.h
+       ea-jump-button.h
 
 libevolution_calendar_la_LIBADD =                                      \
        $(top_builddir)/composer/libevolution-mail-composer.la          \
diff --git a/calendar/gui/comp-util.c b/calendar/gui/comp-util.c
index 16dfd5d..ad80e70 100644
--- a/calendar/gui/comp-util.c
+++ b/calendar/gui/comp-util.c
@@ -30,9 +30,9 @@
 
 #include "calendar-config.h"
 #include "comp-util.h"
+#include "e-calendar-view.h"
 #include "dialogs/delete-comp.h"
 
-#include "gnome-cal.h"
 #include "shell/e-shell-window.h"
 #include "shell/e-shell-view.h"
 
@@ -198,31 +198,28 @@ cal_comp_util_compare_event_timezones (ECalComponent *comp,
 }
 
 /**
- * cal_comp_confirm_delete_empty_comp:
- * @comp: A calendar component.
- * @client: Calendar client where the component purportedly lives.
- * @widget: Widget to be used as the basis for UTF8 conversion.
+ * cal_comp_is_on_server_sync:
+ * @comp: an #ECalComponent
+ * @client: an #ECalClient
+ * @cancellable: (allow none): a #GCancellable
+ * @error: (out): (allow none): a #GError
  *
- * Assumming a calendar component with an empty SUMMARY property (as per
- * string_is_empty()), asks whether the user wants to delete it based on
- * whether the appointment is on the calendar server or not.  If the
- * component is on the server, this function will present a confirmation
- * dialog and delete the component if the user tells it to.  If the component
- * is not on the server it will just return TRUE.
+ * Checks whether @client contains @comp. A "No Such Object" error is not
+ * propagated to the caller, any other errors are.
  *
- * Return value: A result code indicating whether the component
- * was not on the server and is to be deleted locally, whether it
- * was on the server and the user deleted it, or whether the
- * user cancelled the deletion.
+ * Returns: #TRUE, when the @client contains @comp, #FALSE when not or on error.
+ *    The @error is not set when the @client doesn't contain the @comp.
  **/
 gboolean
-cal_comp_is_on_server (ECalComponent *comp,
-                       ECalClient *client)
+cal_comp_is_on_server_sync (ECalComponent *comp,
+                           ECalClient *client,
+                           GCancellable *cancellable,
+                           GError **error)
 {
        const gchar *uid;
        gchar *rid = NULL;
        icalcomponent *icalcomp = NULL;
-       GError *error = NULL;
+       GError *local_error = NULL;
 
        g_return_val_if_fail (comp != NULL, FALSE);
        g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), FALSE);
@@ -244,33 +241,34 @@ cal_comp_is_on_server (ECalComponent *comp,
                rid = e_cal_component_get_recurid_as_string (comp);
        }
 
-       e_cal_client_get_object_sync (
-               client, uid, rid, &icalcomp, NULL, &error);
-
-       if (icalcomp != NULL) {
+       if (e_cal_client_get_object_sync (client, uid, rid, &icalcomp, cancellable, &local_error) &&
+           icalcomp != NULL) {
                icalcomponent_free (icalcomp);
                g_free (rid);
 
                return TRUE;
        }
 
-       if (!g_error_matches (error, E_CAL_CLIENT_ERROR, E_CAL_CLIENT_ERROR_OBJECT_NOT_FOUND))
-               g_warning (G_STRLOC ": %s", error->message);
+       if (g_error_matches (local_error, E_CAL_CLIENT_ERROR, E_CAL_CLIENT_ERROR_OBJECT_NOT_FOUND))
+               g_clear_error (&local_error);
+       else
+               g_propagate_error (error, local_error);
 
-       g_clear_error (&error);
        g_free (rid);
 
        return FALSE;
 }
 
 /**
- * is_icalcomp_on_the_server:
- * same as @cal_comp_is_on_server, only the component parameter is
+ * cal_comp_is_icalcomp_on_server_sync:
+ * The same as cal_comp_is_on_server_sync(), only the component parameter is
  * icalcomponent, not the ECalComponent.
  **/
 gboolean
-is_icalcomp_on_the_server (icalcomponent *icalcomp,
-                           ECalClient *client)
+cal_comp_is_icalcomp_on_server_sync (icalcomponent *icalcomp,
+                                    ECalClient *client,
+                                    GCancellable *cancellable,
+                                    GError **error)
 {
        gboolean on_server;
        ECalComponent *comp;
@@ -278,10 +276,11 @@ is_icalcomp_on_the_server (icalcomponent *icalcomp,
        if (!icalcomp || !client || !icalcomponent_get_uid (icalcomp))
                return FALSE;
 
-       comp = e_cal_component_new ();
-       e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (icalcomp));
+       comp = e_cal_component_new_from_icalcomponent (icalcomponent_new_clone (icalcomp));
+       if (!comp)
+               return FALSE;
 
-       on_server = cal_comp_is_on_server (comp, client);
+       on_server = cal_comp_is_on_server_sync (comp, client, cancellable, error);
 
        g_object_unref (comp);
 
@@ -289,7 +288,7 @@ is_icalcomp_on_the_server (icalcomponent *icalcomp,
 }
 
 /**
- * cal_comp_event_new_with_defaults:
+ * cal_comp_event_new_with_defaults_sync:
  *
  * Creates a new VEVENT component and adds any default alarms to it as set in
  * the program's configuration values, but only if not the all_day event.
@@ -297,11 +296,13 @@ is_icalcomp_on_the_server (icalcomponent *icalcomp,
  * Return value: A newly-created calendar component.
  **/
 ECalComponent *
-cal_comp_event_new_with_defaults (ECalClient *client,
-                                  gboolean all_day,
-                                  gboolean use_default_reminder,
-                                  gint default_reminder_interval,
-                                  EDurationType default_reminder_units)
+cal_comp_event_new_with_defaults_sync (ECalClient *client,
+                                      gboolean all_day,
+                                      gboolean use_default_reminder,
+                                      gint default_reminder_interval,
+                                      EDurationType default_reminder_units,
+                                      GCancellable *cancellable,
+                                      GError **error)
 {
        icalcomponent *icalcomp = NULL;
        ECalComponent *comp;
@@ -309,7 +310,9 @@ cal_comp_event_new_with_defaults (ECalClient *client,
        icalproperty *icalprop;
        ECalComponentAlarmTrigger trigger;
 
-       e_cal_client_get_default_object_sync (client, &icalcomp, NULL, NULL);
+       if (client && !e_cal_client_get_default_object_sync (client, &icalcomp, cancellable, error))
+               return NULL;
+
        if (icalcomp == NULL)
                icalcomp = icalcomponent_new (ICAL_VEVENT_COMPONENT);
 
@@ -368,21 +371,25 @@ cal_comp_event_new_with_defaults (ECalClient *client,
 }
 
 ECalComponent *
-cal_comp_event_new_with_current_time (ECalClient *client,
-                                      gboolean all_day,
-                                      gboolean use_default_reminder,
-                                      gint default_reminder_interval,
-                                      EDurationType default_reminder_units)
+cal_comp_event_new_with_current_time_sync (ECalClient *client,
+                                          gboolean all_day,
+                                          gboolean use_default_reminder,
+                                          gint default_reminder_interval,
+                                          EDurationType default_reminder_units,
+                                          GCancellable *cancellable,
+                                          GError **error)
 {
        ECalComponent *comp;
        struct icaltimetype itt;
        ECalComponentDateTime dt;
        icaltimezone *zone;
 
-       comp = cal_comp_event_new_with_defaults (
+       comp = cal_comp_event_new_with_defaults_sync (
                client, all_day, use_default_reminder,
-               default_reminder_interval, default_reminder_units);
-       g_return_val_if_fail (comp != NULL, NULL);
+               default_reminder_interval, default_reminder_units,
+               cancellable, error);
+       if (!comp)
+               return NULL;
 
        zone = calendar_config_get_icaltimezone ();
 
@@ -410,12 +417,16 @@ cal_comp_event_new_with_current_time (ECalClient *client,
 }
 
 ECalComponent *
-cal_comp_task_new_with_defaults (ECalClient *client)
+cal_comp_task_new_with_defaults_sync (ECalClient *client,
+                                     GCancellable *cancellable,
+                                     GError **error)
 {
        ECalComponent *comp;
        icalcomponent *icalcomp = NULL;
 
-       e_cal_client_get_default_object_sync (client, &icalcomp, NULL, NULL);
+       if (client && !e_cal_client_get_default_object_sync (client, &icalcomp, cancellable, error))
+               return NULL;
+
        if (icalcomp == NULL)
                icalcomp = icalcomponent_new (ICAL_VTODO_COMPONENT);
 
@@ -430,12 +441,16 @@ cal_comp_task_new_with_defaults (ECalClient *client)
 }
 
 ECalComponent *
-cal_comp_memo_new_with_defaults (ECalClient *client)
+cal_comp_memo_new_with_defaults_sync (ECalClient *client,
+                                     GCancellable *cancellable,
+                                     GError **error)
 {
        ECalComponent *comp;
        icalcomponent *icalcomp = NULL;
 
-       e_cal_client_get_default_object_sync (client, &icalcomp, NULL, NULL);
+       if (client && !e_cal_client_get_default_object_sync (client, &icalcomp, cancellable, error))
+               return NULL;
+
        if (icalcomp == NULL)
                icalcomp = icalcomponent_new (ICAL_VJOURNAL_COMPONENT);
 
@@ -470,26 +485,23 @@ cal_comp_update_time_by_active_window (ECalComponent *comp,
                if (g_strcmp0 (active_view, "calendar") == 0) {
                        EShellContent *shell_content;
                        EShellView *shell_view;
-                       GnomeCalendar *gnome_cal;
+                       ECalendarView *cal_view;
                        time_t start = 0, end = 0;
                        icaltimezone *zone;
                        struct icaltimetype itt;
                        icalcomponent *icalcomp;
                        icalproperty *prop;
 
-                       shell_view = e_shell_window_peek_shell_view (
-                               shell_window, "calendar");
+                       shell_view = e_shell_window_peek_shell_view (shell_window, "calendar");
                        g_return_if_fail (shell_view != NULL);
 
-                       gnome_cal = NULL;
+                       cal_view = NULL;
                        shell_content = e_shell_view_get_shell_content (shell_view);
-                       g_object_get (shell_content, "calendar", &gnome_cal, NULL);
-                       g_return_if_fail (gnome_cal != NULL);
+                       g_object_get (shell_content, "current-view", &cal_view, NULL);
+                       g_return_if_fail (cal_view != NULL);
+                       g_return_if_fail (e_calendar_view_get_visible_time_range (cal_view, &start, &end));
 
-                       gnome_calendar_get_current_time_range (gnome_cal, &start, &end);
-                       g_return_if_fail (start != 0);
-
-                       zone = e_cal_model_get_timezone (gnome_calendar_get_model (gnome_cal));
+                       zone = e_cal_model_get_timezone (e_calendar_view_get_model (cal_view));
                        itt = icaltime_from_timet_with_zone (start, FALSE, zone);
 
                        icalcomp = e_cal_component_get_icalcomponent (comp);
@@ -502,6 +514,8 @@ cal_comp_update_time_by_active_window (ECalComponent *comp,
                        }
 
                        e_cal_component_rescan (comp);
+
+                       g_clear_object (&cal_view);
                }
        }
 }
@@ -724,37 +738,28 @@ cal_comp_set_dtend_with_oldzone (ECalClient *client,
        e_cal_component_free_datetime (&olddate);
 }
 
-void
-comp_util_sanitize_recurrence_master (ECalComponent *comp,
-                                      ECalClient *client)
+gboolean
+comp_util_sanitize_recurrence_master_sync (ECalComponent *comp,
+                                          ECalClient *client,
+                                          GCancellable *cancellable,
+                                          GError **error)
 {
        ECalComponent *master = NULL;
        icalcomponent *icalcomp = NULL;
        ECalComponentRange rid;
        ECalComponentDateTime sdt;
        const gchar *uid;
-       GError *error = NULL;
 
        /* Get the master component */
        e_cal_component_get_uid (comp, &uid);
 
-       e_cal_client_get_object_sync (
-               client, uid, NULL, &icalcomp, NULL, &error);
-
-       if (error != NULL) {
-               g_warning (
-                       "Unable to get the master component: %s",
-                       error->message);
-               g_error_free (error);
-               return;
-       }
+       if (!e_cal_client_get_object_sync (client, uid, NULL, &icalcomp, cancellable, error))
+               return FALSE;
 
-       master = e_cal_component_new ();
-       if (!e_cal_component_set_icalcomponent (master, icalcomp)) {
-               icalcomponent_free (icalcomp);
-               g_object_unref (master);
-               g_return_if_reached ();
-               return;
+       master = e_cal_component_new_from_icalcomponent (icalcomp);
+       if (!master) {
+               g_warn_if_reached ();
+               return FALSE;
        }
 
        /* Compare recur id and start date */
@@ -772,9 +777,16 @@ comp_util_sanitize_recurrence_master (ECalComponent *comp,
 
                e_cal_component_get_dtend (comp, &edt);
 
-               g_return_if_fail (msdt.value != NULL);
-               g_return_if_fail (medt.value != NULL);
-               g_return_if_fail (edt.value != NULL);
+               if (!msdt.value || !medt.value || !edt.value) {
+                       g_warn_if_reached ();
+                       e_cal_component_free_datetime (&msdt);
+                       e_cal_component_free_datetime (&medt);
+                       e_cal_component_free_datetime (&edt);
+                       e_cal_component_free_datetime (&sdt);
+                       e_cal_component_free_range (&rid);
+                       g_object_unref (master);
+                       return FALSE;
+               }
 
                sdt.value->year = msdt.value->year;
                sdt.value->month = msdt.value->month;
@@ -800,6 +812,8 @@ comp_util_sanitize_recurrence_master (ECalComponent *comp,
        e_cal_component_set_recurid (comp, NULL);
 
        g_object_unref (master);
+
+       return TRUE;
 }
 
 gchar *
@@ -822,6 +836,102 @@ icalcomp_suggest_filename (icalcomponent *icalcomp,
        return g_strconcat (summary, ".ics", NULL);
 }
 
+void
+cal_comp_get_instance_times (ECalClient *client,
+                            icalcomponent *icalcomp,
+                            const icaltimezone *default_zone,
+                            time_t *instance_start,
+                            gboolean *start_is_date,
+                            time_t *instance_end,
+                            gboolean *end_is_date,
+                            GCancellable *cancellable)
+{
+       struct icaltimetype start_time, end_time;
+       const icaltimezone *zone = default_zone;
+
+       g_return_if_fail (E_IS_CAL_CLIENT (client));
+       g_return_if_fail (icalcomp != NULL);
+       g_return_if_fail (instance_start != NULL);
+       g_return_if_fail (instance_end != NULL);
+
+       start_time = icalcomponent_get_dtstart (icalcomp);
+       end_time = icalcomponent_get_dtend (icalcomp);
+
+       if (start_time.zone) {
+               zone = start_time.zone;
+       } else {
+               icalparameter *param = NULL;
+               icalproperty *prop = icalcomponent_get_first_property (icalcomp, ICAL_DTSTART_PROPERTY);
+
+               if (prop) {
+                       param = icalproperty_get_first_parameter (prop, ICAL_TZID_PARAMETER);
+
+                       if (param) {
+                               const gchar *tzid = NULL;
+                               icaltimezone *st_zone = NULL;
+
+                               tzid = icalparameter_get_tzid (param);
+                               if (tzid)
+                                       e_cal_client_get_timezone_sync (client, tzid, &st_zone, cancellable, 
NULL);
+
+                               if (st_zone)
+                                       zone = st_zone;
+                       }
+              }
+       }
+
+       *instance_start = icaltime_as_timet_with_zone (start_time, zone);
+       if (start_is_date)
+               *start_is_date = start_time.is_date;
+
+       if (end_time.zone) {
+               zone = end_time.zone;
+       } else {
+               icalparameter *param = NULL;
+               icalproperty *prop = icalcomponent_get_first_property (icalcomp, ICAL_DTSTART_PROPERTY);
+
+               if (prop) {
+                       param = icalproperty_get_first_parameter (prop, ICAL_TZID_PARAMETER);
+
+                       if (param) {
+                               const gchar *tzid = NULL;
+                               icaltimezone *end_zone = NULL;
+
+                               tzid = icalparameter_get_tzid (param);
+                               if (tzid)
+                                       e_cal_client_get_timezone_sync (client, tzid, &end_zone, cancellable, 
NULL);
+
+                               if (end_zone)
+                                       zone = end_zone;
+                       }
+              }
+
+       }
+
+       *instance_end = icaltime_as_timet_with_zone (end_time, zone);
+       if (end_is_date)
+               *end_is_date = end_time.is_date;
+}
+
+time_t
+cal_comp_gdate_to_timet (const GDate *date,
+                        const icaltimezone *with_zone)
+{
+       struct tm tm;
+       struct icaltimetype tt;
+
+       g_return_val_if_fail (date != NULL, (time_t) -1);
+       g_return_val_if_fail (g_date_valid (date), (time_t) -1);
+
+       g_date_to_struct_tm (date, &tm);
+
+       tt = tm_to_icaltimetype (&tm, TRUE);
+       if (with_zone)
+               return icaltime_as_timet_with_zone (tt, with_zone);
+
+       return icaltime_as_timet (tt);
+}
+
 typedef struct _AsyncContext {
        ECalClient *src_client;
        icalcomponent *icalcomp_clone;
diff --git a/calendar/gui/comp-util.h b/calendar/gui/comp-util.h
index ec2fe06..a3b2350 100644
--- a/calendar/gui/comp-util.h
+++ b/calendar/gui/comp-util.h
@@ -28,6 +28,7 @@
 #include <libecal/libecal.h>
 
 #include <e-util/e-util.h>
+#include <calendar/gui/e-cal-data-model.h>
 
 struct _EShell;
 
@@ -43,24 +44,40 @@ gboolean cal_comp_util_compare_event_timezones (ECalComponent *comp,
 /* Returns the number of icons owned by the ECalComponent */
 gint     cal_comp_util_get_n_icons (ECalComponent *comp, GSList **pixbufs);
 
-gboolean cal_comp_is_on_server (ECalComponent *comp,
-                               ECalClient *client);
-gboolean is_icalcomp_on_the_server (icalcomponent *icalcomp, ECalClient *client);
+gboolean       cal_comp_is_on_server_sync      (ECalComponent *comp,
+                                                ECalClient *client,
+                                                GCancellable *cancellable,
+                                                GError **error);
+gboolean       cal_comp_is_icalcomp_on_server_sync
+                                               (icalcomponent *icalcomp,
+                                                ECalClient *client,
+                                                GCancellable *cancellable,
+                                                GError **error);
 
-ECalComponent *        cal_comp_event_new_with_defaults
+ECalComponent *        cal_comp_event_new_with_defaults_sync
                                                (ECalClient *client,
                                                 gboolean all_day,
                                                 gboolean use_default_reminder,
                                                 gint default_reminder_interval,
-                                                EDurationType default_reminder_units);
-ECalComponent *        cal_comp_event_new_with_current_time
+                                                EDurationType default_reminder_units,
+                                                GCancellable *cancellable,
+                                                GError **error);
+ECalComponent *        cal_comp_event_new_with_current_time_sync
                                                (ECalClient *client,
                                                 gboolean all_day,
                                                 gboolean use_default_reminder,
                                                 gint default_reminder_interval,
-                                                EDurationType default_reminder_units);
-ECalComponent *cal_comp_task_new_with_defaults (ECalClient *client);
-ECalComponent *cal_comp_memo_new_with_defaults (ECalClient *client);
+                                                EDurationType default_reminder_units,
+                                                GCancellable *cancellable,
+                                                GError **error);
+ECalComponent *        cal_comp_task_new_with_defaults_sync
+                                               (ECalClient *client,
+                                                GCancellable *cancellable,
+                                                GError **error);
+ECalComponent *        cal_comp_memo_new_with_defaults_sync
+                                               (ECalClient *client,
+                                                GCancellable *cancellable,
+                                                GError **error);
 
 void cal_comp_update_time_by_active_window (ECalComponent *comp, struct _EShell *shell);
 
@@ -70,10 +87,25 @@ GSList *cal_comp_selection_get_string_list (GtkSelectionData *data);
 void cal_comp_set_dtstart_with_oldzone (ECalClient *client, ECalComponent *comp, const ECalComponentDateTime 
*pdate);
 void cal_comp_set_dtend_with_oldzone (ECalClient *client, ECalComponent *comp, const ECalComponentDateTime 
*pdate);
 
-void comp_util_sanitize_recurrence_master (ECalComponent *comp, ECalClient *client);
+gboolean       comp_util_sanitize_recurrence_master_sync
+                                               (ECalComponent *comp,
+                                                ECalClient *client,
+                                                GCancellable *cancellable,
+                                                GError **error);
 
 gchar *icalcomp_suggest_filename (icalcomponent *icalcomp, const gchar *default_name);
 
+void           cal_comp_get_instance_times     (ECalClient *client,
+                                                icalcomponent *icalcomp,
+                                                const icaltimezone *default_zone,
+                                                time_t *instance_start,
+                                                gboolean *start_is_date,
+                                                time_t *instance_end,
+                                                gboolean *end_is_date,
+                                                GCancellable *cancellable);
+time_t         cal_comp_gdate_to_timet         (const GDate *date,
+                                                const icaltimezone *with_zone);
+
 void cal_comp_transfer_item_to                 (ECalClient *src_client,
                                                 ECalClient *dest_client,
                                                 icalcomponent *icalcomp_vcal,
diff --git a/calendar/gui/dialogs/Makefile.am b/calendar/gui/dialogs/Makefile.am
index ec5afaa..552bbae 100644
--- a/calendar/gui/dialogs/Makefile.am
+++ b/calendar/gui/dialogs/Makefile.am
@@ -29,7 +29,6 @@ ecalendarinclude_HEADERS =            \
        comp-editor-util.h              \
        copy-source-dialog.h            \
        delete-comp.h                   \
-       delete-error.h                  \
        e-delegate-dialog.h             \
        e-send-options-utils.h          \
        event-editor.h                  \
@@ -73,8 +72,6 @@ libcal_dialogs_la_SOURCES =           \
        copy-source-dialog.h            \
        delete-comp.c                   \
        delete-comp.h                   \
-       delete-error.c                  \
-       delete-error.h                  \
        e-delegate-dialog.c             \
        e-delegate-dialog.h             \
        e-send-options-utils.c          \
diff --git a/calendar/gui/dialogs/comp-editor.c b/calendar/gui/dialogs/comp-editor.c
index 66bda65..a5e1d66 100644
--- a/calendar/gui/dialogs/comp-editor.c
+++ b/calendar/gui/dialogs/comp-editor.c
@@ -551,7 +551,7 @@ save_comp (CompEditor *editor)
                priv->comp, get_attachment_list (editor));
        icalcomp = e_cal_component_get_icalcomponent (priv->comp);
        /* send the component to the server */
-       if (!cal_comp_is_on_server (priv->comp, priv->cal_client)) {
+       if (!cal_comp_is_on_server_sync (priv->comp, priv->cal_client, NULL, NULL)) {
                gchar *uid = NULL;
                result = e_cal_client_create_object_sync (
                        priv->cal_client, icalcomp, &uid, NULL, &error);
@@ -567,8 +567,7 @@ save_comp (CompEditor *editor)
                        e_cal_component_has_recurrences (priv->comp);
 
                if (has_recurrences && priv->mod == CALOBJ_MOD_ALL)
-                       comp_util_sanitize_recurrence_master (
-                               priv->comp, priv->cal_client);
+                       comp_util_sanitize_recurrence_master_sync (priv->comp, priv->cal_client, NULL, NULL);
 
                if (priv->mod == CALOBJ_MOD_THIS) {
                        e_cal_component_set_rdate_list (priv->comp, NULL);
@@ -637,7 +636,7 @@ save_comp (CompEditor *editor)
                if (priv->source_client &&
                    !e_source_equal (e_client_get_source (E_CLIENT (priv->cal_client)),
                                     e_client_get_source (E_CLIENT (priv->source_client))) &&
-                   cal_comp_is_on_server (priv->comp, priv->source_client)) {
+                   cal_comp_is_on_server_sync (priv->comp, priv->source_client, NULL, NULL)) {
                        /* Comp found a new home. Remove it from old one. */
                        GError *error = NULL;
 
@@ -1088,7 +1087,7 @@ save_and_close_editor (CompEditor *editor,
                                        has_recurrences = e_cal_component_has_recurrences (comp);
 
                                        if (has_recurrences && priv->mod == CALOBJ_MOD_ALL)
-                                               comp_util_sanitize_recurrence_master (comp, priv->cal_client);
+                                               comp_util_sanitize_recurrence_master_sync (comp, 
priv->cal_client, NULL, NULL);
 
                                        comp_editor_edit_comp (editor, comp);
                                } else {
@@ -3485,10 +3484,10 @@ real_send_comp (CompEditor *editor,
                e_client_check_capability (
                        E_CLIENT (priv->cal_client),
                        CAL_STATIC_CAPABILITY_CREATE_MESSAGES)) {
-               if (itip_send_comp (
+               if (itip_send_comp_sync (
                        registry, method, send_comp, priv->cal_client,
                        NULL, NULL, users, strip_alarms,
-                       priv->flags & COMP_EDITOR_SEND_TO_NEW_ATTENDEES_ONLY)) {
+                       priv->flags & COMP_EDITOR_SEND_TO_NEW_ATTENDEES_ONLY, NULL, NULL)) {
                        g_object_unref (send_comp);
                        return TRUE;
                }
@@ -3497,7 +3496,7 @@ real_send_comp (CompEditor *editor,
                GSList *attach_list = NULL;
                GSList *mime_attach_list, *attach;
 
-               /* mime_attach_list is freed by itip_send_comp */
+               /* mime_attach_list is freed by itip_send_comp_sync */
                mime_attach_list = comp_editor_get_mime_attach_list (editor);
 
                for (attach = mime_attach_list; attach; attach = attach->next) {
@@ -3515,10 +3514,10 @@ real_send_comp (CompEditor *editor,
                        g_slist_free (attach_list);
                }
 
-               if (itip_send_comp (
+               if (itip_send_comp_sync (
                        registry, method, send_comp, priv->cal_client,
                        NULL, mime_attach_list, users, strip_alarms,
-                       priv->flags & COMP_EDITOR_SEND_TO_NEW_ATTENDEES_ONLY)) {
+                       priv->flags & COMP_EDITOR_SEND_TO_NEW_ATTENDEES_ONLY, NULL, NULL)) {
                        gboolean saved = save_comp (editor);
 
                        g_object_unref (send_comp);
diff --git a/calendar/gui/dialogs/copy-source-dialog.c b/calendar/gui/dialogs/copy-source-dialog.c
index c7a7b4d..6210587 100644
--- a/calendar/gui/dialogs/copy-source-dialog.c
+++ b/calendar/gui/dialogs/copy-source-dialog.c
@@ -25,7 +25,7 @@
 #include <config.h>
 #endif
 
-#include <glib/gi18n.h>
+#include <glib/gi18n-lib.h>
 
 #include "e-util/e-util.h"
 
@@ -33,31 +33,37 @@
 #include "select-source-dialog.h"
 
 typedef struct {
-       GtkWindow *parent;
-       ESource *orig_source;
-       ECalClientSourceType obj_type;
-       ESource *selected_source;
-       ECalClient *source_client, *dest_client;
-} CopySourceDialogData;
+       ECalModel *model;
+       ESource *from_source;
+       ESource *to_source;
+       ECalClient *to_client;
+       const gchar *extension_name;
+} CopySourceData;
 
 static void
-show_error (CopySourceDialogData *csdd,
-            const gchar *msg,
-            const GError *error)
+copy_source_data_free (gpointer ptr)
 {
-       GtkWidget *dialog;
+       CopySourceData *csd = ptr;
+
+       if (csd) {
+               if (csd->to_client)
+                       e_cal_model_emit_object_created (csd->model, csd->to_client);
 
-       dialog = gtk_message_dialog_new (
-               csdd->parent, 0, GTK_MESSAGE_ERROR,
-               GTK_BUTTONS_CLOSE, error ? "%s\n%s" : "%s", msg, error ? error->message : "");
-       gtk_dialog_run (GTK_DIALOG (dialog));
-       gtk_widget_destroy (dialog);
+               g_clear_object (&csd->model);
+               g_clear_object (&csd->from_source);
+               g_clear_object (&csd->to_source);
+               g_clear_object (&csd->to_client);
+               g_free (csd);
+       }
 }
 
 struct ForeachTzidData
 {
-       ECalClient *source_client;
-       ECalClient *dest_client;
+       ECalClient *from_client;
+       ECalClient *to_client;
+       gboolean success;
+       GCancellable *cancellable;
+       GError **error;
 };
 
 static void
@@ -69,169 +75,111 @@ add_timezone_to_cal_cb (icalparameter *param,
        const gchar *tzid;
 
        g_return_if_fail (ftd != NULL);
-       g_return_if_fail (ftd->source_client != NULL);
-       g_return_if_fail (ftd->dest_client != NULL);
+       g_return_if_fail (ftd->from_client != NULL);
+       g_return_if_fail (ftd->to_client != NULL);
+
+       if (!ftd->success)
+               return;
 
        tzid = icalparameter_get_tzid (param);
        if (!tzid || !*tzid)
                return;
 
-       e_cal_client_get_timezone_sync (
-               ftd->source_client, tzid, &tz, NULL, NULL);
-       if (tz != NULL)
-               e_cal_client_add_timezone_sync (
-                       ftd->dest_client, tz, NULL, NULL);
-}
-
-static void
-free_copy_data (CopySourceDialogData *csdd)
-{
-       if (!csdd)
+       if (g_cancellable_set_error_if_cancelled (ftd->cancellable, ftd->error)) {
+               ftd->success = FALSE;
                return;
+       }
 
-       if (csdd->orig_source)
-               g_object_unref (csdd->orig_source);
-       if (csdd->selected_source)
-               g_object_unref (csdd->selected_source);
-       if (csdd->source_client)
-               g_object_unref (csdd->source_client);
-       if (csdd->dest_client)
-               g_object_unref (csdd->dest_client);
-       g_free (csdd);
+       ftd->success = e_cal_client_get_timezone_sync (ftd->from_client, tzid, &tz, ftd->cancellable, 
ftd->error);
+       if (ftd->success && tz != NULL)
+               ftd->success = e_cal_client_add_timezone_sync (ftd->to_client, tz, ftd->cancellable, 
ftd->error);
 }
 
 static void
-dest_source_connected_cb (GObject *source_object,
-                          GAsyncResult *result,
-                          gpointer user_data)
+copy_source_thread (EAlertSinkThreadJobData *job_data,
+                   gpointer user_data,
+                   GCancellable *cancellable,
+                   GError **error)
 {
-       CopySourceDialogData *csdd = user_data;
+       CopySourceData *csd = user_data;
        EClient *client;
-       GError *error = NULL;
+       ECalClient *from_client = NULL, *to_client = NULL;
+       GSList *objects = NULL, *link;
+       struct ForeachTzidData ftd;
+       gint n_objects, ii, last_percent = 0;
 
-       client = e_cal_client_connect_finish (result, &error);
+       if (!csd)
+               goto out;
 
-       /* Sanity check. */
-       g_return_if_fail (
-               ((client != NULL) && (error == NULL)) ||
-               ((client == NULL) && (error != NULL)));
+       client = e_util_open_client_sync (job_data, e_cal_model_get_client_cache (csd->model), 
csd->extension_name, csd->from_source, cancellable, error);
+       if (client)
+               from_client = E_CAL_CLIENT (client);
 
-       if (error != NULL) {
-               show_error (csdd, _("Could not open destination"), error);
-               g_error_free (error);
-               free_copy_data (csdd);
-               return;
-       }
+       if (!from_client)
+               goto out;
 
-       csdd->dest_client = E_CAL_CLIENT (client);
-
-       /* check if the destination is read only */
-       if (e_client_is_readonly (E_CLIENT (csdd->dest_client))) {
-               show_error (csdd, _("Destination is read only"), NULL);
-       } else {
-               GSList *obj_list = NULL;
-
-               e_cal_client_get_object_list_sync (
-                       csdd->source_client, "#t", &obj_list, NULL, NULL);
-               if (obj_list != NULL) {
-                       GSList *l;
-                       icalcomponent *icalcomp;
-                       struct ForeachTzidData ftd;
-
-                       ftd.source_client = csdd->source_client;
-                       ftd.dest_client = csdd->dest_client;
-
-                       for (l = obj_list; l != NULL; l = l->next) {
-                               icalcomp = NULL;
-
-                               /* FIXME: process recurrences */
-                               /* FIXME: process errors */
-                               if (e_cal_client_get_object_sync (
-                                       csdd->dest_client,
-                                       icalcomponent_get_uid (l->data),
-                                       NULL, &icalcomp, NULL, NULL) &&
-                                   icalcomp != NULL) {
-                                       e_cal_client_modify_object_sync (
-                                               csdd->dest_client, l->data,
-                                               CALOBJ_MOD_ALL, NULL, NULL);
-                                       icalcomponent_free (icalcomp);
-                               } else {
-                                       GError *error = NULL;
-
-                                       icalcomp = l->data;
-
-                                       /* Add timezone information from source
-                                        * ECal to the destination ECal. */
-                                       icalcomponent_foreach_tzid (
-                                               icalcomp,
-                                               add_timezone_to_cal_cb, &ftd);
-
-                                       e_cal_client_create_object_sync (
-                                               csdd->dest_client,
-                                               icalcomp, NULL, NULL, &error);
-
-                                       if (error != NULL) {
-                                               show_error (csdd, _("Cannot create object"), error);
-                                               g_error_free (error);
-                                               break;
-                                       }
-                               }
-                       }
-
-                       e_cal_client_free_icalcomp_slist (obj_list);
-               }
+       client = e_util_open_client_sync (job_data, e_cal_model_get_client_cache (csd->model), 
csd->extension_name, csd->to_source, cancellable, error);
+       if (client)
+               to_client = E_CAL_CLIENT (client);
+
+       if (!to_client)
+               goto out;
+
+       if (e_client_is_readonly (E_CLIENT (to_client))) {
+               g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_READ_ONLY, _("Destination is read only"));
+               goto out;
        }
 
-       free_copy_data (csdd);
-}
+       if (!e_cal_client_get_object_list_sync (from_client, "#t", &objects, cancellable, error))
+               goto out;
 
-static void
-orig_source_connected_cb (GObject *source_object,
-                          GAsyncResult *result,
-                          gpointer user_data)
-{
-       CopySourceDialogData *csdd = user_data;
-       EClient *client;
-       GError *error = NULL;
+       ftd.from_client = from_client;
+       ftd.to_client = to_client;
+       ftd.success = TRUE;
+       ftd.cancellable = cancellable;
+       ftd.error = error;
 
-       client = e_cal_client_connect_finish (result, &error);
+       n_objects = g_slist_length (objects);
 
-       /* Sanity check. */
-       g_return_if_fail (
-               ((client != NULL) && (error == NULL)) ||
-               ((client == NULL) && (error != NULL)));
+       for (link = objects, ii = 0; link && ftd.success && !g_cancellable_is_cancelled (cancellable); link = 
g_slist_next (link), ii++) {
+               icalcomponent *icalcomp = link->data;
+               icalcomponent *existing_icalcomp = NULL;
+               gint percent = 100 * (ii + 1) / n_objects;
+               GError *local_error = NULL;
 
-       if (error != NULL) {
-               show_error (csdd, _("Could not open source"), error);
-               g_error_free (error);
-               free_copy_data (csdd);
-               return;
-       }
+               if (e_cal_client_get_object_sync (to_client, icalcomponent_get_uid (icalcomp), NULL, 
&existing_icalcomp, cancellable, &local_error) &&
+                   icalcomp != NULL) {
+                       if (!e_cal_client_modify_object_sync (to_client, icalcomp, E_CAL_OBJ_MOD_ALL, 
cancellable, error))
+                               break;
 
-       csdd->source_client = E_CAL_CLIENT (client);
+                       icalcomponent_free (existing_icalcomp);
+               } else if (local_error && !g_error_matches (local_error, E_CAL_CLIENT_ERROR, 
E_CAL_CLIENT_ERROR_OBJECT_NOT_FOUND)) {
+                       g_propagate_error (error, local_error);
+                       break;
+               } else {
+                       icalcomponent_foreach_tzid (icalcomp, add_timezone_to_cal_cb, &ftd);
 
-       e_cal_client_connect (
-               csdd->selected_source, csdd->obj_type, NULL,
-               dest_source_connected_cb, csdd);
-}
+                       g_clear_error (&local_error);
 
-static void
-copy_source (const CopySourceDialogData *const_csdd)
-{
-       CopySourceDialogData *csdd;
+                       if (!ftd.success)
+                               break;
 
-       if (!const_csdd->selected_source)
-               return;
+                       if (!e_cal_client_create_object_sync (to_client, icalcomp, NULL, cancellable, error))
+                               break;
+               }
 
-       csdd = g_new0 (CopySourceDialogData, 1);
-       csdd->parent = const_csdd->parent;
-       csdd->orig_source = g_object_ref (const_csdd->orig_source);
-       csdd->obj_type = const_csdd->obj_type;
-       csdd->selected_source = g_object_ref (const_csdd->selected_source);
+               if (percent != last_percent) {
+                       camel_operation_progress (cancellable, percent);
+                       last_percent = percent;
+               }
+       }
 
-       e_cal_client_connect (
-               csdd->orig_source, csdd->obj_type, NULL,
-               orig_source_connected_cb, csdd);
+       if (ii > 0 && ftd.success)
+               csd->to_client = g_object_ref (to_client);
+ out:
+       e_cal_client_free_icalcomp_slist (objects);
+       g_clear_object (&from_client);
+       g_clear_object (&to_client);
 }
 
 /**
@@ -242,29 +190,67 @@ copy_source (const CopySourceDialogData *const_csdd)
  */
 void
 copy_source_dialog (GtkWindow *parent,
-                    ESourceRegistry *registry,
-                    ESource *source,
-                    ECalClientSourceType obj_type)
+                    ECalModel *model,
+                    ESource *from_source)
 {
-       CopySourceDialogData csdd;
-
-       g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
-       g_return_if_fail (E_IS_SOURCE (source));
-       g_return_if_fail (obj_type == E_CAL_CLIENT_SOURCE_TYPE_EVENTS ||
-                         obj_type == E_CAL_CLIENT_SOURCE_TYPE_TASKS ||
-                         obj_type == E_CAL_CLIENT_SOURCE_TYPE_MEMOS);
-
-       csdd.parent = parent;
-       csdd.orig_source = source;
-       csdd.selected_source = NULL;
-       csdd.obj_type = obj_type;
-
-       csdd.selected_source = select_source_dialog (
-               parent, registry, obj_type, source);
-       if (csdd.selected_source) {
-               copy_source (&csdd);
-
-               /* free memory */
-               g_object_unref (csdd.selected_source);
+       ECalClientSourceType obj_type;
+       ESource *to_source;
+       const gchar *extension_name;
+       const gchar *format;
+       const gchar *alert_ident;
+
+       g_return_if_fail (E_IS_CAL_MODEL (model));
+       g_return_if_fail (E_IS_SOURCE (from_source));
+
+       switch (e_cal_model_get_component_kind (model)) {
+               case ICAL_VEVENT_COMPONENT:
+                       obj_type = E_CAL_CLIENT_SOURCE_TYPE_EVENTS;
+                       extension_name = E_SOURCE_EXTENSION_CALENDAR;
+                       format = _("Copying events to the calendar '%s'");
+                       alert_ident = "calendar:failed-copy-event";
+                       break;
+               case ICAL_VJOURNAL_COMPONENT:
+                       obj_type = E_CAL_CLIENT_SOURCE_TYPE_MEMOS;
+                       extension_name = E_SOURCE_EXTENSION_MEMO_LIST;
+                       format = _("Copying memos to the memo list '%s'");
+                       alert_ident = "calendar:failed-copy-memo";
+                       break;
+               case ICAL_VTODO_COMPONENT:
+                       obj_type = E_CAL_CLIENT_SOURCE_TYPE_TASKS;
+                       extension_name = E_SOURCE_EXTENSION_TASK_LIST;
+                       format = _("Copying tasks to the task list '%s'");
+                       alert_ident = "calendar:failed-copy-task";
+                       break;
+               default:
+                       g_warn_if_reached ();
+                       return;
+       }
+
+       to_source = select_source_dialog (parent, e_cal_model_get_registry (model), obj_type, from_source);
+       if (to_source) {
+               CopySourceData *csd;
+               GCancellable *cancellable;
+               ECalDataModel *data_model;
+               const gchar *alert_arg_0;
+               gchar *description;
+
+               csd = g_new0 (CopySourceData, 1);
+               csd->model = g_object_ref (model);
+               csd->from_source = g_object_ref (from_source);
+               csd->to_source = g_object_ref (to_source);
+               csd->to_client = NULL;
+               csd->extension_name = extension_name;
+
+               alert_arg_0 = e_source_get_display_name (to_source);
+               description = g_strdup_printf (format, alert_arg_0);
+               data_model = e_cal_model_get_data_model (model);
+
+               cancellable = e_cal_data_model_submit_thread_job (data_model, description, alert_ident, 
alert_arg_0,
+                       copy_source_thread, csd, copy_source_data_free);
+
+               g_clear_object (&cancellable);
+               g_free (description);
        }
+
+       g_clear_object (&to_source);
 }
diff --git a/calendar/gui/dialogs/copy-source-dialog.h b/calendar/gui/dialogs/copy-source-dialog.h
index 2b551b4..c6824c2 100644
--- a/calendar/gui/dialogs/copy-source-dialog.h
+++ b/calendar/gui/dialogs/copy-source-dialog.h
@@ -27,10 +27,10 @@
 
 #include <gtk/gtk.h>
 #include <libecal/libecal.h>
+#include <calendar/gui/e-cal-model.h>
 
 void           copy_source_dialog              (GtkWindow *parent,
-                                                ESourceRegistry *registry,
-                                                ESource *source,
-                                                ECalClientSourceType type);
+                                                ECalModel *model,
+                                                ESource *from_source);
 
 #endif /* COPY_SOURCE_DIALOG_H */
diff --git a/calendar/gui/dialogs/event-editor.c b/calendar/gui/dialogs/event-editor.c
index 1097089..9d82be7 100644
--- a/calendar/gui/dialogs/event-editor.c
+++ b/calendar/gui/dialogs/event-editor.c
@@ -734,9 +734,9 @@ event_editor_send_comp (CompEditor *editor,
                gboolean result;
 
                client = e_meeting_store_get_client (priv->model);
-               result = itip_send_comp (
+               result = itip_send_comp_sync (
                        registry, E_CAL_COMPONENT_METHOD_CANCEL, comp,
-                       client, NULL, NULL, NULL, strip_alarms, FALSE);
+                       client, NULL, NULL, NULL, strip_alarms, FALSE, NULL, NULL);
                g_object_unref (comp);
 
                if (!result)
diff --git a/calendar/gui/dialogs/goto-dialog.c b/calendar/gui/dialogs/goto-dialog.c
index 0fee662..73d4784 100644
--- a/calendar/gui/dialogs/goto-dialog.c
+++ b/calendar/gui/dialogs/goto-dialog.c
@@ -46,12 +46,15 @@ typedef struct
        ECalendar *ecal;
        GtkWidget *vbox;
 
-       GnomeCalendar *gcal;
        gint year_val;
        gint month_val;
        gint day_val;
 
-       GCancellable *cancellable;
+       ETagCalendar *tag_calendar;
+
+       ECalDataModel *data_model;
+       ECalendarViewMoveType *out_move_type;
+       time_t *out_exact_date;
 } GoToDialog;
 
 static GoToDialog *dlg = NULL;
@@ -86,23 +89,6 @@ month_changed (GtkToggleButton *toggle,
                dlg->ecal->calitem, dlg->year_val, dlg->month_val);
 }
 
-static void
-ecal_date_range_changed (ECalendarItem *calitem,
-                         gpointer user_data)
-{
-       GoToDialog *dlg = user_data;
-       ECalModel *model;
-       ECalClient *client;
-
-       model = gnome_calendar_get_model (dlg->gcal);
-       client = e_cal_model_ref_default_client (model);
-
-       if (client != NULL) {
-               tag_calendar_by_client (dlg->ecal, client, dlg->cancellable);
-               g_object_unref (client);
-       }
-}
-
 /* Event handler for day groups in the month item.  A button press makes
  * the calendar jump to the selected day and destroys the Go-to dialog box. */
 static void
@@ -111,14 +97,12 @@ ecal_event (ECalendarItem *calitem,
 {
        GoToDialog *dlg = user_data;
        GDate start_date, end_date;
-       ECalModel *model;
        struct icaltimetype tt = icaltime_null_time ();
        icaltimezone *timezone;
        time_t et;
 
-       model = gnome_calendar_get_model (dlg->gcal);
        e_calendar_item_get_selection (calitem, &start_date, &end_date);
-       timezone = e_cal_model_get_timezone (model);
+       timezone = e_cal_data_model_get_timezone (dlg->data_model);
 
        tt.year = g_date_get_year (&start_date);
        tt.month = g_date_get_month (&start_date);
@@ -126,9 +110,10 @@ ecal_event (ECalendarItem *calitem,
 
        et = icaltime_as_timet_with_zone (tt, timezone);
 
-       gnome_calendar_goto (dlg->gcal, et);
+       *(dlg->out_move_type) = E_CALENDAR_VIEW_MOVE_TO_EXACT_DAY;
+       *(dlg->out_exact_date) = et;
 
-       gtk_dialog_response (GTK_DIALOG (dlg->dialog), GTK_RESPONSE_NONE);
+       gtk_dialog_response (GTK_DIALOG (dlg->dialog), GTK_RESPONSE_APPLY);
 }
 
 /* Returns the current time, for the ECalendarItem. */
@@ -164,6 +149,8 @@ create_ecal (GoToDialog *dlg)
        ECalendarItem *calitem;
 
        dlg->ecal = E_CALENDAR (e_calendar_new ());
+       dlg->tag_calendar = e_tag_calendar_new (dlg->ecal);
+
        calitem = dlg->ecal->calitem;
 
        gnome_canvas_item_set (
@@ -179,14 +166,6 @@ create_ecal (GoToDialog *dlg)
                calitem,
                get_current_time,
                dlg, NULL);
-
-       ecal_date_range_changed (calitem, dlg);
-}
-
-static void
-goto_today (GoToDialog *dlg)
-{
-       gnome_calendar_goto_today (dlg->gcal);
 }
 
 /* Gets the widgets from the XML file and returns if they are all available. */
@@ -224,28 +203,30 @@ goto_dialog_init_widgets (GoToDialog *dlg)
                G_CALLBACK (year_changed), dlg);
 
        g_signal_connect (
-               dlg->ecal->calitem, "date_range_changed",
-               G_CALLBACK (ecal_date_range_changed), dlg);
-       g_signal_connect (
                dlg->ecal->calitem, "selection_changed",
                G_CALLBACK (ecal_event), dlg);
 }
 
+/* Create a copy, thus a move to a distant date will not cause large event lookups */
+
 /* Creates a "goto date" dialog and runs it */
-void
-goto_dialog (GtkWindow *parent,
-             GnomeCalendar *gcal)
+gboolean
+goto_dialog_run (GtkWindow *parent,
+                ECalDataModel *data_model,
+                const GDate *from_date,
+                ECalendarViewMoveType *out_move_type,
+                time_t *out_exact_date)
 {
-       ECalModel *model;
-       time_t start_time;
-       struct icaltimetype tt;
-       icaltimezone *timezone;
-       gint b;
+       gint response;
 
        if (dlg) {
-               return;
+               return FALSE;
        }
 
+       g_return_val_if_fail (E_IS_CAL_DATA_MODEL (data_model), FALSE);
+       g_return_val_if_fail (out_move_type != NULL, FALSE);
+       g_return_val_if_fail (out_exact_date != NULL, FALSE);
+
        dlg = g_new0 (GoToDialog, 1);
 
        /* Load the content widgets */
@@ -253,20 +234,31 @@ goto_dialog (GtkWindow *parent,
        e_load_ui_builder_definition (dlg->builder, "goto-dialog.ui");
 
        if (!get_widgets (dlg)) {
-               g_message ("goto_dialog(): Could not find all widgets in the XML file!");
+               g_message ("goto_dialog_run(): Could not find all widgets in the XML file!");
                g_free (dlg);
-               return;
+               dlg = NULL;
+               return FALSE;
        }
-       dlg->gcal = gcal;
-       dlg->cancellable = g_cancellable_new ();
 
-       model = gnome_calendar_get_model (gcal);
-       timezone = e_cal_model_get_timezone (model);
-       e_cal_model_get_time_range (model, &start_time, NULL);
-       tt = icaltime_from_timet_with_zone (start_time, FALSE, timezone);
-       dlg->year_val = tt.year;
-       dlg->month_val = tt.month - 1;
-       dlg->day_val = tt.day;
+       dlg->data_model = e_cal_data_model_new_clone (data_model);
+       dlg->out_move_type = out_move_type;
+       dlg->out_exact_date = out_exact_date;
+
+       if (from_date) {
+               dlg->year_val = g_date_get_year (from_date);
+               dlg->month_val = g_date_get_month (from_date) - 1;
+               dlg->day_val = g_date_get_day (from_date);
+       } else {
+               struct icaltimetype tt;
+               icaltimezone *timezone;
+
+               timezone = e_cal_data_model_get_timezone (dlg->data_model);
+               tt = icaltime_current_time_with_zone (timezone);
+
+               dlg->year_val = tt.year;
+               dlg->month_val = tt.month - 1;
+               dlg->day_val = tt.day;
+       }
 
        gtk_combo_box_set_active (GTK_COMBO_BOX (dlg->month_combobox), dlg->month_val);
        gtk_spin_button_set_value (GTK_SPIN_BUTTON (dlg->year), dlg->year_val);
@@ -281,21 +273,29 @@ goto_dialog (GtkWindow *parent,
 
        dlg->ecal->calitem->selection_set = TRUE;
        dlg->ecal->calitem->selection_start_month_offset = 0;
-       dlg->ecal->calitem->selection_start_day = tt.day;
+       dlg->ecal->calitem->selection_start_day = dlg->day_val;
        dlg->ecal->calitem->selection_end_month_offset = 0;
-       dlg->ecal->calitem->selection_end_day = tt.day;
+       dlg->ecal->calitem->selection_end_day = dlg->day_val;
 
        gnome_canvas_item_grab_focus (GNOME_CANVAS_ITEM (dlg->ecal->calitem));
 
-       b = gtk_dialog_run (GTK_DIALOG (dlg->dialog));
+       e_tag_calendar_subscribe (dlg->tag_calendar, dlg->data_model);
+
+       response = gtk_dialog_run (GTK_DIALOG (dlg->dialog));
+
+       e_tag_calendar_unsubscribe (dlg->tag_calendar, dlg->data_model);
+
        gtk_widget_destroy (dlg->dialog);
 
-       if (b == 0)
-               goto_today (dlg);
+       if (response == GTK_RESPONSE_ACCEPT)
+               *(dlg->out_move_type) = E_CALENDAR_VIEW_MOVE_TO_TODAY;
 
        g_object_unref (dlg->builder);
-       g_cancellable_cancel (dlg->cancellable);
-       g_object_unref (dlg->cancellable);
+       g_clear_object (&dlg->tag_calendar);
+       g_clear_object (&dlg->data_model);
+
        g_free (dlg);
        dlg = NULL;
+
+       return response == GTK_RESPONSE_ACCEPT || response == GTK_RESPONSE_APPLY;
 }
diff --git a/calendar/gui/dialogs/goto-dialog.h b/calendar/gui/dialogs/goto-dialog.h
index 10d91d8..8951a89 100644
--- a/calendar/gui/dialogs/goto-dialog.h
+++ b/calendar/gui/dialogs/goto-dialog.h
@@ -26,8 +26,13 @@
 #ifndef GOTO_DIALOG_H
 #define GOTO_DIALOG_H
 
-#include "calendar/gui/gnome-cal.h"
+#include "calendar/gui/e-cal-data-model.h"
+#include "calendar/gui/e-calendar-view.h"
 
-void goto_dialog (GtkWindow *parent, GnomeCalendar *gcal);
+gboolean       goto_dialog_run (GtkWindow *parent,
+                                ECalDataModel *data_model,
+                                const GDate *from_date,
+                                ECalendarViewMoveType *out_move_type,
+                                time_t *out_exact_date);
 
 #endif
diff --git a/calendar/gui/dialogs/goto-dialog.ui b/calendar/gui/dialogs/goto-dialog.ui
index 51d2702..803bcc0 100644
--- a/calendar/gui/dialogs/goto-dialog.ui
+++ b/calendar/gui/dialogs/goto-dialog.ui
@@ -174,7 +174,7 @@
       </object>
     </child>
     <action-widgets>
-      <action-widget response="0">button4</action-widget>
+      <action-widget response="-3">button4</action-widget>
       <action-widget response="-6">button5</action-widget>
     </action-widgets>
   </object>
diff --git a/calendar/gui/dialogs/recur-comp.c b/calendar/gui/dialogs/recur-comp.c
index d59c09a..b0123ca 100644
--- a/calendar/gui/dialogs/recur-comp.c
+++ b/calendar/gui/dialogs/recur-comp.c
@@ -31,7 +31,7 @@
 gboolean
 recur_component_dialog (ECalClient *client,
                         ECalComponent *comp,
-                        CalObjModType *mod,
+                        ECalObjModType *mod,
                         GtkWindow *parent,
                         gboolean delegated)
 {
@@ -112,17 +112,46 @@ recur_component_dialog (ECalClient *client,
        ret = gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK;
 
        if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (rb_this)))
-               *mod = CALOBJ_MOD_THIS;
+               *mod = E_CAL_OBJ_MOD_THIS;
        else if (rb_prior && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (rb_prior)))
-               *mod = CALOBJ_MOD_THISANDPRIOR;
+               *mod = E_CAL_OBJ_MOD_THIS_AND_PRIOR;
        else if (rb_future && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (rb_future)))
-               *mod = CALOBJ_MOD_THISANDFUTURE;
+               *mod = E_CAL_OBJ_MOD_THIS_AND_FUTURE;
        else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (rb_all))) {
-               *mod = CALOBJ_MOD_ALL;
-
+               *mod = E_CAL_OBJ_MOD_ALL;
        }
 
        gtk_widget_destroy (dialog);
 
        return ret;
 }
+
+gboolean
+recur_icalcomp_dialog (ECalClient *client,
+                      icalcomponent *icalcomp,
+                      ECalObjModType *mod,
+                      GtkWindow *parent,
+                      gboolean delegated)
+{
+       ECalComponent *comp;
+       gboolean res;
+
+       g_return_val_if_fail (icalcomp != NULL, FALSE);
+
+       comp = e_cal_component_new_from_icalcomponent (icalcomponent_new_clone (icalcomp));
+       if (!comp)
+               return FALSE;
+
+       if (!e_cal_component_is_instance (comp)) {
+               *mod = E_CAL_OBJ_MOD_ALL;
+               g_object_unref (comp);
+
+               return TRUE;
+       }
+
+       res = recur_component_dialog (client, comp, mod, parent, delegated);
+
+       g_object_unref (comp);
+
+       return res;
+}
diff --git a/calendar/gui/dialogs/recur-comp.h b/calendar/gui/dialogs/recur-comp.h
index 59f2359..7d94e09 100644
--- a/calendar/gui/dialogs/recur-comp.h
+++ b/calendar/gui/dialogs/recur-comp.h
@@ -29,7 +29,13 @@
 
 gboolean recur_component_dialog (ECalClient *client,
                                 ECalComponent *comp,
-                                CalObjModType *mod,
+                                ECalObjModType *mod,
+                                GtkWindow *parent,
+                                gboolean delegated);
+
+gboolean recur_icalcomp_dialog (ECalClient *client,
+                                icalcomponent *icalcomp,
+                                ECalObjModType *mod,
                                 GtkWindow *parent,
                                 gboolean delegated);
 
diff --git a/calendar/gui/dialogs/task-editor.c b/calendar/gui/dialogs/task-editor.c
index 96499ee..347dab4 100644
--- a/calendar/gui/dialogs/task-editor.c
+++ b/calendar/gui/dialogs/task-editor.c
@@ -403,9 +403,9 @@ task_editor_send_comp (CompEditor *editor,
                gboolean result;
 
                client = e_meeting_store_get_client (priv->model);
-               result = itip_send_comp (
+               result = itip_send_comp_sync (
                        registry, E_CAL_COMPONENT_METHOD_CANCEL, comp,
-                       client, NULL, NULL, NULL, strip_alarms, FALSE);
+                       client, NULL, NULL, NULL, strip_alarms, FALSE, NULL, NULL);
                g_object_unref (comp);
 
                if (!result)
diff --git a/calendar/gui/dialogs/task-page.c b/calendar/gui/dialogs/task-page.c
index a251017..ba8411c 100644
--- a/calendar/gui/dialogs/task-page.c
+++ b/calendar/gui/dialogs/task-page.c
@@ -528,6 +528,7 @@ task_page_finalize (GObject *object)
 
        g_strfreev (priv->address_strings);
        g_free (priv->fallback_address);
+       g_free (priv->user_add);
 
        g_ptr_array_foreach (
                priv->deleted_attendees, (GFunc) g_object_unref, NULL);
@@ -745,6 +746,7 @@ task_page_fill_widgets (CompEditorPage *page,
                gchar *name = NULL;
                gchar *mailto = NULL;
 
+               g_free (priv->user_add);
                priv->user_add = itip_get_comp_attendee (
                        registry, comp, client);
 
diff --git a/calendar/gui/e-cal-data-model-subscriber.c b/calendar/gui/e-cal-data-model-subscriber.c
new file mode 100644
index 0000000..b08b0c1
--- /dev/null
+++ b/calendar/gui/e-cal-data-model-subscriber.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Milan Crha <mcrha redhat com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-cal-data-model-subscriber.h"
+
+G_DEFINE_INTERFACE (ECalDataModelSubscriber, e_cal_data_model_subscriber, G_TYPE_OBJECT)
+
+static void
+e_cal_data_model_subscriber_default_init (ECalDataModelSubscriberInterface *iface)
+{
+}
+
+/**
+ * e_cal_data_model_subscriber_component_added:
+ * @subscriber: an #ECalDataModelSubscriber
+ * @client: an #ECalClient, which notifies about the component addition
+ * @icalcomp: an #ECalComponent which was added
+ *
+ * Notifies the @subscriber about an added component which belongs
+ * to the time range used by the @subscriber.
+ *
+ * Note: The @subscriber can be frozen during these calls, to be able
+ *    to cumulate multiple changes and propagate them at once.
+ **/
+void
+e_cal_data_model_subscriber_component_added (ECalDataModelSubscriber *subscriber,
+                                            ECalClient *client,
+                                            ECalComponent *comp)
+{
+       ECalDataModelSubscriberInterface *iface;
+
+       g_return_if_fail (E_IS_CAL_DATA_MODEL_SUBSCRIBER (subscriber));
+       g_return_if_fail (E_IS_CAL_COMPONENT (comp));
+
+       iface = E_CAL_DATA_MODEL_SUBSCRIBER_GET_INTERFACE (subscriber);
+       g_return_if_fail (iface->component_added != NULL);
+
+       iface->component_added (subscriber, client, comp);
+}
+
+/**
+ * e_cal_data_model_subscriber_component_modified:
+ * @subscriber: an #ECalDataModelSubscriber
+ * @client: an #ECalClient, which notifies about the component modification
+ * @comp: an #ECalComponent which was modified
+ *
+ * Notifies the @subscriber about a modified component which belongs
+ * to the time range used by the @subscriber.
+ *
+ * Note: The @subscriber can be frozen during these calls, to be able
+ *    to cumulate multiple changes and propagate them at once.
+ **/
+void
+e_cal_data_model_subscriber_component_modified (ECalDataModelSubscriber *subscriber,
+                                               ECalClient *client,
+                                               ECalComponent *comp)
+{
+       ECalDataModelSubscriberInterface *iface;
+
+       g_return_if_fail (E_IS_CAL_DATA_MODEL_SUBSCRIBER (subscriber));
+       g_return_if_fail (E_IS_CAL_COMPONENT (comp));
+
+       iface = E_CAL_DATA_MODEL_SUBSCRIBER_GET_INTERFACE (subscriber);
+       g_return_if_fail (iface->component_modified != NULL);
+
+       iface->component_modified (subscriber, client, comp);
+}
+
+/**
+ * e_cal_data_model_subscriber_component_removed:
+ * @subscriber: an #ECalDataModelSubscriber
+ * @client: an #ECalClient, which notifies about the component removal
+ * @uid: UID of a removed component
+ * @rid: RID of a removed component
+ *
+ * Notifies the @subscriber about a removed component identified
+ * by @uid and @rid. This component may or may not be within
+ * the time range specified by the @subscriber.
+ *
+ * Note: The @subscriber can be frozen during these calls, to be able
+ *    to cumulate multiple changes and propagate them at once.
+ **/
+void
+e_cal_data_model_subscriber_component_removed (ECalDataModelSubscriber *subscriber,
+                                              ECalClient *client,
+                                              const gchar *uid,
+                                              const gchar *rid)
+{
+       ECalDataModelSubscriberInterface *iface;
+
+       g_return_if_fail (E_IS_CAL_DATA_MODEL_SUBSCRIBER (subscriber));
+
+       iface = E_CAL_DATA_MODEL_SUBSCRIBER_GET_INTERFACE (subscriber);
+       g_return_if_fail (iface->component_removed != NULL);
+
+       iface->component_removed (subscriber, client, uid, rid);
+}
+
+/**
+ * e_cal_data_model_subscriber_freeze:
+ * @subscriber: an #ECalDataModelSubscriber
+ *
+ * Tells the @subscriber that it'll be notified about multiple
+ * changes. Once all the notifications are done,
+ * a e_cal_data_model_subscriber_thaw() is called.
+ *
+ * Note: This function can be called multiple times/recursively, with
+ *   the same count of the e_cal_data_model_subscriber_thaw(), thus
+ *   count with it.
+ **/
+void
+e_cal_data_model_subscriber_freeze (ECalDataModelSubscriber *subscriber)
+{
+       ECalDataModelSubscriberInterface *iface;
+
+       g_return_if_fail (E_IS_CAL_DATA_MODEL_SUBSCRIBER (subscriber));
+
+       iface = E_CAL_DATA_MODEL_SUBSCRIBER_GET_INTERFACE (subscriber);
+       g_return_if_fail (iface->freeze != NULL);
+
+       iface->freeze (subscriber);
+}
+
+/**
+ * e_cal_data_model_subscriber_thaw:
+ * @subscriber: an #ECalDataModelSubscriber
+ *
+ * A pair function for e_cal_data_model_subscriber_freeze(), which notifies
+ * about the end of a content update.
+ **/
+void
+e_cal_data_model_subscriber_thaw (ECalDataModelSubscriber *subscriber)
+{
+       ECalDataModelSubscriberInterface *iface;
+
+       g_return_if_fail (E_IS_CAL_DATA_MODEL_SUBSCRIBER (subscriber));
+
+       iface = E_CAL_DATA_MODEL_SUBSCRIBER_GET_INTERFACE (subscriber);
+       g_return_if_fail (iface->thaw != NULL);
+
+       iface->thaw (subscriber);
+}
diff --git a/calendar/gui/e-cal-data-model-subscriber.h b/calendar/gui/e-cal-data-model-subscriber.h
new file mode 100644
index 0000000..8d76fb0
--- /dev/null
+++ b/calendar/gui/e-cal-data-model-subscriber.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Milan Crha <mcrha redhat com>
+ */
+
+#ifndef E_CAL_DATA_MODEL_SUBSCRIBER_H
+#define E_CAL_DATA_MODEL_SUBSCRIBER_H
+
+#include <libecal/libecal.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CAL_DATA_MODEL_SUBSCRIBER \
+       (e_cal_data_model_subscriber_get_type ())
+#define E_CAL_DATA_MODEL_SUBSCRIBER(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_CAL_DATA_MODEL_SUBSCRIBER, ECalDataModelSubscriber))
+#define E_CAL_DATA_MODEL_SUBSCRIBER_INTERFACE(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_CAL_DATA_MODEL_SUBSCRIBER, ECalDataModelSubscriberInterface))
+#define E_IS_CAL_DATA_MODEL_SUBSCRIBER(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_CAL_DATA_MODEL_SUBSCRIBER))
+#define E_IS_CAL_DATA_MODEL_SUBSCRIBER_INTERFACE(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_CAL_DATA_MODEL_SUBSCRIBER))
+#define E_CAL_DATA_MODEL_SUBSCRIBER_GET_INTERFACE(obj) \
+       (G_TYPE_INSTANCE_GET_INTERFACE \
+       ((obj), E_TYPE_CAL_DATA_MODEL_SUBSCRIBER, ECalDataModelSubscriberInterface))
+
+G_BEGIN_DECLS
+
+typedef struct _ECalDataModelSubscriber ECalDataModelSubscriber;
+typedef struct _ECalDataModelSubscriberInterface ECalDataModelSubscriberInterface;
+
+struct _ECalDataModelSubscriberInterface {
+       GTypeInterface parent_interface;
+
+       void    (*component_added)      (ECalDataModelSubscriber *subscriber,
+                                        ECalClient *client,
+                                        ECalComponent *comp);
+       void    (*component_modified)   (ECalDataModelSubscriber *subscriber,
+                                        ECalClient *client,
+                                        ECalComponent *comp);
+       void    (*component_removed)    (ECalDataModelSubscriber *subscriber,
+                                        ECalClient *client,
+                                        const gchar *uid,
+                                        const gchar *rid);
+       void    (*freeze)               (ECalDataModelSubscriber *subscriber);
+       void    (*thaw)                 (ECalDataModelSubscriber *subscriber);
+};
+
+GType          e_cal_data_model_subscriber_get_type            (void) G_GNUC_CONST;
+void           e_cal_data_model_subscriber_component_added     (ECalDataModelSubscriber *subscriber,
+                                                                ECalClient *client,
+                                                                ECalComponent *comp);
+void           e_cal_data_model_subscriber_component_modified  (ECalDataModelSubscriber *subscriber,
+                                                                ECalClient *client,
+                                                                ECalComponent *comp);
+void           e_cal_data_model_subscriber_component_removed   (ECalDataModelSubscriber *subscriber,
+                                                                ECalClient *client,
+                                                                const gchar *uid,
+                                                                const gchar *rid);
+void           e_cal_data_model_subscriber_freeze              (ECalDataModelSubscriber *subscriber);
+void           e_cal_data_model_subscriber_thaw                (ECalDataModelSubscriber *subscriber);
+
+G_END_DECLS
+
+#endif /* E_CAL_DATA_MODEL_SUBSCRIBER_H */
diff --git a/calendar/gui/e-cal-data-model.c b/calendar/gui/e-cal-data-model.c
new file mode 100644
index 0000000..f010540
--- /dev/null
+++ b/calendar/gui/e-cal-data-model.c
@@ -0,0 +1,2785 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Milan Crha <mcrha redhat com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+
+#include "comp-util.h"
+#include "e-cal-data-model.h"
+
+#define LOCK_PROPS() g_rec_mutex_lock (&data_model->priv->props_lock)
+#define UNLOCK_PROPS() g_rec_mutex_unlock (&data_model->priv->props_lock)
+
+struct _ECalDataModelPrivate {
+       GThread *main_thread;
+       ECalDataModelSubmitThreadJobFunc submit_thread_job_func;
+       GWeakRef *submit_thread_job_responder;
+       GThreadPool *thread_pool;
+
+       GRecMutex props_lock;   /* to guard all the below members */
+
+       gboolean disposing;
+       gboolean expand_recurrences;
+       gchar *filter;
+       gchar *full_filter;     /* to be used with views */
+       icaltimezone *zone;
+       time_t range_start;
+       time_t range_end;
+
+       GHashTable *clients;    /* ESource::uid ~> ECalClient */
+       GHashTable *views;      /* ECalClient ~> ViewData */
+       GSList *subscribers;    /* ~> SubscriberData */
+
+       guint32 views_update_freeze;
+       gboolean views_update_required;
+};
+
+enum {
+       PROP_0,
+       PROP_EXPAND_RECURRENCES,
+       PROP_TIMEZONE
+};
+
+G_DEFINE_TYPE (ECalDataModel, e_cal_data_model, G_TYPE_OBJECT)
+
+typedef struct _ComponentData {
+       ECalComponent *component;
+       time_t instance_start;
+       time_t instance_end;
+       gboolean is_detached;
+} ComponentData;
+
+typedef struct _ViewData {
+       gint ref_count;
+       GRecMutex lock;
+       gboolean is_used;
+
+       ECalClient *client;
+       ECalClientView *view;
+       gulong objects_added_id;
+       gulong objects_modified_id;
+       gulong objects_removed_id;
+       gulong progress_id;
+       gulong complete_id;
+
+       GHashTable *components; /* ECalComponentId ~> ComponentData */
+       GHashTable *lost_components; /* ECalComponentId ~> ComponentData; when re-running view, valid till 
'complete' is received */
+       gboolean received_complete;
+       GSList *to_expand_recurrences; /* icalcomponent */
+       GSList *expanded_recurrences; /* ComponentData */
+       gint pending_expand_recurrences; /* how many is waiting to be processed */
+
+       GCancellable *cancellable;
+} ViewData;
+
+typedef struct _SubscriberData {
+       ECalDataModelSubscriber *subscriber;
+       time_t range_start;
+       time_t range_end;
+} SubscriberData;
+
+static ComponentData *
+component_data_new (ECalComponent *comp,
+                   time_t instance_start,
+                   time_t instance_end,
+                   gboolean is_detached)
+{
+       ComponentData *comp_data;
+
+       g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
+
+       comp_data = g_new0 (ComponentData, 1);
+       comp_data->component = g_object_ref (comp);
+       comp_data->instance_start = instance_start;
+       comp_data->instance_end = instance_end;
+       comp_data->is_detached = is_detached;
+
+       return comp_data;
+}
+
+static void
+component_data_free (gpointer ptr)
+{
+       ComponentData *comp_data = ptr;
+
+       if (comp_data) {
+               g_object_unref (comp_data->component);
+               g_free (comp_data);
+       }
+}
+
+static gboolean
+component_data_equal (ComponentData *comp_data1,
+                     ComponentData *comp_data2)
+{
+       icalcomponent *icomp1, *icomp2;
+       struct icaltimetype tt1, tt2;
+       gchar *as_str1, *as_str2;
+       gboolean equal;
+
+       if (comp_data1 == comp_data2)
+               return TRUE;
+
+       if (!comp_data1 || !comp_data2 || !comp_data1->component || !comp_data2->component)
+               return FALSE;
+
+       if (comp_data1->instance_start != comp_data2->instance_start ||
+           comp_data1->instance_end != comp_data2->instance_end)
+               return FALSE;
+
+       icomp1 = e_cal_component_get_icalcomponent (comp_data1->component);
+       icomp2 = e_cal_component_get_icalcomponent (comp_data2->component);
+
+       if (!icomp1 || !icomp2 ||
+           icalcomponent_get_sequence (icomp1) != icalcomponent_get_sequence (icomp2) ||
+           g_strcmp0 (icalcomponent_get_uid (icomp1), icalcomponent_get_uid (icomp2)) != 0)
+               return FALSE;
+
+       tt1 = icalcomponent_get_recurrenceid (icomp1);
+       tt2 = icalcomponent_get_recurrenceid (icomp2);
+       if ((icaltime_is_valid_time (tt1) ? 1 : 0) != (icaltime_is_valid_time (tt2) ? 1 : 0) ||
+           (icaltime_is_null_time (tt1) ? 1 : 0) != (icaltime_is_null_time (tt2) ? 1 : 0) ||
+           icaltime_compare (tt1, tt2) != 0)
+               return FALSE;
+
+       tt1 = icalcomponent_get_dtstamp (icomp1);
+       tt2 = icalcomponent_get_dtstamp (icomp2);
+       if ((icaltime_is_valid_time (tt1) ? 1 : 0) != (icaltime_is_valid_time (tt2) ? 1 : 0) ||
+           (icaltime_is_null_time (tt1) ? 1 : 0) != (icaltime_is_null_time (tt2) ? 1 : 0) ||
+           icaltime_compare (tt1, tt2) != 0)
+               return FALSE;
+
+       /* Maybe not so effective compare, but might be still more effective
+          than updating whole UI with false notifications */
+       as_str1 = icalcomponent_as_ical_string_r (icomp1);
+       as_str2 = icalcomponent_as_ical_string_r (icomp2);
+
+       equal = g_strcmp0 (as_str1, as_str2) == 0;
+
+       g_free (as_str1);
+       g_free (as_str2);
+
+       return equal;
+}
+
+static ViewData *
+view_data_new (ECalClient *client)
+{
+       ViewData *view_data;
+
+       g_return_val_if_fail (E_IS_CAL_CLIENT (client), NULL);
+
+       view_data = g_new0 (ViewData, 1);
+       view_data->ref_count = 1;
+       g_rec_mutex_init (&view_data->lock);
+       view_data->is_used = TRUE;
+       view_data->client = g_object_ref (client);
+       view_data->components = g_hash_table_new_full (
+               (GHashFunc) e_cal_component_id_hash, (GEqualFunc) e_cal_component_id_equal,
+               (GDestroyNotify) e_cal_component_free_id, component_data_free);
+
+       return view_data;
+}
+
+static void
+view_data_disconnect_view (ViewData *view_data)
+{
+       if (view_data && view_data->view) {
+               #define disconnect(x) G_STMT_START { \
+                       if (view_data->x) { \
+                               g_signal_handler_disconnect (view_data->view, view_data->x); \
+                               view_data->x = 0; \
+                       } \
+               } G_STMT_END
+
+               disconnect (objects_added_id);
+               disconnect (objects_modified_id);
+               disconnect (objects_removed_id);
+               disconnect (progress_id);
+               disconnect (complete_id);
+
+               #undef disconnect
+       }
+}
+
+static ViewData *
+view_data_ref (ViewData *view_data)
+{
+       g_return_val_if_fail (view_data != NULL, NULL);
+
+       g_atomic_int_inc (&view_data->ref_count);
+
+       return view_data;
+}
+
+static void
+view_data_unref (gpointer ptr)
+{
+       ViewData *view_data = ptr;
+
+       if (view_data) {
+               if (g_atomic_int_dec_and_test  (&view_data->ref_count)) {
+                       view_data_disconnect_view (view_data);
+                       if (view_data->cancellable)
+                               g_cancellable_cancel (view_data->cancellable);
+                       g_clear_object (&view_data->cancellable);
+                       g_clear_object (&view_data->client);
+                       g_clear_object (&view_data->view);
+                       g_hash_table_destroy (view_data->components);
+                       if (view_data->lost_components)
+                               g_hash_table_destroy (view_data->lost_components);
+                       g_slist_free_full (view_data->to_expand_recurrences, (GDestroyNotify) 
icalcomponent_free);
+                       g_slist_free_full (view_data->expanded_recurrences, component_data_free);
+                       g_rec_mutex_clear (&view_data->lock);
+                       g_free (view_data);
+               }
+       }
+}
+
+static void
+view_data_lock (ViewData *view_data)
+{
+       g_return_if_fail (view_data != NULL);
+
+       g_rec_mutex_lock (&view_data->lock);
+}
+
+static void
+view_data_unlock (ViewData *view_data)
+{
+       g_return_if_fail (view_data != NULL);
+
+       g_rec_mutex_unlock (&view_data->lock);
+}
+
+static SubscriberData *
+subscriber_data_new (ECalDataModelSubscriber *subscriber,
+                    time_t range_start,
+                    time_t range_end)
+{
+       SubscriberData *subs_data;
+
+       g_return_val_if_fail (E_IS_CAL_DATA_MODEL_SUBSCRIBER (subscriber), NULL);
+
+       subs_data = g_new0 (SubscriberData, 1);
+       subs_data->subscriber = g_object_ref (subscriber);
+       subs_data->range_start = range_start;
+       subs_data->range_end = range_end;
+
+       return subs_data;
+}
+
+static void
+subscriber_data_free (gpointer ptr)
+{
+       SubscriberData *subs_data = ptr;
+
+       if (subs_data) {
+               g_clear_object (&subs_data->subscriber);
+               g_free (subs_data);
+       }
+}
+
+typedef void (* InternalThreadJobFunc) (ECalDataModel *data_model, gpointer user_data);
+
+typedef struct _InternalThreadJobData {
+       InternalThreadJobFunc func;
+       gpointer user_data;
+} InternalThreadJobData;
+
+static void
+cal_data_model_internal_thread_job_func (gpointer data,
+                                        gpointer user_data)
+{
+       ECalDataModel *data_model = user_data;
+       InternalThreadJobData *job_data = data;
+
+       g_return_if_fail (job_data != NULL);
+       g_return_if_fail (job_data->func != NULL);
+
+       job_data->func (data_model, job_data->user_data);
+
+       g_free (job_data);
+}
+
+static void
+cal_data_model_submit_internal_thread_job (ECalDataModel *data_model,
+                                          InternalThreadJobFunc func,
+                                          gpointer user_data)
+{
+       InternalThreadJobData *job_data;
+
+       g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model));
+       g_return_if_fail (func != NULL);
+
+       job_data = g_new0 (InternalThreadJobData, 1);
+       job_data->func = func;
+       job_data->user_data = user_data;
+
+       g_thread_pool_push (data_model->priv->thread_pool, job_data, NULL);
+}
+
+typedef struct _SubmitThreadJobData {
+       ECalDataModel *data_model;
+       const gchar *description;
+       const gchar *alert_ident;
+       const gchar *alert_arg_0;
+       EAlertSinkThreadJobFunc func;
+       gpointer user_data;
+       GDestroyNotify free_user_data;
+
+       GCancellable *cancellable;
+       gboolean finished;
+       GMutex mutex;
+       GCond cond;
+} SubmitThreadJobData;
+
+static gboolean
+cal_data_model_call_submit_thread_job (gpointer user_data)
+{
+       SubmitThreadJobData *stj_data = user_data;
+       GObject *responder;
+
+       g_return_val_if_fail (stj_data != NULL, FALSE);
+
+       g_mutex_lock (&stj_data->mutex);
+       responder = g_weak_ref_get (stj_data->data_model->priv->submit_thread_job_responder);
+
+       stj_data->cancellable = stj_data->data_model->priv->submit_thread_job_func (
+               responder, stj_data->description, stj_data->alert_ident, stj_data->alert_arg_0,
+               stj_data->func, stj_data->user_data, stj_data->free_user_data);
+
+       g_clear_object (&responder);
+
+       stj_data->finished = TRUE;
+       g_cond_signal (&stj_data->cond);
+       g_mutex_unlock (&stj_data->mutex);
+
+       return FALSE;
+}
+
+/**
+ * e_cal_data_model_submit_thread_job:
+ * @data_model: an #ECalDataModel
+ * @description: user-friendly description of the job, to be shown in UI
+ * @alert_ident: in case of an error, this alert identificator is used
+ *    for EAlert construction
+ * @alert_arg_0: (allow-none): in case of an error, use this string as
+ *    the first argument to the EAlert construction; the second argument
+ *    is the actual error message; can be #NULL, in which case only
+ *    the error message is passed to the EAlert construction
+ * @func: function to be run in a dedicated thread
+ * @user_data: (allow-none): custom data passed into @func; can be #NULL
+ * @free_user_data: (allow-none): function to be called on @user_data,
+ *   when the job is over; can be #NULL
+ *
+ * Runs the @func in a dedicated thread. Any error is propagated to UI.
+ * The cancellable passed into the @func is a #CamelOperation, thus
+ * the caller can overwrite progress and description message on it.
+ *
+ * Returns: (transfer full): Newly created #GCancellable on success.
+ *   The caller is responsible to g_object_unref() it when done with it.
+ *
+ * Note: The @free_user_data, if set, is called in the main thread.
+ *
+ * Note: This is a blocking call, it waits until the thread job is submitted.
+ *
+ * Since: 3.14
+ **/
+GCancellable *
+e_cal_data_model_submit_thread_job (ECalDataModel *data_model,
+                                   const gchar *description,
+                                   const gchar *alert_ident,
+                                   const gchar *alert_arg_0,
+                                   EAlertSinkThreadJobFunc func,
+                                   gpointer user_data,
+                                   GDestroyNotify free_user_data)
+{
+       SubmitThreadJobData stj_data;
+
+       g_return_val_if_fail (E_IS_CAL_DATA_MODEL (data_model), NULL);
+       g_return_val_if_fail (data_model->priv->submit_thread_job_func != NULL, NULL);
+
+       if (g_thread_self () == data_model->priv->main_thread) {
+               GCancellable *cancellable;
+               GObject *responder;
+
+               responder = g_weak_ref_get (data_model->priv->submit_thread_job_responder);
+               cancellable = data_model->priv->submit_thread_job_func (
+                       responder, description, alert_ident, alert_arg_0,
+                       func, user_data, free_user_data);
+               g_clear_object (&responder);
+
+               return cancellable;
+       }
+
+       stj_data.data_model = data_model;
+       stj_data.description = description;
+       stj_data.alert_ident = alert_ident;
+       stj_data.alert_arg_0 = alert_arg_0;
+       stj_data.func = func;
+       stj_data.user_data = user_data;
+       stj_data.free_user_data = free_user_data;
+       stj_data.cancellable = NULL;
+       stj_data.finished = FALSE;
+       g_mutex_init (&stj_data.mutex);
+       g_cond_init (&stj_data.cond);
+
+       g_timeout_add (1, cal_data_model_call_submit_thread_job, &stj_data);
+
+       g_mutex_lock (&stj_data.mutex);
+       while (!stj_data.finished) {
+               g_cond_wait (&stj_data.cond, &stj_data.mutex);
+       }
+       g_mutex_unlock (&stj_data.mutex);
+
+       g_cond_clear (&stj_data.cond);
+       g_mutex_clear (&stj_data.mutex);
+
+       return stj_data.cancellable;
+}
+
+typedef void (* ECalDataModelForeachSubscriberFunc) (ECalDataModel *data_model,
+                                                    ECalClient *client,
+                                                    ECalDataModelSubscriber *subscriber,
+                                                    gpointer user_data);
+
+static void
+cal_data_model_foreach_subscriber_in_range (ECalDataModel *data_model,
+                                           ECalClient *client,
+                                           time_t in_range_start,
+                                           time_t in_range_end,
+                                           ECalDataModelForeachSubscriberFunc func,
+                                           gpointer user_data)
+{
+       GSList *link;
+
+       g_return_if_fail (func != NULL);
+
+       LOCK_PROPS ();
+
+       if (in_range_end == (time_t) 0) {
+               in_range_end = in_range_start;
+       }
+
+       for (link = data_model->priv->subscribers; link; link = g_slist_next (link)) {
+               SubscriberData *subs_data = link->data;
+
+               if ((in_range_start == (time_t) 0 && in_range_end == (time_t) 0) ||
+                   (subs_data->range_start == (time_t) 0 && subs_data->range_end == (time_t) 0) ||
+                   (subs_data->range_start <= in_range_end && subs_data->range_end >= in_range_start))
+                       func (data_model, client, subs_data->subscriber, user_data);
+       }
+
+       UNLOCK_PROPS ();
+}
+
+static void
+cal_data_model_foreach_subscriber (ECalDataModel *data_model,
+                                  ECalClient *client,
+                                  ECalDataModelForeachSubscriberFunc func,
+                                  gpointer user_data)
+{
+       g_return_if_fail (func != NULL);
+
+       cal_data_model_foreach_subscriber_in_range (data_model, client, (time_t) 0, (time_t) 0, func, 
user_data);
+}
+
+static void
+cal_data_model_freeze_subscriber_cb (ECalDataModel *data_model,
+                                    ECalClient *client,
+                                    ECalDataModelSubscriber *subscriber,
+                                    gpointer user_data)
+{
+       e_cal_data_model_subscriber_freeze (subscriber);
+}
+
+static void
+cal_data_model_thaw_subscriber_cb (ECalDataModel *data_model,
+                                  ECalClient *client,
+                                  ECalDataModelSubscriber *subscriber,
+                                  gpointer user_data)
+{
+       e_cal_data_model_subscriber_thaw (subscriber);
+}
+
+static void
+cal_data_model_freeze_all_subscribers (ECalDataModel *data_model)
+{
+       cal_data_model_foreach_subscriber (data_model, NULL, cal_data_model_freeze_subscriber_cb, NULL);
+}
+
+static void
+cal_data_model_thaw_all_subscribers (ECalDataModel *data_model)
+{
+       cal_data_model_foreach_subscriber (data_model, NULL, cal_data_model_thaw_subscriber_cb, NULL);
+}
+
+static void
+cal_data_model_add_component_cb (ECalDataModel *data_model,
+                                ECalClient *client,
+                                ECalDataModelSubscriber *subscriber,
+                                gpointer user_data)
+{
+       ECalComponent *comp = user_data;
+
+       g_return_if_fail (comp != NULL);
+
+       e_cal_data_model_subscriber_component_added (subscriber, client, comp);
+}
+
+static void
+cal_data_model_modify_component_cb (ECalDataModel *data_model,
+                                   ECalClient *client,
+                                   ECalDataModelSubscriber *subscriber,
+                                   gpointer user_data)
+{
+       ECalComponent *comp = user_data;
+
+       g_return_if_fail (comp != NULL);
+
+       e_cal_data_model_subscriber_component_modified (subscriber, client, comp);
+}
+
+static void
+cal_data_model_remove_one_view_component_cb (ECalDataModel *data_model,
+                                            ECalClient *client,
+                                            ECalDataModelSubscriber *subscriber,
+                                            gpointer user_data)
+{
+       const ECalComponentId *id = user_data;
+
+       g_return_if_fail (id != NULL);
+
+       e_cal_data_model_subscriber_component_removed (subscriber, client, id->uid, id->rid);
+}
+
+static void
+cal_data_model_remove_components (ECalDataModel *data_model,
+                                 ECalClient *client,
+                                 GHashTable *components,
+                                 GHashTable *also_remove_from)
+{
+       GList *ids, *ilink;
+
+       g_return_if_fail (data_model != NULL);
+       g_return_if_fail (components != NULL);
+
+       cal_data_model_freeze_all_subscribers (data_model);
+
+       ids = g_hash_table_get_keys (components);
+
+       for (ilink = ids; ilink; ilink = g_list_next (ilink)) {
+               ECalComponentId *id = ilink->data;
+               ComponentData *comp_data;
+               time_t instance_start = (time_t) 0, instance_end = (time_t) 0;
+
+               if (!id)
+                       continue;
+
+               /* Try to limit which subscribers will be notified about removal */
+               comp_data = g_hash_table_lookup (components, id);
+               if (comp_data) {
+                       instance_start = comp_data->instance_start;
+                       instance_end = comp_data->instance_end;
+               }
+
+               cal_data_model_foreach_subscriber_in_range (data_model, client,
+                       instance_start, instance_end,
+                       cal_data_model_remove_one_view_component_cb, id);
+
+               if (also_remove_from)
+                       g_hash_table_remove (also_remove_from, id);
+       }
+
+       g_list_free (ids);
+
+       cal_data_model_thaw_all_subscribers (data_model);
+}
+
+static void
+cal_data_model_calc_range (ECalDataModel *data_model,
+                          time_t *range_start,
+                          time_t *range_end)
+{
+       GSList *link;
+
+       g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model));
+       g_return_if_fail (range_start != NULL);
+       g_return_if_fail (range_end != NULL);
+
+       *range_start = (time_t) 0;
+       *range_end = (time_t) 0;
+
+       LOCK_PROPS ();
+
+       for (link = data_model->priv->subscribers; link; link = g_slist_next (link)) {
+               SubscriberData *subs_data = link->data;
+
+               if (!subs_data)
+                       continue;
+
+               if (subs_data->range_start == (time_t) 0 && subs_data->range_end == (time_t) 0) {
+                       *range_start = (time_t) 0;
+                       *range_end = (time_t) 0;
+                       break;
+               }
+
+               if (link == data_model->priv->subscribers) {
+                       *range_start = subs_data->range_start;
+                       *range_end = subs_data->range_end;
+               } else {
+                       if (*range_start > subs_data->range_start)
+                               *range_start = subs_data->range_start;
+                       if (*range_end < subs_data->range_end)
+                               *range_end = subs_data->range_end;
+               }
+       }
+
+       UNLOCK_PROPS ();
+}
+
+static gboolean
+cal_data_model_update_full_filter (ECalDataModel *data_model)
+{
+       gchar *filter;
+       time_t range_start, range_end;
+       gboolean changed;
+
+       LOCK_PROPS ();
+
+       cal_data_model_calc_range (data_model, &range_start, &range_end);
+
+       if (range_start != (time_t) 0 || range_end != (time_t) 0) {
+               gchar *iso_start, *iso_end;
+               const gchar *default_tzloc = NULL;
+
+               iso_start = isodate_from_time_t (range_start);
+               iso_end = isodate_from_time_t (range_end);
+
+               if (data_model->priv->zone && data_model->priv->zone != icaltimezone_get_utc_timezone ())
+                       default_tzloc = icaltimezone_get_location (data_model->priv->zone);
+               if (!default_tzloc)
+                       default_tzloc = "";
+
+               if (data_model->priv->filter) {
+                       filter = g_strdup_printf (
+                               "(and (occur-in-time-range? (make-time \"%s\") (make-time \"%s\") \"%s\") 
%s)",
+                               iso_start, iso_end, default_tzloc, data_model->priv->filter);
+               } else {
+                       filter = g_strdup_printf (
+                               "(occur-in-time-range? (make-time \"%s\") (make-time \"%s\") \"%s\")",
+                               iso_start, iso_end, default_tzloc);
+               }
+
+               g_free (iso_start);
+               g_free (iso_end);
+       } else if (data_model->priv->filter) {
+               filter = g_strdup (data_model->priv->filter);
+       } else {
+               filter = g_strdup ("#t");
+       }
+
+       changed = g_strcmp0 (data_model->priv->full_filter, filter) != 0;
+
+       if (changed) {
+               g_free (data_model->priv->full_filter);
+               data_model->priv->full_filter = filter;
+       } else {
+               g_free (filter);
+       }
+
+       UNLOCK_PROPS ();
+
+       return changed;
+}
+
+/* This consumes the comp_data - not so nice, but simpler
+   than adding reference counter for the structure */
+static void
+cal_data_model_process_added_component (ECalDataModel *data_model,
+                                       ViewData *view_data,
+                                       ComponentData *comp_data,
+                                       GHashTable *known_instances)
+{
+       ECalComponentId *id;
+       ComponentData *old_comp_data = NULL;
+       gboolean comp_data_equal;
+
+       g_return_if_fail (data_model != NULL);
+       g_return_if_fail (view_data != NULL);
+       g_return_if_fail (comp_data != NULL);
+
+       id = e_cal_component_get_id (comp_data->component);
+       g_return_if_fail (id != NULL);
+
+       view_data_lock (view_data);
+
+       if (!old_comp_data && view_data->lost_components)
+               old_comp_data = g_hash_table_lookup (view_data->lost_components, id);
+
+       if (!old_comp_data && known_instances)
+               old_comp_data = g_hash_table_lookup (known_instances, id);
+
+       if (!old_comp_data)
+               old_comp_data = g_hash_table_lookup (view_data->components, id);
+
+       if (old_comp_data) {
+               /* It can be a previously added detached instance received
+                  during recurrences expand */
+               if (!comp_data->is_detached)
+                       comp_data->is_detached = old_comp_data->is_detached;
+       }
+
+       comp_data_equal = component_data_equal (comp_data, old_comp_data);
+
+       if (view_data->lost_components)
+               g_hash_table_remove (view_data->lost_components, id);
+
+       if (known_instances)
+               g_hash_table_remove (known_instances, id);
+
+       /* Note: old_comp_data is freed or NULL now */
+
+       /* 'id' is stolen by view_data->components */
+       g_hash_table_insert (view_data->components, id, comp_data);
+
+       if (!comp_data_equal) {
+               if (!old_comp_data)
+                       cal_data_model_foreach_subscriber_in_range (data_model, view_data->client,
+                               comp_data->instance_start, comp_data->instance_end,
+                               cal_data_model_add_component_cb, comp_data->component);
+               else
+                       cal_data_model_foreach_subscriber_in_range (data_model, view_data->client,
+                               comp_data->instance_start, comp_data->instance_end,
+                               cal_data_model_modify_component_cb, comp_data->component);
+       }
+
+       view_data_unlock (view_data);
+}
+
+typedef struct _GatherComponentsData {
+       const gchar *uid;
+       GList **pcomponent_ids; /* ECalComponentId, can be owned by the hash table */
+       GHashTable *component_ids_hash;
+       gboolean copy_ids;
+       gboolean all_instances; /* FALSE to get only nondetached component instances */
+} GatherComponentsData;
+
+static void
+cal_data_model_gather_components (gpointer key,
+                                 gpointer value,
+                                 gpointer user_data)
+{
+       ECalComponentId *id = key;
+       ComponentData *comp_data = value;
+       GatherComponentsData *gather_data = user_data;
+
+       g_return_if_fail (id != NULL);
+       g_return_if_fail (comp_data != NULL);
+       g_return_if_fail (gather_data != NULL);
+       g_return_if_fail (gather_data->pcomponent_ids != NULL || gather_data->component_ids_hash != NULL);
+       g_return_if_fail (gather_data->pcomponent_ids == NULL || gather_data->component_ids_hash == NULL);
+
+       if ((gather_data->all_instances || !comp_data->is_detached) && g_strcmp0 (id->uid, gather_data->uid) 
== 0) {
+               if (gather_data->component_ids_hash) {
+                       ComponentData *comp_data_copy;
+
+                       comp_data_copy = component_data_new (comp_data->component,
+                               comp_data->instance_start, comp_data->instance_end,
+                               comp_data->is_detached);
+
+                       if (gather_data->copy_ids) {
+                               g_hash_table_insert (gather_data->component_ids_hash,
+                                       e_cal_component_id_copy (id), comp_data_copy);
+                       } else {
+                               g_hash_table_insert (gather_data->component_ids_hash, id, comp_data_copy);
+                       }
+               } else if (gather_data->copy_ids) {
+                       *gather_data->pcomponent_ids = g_list_prepend (*gather_data->pcomponent_ids,
+                               e_cal_component_id_copy (id));
+               } else {
+                       *gather_data->pcomponent_ids = g_list_prepend (*gather_data->pcomponent_ids, id);
+               }
+       }
+}
+
+typedef struct _NotifyRecurrencesData {
+       ECalDataModel *data_model;
+       ECalClient *client;
+} NotifyRecurrencesData;
+
+static gboolean
+cal_data_model_notify_recurrences_cb (gpointer user_data)
+{
+       NotifyRecurrencesData *notif_data = user_data;
+       ECalDataModel *data_model;
+       ViewData *view_data;
+
+       g_return_val_if_fail (notif_data != NULL, FALSE);
+
+       data_model = notif_data->data_model;
+
+       LOCK_PROPS ();
+
+       view_data = g_hash_table_lookup (data_model->priv->views, notif_data->client);
+       if (view_data)
+               view_data_ref (view_data);
+
+       UNLOCK_PROPS ();
+
+       if (view_data) {
+               GHashTable *gathered_uids;
+               GHashTable *known_instances;
+               GSList *expanded_recurrences, *link;
+
+               view_data_lock (view_data);
+               expanded_recurrences = view_data->expanded_recurrences;
+               view_data->expanded_recurrences = NULL;
+
+               cal_data_model_freeze_all_subscribers (data_model);
+
+               gathered_uids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+               known_instances = g_hash_table_new_full (
+                       (GHashFunc) e_cal_component_id_hash, (GEqualFunc) e_cal_component_id_equal,
+                       (GDestroyNotify) e_cal_component_free_id, component_data_free);
+
+               for (link = expanded_recurrences; link && view_data->is_used; link = g_slist_next (link)) {
+                       ComponentData *comp_data = link->data;
+                       icalcomponent *icomp;
+                       const gchar *uid;
+
+                       if (!comp_data)
+                               continue;
+
+                       icomp = e_cal_component_get_icalcomponent (comp_data->component);
+                       if (!icomp || !icalcomponent_get_uid (icomp))
+                               continue;
+
+                       uid = icalcomponent_get_uid (icomp);
+
+                       if (!g_hash_table_contains (gathered_uids, uid)) {
+                               GatherComponentsData gather_data;
+
+                               gather_data.uid = uid;
+                               gather_data.pcomponent_ids = NULL;
+                               gather_data.component_ids_hash = known_instances;
+                               gather_data.copy_ids = TRUE;
+                               gather_data.all_instances = FALSE;
+
+                               g_hash_table_foreach (view_data->components,
+                                       cal_data_model_gather_components, &gather_data);
+
+                               g_hash_table_insert (gathered_uids, g_strdup (uid), GINT_TO_POINTER (1));
+                       }
+
+                       /* Steal the comp_data */
+                       link->data = NULL;
+
+                       cal_data_model_process_added_component (data_model, view_data, comp_data, 
known_instances);
+               }
+
+               if (view_data->is_used && g_hash_table_size (known_instances) > 0) {
+                       cal_data_model_remove_components (data_model, view_data->client, known_instances, 
view_data->components);
+                       g_hash_table_remove_all (known_instances);
+               }
+
+               if (g_atomic_int_dec_and_test (&view_data->pending_expand_recurrences) &&
+                   view_data->is_used && view_data->lost_components && view_data->received_complete) {
+                       cal_data_model_remove_components (data_model, view_data->client, 
view_data->lost_components, NULL);
+                       g_hash_table_destroy (view_data->lost_components);
+                       view_data->lost_components = NULL;
+               }
+
+               g_hash_table_destroy (gathered_uids);
+               g_hash_table_destroy (known_instances);
+
+               view_data_unlock (view_data);
+
+               cal_data_model_thaw_all_subscribers (data_model);
+
+               view_data_unref (view_data);
+
+               g_slist_free_full (expanded_recurrences, component_data_free);
+       }
+
+       g_clear_object (&notif_data->client);
+       g_clear_object (&notif_data->data_model);
+       g_free (notif_data);
+
+       return FALSE;
+}
+
+typedef struct
+{
+       ECalClient *client;
+       icaltimezone *zone;
+       GSList **pexpanded_recurrences;
+} GenerateInstancesData;
+
+static gboolean
+cal_data_model_instance_generated (ECalComponent *comp,
+                                  time_t instance_start,
+                                  time_t instance_end,
+                                  gpointer data)
+{
+       GenerateInstancesData *gid = data;
+       ComponentData *comp_data;
+
+       g_return_val_if_fail (gid != NULL, FALSE);
+
+       cal_comp_get_instance_times (gid->client, e_cal_component_get_icalcomponent (comp),
+               gid->zone, &instance_start, NULL, &instance_end, NULL, NULL);
+
+       if (instance_end > instance_start)
+               instance_end--;
+
+       comp_data = component_data_new (comp, instance_start, instance_end, FALSE);
+       *gid->pexpanded_recurrences = g_slist_prepend (*gid->pexpanded_recurrences, comp_data);
+
+       return TRUE;
+}
+
+static void
+cal_data_model_expand_recurrences_thread (ECalDataModel *data_model,
+                                         gpointer user_data)
+{
+       ECalClient *client = user_data;
+       GSList *to_expand_recurrences, *link;
+       GSList *expanded_recurrences = NULL;
+       time_t range_start, range_end;
+       ViewData *view_data;
+
+       g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model));
+
+       LOCK_PROPS ();
+
+       view_data = g_hash_table_lookup (data_model->priv->views, client);
+       if (view_data)
+               view_data_ref (view_data);
+
+       range_start = data_model->priv->range_start;
+       range_end = data_model->priv->range_end;
+
+       UNLOCK_PROPS ();
+
+       if (!view_data) {
+               g_object_unref (client);
+               return;
+       }
+
+       view_data_lock (view_data);
+
+       if (!view_data->is_used) {
+               view_data_unlock (view_data);
+               view_data_unref (view_data);
+               g_object_unref (client);
+               return;
+       }
+
+       to_expand_recurrences = view_data->to_expand_recurrences;
+       view_data->to_expand_recurrences = NULL;
+
+       view_data_unlock (view_data);
+
+       for (link = to_expand_recurrences; link && view_data->is_used; link = g_slist_next (link)) {
+               icalcomponent *icomp = link->data;
+               GenerateInstancesData gid;
+
+               if (!icomp)
+                       continue;
+
+               gid.client = client;
+               gid.pexpanded_recurrences = &expanded_recurrences;
+               gid.zone = data_model->priv->zone;
+
+               e_cal_client_generate_instances_for_object_sync (client, icomp, range_start, range_end,
+                       cal_data_model_instance_generated, &gid);
+       }
+
+       g_slist_free_full (to_expand_recurrences, (GDestroyNotify) icalcomponent_free);
+
+       view_data_lock (view_data);
+       if (expanded_recurrences)
+               view_data->expanded_recurrences = g_slist_concat (view_data->expanded_recurrences, 
expanded_recurrences);
+       if (view_data->is_used) {
+               NotifyRecurrencesData *notif_data;
+
+               notif_data = g_new0 (NotifyRecurrencesData, 1);
+               notif_data->data_model = g_object_ref (data_model);
+               notif_data->client = g_object_ref (client);
+
+               g_timeout_add (1, cal_data_model_notify_recurrences_cb, notif_data);
+       }
+
+       view_data_unlock (view_data);
+       view_data_unref (view_data);
+       g_object_unref (client);
+}
+
+static void
+cal_data_model_process_modified_or_added_objects (ECalClientView *view,
+                                                 const GSList *objects,
+                                                 ECalDataModel *data_model,
+                                                 gboolean is_add)
+{
+       ViewData *view_data;
+       ECalClient *client;
+
+       g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model));
+
+       LOCK_PROPS ();
+
+       client = e_cal_client_view_get_client (view);
+       view_data = g_hash_table_lookup (data_model->priv->views, client);
+       if (view_data) {
+               view_data_ref (view_data);
+               g_warn_if_fail (view_data->view == view);
+       }
+
+       UNLOCK_PROPS ();
+
+       if (!view_data)
+               return;
+
+       view_data_lock (view_data);
+
+       if (view_data->is_used) {
+               const GSList *link;
+               GSList *to_expand_recurrences = NULL;
+
+               if (!is_add) {
+                       /* Received a modify before the view was claimed as being complete,
+                          aka fully populated, thus drop any previously known components,
+                          because there is no hope for a merge. */
+                       if (view_data->lost_components) {
+                               cal_data_model_remove_components (data_model, client, 
view_data->lost_components, NULL);
+                               g_hash_table_destroy (view_data->lost_components);
+                               view_data->lost_components = NULL;
+                       }
+               }
+
+               cal_data_model_freeze_all_subscribers (data_model);
+
+               for (link = objects; link; link = g_slist_next (link)) {
+                       icalcomponent *icomp = link->data;
+
+                       if (!icomp || !icalcomponent_get_uid (icomp))
+                               continue;
+
+                       if (data_model->priv->expand_recurrences &&
+                           !e_cal_util_component_is_instance (icomp) &&
+                           e_cal_util_component_has_recurrences (icomp)) {
+                               /* This component requires an expand of recurrences, which
+                                  will be done in a dedicated thread, thus remember it */
+                               to_expand_recurrences = g_slist_prepend (to_expand_recurrences,
+                                       icalcomponent_new_clone (icomp));
+                       } else {
+                               /* Single or detached instance, the simple case */
+                               ECalComponent *comp;
+                               ComponentData *comp_data;
+                               time_t instance_start, instance_end;
+
+                               comp = e_cal_component_new_from_icalcomponent (icalcomponent_new_clone 
(icomp));
+                               if (!comp)
+                                       continue;
+
+                               cal_comp_get_instance_times (client, icomp, data_model->priv->zone, 
&instance_start, NULL, &instance_end, NULL, NULL);
+
+                               if (instance_end > instance_start)
+                                       instance_end--;
+
+                               comp_data = component_data_new (comp, instance_start, instance_end,
+                                       e_cal_util_component_is_instance (icomp));
+
+                               cal_data_model_process_added_component (data_model, view_data, comp_data, 
NULL);
+
+                               g_object_unref (comp);
+                       }
+               }
+
+               cal_data_model_thaw_all_subscribers (data_model);
+
+               if (to_expand_recurrences) {
+                       ECalClient *client = e_cal_client_view_get_client (view);
+
+                       view_data_lock (view_data);
+                       view_data->to_expand_recurrences = g_slist_concat (
+                               view_data->to_expand_recurrences, to_expand_recurrences);
+                       g_atomic_int_inc (&view_data->pending_expand_recurrences);
+                       view_data_unlock (view_data);
+
+                       cal_data_model_submit_internal_thread_job (data_model,
+                               cal_data_model_expand_recurrences_thread, g_object_ref (client));
+               }
+       }
+
+       view_data_unlock (view_data);
+       view_data_unref (view_data);
+}
+
+static void
+cal_data_model_view_objects_added (ECalClientView *view,
+                                  const GSList *objects,
+                                  ECalDataModel *data_model)
+{
+       cal_data_model_process_modified_or_added_objects (view, objects, data_model, TRUE);
+}
+
+static void
+cal_data_model_view_objects_modified (ECalClientView *view,
+                                     const GSList *objects,
+                                     ECalDataModel *data_model)
+{
+       cal_data_model_process_modified_or_added_objects (view, objects, data_model, FALSE);
+}
+
+static void
+cal_data_model_view_objects_removed (ECalClientView *view,
+                                    const GSList *uids,
+                                    ECalDataModel *data_model)
+{
+       ViewData *view_data;
+       const GSList *link;
+
+       g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model));
+
+       LOCK_PROPS ();
+
+       view_data = g_hash_table_lookup (data_model->priv->views,
+               e_cal_client_view_get_client (view));
+
+       if (view_data) {
+               view_data_ref (view_data);
+               g_warn_if_fail (view_data->view == view);
+       }
+
+       UNLOCK_PROPS ();
+
+       if (!view_data)
+               return;
+
+       view_data_lock (view_data);
+       if (view_data->is_used) {
+               GHashTable *gathered_uids;
+               GList *removed = NULL, *rlink;
+
+               gathered_uids = g_hash_table_new (g_str_hash, g_str_equal);
+
+               for (link = uids; link; link = g_slist_next (link)) {
+                       const ECalComponentId *id = link->data;
+
+                       if (id) {
+                               if (!id->rid || !*id->rid) {
+                                       if (!g_hash_table_contains (gathered_uids, id->uid)) {
+                                               GatherComponentsData gather_data;
+
+                                               gather_data.uid = id->uid;
+                                               gather_data.pcomponent_ids = &removed;
+                                               gather_data.component_ids_hash = NULL;
+                                               gather_data.copy_ids = TRUE;
+                                               gather_data.all_instances = TRUE;
+
+                                               g_hash_table_foreach (view_data->components,
+                                                       cal_data_model_gather_components, &gather_data);
+                                               if (view_data->lost_components)
+                                                       g_hash_table_foreach (view_data->lost_components,
+                                                               cal_data_model_gather_components, 
&gather_data);
+
+                                               g_hash_table_insert (gathered_uids, id->uid, GINT_TO_POINTER 
(1));
+                                       }
+                               } else {
+                                       removed = g_list_prepend (removed, e_cal_component_id_copy (id));
+                               }
+                       }
+               }
+
+               cal_data_model_freeze_all_subscribers (data_model);
+
+               for (rlink = removed; rlink; rlink = g_list_next (rlink)) {
+                       ECalComponentId *id = rlink->data;
+
+                       if (id) {
+                               ComponentData *comp_data;
+                               time_t instance_start = (time_t) 0, instance_end = (time_t) 0;
+
+                               /* Try to limit which subscribers will be notified about removal */
+                               comp_data = g_hash_table_lookup (view_data->components, id);
+                               if (comp_data) {
+                                       instance_start = comp_data->instance_start;
+                                       instance_end = comp_data->instance_end;
+                               } else if (view_data->lost_components) {
+                                       comp_data = g_hash_table_lookup (view_data->lost_components, id);
+                                       if (comp_data) {
+                                               instance_start = comp_data->instance_start;
+                                               instance_end = comp_data->instance_end;
+                                       }
+                               }
+
+                               g_hash_table_remove (view_data->components, id);
+                               if (view_data->lost_components)
+                                       g_hash_table_remove (view_data->lost_components, id);
+
+                               cal_data_model_foreach_subscriber_in_range (data_model, view_data->client,
+                                       instance_start, instance_end,
+                                       cal_data_model_remove_one_view_component_cb, id);
+                       }
+               }
+
+               cal_data_model_thaw_all_subscribers (data_model);
+
+               g_list_free_full (removed, (GDestroyNotify) e_cal_component_free_id);
+               g_hash_table_destroy (gathered_uids);
+       }
+       view_data_unlock (view_data);
+       view_data_unref (view_data);
+}
+
+static void
+cal_data_model_view_progress (ECalClientView *view,
+                             guint percent,
+                             const gchar *message,
+                             ECalDataModel *data_model)
+{
+       g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model));
+}
+
+static void
+cal_data_model_view_complete (ECalClientView *view,
+                             const GError *error,
+                             ECalDataModel *data_model)
+{
+       ViewData *view_data;
+
+       g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model));
+
+       LOCK_PROPS ();
+
+       view_data = g_hash_table_lookup (data_model->priv->views,
+               e_cal_client_view_get_client (view));
+       if (view_data) {
+               view_data_ref (view_data);
+               g_warn_if_fail (view_data->view == view);
+       }
+
+       UNLOCK_PROPS ();
+
+       if (!view_data)
+               return;
+
+       view_data_lock (view_data);
+
+       view_data->received_complete = TRUE;
+       if (view_data->is_used &&
+           view_data->lost_components &&
+           !view_data->pending_expand_recurrences) {
+               cal_data_model_remove_components (data_model, view_data->client, view_data->lost_components, 
NULL);
+               g_hash_table_destroy (view_data->lost_components);
+               view_data->lost_components = NULL;
+       }
+
+       view_data_unlock (view_data);
+       view_data_unref (view_data);
+}
+
+typedef struct _CreateViewData {
+       ECalDataModel *data_model;
+       ECalClient *client;
+} CreateViewData;
+
+static void
+create_view_data_free (gpointer ptr)
+{
+       CreateViewData *cv_data = ptr;
+
+       if (cv_data) {
+               g_clear_object (&cv_data->data_model);
+               g_clear_object (&cv_data->client);
+               g_free (cv_data);
+       }
+}
+
+static void
+cal_data_model_create_view_thread (EAlertSinkThreadJobData *job_data,
+                                  gpointer user_data,
+                                  GCancellable *cancellable,
+                                  GError **error)
+{
+       CreateViewData *cv_data = user_data;
+       ViewData *view_data;
+       ECalDataModel *data_model;
+       ECalClient *client;
+       ECalClientView *view;
+       gchar *filter;
+
+       g_return_if_fail (cv_data != NULL);
+
+       data_model = cv_data->data_model;
+       client = cv_data->client;
+       g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model));
+       g_return_if_fail (E_IS_CAL_CLIENT (client));
+
+       LOCK_PROPS ();
+
+       if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
+               UNLOCK_PROPS ();
+               return;
+       }
+
+       view_data = g_hash_table_lookup (data_model->priv->views, client);
+       if (!view_data) {
+               UNLOCK_PROPS ();
+               g_warn_if_reached ();
+               return;
+       }
+
+       filter = g_strdup (data_model->priv->full_filter);
+
+       view_data_ref (view_data);
+       UNLOCK_PROPS ();
+
+       view_data_lock (view_data);
+       g_warn_if_fail (view_data->view == NULL);
+
+       if (!e_cal_client_get_view_sync (client, filter, &view_data->view, cancellable, error)) {
+               view_data_unlock (view_data);
+               view_data_unref (view_data);
+               g_free (filter);
+               return;
+       }
+
+       g_warn_if_fail (view_data->view != NULL);
+
+       view_data->objects_added_id = g_signal_connect (view_data->view, "objects-added",
+               G_CALLBACK (cal_data_model_view_objects_added), data_model);
+       view_data->objects_modified_id = g_signal_connect (view_data->view, "objects-modified",
+               G_CALLBACK (cal_data_model_view_objects_modified), data_model);
+       view_data->objects_removed_id = g_signal_connect (view_data->view, "objects-removed",
+               G_CALLBACK (cal_data_model_view_objects_removed), data_model);
+       view_data->progress_id = g_signal_connect (view_data->view, "progress",
+               G_CALLBACK (cal_data_model_view_progress), data_model);
+       view_data->complete_id = g_signal_connect (view_data->view, "complete",
+               G_CALLBACK (cal_data_model_view_complete), data_model);
+
+       view = g_object_ref (view_data->view);
+
+       view_data_unlock (view_data);
+       view_data_unref (view_data);
+
+       g_free (filter);
+
+       if (!g_cancellable_is_cancelled (cancellable))
+               e_cal_client_view_start (view, error);
+
+       g_clear_object (&view);
+}
+
+typedef struct _NotifyRemoveComponentsData {
+       ECalDataModel *data_model;
+       ECalClient *client;
+} NotifyRemoveComponentsData;
+
+static void
+cal_data_model_notify_remove_components_cb (gpointer key,
+                                           gpointer value,
+                                           gpointer user_data)
+{
+       ECalComponentId *id = key;
+       ComponentData *comp_data = value;
+       NotifyRemoveComponentsData *nrc_data = user_data;
+
+       g_return_if_fail (id != NULL);
+       g_return_if_fail (comp_data != NULL);
+       g_return_if_fail (nrc_data != NULL);
+
+       cal_data_model_foreach_subscriber_in_range (nrc_data->data_model, nrc_data->client,
+               comp_data->instance_start, comp_data->instance_end,
+               cal_data_model_remove_one_view_component_cb, id);
+}
+
+static void
+cal_data_model_update_client_view (ECalDataModel *data_model,
+                                  ECalClient *client)
+{
+       ESource *source;
+       ViewData *view_data;
+       CreateViewData *cv_data;
+       const gchar *alert_ident;
+       gchar *description;
+
+       LOCK_PROPS ();
+
+       view_data = g_hash_table_lookup (data_model->priv->views, client);
+       if (!view_data) {
+               view_data = view_data_new (client);
+               g_hash_table_insert (data_model->priv->views, client, view_data);
+       }
+
+       view_data_lock (view_data);
+
+       if (view_data->cancellable)
+               g_cancellable_cancel (view_data->cancellable);
+       g_clear_object (&view_data->cancellable);
+
+       if (view_data->view) {
+               view_data_disconnect_view (view_data);
+               g_clear_object (&view_data->view);
+       }
+
+       if (!view_data->received_complete) {
+               NotifyRemoveComponentsData nrc_data;
+
+               nrc_data.data_model = data_model;
+               nrc_data.client = client;
+
+               cal_data_model_freeze_all_subscribers (data_model);
+
+               g_hash_table_foreach (view_data->components,
+                       cal_data_model_notify_remove_components_cb, &nrc_data);
+
+               g_hash_table_remove_all (view_data->components);
+               if (view_data->lost_components) {
+                       g_hash_table_foreach (view_data->lost_components,
+                               cal_data_model_notify_remove_components_cb, &nrc_data);
+
+                       g_hash_table_destroy (view_data->lost_components);
+                       view_data->lost_components = NULL;
+               }
+
+               cal_data_model_thaw_all_subscribers (data_model);
+       } else {
+               if (view_data->lost_components) {
+                       NotifyRemoveComponentsData nrc_data;
+
+                       nrc_data.data_model = data_model;
+                       nrc_data.client = client;
+
+                       cal_data_model_freeze_all_subscribers (data_model);
+                       g_hash_table_foreach (view_data->lost_components,
+                               cal_data_model_notify_remove_components_cb, &nrc_data);
+                       cal_data_model_thaw_all_subscribers (data_model);
+
+                       g_hash_table_destroy (view_data->lost_components);
+                       view_data->lost_components = NULL;
+               }
+
+               view_data->lost_components = view_data->components;
+               view_data->components = g_hash_table_new_full (
+                       (GHashFunc) e_cal_component_id_hash, (GEqualFunc) e_cal_component_id_equal,
+                       (GDestroyNotify) e_cal_component_free_id, component_data_free);
+       }
+
+       view_data_unlock (view_data);
+
+       if (!data_model->priv->full_filter) {
+               UNLOCK_PROPS ();
+               return;
+       }
+
+       source = e_client_get_source (E_CLIENT (client));
+
+       switch (e_cal_client_get_source_type (client)) {
+               case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+                       alert_ident = "calendar:failed-create-view-calendar";
+                       description = g_strdup_printf (_("Creating view for calendar '%s'"), 
e_source_get_display_name (source));
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+                       alert_ident = "calendar:failed-create-view-tasks";
+                       description = g_strdup_printf (_("Creating view for task list '%s'"), 
e_source_get_display_name (source));
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+                       alert_ident = "calendar:failed-create-view-memos";
+                       description = g_strdup_printf (_("Creating view for memo list '%s'"), 
e_source_get_display_name (source));
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_LAST:
+                       g_warn_if_reached ();
+                       UNLOCK_PROPS ();
+                       return;
+       }
+
+       cv_data = g_new0 (CreateViewData, 1);
+       cv_data->data_model = g_object_ref (data_model);
+       cv_data->client = g_object_ref (client);
+
+       view_data->received_complete = FALSE;
+       view_data->cancellable = e_cal_data_model_submit_thread_job (data_model,
+               description, alert_ident, e_source_get_display_name (source),
+               cal_data_model_create_view_thread, cv_data, create_view_data_free);
+
+       g_free (description);
+
+       UNLOCK_PROPS ();
+}
+
+static void
+cal_data_model_remove_client_view (ECalDataModel *data_model,
+                                  ECalClient *client)
+{
+       ViewData *view_data;
+
+       LOCK_PROPS ();
+
+       view_data = g_hash_table_lookup (data_model->priv->views, client);
+
+       if (view_data) {
+               NotifyRemoveComponentsData nrc_data;
+
+               view_data_lock (view_data);
+
+               nrc_data.data_model = data_model;
+               nrc_data.client = client;
+
+               cal_data_model_freeze_all_subscribers (data_model);
+
+               g_hash_table_foreach (view_data->components,
+                       cal_data_model_notify_remove_components_cb, &nrc_data);
+               g_hash_table_remove_all (view_data->components);
+
+               cal_data_model_thaw_all_subscribers (data_model);
+
+               view_data->is_used = FALSE;
+               view_data_unlock (view_data);
+
+               g_hash_table_remove (data_model->priv->views, client);
+       }
+
+       UNLOCK_PROPS ();
+}
+
+static gboolean
+cal_data_model_add_to_subscriber (ECalDataModel *data_model,
+                                 ECalClient *client,
+                                 const ECalComponentId *id,
+                                 ECalComponent *component,
+                                 time_t instance_start,
+                                 time_t instance_end,
+                                 gpointer user_data)
+{
+       ECalDataModelSubscriber *subscriber = user_data;
+
+       g_return_val_if_fail (subscriber != NULL, FALSE);
+       g_return_val_if_fail (id != NULL, FALSE);
+
+       e_cal_data_model_subscriber_component_added (subscriber, client, component);
+
+       return TRUE;
+}
+
+static gboolean
+cal_data_model_add_to_subscriber_except_its_range (ECalDataModel *data_model,
+                                                  ECalClient *client,
+                                                  const ECalComponentId *id,
+                                                  ECalComponent *component,
+                                                  time_t instance_start,
+                                                  time_t instance_end,
+                                                  gpointer user_data)
+{
+       SubscriberData *subs_data = user_data;
+
+       g_return_val_if_fail (subs_data != NULL, FALSE);
+       g_return_val_if_fail (id != NULL, FALSE);
+
+       /* subs_data should have set the old time range, which
+          means only components which didn't fit into the old
+          time range will be added */
+       if (!(instance_start <= subs_data->range_end &&
+           instance_end >= subs_data->range_start))
+               e_cal_data_model_subscriber_component_added (subs_data->subscriber, client, component);
+
+       return TRUE;
+}
+
+static gboolean
+cal_data_model_remove_from_subscriber_except_its_range (ECalDataModel *data_model,
+                                                       ECalClient *client,
+                                                       const ECalComponentId *id,
+                                                       ECalComponent *component,
+                                                       time_t instance_start,
+                                                       time_t instance_end,
+                                                       gpointer user_data)
+{
+       SubscriberData *subs_data = user_data;
+
+       g_return_val_if_fail (subs_data != NULL, FALSE);
+       g_return_val_if_fail (id != NULL, FALSE);
+
+       /* subs_data should have set the new time range, which
+          means only components which don't fit into this new
+          time range will be removed */
+       if (!(instance_start <= subs_data->range_end &&
+           instance_end >= subs_data->range_start))
+               e_cal_data_model_subscriber_component_removed (subs_data->subscriber, client, id->uid, 
id->rid);
+
+       return TRUE;
+}
+
+static void
+cal_data_model_set_client_default_zone_cb (gpointer key,
+                                          gpointer value,
+                                          gpointer user_data)
+{
+       ECalClient *client = value;
+       icaltimezone *zone = user_data;
+
+       g_return_if_fail (E_IS_CAL_CLIENT (client));
+       g_return_if_fail (zone != NULL);
+
+       e_cal_client_set_default_timezone (client, zone);
+}
+
+static void
+cal_data_model_rebuild_everything (ECalDataModel *data_model,
+                                  gboolean complete_rebuild)
+{
+       GHashTableIter iter;
+       gpointer key, value;
+
+       g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model));
+
+       LOCK_PROPS ();
+
+       if (data_model->priv->views_update_freeze > 0) {
+               data_model->priv->views_update_required = TRUE;
+               UNLOCK_PROPS ();
+               return;
+       }
+
+       data_model->priv->views_update_required = FALSE;
+
+       g_hash_table_iter_init (&iter, data_model->priv->clients);
+       while (g_hash_table_iter_next (&iter, &key, &value)) {
+               ECalClient *client = value;
+
+               if (complete_rebuild)
+                       cal_data_model_remove_client_view (data_model, client);
+               cal_data_model_update_client_view (data_model, client);
+       }
+
+       UNLOCK_PROPS ();
+}
+
+static void
+cal_data_model_update_time_range (ECalDataModel *data_model)
+{
+       time_t range_start, range_end;
+
+       g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model));
+
+       LOCK_PROPS ();
+
+       if (data_model->priv->disposing) {
+               UNLOCK_PROPS ();
+
+               return;
+       }
+
+       range_start = data_model->priv->range_start;
+       range_end = data_model->priv->range_end;
+
+       cal_data_model_calc_range (data_model, &range_start, &range_end);
+
+       if (data_model->priv->range_start != range_start ||
+           data_model->priv->range_end != range_end) {
+               data_model->priv->range_start = range_start;
+               data_model->priv->range_end = range_end;
+
+               if (cal_data_model_update_full_filter (data_model))
+                       cal_data_model_rebuild_everything (data_model, FALSE);
+       }
+
+       UNLOCK_PROPS ();
+}
+
+static void
+cal_data_model_set_property (GObject *object,
+                            guint property_id,
+                            const GValue *value,
+                            GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_EXPAND_RECURRENCES:
+                       e_cal_data_model_set_expand_recurrences (
+                               E_CAL_DATA_MODEL (object),
+                               g_value_get_boolean (value));
+                       return;
+
+               case PROP_TIMEZONE:
+                       e_cal_data_model_set_timezone (
+                               E_CAL_DATA_MODEL (object),
+                               g_value_get_pointer (value));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+cal_data_model_get_property (GObject *object,
+                            guint property_id,
+                            GValue *value,
+                            GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_EXPAND_RECURRENCES:
+                       g_value_set_boolean (
+                               value,
+                               e_cal_data_model_get_expand_recurrences (
+                               E_CAL_DATA_MODEL (object)));
+                       return;
+
+               case PROP_TIMEZONE:
+                       g_value_set_pointer (
+                               value,
+                               e_cal_data_model_get_timezone (
+                               E_CAL_DATA_MODEL (object)));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+cal_data_model_dispose (GObject *object)
+{
+       ECalDataModel *data_model = E_CAL_DATA_MODEL (object);
+
+       data_model->priv->disposing = TRUE;
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_cal_data_model_parent_class)->dispose (object);
+}
+
+static void
+cal_data_model_finalize (GObject *object)
+{
+       ECalDataModel *data_model = E_CAL_DATA_MODEL (object);
+
+       g_thread_pool_free (data_model->priv->thread_pool, TRUE, FALSE);
+       g_hash_table_destroy (data_model->priv->clients);
+       g_hash_table_destroy (data_model->priv->views);
+       g_slist_free_full (data_model->priv->subscribers, subscriber_data_free);
+       g_free (data_model->priv->filter);
+       g_free (data_model->priv->full_filter);
+
+       e_weak_ref_free (data_model->priv->submit_thread_job_responder);
+       g_rec_mutex_clear (&data_model->priv->props_lock);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_cal_data_model_parent_class)->finalize (object);
+}
+
+static void
+e_cal_data_model_class_init (ECalDataModelClass *class)
+{
+       GObjectClass *object_class;
+
+       g_type_class_add_private (class, sizeof (ECalDataModelPrivate));
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->set_property = cal_data_model_set_property;
+       object_class->get_property = cal_data_model_get_property;
+       object_class->dispose = cal_data_model_dispose;
+       object_class->finalize = cal_data_model_finalize;
+
+       g_object_class_install_property (
+               object_class,
+               PROP_EXPAND_RECURRENCES,
+               g_param_spec_boolean (
+                       "expand-recurrences",
+                       "Expand Recurrences",
+                       NULL,
+                       FALSE,
+                       G_PARAM_READWRITE));
+
+       g_object_class_install_property (
+               object_class,
+               PROP_TIMEZONE,
+               g_param_spec_pointer (
+                       "timezone",
+                       "Time Zone",
+                       NULL,
+                       G_PARAM_READWRITE));
+}
+
+static void
+e_cal_data_model_init (ECalDataModel *data_model)
+{
+       data_model->priv = G_TYPE_INSTANCE_GET_PRIVATE (data_model, E_TYPE_CAL_DATA_MODEL, 
ECalDataModelPrivate);
+
+       /* Suppose the data_model is always created in the main/UI thread */
+       data_model->priv->main_thread = g_thread_self ();
+       data_model->priv->thread_pool = g_thread_pool_new (
+               cal_data_model_internal_thread_job_func, data_model, 5, FALSE, NULL);
+
+       data_model->priv->clients = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+       data_model->priv->views = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, 
view_data_unref);
+       data_model->priv->subscribers = NULL;
+
+       data_model->priv->disposing = FALSE;
+       data_model->priv->expand_recurrences = FALSE;
+       data_model->priv->zone = icaltimezone_get_utc_timezone ();
+
+       data_model->priv->views_update_freeze = 0;
+       data_model->priv->views_update_required = FALSE;
+
+       g_rec_mutex_init (&data_model->priv->props_lock);
+}
+
+/**
+ * e_cal_data_model_new:
+ * @func: a function to be called when the data model needs to create
+ *    a thread job within UI
+ * @func_responder: (allow none): a responder for @func, which is passed
+ *    as the first paramter; can be #NULL
+ *
+ * Creates a new instance of #ECalDataModel. The @func is mandatory, because
+ * it is used to create new thread jobs with UI feedback.
+ *
+ * Returns: (transfer full): A new #ECalDataModel instance
+ *
+ * Since: 3.14
+ **/
+ECalDataModel *
+e_cal_data_model_new (ECalDataModelSubmitThreadJobFunc func,
+                     GObject *func_responder)
+{
+       ECalDataModel *data_model;
+
+       g_return_val_if_fail (func != NULL, NULL);
+
+       data_model = g_object_new (E_TYPE_CAL_DATA_MODEL, NULL);
+       data_model->priv->submit_thread_job_func = func;
+       data_model->priv->submit_thread_job_responder = e_weak_ref_new (func_responder);
+
+       return data_model;
+}
+
+/**
+ * e_cal_data_model_new_clone:
+ * @src_data_model: an #ECalDataModel to clone
+ *
+ * Creates a clone of @src_data_model, which means a copy with the same clients, filter and
+ * other properties set (not the subscribers).
+ *
+ * Returns: (transfer full): A new #ECalDataModel instance deriving settings from @src_data_model
+ *
+ * Since: 3.14
+ **/
+ECalDataModel *
+e_cal_data_model_new_clone (ECalDataModel *src_data_model)
+{
+       ECalDataModel *clone;
+       GObject *func_responder;
+       GList *clients, *link;
+
+       g_return_val_if_fail (E_IS_CAL_DATA_MODEL (src_data_model), NULL);
+
+       func_responder = g_weak_ref_get (src_data_model->priv->submit_thread_job_responder);
+       g_return_val_if_fail (func_responder != NULL, NULL);
+
+       clone = e_cal_data_model_new (src_data_model->priv->submit_thread_job_func, func_responder);
+
+       g_clear_object (&func_responder);
+
+       e_cal_data_model_set_expand_recurrences (clone, e_cal_data_model_get_expand_recurrences 
(src_data_model));
+       e_cal_data_model_set_timezone (clone, e_cal_data_model_get_timezone (src_data_model));
+       e_cal_data_model_set_filter (clone, src_data_model->priv->filter);
+
+       clients = e_cal_data_model_get_clients (src_data_model);
+       for (link = clients; link; link = g_list_next (link)) {
+               ECalClient *client = link->data;
+
+               e_cal_data_model_add_client (clone, client);
+       }
+
+       g_list_free_full (clients, g_object_unref);
+
+       return clone;
+}
+
+/**
+ * e_cal_data_model_get_disposing:
+ * @data_model: an #EDataModel instance
+ *
+ * Obtains whether the @data_model is disposing and will be freed (soon).
+ *
+ * Returns: Whether the @data_model is disposing.
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_cal_data_model_get_disposing (ECalDataModel *data_model)
+{
+       gboolean disposing;
+
+       g_return_val_if_fail (E_IS_CAL_DATA_MODEL (data_model), FALSE);
+
+       LOCK_PROPS ();
+
+       disposing = data_model->priv->disposing;
+
+       UNLOCK_PROPS ();
+
+       return disposing;
+}
+
+/**
+ * e_cal_data_model_set_disposing:
+ * @data_model: an #EDataModel instance
+ * @disposing: whether the object is disposing
+ *
+ * Sets whether the @data_model is disposing itself (soon).
+ * If set to %TRUE, then no updates are done on changes
+ * which would otherwise trigger view and subscriber updates.
+ *
+ * Since: 3.14
+ **/
+void
+e_cal_data_model_set_disposing (ECalDataModel *data_model,
+                               gboolean disposing)
+{
+       g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model));
+
+       LOCK_PROPS ();
+
+       if ((data_model->priv->disposing ? 1 : 0) == (disposing ? 1 : 0)) {
+               UNLOCK_PROPS ();
+               return;
+       }
+
+       data_model->priv->disposing = disposing;
+
+       UNLOCK_PROPS ();
+}
+
+/**
+ * e_cal_data_model_get_expand_recurrences:
+ * @data_model: an #EDataModel instance
+ *
+ * Obtains whether the @data_model expands recurrences of recurring
+ * components by default. The default value is #FALSE, to not expand
+ * recurrences.
+ *
+ * Returns: Whether the @data_model expands recurrences of recurring
+ *    components.
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_cal_data_model_get_expand_recurrences (ECalDataModel *data_model)
+{
+       gboolean expand_recurrences;
+
+       g_return_val_if_fail (E_IS_CAL_DATA_MODEL (data_model), FALSE);
+
+       LOCK_PROPS ();
+
+       expand_recurrences = data_model->priv->expand_recurrences;
+
+       UNLOCK_PROPS ();
+
+       return expand_recurrences;
+}
+
+/**
+ * e_cal_data_model_set_expand_recurrences:
+ * @data_model: an #EDataModel instance
+ * @expand_recurrences: whether to expand recurrences
+ *
+ * Sets whether the @data_model should expand recurrences of recurring
+ * components by default.
+ *
+ * Since: 3.14
+ **/
+void
+e_cal_data_model_set_expand_recurrences (ECalDataModel *data_model,
+                                        gboolean expand_recurrences)
+{
+       g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model));
+
+       LOCK_PROPS ();
+
+       if ((data_model->priv->expand_recurrences ? 1 : 0) == (expand_recurrences ? 1 : 0)) {
+               UNLOCK_PROPS ();
+               return;
+       }
+
+       data_model->priv->expand_recurrences = expand_recurrences;
+
+       cal_data_model_rebuild_everything (data_model, TRUE);
+
+       UNLOCK_PROPS ();
+}
+
+/**
+ * e_cal_data_model_get_timezone:
+ * @data_model: an #EDataModel instance
+ *
+ * Obtains a timezone being used for calendar views. The returned
+ * timezone is owned by the @data_model.
+ *
+ * Returns: (transfer none): An #icaltimezone being used for calendar views.
+ *
+ * Since: 3.14
+ **/
+icaltimezone *
+e_cal_data_model_get_timezone (ECalDataModel *data_model)
+{
+       icaltimezone *zone;
+
+       g_return_val_if_fail (E_IS_CAL_DATA_MODEL (data_model), NULL);
+
+       LOCK_PROPS ();
+
+       zone = data_model->priv->zone;
+
+       UNLOCK_PROPS ();
+
+       return zone;
+}
+/**
+ * e_cal_data_model_set_timezone:
+ * @data_model: an #EDataModel instance
+ * @zone: an #icaltimezone
+ *
+ * Sets a trimezone to be used for calendar views. This change
+ * regenerates all views.
+ *
+ * Since: 3.14
+ **/
+void
+e_cal_data_model_set_timezone (ECalDataModel *data_model,
+                              icaltimezone *zone)
+{
+       g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model));
+       g_return_if_fail (zone != NULL);
+
+       LOCK_PROPS ();
+
+       if (data_model->priv->zone != zone) {
+               data_model->priv->zone = zone;
+
+               g_hash_table_foreach (data_model->priv->clients, cal_data_model_set_client_default_zone_cb, 
zone);
+
+               if (cal_data_model_update_full_filter (data_model))
+                       cal_data_model_rebuild_everything (data_model, TRUE);
+       }
+
+       UNLOCK_PROPS ();
+}
+
+/**
+ * e_cal_data_model_set_filter:
+ * @data_model: an #EDataModel instance
+ * @sexp: an expression defining a filter
+ *
+ * Sets an additional filter for the views. The filter should not
+ * contain time constraints, these are meant to be defined by
+ * subscribers.
+ *
+ * Since: 3.14
+ **/
+void
+e_cal_data_model_set_filter (ECalDataModel *data_model,
+                            const gchar *sexp)
+{
+       g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model));
+       g_return_if_fail (sexp != NULL);
+
+       LOCK_PROPS ();
+
+       if (sexp && !*sexp)
+               sexp = NULL;
+
+       if (g_strcmp0 (data_model->priv->filter, sexp) != 0) {
+               g_free (data_model->priv->filter);
+               data_model->priv->filter = g_strdup (sexp);
+
+               if (cal_data_model_update_full_filter (data_model))
+                       cal_data_model_rebuild_everything (data_model, TRUE);
+       }
+
+       UNLOCK_PROPS ();
+}
+
+/**
+ * e_cal_data_model_dup_filter:
+ * @data_model: an #EDataModel instance
+ *
+ * Obtains currently used filter (an expression) for the views.
+ *
+ * Returns: (transfer full): A copy of the currently used
+ *   filter for views. Free it with g_free() when done with it.
+ *   Returns #NULL when there is no extra filter set.
+ *
+ * Since: 3.14
+ **/
+gchar *
+e_cal_data_model_dup_filter (ECalDataModel *data_model)
+{
+       gchar *filter;
+
+       g_return_val_if_fail (E_IS_CAL_DATA_MODEL (data_model), NULL);
+
+       LOCK_PROPS ();
+
+       filter = g_strdup (data_model->priv->filter);
+
+       UNLOCK_PROPS ();
+
+       return filter;
+}
+
+/**
+ * e_cal_data_model_add_client:
+ * @data_model: an #EDataModel instance
+ * @client: an #ECalClient
+ *
+ * Adds a new @client into the set of clients which should be used
+ * to populate data for subscribers. Adding the same client multiple
+ * times does nothing.
+ *
+ * Since: 3.14
+ **/
+void
+e_cal_data_model_add_client (ECalDataModel *data_model,
+                            ECalClient *client)
+{
+       ESource *source;
+
+       g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model));
+       g_return_if_fail (E_IS_CAL_CLIENT (client));
+
+       source = e_client_get_source (E_CLIENT (client));
+       g_return_if_fail (E_IS_SOURCE (source));
+       g_return_if_fail (e_source_get_uid (source) != NULL);
+
+       LOCK_PROPS ();
+
+       if (g_hash_table_contains (data_model->priv->clients, e_source_get_uid (source))) {
+               UNLOCK_PROPS ();
+               return;
+       }
+
+       g_hash_table_insert (data_model->priv->clients, e_source_dup_uid (source), g_object_ref (client));
+
+       e_cal_client_set_default_timezone (client, data_model->priv->zone);
+
+       cal_data_model_update_client_view (data_model, client);
+
+       UNLOCK_PROPS ();
+}
+
+/**
+ * e_cal_data_model_remove_client:
+ * @uid: a UID of a client to remove
+ *
+ * Removes a client identified by @uid from a set of clients
+ * which populate the data for subscribers. Removing the client
+ * which is not used in the @data_model does nothing.
+ *
+ * Since: 3.14
+ **/
+void
+e_cal_data_model_remove_client (ECalDataModel *data_model,
+                               const gchar *uid)
+{
+       ECalClient *client;
+
+       g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model));
+       g_return_if_fail (uid != NULL);
+
+       LOCK_PROPS ();
+
+       client = g_hash_table_lookup (data_model->priv->clients, uid);
+       if (!client) {
+               UNLOCK_PROPS ();
+               return;
+       }
+
+       cal_data_model_remove_client_view (data_model, client);
+       g_hash_table_remove (data_model->priv->clients, uid);
+
+       UNLOCK_PROPS ();
+}
+
+/**
+ * e_cal_data_model_ref_client:
+ * @data_model: an #EDataModel instance
+ * @uid: a UID of a client to return
+ *
+ * Obtains an #ECalClient with given @uid from the set of clients
+ * being used by the @data_modal. Returns #NULL, if no such client
+ * is used by the @data_model.
+ *
+ * Returns: (tranfer full): An #ECalClient with given @uid being
+ *    used by @data_model, or NULL, when no such is used by
+ *    the @data_model. Unref returned (non-NULL) client with
+ *    g_object_unref() when done with it.
+ *
+ * Since: 3.14
+ **/
+ECalClient *
+e_cal_data_model_ref_client (ECalDataModel *data_model,
+                            const gchar *uid)
+{
+       ECalClient *client;
+
+       g_return_val_if_fail (E_IS_CAL_DATA_MODEL (data_model), NULL);
+
+       LOCK_PROPS ();
+
+       client = g_hash_table_lookup (data_model->priv->clients, uid);
+       if (client)
+               g_object_ref (client);
+
+       UNLOCK_PROPS ();
+
+       return client;
+}
+
+/**
+ * e_cal_data_model_get_clients:
+ * @data_model: an #EDataModel instance
+ *
+ * Obtains a list of all clients being used by the @data_model.
+ * Each client in the returned list is referenced and the list
+ * itself is also newly allocated, thus free it with
+ * g_list_free_full (list, g_object_unref); when done with it.
+ *
+ * Returns: (transfer full): A list of currently used #ECalClient-s.
+ *
+ * Since: 3.14
+ **/
+GList *
+e_cal_data_model_get_clients (ECalDataModel *data_model)
+{
+       GList *clients;
+
+       g_return_val_if_fail (E_IS_CAL_DATA_MODEL (data_model), NULL);
+
+       LOCK_PROPS ();
+
+       clients = g_hash_table_get_values (data_model->priv->clients);
+       g_list_foreach (clients, (GFunc) g_object_ref, NULL);
+
+       UNLOCK_PROPS ();
+
+       return clients;
+}
+
+static gboolean
+cal_data_model_prepend_component (ECalDataModel *data_model,
+                                 ECalClient *client,
+                                 const ECalComponentId *id,
+                                 ECalComponent *comp,
+                                 time_t instance_start,
+                                 time_t instance_end,
+                                 gpointer user_data)
+{
+       GSList **components = user_data;
+
+       g_return_val_if_fail (components != NULL, FALSE);
+       g_return_val_if_fail (comp != NULL, FALSE);
+
+       *components = g_slist_prepend (*components, g_object_ref (comp));
+
+       return TRUE;
+}
+
+/**
+ * e_cal_data_model_get_components:
+ * @data_model: an #EDataModel instance
+ * @in_range_start: Start of the time range
+ * @in_range_end: End of the time range
+ *
+ * Obtains a list of components from the given time range. The time range is
+ * clamp by the actual time range defined by subscribers (if there is no
+ * subscriber, or all subscribers define times out of the given time range,
+ * then no components are returned).
+ *
+ * Returns: (transfer full): A #GSList of #ECalComponent-s known for the given
+ *    time range in the time of the call. The #GSList, togher with the components,
+ *    is owned by the caller, which should free it with
+ *    g_slist_free_full (list, g_object_unref); when done with it.
+ *
+ * Note: A special case when both @in_range_start and @in_range_end are zero
+ *    is treated as a request for all known components.
+ *
+ * Since: 3.14
+ **/
+GSList *
+e_cal_data_model_get_components (ECalDataModel *data_model,
+                                time_t in_range_start,
+                                time_t in_range_end)
+{
+       GSList *components = NULL;
+
+       g_return_val_if_fail (E_IS_CAL_DATA_MODEL (data_model), NULL);
+
+       e_cal_data_model_foreach_component (data_model, in_range_start, in_range_end,
+               cal_data_model_prepend_component, &components);
+
+       return g_slist_reverse (components);
+}
+
+static gboolean
+cal_data_model_foreach_component (ECalDataModel *data_model,
+                                 time_t in_range_start,
+                                 time_t in_range_end,
+                                 ECalDataModelForeachFunc func,
+                                 gpointer user_data,
+                                 gboolean include_lost_components)
+{
+       GHashTableIter viter;
+       gpointer key, value;
+       gboolean checked_all = TRUE;
+
+       g_return_val_if_fail (E_IS_CAL_DATA_MODEL (data_model), FALSE);
+       g_return_val_if_fail (func != NULL, FALSE);
+
+       LOCK_PROPS ();
+
+       /* Is the given time range in the currently used time range? */
+       if (!(in_range_start == in_range_end && in_range_start == (time_t) 0) &&
+           (in_range_start >= data_model->priv->range_end ||
+           in_range_end <= data_model->priv->range_start)) {
+               UNLOCK_PROPS ();
+               return checked_all;
+       }
+
+       g_hash_table_iter_init (&viter, data_model->priv->views);
+       while (checked_all && g_hash_table_iter_next (&viter, &key, &value)) {
+               ViewData *view_data = value;
+               GHashTableIter citer;
+
+               if (!view_data)
+                       continue;
+
+               view_data_lock (view_data);
+
+               g_hash_table_iter_init (&citer, view_data->components);
+               while (checked_all && g_hash_table_iter_next (&citer, &key, &value)) {
+                       ECalComponentId *id = key;
+                       ComponentData *comp_data = value;
+
+                       if (!comp_data)
+                               continue;
+
+                       if ((in_range_start == in_range_end && in_range_start == (time_t) 0) ||
+                           (comp_data->instance_start < in_range_end &&
+                            comp_data->instance_end > in_range_start)) {
+                               if (!func (data_model, view_data->client, id, comp_data->component,
+                                          comp_data->instance_start, comp_data->instance_end, user_data))
+                                       checked_all = FALSE;
+                       }
+               }
+
+               if (include_lost_components && view_data->lost_components) {
+                       g_hash_table_iter_init (&citer, view_data->lost_components);
+                       while (checked_all && g_hash_table_iter_next (&citer, &key, &value)) {
+                               ECalComponentId *id = key;
+                               ComponentData *comp_data = value;
+
+                               if (!comp_data)
+                                       continue;
+
+                               if ((in_range_start == in_range_end && in_range_start == (time_t) 0) ||
+                                   (comp_data->instance_start < in_range_end &&
+                                    comp_data->instance_end > in_range_start)) {
+                                       if (!func (data_model, view_data->client, id, comp_data->component,
+                                                  comp_data->instance_start, comp_data->instance_end, 
user_data))
+                                               checked_all = FALSE;
+                               }
+                       }
+               }
+
+               view_data_unlock (view_data);
+       }
+
+       UNLOCK_PROPS ();
+
+       return checked_all;
+}
+
+/**
+ * e_cal_data_model_foreach_component:
+ * @data_model: an #EDataModel instance
+ * @in_range_start: Start of the time range
+ * @in_range_end: End of the time range
+ * @func: a function to be called for each component in the given time range
+ * @user_data: user data being passed into the @func
+ *
+ * Calls @func for each component in the given time range. The time range is
+ * clamp by the actual time range defined by subscribers (if there is no
+ * subscriber, or all subscribers define times out of the given time range,
+ * then the function is not called at all and a #FALSE is returned).
+ *
+ * The @func returns #TRUE to continue the traversal. If it wants to stop
+ * the traversal earlier, then it returns #FALSE.
+ *
+ * Returns: Whether all the components were checked. The returned value is
+ *    usually #TRUE, unless the @func stops traversal earlier.
+ *
+ * Note: A special case when both @in_range_start and @in_range_end are zero
+ *    is treated as a request for all known components.
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_cal_data_model_foreach_component (ECalDataModel *data_model,
+                                   time_t in_range_start,
+                                   time_t in_range_end,
+                                   ECalDataModelForeachFunc func,
+                                   gpointer user_data)
+{
+       g_return_val_if_fail (E_IS_CAL_DATA_MODEL (data_model), FALSE);
+       g_return_val_if_fail (func != NULL, FALSE);
+
+       return cal_data_model_foreach_component (data_model, in_range_start, in_range_end, func, user_data, 
FALSE);
+}
+
+/**
+ * e_cal_data_model_subscribe:
+ * @data_model: an #EDataModel instance
+ * @subscriber: an #ECalDataModelSubscriber instance
+ * @range_start: Start of the time range used by the @subscriber
+ * @range_end: End of the time range used by the @subscriber
+ *
+ * Either adds a new @subscriber to the set of subscribers for this
+ * @data_model, or changes a time range used by the @subscriber,
+ * in case it was added to the @data_model earlier.
+ *
+ * Reference count of the @subscriber is increased by one, in case
+ * it is newly added. The reference count is decreased by one
+ * when e_cal_data_model_unsubscribe() is called.
+ *
+ * Note: A special case when both @range_start and @range_end are zero
+ *    is treated as a request with no time constraint. This limits
+ *    the result only to those components which satisfy given filter.
+ *
+ * Since: 3.14
+ **/
+void
+e_cal_data_model_subscribe (ECalDataModel *data_model,
+                           ECalDataModelSubscriber *subscriber,
+                           time_t range_start,
+                           time_t range_end)
+{
+       SubscriberData *subs_data = NULL;
+       GSList *link;
+
+       g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model));
+       g_return_if_fail (E_IS_CAL_DATA_MODEL_SUBSCRIBER (subscriber));
+
+       LOCK_PROPS ();
+
+       for (link = data_model->priv->subscribers; link; link = g_slist_next (link)) {
+               SubscriberData *subs_data = link->data;
+
+               if (!subs_data)
+                       continue;
+
+               if (subs_data->subscriber == subscriber)
+                       break;
+       }
+
+       if (link != NULL) {
+               time_t new_range_start = range_start, new_range_end = range_end;
+               time_t old_range_start, old_range_end;
+
+               /* The subscriber updates its time range (it is already known) */
+               subs_data = link->data;
+
+               /* No range change */
+               if (range_start == subs_data->range_start &&
+                   range_end == subs_data->range_end) {
+                       UNLOCK_PROPS ();
+                       return;
+               }
+
+               old_range_start = subs_data->range_start;
+               old_range_end = subs_data->range_end;
+
+               if (new_range_start == (time_t) 0 && new_range_end == (time_t) 0) {
+                       new_range_start = data_model->priv->range_start;
+                       new_range_end = data_model->priv->range_end;
+               }
+
+               if (new_range_start == (time_t) 0 && new_range_end == (time_t) 0) {
+                       /* The subscriber is looking for everything and the data_model has everything too */
+                       e_cal_data_model_subscriber_freeze (subs_data->subscriber);
+                       cal_data_model_foreach_component (data_model,
+                               new_range_start, old_range_start,
+                               cal_data_model_add_to_subscriber_except_its_range, subs_data, TRUE);
+                       e_cal_data_model_subscriber_thaw (subs_data->subscriber);
+               } else {
+                       e_cal_data_model_subscriber_freeze (subs_data->subscriber);
+
+                       if (new_range_start >= old_range_end ||
+                           new_range_end <= old_range_start) {
+                               subs_data->range_start = range_start;
+                               subs_data->range_end = range_end;
+
+                               /* Completely new range, not overlapping with the former range,
+                                  everything previously added can be removed... */
+                               cal_data_model_foreach_component (data_model,
+                                       old_range_start, old_range_end,
+                                       cal_data_model_remove_from_subscriber_except_its_range, subs_data, 
TRUE);
+
+                               subs_data->range_start = old_range_start;
+                               subs_data->range_end = old_range_end;
+
+                               /* ...and components from the new range can be added */
+                               cal_data_model_foreach_component (data_model,
+                                       new_range_start, new_range_end,
+                                       cal_data_model_add_to_subscriber_except_its_range, subs_data, TRUE);
+                       } else {
+                               if (new_range_start < old_range_start) {
+                                       /* Add those known in the new extended range from the start */
+                                       cal_data_model_foreach_component (data_model,
+                                               new_range_start, old_range_start,
+                                               cal_data_model_add_to_subscriber_except_its_range, subs_data, 
TRUE);
+                               } else if (new_range_start > old_range_start) {
+                                       subs_data->range_start = range_start;
+                                       subs_data->range_end = range_end;
+
+                                       /* Remove those out of the new range from the start */
+                                       cal_data_model_foreach_component (data_model,
+                                               old_range_start, new_range_start,
+                                               cal_data_model_remove_from_subscriber_except_its_range, 
subs_data, TRUE);
+
+                                       subs_data->range_start = old_range_start;
+                                       subs_data->range_end = old_range_end;
+                               }
+
+                               if (new_range_end > old_range_end) {
+                                       /* Add those known in the new extended range from the end */
+                                       cal_data_model_foreach_component (data_model,
+                                               old_range_end, new_range_end,
+                                               cal_data_model_add_to_subscriber_except_its_range, subs_data, 
TRUE);
+                               } else if (new_range_end < old_range_end) {
+                                       subs_data->range_start = range_start;
+                                       subs_data->range_end = range_end;
+
+                                       /* Remove those out of the new range from the end */
+                                       cal_data_model_foreach_component (data_model,
+                                               new_range_end, old_range_end,
+                                               cal_data_model_remove_from_subscriber_except_its_range, 
subs_data, TRUE);
+
+                                       subs_data->range_start = old_range_start;
+                                       subs_data->range_end = old_range_end;
+                               }
+                       }
+
+                       e_cal_data_model_subscriber_thaw (subs_data->subscriber);
+               }
+
+               subs_data->range_start = range_start;
+               subs_data->range_end = range_end;
+       } else {
+               subs_data = subscriber_data_new (subscriber, range_start, range_end);
+
+               data_model->priv->subscribers = g_slist_prepend (data_model->priv->subscribers, subs_data);
+
+               e_cal_data_model_subscriber_freeze (subscriber);
+               cal_data_model_foreach_component (data_model, range_start, range_end,
+                       cal_data_model_add_to_subscriber, subscriber, TRUE);
+               e_cal_data_model_subscriber_thaw (subscriber);
+       }
+
+       cal_data_model_update_time_range (data_model);
+
+       UNLOCK_PROPS ();
+}
+
+/**
+ * e_cal_data_model_unsubscribe:
+ * @data_model: an #EDataModel instance
+ * @subscriber: an #ECalDataModelSubscriber instance
+ *
+ * Removes the @subscriber from the set of subscribers for the @data_model.
+ * Remove of the @subscriber, which is not in the set of subscribers for
+ * the @data_model does nothing.
+ *
+ * Note: The @subscriber is not notified about a removal of the components
+ *   which could be added previously, while it was subscribed for the change
+ *   notifications.
+ *
+ * Since: 3.14
+ **/
+void
+e_cal_data_model_unsubscribe (ECalDataModel *data_model,
+                             ECalDataModelSubscriber *subscriber)
+{
+       GSList *link;
+
+       g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model));
+       g_return_if_fail (E_IS_CAL_DATA_MODEL_SUBSCRIBER (subscriber));
+
+       LOCK_PROPS ();
+
+       for (link = data_model->priv->subscribers; link; link = g_slist_next (link)) {
+               SubscriberData *subs_data = link->data;
+
+               if (!subs_data)
+                       continue;
+
+               if (subs_data->subscriber == subscriber) {
+                       data_model->priv->subscribers = g_slist_remove (data_model->priv->subscribers, 
subs_data);
+                       subscriber_data_free (subs_data);
+                       break;
+               }
+       }
+
+       cal_data_model_update_time_range (data_model);
+
+       UNLOCK_PROPS ();
+}
+
+/**
+ * e_cal_data_model_get_subscriber_range:
+ * @data_model: an #EDataModel instance
+ * @subscriber: an #ECalDataModelSubscriber instance
+ * @range_start: (out): time range start for the @subscriber
+ * @range_end: (out): time range end for the @subscriber
+ *
+ * Obtains currently set time range for the @subscriber. In case
+ * the subscriber is not found returns #FALSE and both @range_start
+ * and @range_end are left untouched.
+ *
+ * Returns: Whether the @subscriber was found and the @range_start with
+ *    the @range_end were set to its current time range it uses.
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_cal_data_model_get_subscriber_range (ECalDataModel *data_model,
+                                      ECalDataModelSubscriber *subscriber,
+                                      time_t *range_start,
+                                      time_t *range_end)
+{
+       GSList *link;
+
+       g_return_val_if_fail (E_IS_CAL_DATA_MODEL (data_model), FALSE);
+       g_return_val_if_fail (E_IS_CAL_DATA_MODEL_SUBSCRIBER (subscriber), FALSE);
+       g_return_val_if_fail (range_start, FALSE);
+       g_return_val_if_fail (range_end, FALSE);
+
+       LOCK_PROPS ();
+
+       for (link = data_model->priv->subscribers; link; link = g_slist_next (link)) {
+               SubscriberData *subs_data = link->data;
+
+               if (!subs_data)
+                       continue;
+
+               if (subs_data->subscriber == subscriber) {
+                       *range_start = subs_data->range_start;
+                       *range_end = subs_data->range_end;
+                       break;
+               }
+       }
+
+       UNLOCK_PROPS ();
+
+       return link != NULL;
+}
+
+/**
+ * e_cal_data_model_freeze_views_update:
+ * @data_model: an #EDataModel instance
+ *
+ * Freezes any views updates until e_cal_data_model_thaw_views_update() is
+ * called. This can be called nested, then the same count of the calls of
+ * e_cal_data_model_thaw_views_update() is expected to unlock the views update.
+ *
+ * Since: 3.14
+ **/
+void
+e_cal_data_model_freeze_views_update (ECalDataModel *data_model)
+{
+       g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model));
+
+       LOCK_PROPS ();
+
+       data_model->priv->views_update_freeze++;
+
+       UNLOCK_PROPS ();
+}
+
+/**
+ * e_cal_data_model_thaw_views_update:
+ * @data_model: an #EDataModel instance
+ *
+ * A pair function for e_cal_data_model_freeze_views_update(), to unlock
+ * views update.
+ *
+ * Since: 3.14
+ **/
+void
+e_cal_data_model_thaw_views_update (ECalDataModel *data_model)
+{
+       g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model));
+
+       LOCK_PROPS ();
+
+       if (!data_model->priv->views_update_freeze) {
+               UNLOCK_PROPS ();
+               g_warn_if_reached ();
+               return;
+       }
+
+       data_model->priv->views_update_freeze--;
+       if (data_model->priv->views_update_freeze == 0 &&
+           data_model->priv->views_update_required)
+               cal_data_model_rebuild_everything (data_model, TRUE);
+
+       UNLOCK_PROPS ();
+}
+
+/**
+ * e_cal_data_model_is_views_update_frozen:
+ * @data_model: an #EDataModel instance
+ *
+ * Check whether any views updates are currently frozen. This is influenced by
+ * e_cal_data_model_freeze_views_update() and e_cal_data_model_thaw_views_update().
+ *
+ * Returns: Whether any views updates are currently frozen.
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_cal_data_model_is_views_update_frozen (ECalDataModel *data_model)
+{
+       gboolean is_frozen;
+
+       g_return_val_if_fail (E_IS_CAL_DATA_MODEL (data_model), FALSE);
+
+       LOCK_PROPS ();
+
+       is_frozen = data_model->priv->views_update_freeze > 0;
+
+       UNLOCK_PROPS ();
+
+       return is_frozen;
+}
diff --git a/calendar/gui/e-cal-data-model.h b/calendar/gui/e-cal-data-model.h
new file mode 100644
index 0000000..8047644
--- /dev/null
+++ b/calendar/gui/e-cal-data-model.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Milan Crha <mcrha redhat com>
+ */
+
+#ifndef E_CAL_DATA_MODEL_H
+#define E_CAL_DATA_MODEL_H
+
+#include <libecal/libecal.h>
+#include <e-util/e-util.h>
+
+#include "e-cal-data-model-subscriber.h"
+
+/* Standard GObject macros */
+#define E_TYPE_CAL_DATA_MODEL \
+       (e_cal_data_model_get_type ())
+#define E_CAL_DATA_MODEL(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_CAL_DATA_MODEL, ECalDataModel))
+#define E_CAL_DATA_MODEL_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_CAL_DATA_MODEL, ECalDataModelClass))
+#define E_IS_CAL_DATA_MODEL(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_CAL_DATA_MODEL))
+#define E_IS_CAL_DATA_MODEL_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_CAL_DATA_MODEL))
+#define E_CAL_DATA_MODEL_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_CAL_DATA_MODEL, ECalDataModelClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ECalDataModel ECalDataModel;
+typedef struct _ECalDataModelClass ECalDataModelClass;
+typedef struct _ECalDataModelPrivate ECalDataModelPrivate;
+
+struct _ECalDataModel {
+       GObject parent;
+       ECalDataModelPrivate *priv;
+};
+
+struct _ECalDataModelClass {
+       GObjectClass parent_class;
+};
+
+typedef GCancellable * (* ECalDataModelSubmitThreadJobFunc)
+                                               (GObject *responder,
+                                                const gchar *description,
+                                                const gchar *alert_ident,
+                                                const gchar *alert_arg_0,
+                                                EAlertSinkThreadJobFunc func,
+                                                gpointer user_data,
+                                                GDestroyNotify free_user_data);
+
+GType          e_cal_data_model_get_type       (void);
+ECalDataModel *        e_cal_data_model_new            (ECalDataModelSubmitThreadJobFunc func,
+                                                GObject *func_responder);
+ECalDataModel * e_cal_data_model_new_clone     (ECalDataModel *src_data_model);
+GCancellable * e_cal_data_model_submit_thread_job
+                                               (ECalDataModel *data_model,
+                                                const gchar *description,
+                                                const gchar *alert_ident,
+                                                const gchar *alert_arg_0,
+                                                EAlertSinkThreadJobFunc func,
+                                                gpointer user_data,
+                                                GDestroyNotify free_user_data);
+gboolean       e_cal_data_model_get_disposing  (ECalDataModel *data_model);
+void           e_cal_data_model_set_disposing  (ECalDataModel *data_model,
+                                                gboolean disposing);
+gboolean       e_cal_data_model_get_expand_recurrences
+                                               (ECalDataModel *data_model);
+void           e_cal_data_model_set_expand_recurrences
+                                               (ECalDataModel *data_model,
+                                                gboolean expand_recurrences);
+icaltimezone * e_cal_data_model_get_timezone   (ECalDataModel *data_model);
+void           e_cal_data_model_set_timezone   (ECalDataModel *data_model,
+                                                icaltimezone *zone);
+void           e_cal_data_model_set_filter     (ECalDataModel *data_model,
+                                                const gchar *sexp);
+gchar *                e_cal_data_model_dup_filter     (ECalDataModel *data_model);
+void           e_cal_data_model_add_client     (ECalDataModel *data_model,
+                                                ECalClient *client);
+void           e_cal_data_model_remove_client  (ECalDataModel *data_model,
+                                                const gchar *uid);
+ECalClient *   e_cal_data_model_ref_client     (ECalDataModel *data_model,
+                                                const gchar *uid);
+GList *                e_cal_data_model_get_clients    (ECalDataModel *data_model);
+GSList *       e_cal_data_model_get_components (ECalDataModel *data_model,
+                                                time_t in_range_start,
+                                                time_t in_range_end);
+
+typedef gboolean (* ECalDataModelForeachFunc)  (ECalDataModel *data_model,
+                                                ECalClient *client,
+                                                const ECalComponentId *id,
+                                                ECalComponent *comp,
+                                                time_t instance_start,
+                                                time_t instance_end,
+                                                gpointer user_data);
+
+gboolean       e_cal_data_model_foreach_component
+                                               (ECalDataModel *data_model,
+                                                time_t in_range_start,
+                                                time_t in_range_end,
+                                                ECalDataModelForeachFunc func,
+                                                gpointer user_data);
+
+void           e_cal_data_model_subscribe      (ECalDataModel *data_model,
+                                                ECalDataModelSubscriber *subscriber,
+                                                time_t range_start,
+                                                time_t range_end);
+void           e_cal_data_model_unsubscribe    (ECalDataModel *data_model,
+                                                ECalDataModelSubscriber *subscriber);
+gboolean       e_cal_data_model_get_subscriber_range
+                                               (ECalDataModel *data_model,
+                                                ECalDataModelSubscriber *subscriber,
+                                                time_t *range_start,
+                                                time_t *range_end);
+void           e_cal_data_model_freeze_views_update
+                                               (ECalDataModel *data_model);
+void           e_cal_data_model_thaw_views_update
+                                               (ECalDataModel *data_model);
+gboolean       e_cal_data_model_is_views_update_frozen
+                                               (ECalDataModel *data_model);
+
+G_END_DECLS
+
+#endif /* E_CAL_DATA_MODEL_H */
diff --git a/calendar/gui/e-cal-list-view.c b/calendar/gui/e-cal-list-view.c
index 95eec04..1694b52 100644
--- a/calendar/gui/e-cal-list-view.c
+++ b/calendar/gui/e-cal-list-view.c
@@ -37,7 +37,6 @@
 #include "e-cal-model-calendar.h"
 #include "e-cell-date-edit-text.h"
 #include "dialogs/delete-comp.h"
-#include "dialogs/delete-error.h"
 #include "dialogs/goto-dialog.h"
 #include "dialogs/send-comp.h"
 #include "dialogs/cancel-comp.h"
diff --git a/calendar/gui/e-cal-list-view.h b/calendar/gui/e-cal-list-view.h
index 06d71ed..b8a6aaa 100644
--- a/calendar/gui/e-cal-list-view.h
+++ b/calendar/gui/e-cal-list-view.h
@@ -29,7 +29,6 @@
 #include <e-util/e-util.h>
 
 #include "e-calendar-view.h"
-#include "gnome-cal.h"
 
 /*
  * ECalListView - displays calendar events in an ETable.
diff --git a/calendar/gui/e-cal-model-calendar.c b/calendar/gui/e-cal-model-calendar.c
index b3099cd..2e23784 100644
--- a/calendar/gui/e-cal-model-calendar.c
+++ b/calendar/gui/e-cal-model-calendar.c
@@ -71,15 +71,14 @@ get_dtend (ECalModelCalendar *model,
 
                model_zone = e_cal_model_get_timezone (E_CAL_MODEL (model));
 
-               if (e_cal_model_get_flags (E_CAL_MODEL (model)) & E_CAL_MODEL_FLAGS_EXPAND_RECURRENCES) {
-                       if (got_zone) {
-                               tt_end = icaltime_from_timet_with_zone (comp_data->instance_end, 
tt_end.is_date, zone);
-                               if (model_zone)
-                                       icaltimezone_convert_time (&tt_end, zone, model_zone);
-                       } else
-                               tt_end = icaltime_from_timet_with_zone (
-                                       comp_data->instance_end,
-                                       tt_end.is_date, model_zone);
+               if (got_zone) {
+                       tt_end = icaltime_from_timet_with_zone (comp_data->instance_end, tt_end.is_date, 
zone);
+                       if (model_zone)
+                               icaltimezone_convert_time (&tt_end, zone, model_zone);
+               } else {
+                       tt_end = icaltime_from_timet_with_zone (
+                               comp_data->instance_end,
+                               tt_end.is_date, model_zone);
                }
 
                if (!icaltime_is_valid_time (tt_end) || icaltime_is_null_time (tt_end))
@@ -200,24 +199,32 @@ set_transparency (ECalModelComponent *comp_data,
 }
 
 static void
-cal_model_calendar_fill_component_from_model (ECalModel *model,
-                                              ECalModelComponent *comp_data,
-                                              ETableModel *source_model,
-                                              gint row)
+cal_model_calendar_store_values_from_model (ECalModel *model,
+                                           ETableModel *source_model,
+                                           gint row,
+                                           GHashTable *values)
 {
        g_return_if_fail (E_IS_CAL_MODEL_CALENDAR (model));
-       g_return_if_fail (comp_data != NULL);
        g_return_if_fail (E_IS_TABLE_MODEL (source_model));
+       g_return_if_fail (values != NULL);
+
+       e_cal_model_util_set_value (values, source_model, E_CAL_MODEL_CALENDAR_FIELD_DTEND, row);
+       e_cal_model_util_set_value (values, source_model, E_CAL_MODEL_CALENDAR_FIELD_LOCATION, row);
+       e_cal_model_util_set_value (values, source_model, E_CAL_MODEL_CALENDAR_FIELD_TRANSPARENCY, row);
+}
+
+static void
+cal_model_calendar_fill_component_from_values (ECalModel *model,
+                                              ECalModelComponent *comp_data,
+                                              GHashTable *values)
+{
+       g_return_if_fail (E_IS_CAL_MODEL_CALENDAR (model));
+       g_return_if_fail (comp_data != NULL);
+       g_return_if_fail (values != NULL);
 
-       set_dtend (
-               model, comp_data,
-               e_table_model_value_at (source_model, E_CAL_MODEL_CALENDAR_FIELD_DTEND, row));
-       set_location (
-               comp_data,
-               e_table_model_value_at (source_model, E_CAL_MODEL_CALENDAR_FIELD_LOCATION, row));
-       set_transparency (
-               comp_data,
-               e_table_model_value_at (source_model, E_CAL_MODEL_CALENDAR_FIELD_TRANSPARENCY, row));
+       set_dtend (model, comp_data, e_cal_model_util_get_value (values, E_CAL_MODEL_CALENDAR_FIELD_DTEND));
+       set_location (comp_data, e_cal_model_util_get_value (values, E_CAL_MODEL_CALENDAR_FIELD_LOCATION));
+       set_transparency (comp_data, e_cal_model_util_get_value (values, 
E_CAL_MODEL_CALENDAR_FIELD_TRANSPARENCY));
 }
 
 static gint
@@ -265,18 +272,14 @@ cal_model_calendar_set_value_at (ETableModel *etm,
                                  gconstpointer value)
 {
        ECalModelComponent *comp_data;
-       CalObjModType mod = CALOBJ_MOD_ALL;
+       ECalObjModType mod = E_CAL_OBJ_MOD_ALL;
        ECalComponent *comp;
        ECalModelCalendar *model = (ECalModelCalendar *) etm;
-       ESourceRegistry *registry;
-       GError *error = NULL;
 
        g_return_if_fail (E_IS_CAL_MODEL_CALENDAR (model));
        g_return_if_fail (col >= 0 && col < E_CAL_MODEL_CALENDAR_FIELD_LAST);
        g_return_if_fail (row >= 0 && row < e_table_model_row_count (etm));
 
-       registry = e_cal_model_get_registry (E_CAL_MODEL (model));
-
        if (col < E_CAL_MODEL_FIELD_LAST) {
                table_model_parent_interface->set_value_at (etm, col, row, value);
                return;
@@ -286,9 +289,8 @@ cal_model_calendar_set_value_at (ETableModel *etm,
        if (!comp_data)
                return;
 
-       comp = e_cal_component_new ();
-       if (!e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (comp_data->icalcomp))) {
-               g_object_unref (comp);
+       comp = e_cal_component_new_from_icalcomponent (icalcomponent_new_clone (comp_data->icalcomp));
+       if (!comp) {
                return;
        }
 
@@ -312,51 +314,7 @@ cal_model_calendar_set_value_at (ETableModel *etm,
                break;
        }
 
-       e_cal_client_modify_object_sync (
-               comp_data->client, comp_data->icalcomp, mod, NULL, &error);
-
-       if (error == NULL) {
-               gboolean strip_alarms = TRUE;
-
-               if (itip_organizer_is_user (registry, comp, comp_data->client) &&
-                   send_component_dialog (NULL, comp_data->client, comp, FALSE, &strip_alarms, NULL)) {
-                       ECalComponent *send_comp = NULL;
-
-                       if (mod == CALOBJ_MOD_ALL && e_cal_component_is_instance (comp)) {
-                               /* Ensure we send the master object, not the instance only */
-                               icalcomponent *icalcomp = NULL;
-                               const gchar *uid = NULL;
-
-                               e_cal_component_get_uid (comp, &uid);
-                               e_cal_client_get_object_sync (
-                                       comp_data->client, uid, NULL,
-                                       &icalcomp, NULL, NULL);
-                               if (icalcomp != NULL) {
-                                       send_comp = e_cal_component_new ();
-                                       if (!e_cal_component_set_icalcomponent (send_comp, icalcomp)) {
-                                               icalcomponent_free (icalcomp);
-                                               g_object_unref (send_comp);
-                                               send_comp = NULL;
-                                       }
-                               }
-                       }
-
-                       itip_send_comp (
-                               registry, E_CAL_COMPONENT_METHOD_REQUEST,
-                               send_comp ? send_comp : comp, comp_data->client,
-                               NULL, NULL, NULL, strip_alarms, FALSE);
-
-                       if (send_comp)
-                               g_object_unref (send_comp);
-               }
-       } else {
-               g_warning (
-                       G_STRLOC ": Could not modify the object! %s",
-                       error->message);
-
-               /* FIXME Show error dialog */
-               g_error_free (error);
-       }
+       e_cal_model_modify_component (E_CAL_MODEL (model), comp_data, mod);
 
        g_object_unref (comp);
 }
@@ -506,7 +464,8 @@ e_cal_model_calendar_class_init (ECalModelCalendarClass *class)
        ECalModelClass *model_class;
 
        model_class = E_CAL_MODEL_CLASS (class);
-       model_class->fill_component_from_model = cal_model_calendar_fill_component_from_model;
+       model_class->store_values_from_model = cal_model_calendar_store_values_from_model;
+       model_class->fill_component_from_values = cal_model_calendar_fill_component_from_values;
 }
 
 static void
@@ -534,12 +493,19 @@ e_cal_model_calendar_init (ECalModelCalendar *model)
 }
 
 ECalModel *
-e_cal_model_calendar_new (ESourceRegistry *registry)
+e_cal_model_calendar_new (ECalDataModel *data_model,
+                         ESourceRegistry *registry,
+                         EShell *shell)
 {
+       g_return_val_if_fail (E_IS_CAL_DATA_MODEL (data_model), NULL);
        g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
+       g_return_val_if_fail (E_IS_SHELL (shell), NULL);
 
        return g_object_new (
                E_TYPE_CAL_MODEL_CALENDAR,
-               "registry", registry, NULL);
+               "data-model", data_model,
+               "registry", registry,
+               "shell", shell,
+               NULL);
 }
 
diff --git a/calendar/gui/e-cal-model-calendar.h b/calendar/gui/e-cal-model-calendar.h
index f1a6225..c5d6833 100644
--- a/calendar/gui/e-cal-model-calendar.h
+++ b/calendar/gui/e-cal-model-calendar.h
@@ -71,7 +71,9 @@ struct _ECalModelCalendarClass {
 };
 
 GType          e_cal_model_calendar_get_type   (void);
-ECalModel *    e_cal_model_calendar_new        (ESourceRegistry *registry);
+ECalModel *    e_cal_model_calendar_new        (ECalDataModel *data_model,
+                                                ESourceRegistry *registry,
+                                                EShell *shell);
 
 G_END_DECLS
 
diff --git a/calendar/gui/e-cal-model-memos.c b/calendar/gui/e-cal-model-memos.c
index 22188da..0b00768 100644
--- a/calendar/gui/e-cal-model-memos.c
+++ b/calendar/gui/e-cal-model-memos.c
@@ -49,15 +49,28 @@ G_DEFINE_TYPE_WITH_CODE (
                e_cal_model_memos_table_model_init))
 
 static void
-cal_model_memos_fill_component_from_model (ECalModel *model,
-                                           ECalModelComponent *comp_data,
-                                           ETableModel *source_model,
-                                           gint row)
+cal_model_memos_store_values_from_model (ECalModel *model,
+                                        ETableModel *source_model,
+                                        gint row,
+                                        GHashTable *values)
+{
+       g_return_if_fail (E_IS_CAL_MODEL_MEMOS (model));
+       g_return_if_fail (E_IS_TABLE_MODEL (source_model));
+       g_return_if_fail (values != NULL);
+
+       /* nothing is stored from UI currently */
+}
+
+static void
+cal_model_memos_fill_component_from_values (ECalModel *model,
+                                           ECalModelComponent *comp_data,
+                                           GHashTable *values)
 {
        icaltimetype start;
+
        g_return_if_fail (E_IS_CAL_MODEL_MEMOS (model));
        g_return_if_fail (comp_data != NULL);
-       g_return_if_fail (E_IS_TABLE_MODEL (source_model));
+       g_return_if_fail (values != NULL);
 
        start = icalcomponent_get_dtstart (comp_data->icalcomp);
        if (icaltime_compare_date_only (start, icaltime_null_time ()) == 0) {
@@ -103,7 +116,6 @@ cal_model_memos_set_value_at (ETableModel *etm,
 {
        ECalModelComponent *comp_data;
        ECalModelMemos *model = (ECalModelMemos *) etm;
-       GError *error = NULL;
 
        g_return_if_fail (E_IS_CAL_MODEL_MEMOS (model));
        g_return_if_fail (col >= 0 && col < E_CAL_MODEL_MEMOS_FIELD_LAST);
@@ -120,19 +132,7 @@ cal_model_memos_set_value_at (ETableModel *etm,
                return;
        }
 
-       /* TODO ask about mod type */
-       e_cal_client_modify_object_sync (
-               comp_data->client, comp_data->icalcomp,
-               CALOBJ_MOD_ALL, NULL, &error);
-
-       if (error != NULL) {
-               g_warning (
-                       G_STRLOC ": Could not modify the object! %s",
-                       error->message);
-
-               /* TODO Show error dialog */
-               g_error_free (error);
-       }
+       e_cal_model_modify_component (E_CAL_MODEL (model), comp_data, E_CAL_OBJ_MOD_ALL);
 }
 
 static gboolean
@@ -226,7 +226,8 @@ e_cal_model_memos_class_init (ECalModelMemosClass *class)
        ECalModelClass *model_class;
 
        model_class = E_CAL_MODEL_CLASS (class);
-       model_class->fill_component_from_model = cal_model_memos_fill_component_from_model;
+       model_class->store_values_from_model = cal_model_memos_store_values_from_model;
+       model_class->fill_component_from_values = cal_model_memos_fill_component_from_values;
 }
 
 static void
@@ -256,12 +257,19 @@ e_cal_model_memos_init (ECalModelMemos *model)
 }
 
 ECalModel *
-e_cal_model_memos_new (ESourceRegistry *registry)
+e_cal_model_memos_new (ECalDataModel *data_model,
+                      ESourceRegistry *registry,
+                      EShell *shell)
 {
+       g_return_val_if_fail (E_IS_CAL_DATA_MODEL (data_model), NULL);
        g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
+       g_return_val_if_fail (E_IS_SHELL (shell), NULL);
 
        return g_object_new (
                E_TYPE_CAL_MODEL_MEMOS,
-               "registry", registry, NULL);
+               "data-model", data_model,
+               "registry", registry,
+               "shell", shell,
+               NULL);
 }
 
diff --git a/calendar/gui/e-cal-model-memos.h b/calendar/gui/e-cal-model-memos.h
index 6ca6270..b5bf0a5 100644
--- a/calendar/gui/e-cal-model-memos.h
+++ b/calendar/gui/e-cal-model-memos.h
@@ -70,7 +70,9 @@ struct _ECalModelMemosClass {
 };
 
 GType          e_cal_model_memos_get_type      (void);
-ECalModel *    e_cal_model_memos_new           (ESourceRegistry *registry);
+ECalModel *    e_cal_model_memos_new           (ECalDataModel *data_model,
+                                                ESourceRegistry *registry,
+                                                EShell *shell);
 
 G_END_DECLS
 
diff --git a/calendar/gui/e-cal-model-tasks.c b/calendar/gui/e-cal-model-tasks.c
index f07d9bf..4232389 100644
--- a/calendar/gui/e-cal-model-tasks.c
+++ b/calendar/gui/e-cal-model-tasks.c
@@ -684,34 +684,6 @@ set_url (ECalModelComponent *comp_data,
        }
 }
 
-/**
- * commit_component_changes
- * @comp_data: Component of our interest, which has been changed.
- *
- * Commits changes to the backend calendar of the component.
- **/
-static void
-commit_component_changes (ECalModelComponent *comp_data)
-{
-       GError *error = NULL;
-
-       g_return_if_fail (comp_data != NULL);
-
-       /* FIXME ask about mod type */
-       e_cal_client_modify_object_sync (
-               comp_data->client, comp_data->icalcomp,
-               CALOBJ_MOD_ALL, NULL, &error);
-
-       if (error != NULL) {
-               g_warning (
-                       G_STRLOC ": Could not modify the object! %s",
-                       error->message);
-
-               /* FIXME Show error dialog */
-               g_error_free (error);
-       }
-}
-
 static void
 cal_model_tasks_set_property (GObject *object,
                               guint property_id,
@@ -834,41 +806,51 @@ cal_model_tasks_get_color_for_component (ECalModel *model,
 }
 
 static void
-cal_model_tasks_fill_component_from_model (ECalModel *model,
-                                           ECalModelComponent *comp_data,
-                                           ETableModel *source_model,
-                                           gint row)
+cal_model_tasks_store_values_from_model (ECalModel *model,
+                                        ETableModel *source_model,
+                                        gint row,
+                                        GHashTable *values)
+{
+       g_return_if_fail (E_IS_CAL_MODEL_TASKS (model));
+       g_return_if_fail (E_IS_TABLE_MODEL (source_model));
+       g_return_if_fail (values != NULL);
+
+       e_cal_model_util_set_value (values, source_model, E_CAL_MODEL_TASKS_FIELD_COMPLETED, row);
+       e_cal_model_util_set_value (values, source_model, E_CAL_MODEL_TASKS_FIELD_PERCENT, row);
+       e_cal_model_util_set_value (values, source_model, E_CAL_MODEL_TASKS_FIELD_STATUS, row);
+       e_cal_model_util_set_value (values, source_model, E_CAL_MODEL_TASKS_FIELD_DUE, row);
+       e_cal_model_util_set_value (values, source_model, E_CAL_MODEL_TASKS_FIELD_GEO, row);
+       e_cal_model_util_set_value (values, source_model, E_CAL_MODEL_TASKS_FIELD_PRIORITY, row);
+       e_cal_model_util_set_value (values, source_model, E_CAL_MODEL_TASKS_FIELD_URL, row);
+}
+
+static void
+cal_model_tasks_fill_component_from_values (ECalModel *model,
+                                           ECalModelComponent *comp_data,
+                                           GHashTable *values)
 {
        gpointer value;
 
        g_return_if_fail (E_IS_CAL_MODEL_TASKS (model));
        g_return_if_fail (comp_data != NULL);
-       g_return_if_fail (E_IS_TABLE_MODEL (source_model));
+       g_return_if_fail (values != NULL);
 
        /* This just makes sure if anything indicates completion, all
         * three fields do or if percent is 0, status is sane */
 
-       value = e_table_model_value_at (source_model, E_CAL_MODEL_TASKS_FIELD_COMPLETED, row);
+       value = e_cal_model_util_get_value (values, E_CAL_MODEL_TASKS_FIELD_COMPLETED);
        set_completed ((ECalModelTasks *) model, comp_data, value);
        if (!value) {
-               value = e_table_model_value_at (source_model, E_CAL_MODEL_TASKS_FIELD_PERCENT, row);
+               value = e_cal_model_util_get_value (values, E_CAL_MODEL_TASKS_FIELD_PERCENT);
                set_percent (comp_data, value);
                if (GPOINTER_TO_INT (value) != 100 && GPOINTER_TO_INT (value) != 0)
-                       set_status (comp_data, e_table_model_value_at (source_model, 
E_CAL_MODEL_TASKS_FIELD_STATUS, row));
+                       set_status (comp_data, e_cal_model_util_get_value (values, 
E_CAL_MODEL_TASKS_FIELD_STATUS));
        }
 
-       set_due (
-               model, comp_data,
-               e_table_model_value_at (source_model, E_CAL_MODEL_TASKS_FIELD_DUE, row));
-       set_geo (
-               comp_data,
-               e_table_model_value_at (source_model, E_CAL_MODEL_TASKS_FIELD_GEO, row));
-       set_priority (
-               comp_data,
-               e_table_model_value_at (source_model, E_CAL_MODEL_TASKS_FIELD_PRIORITY, row));
-       set_url (
-               comp_data,
-               e_table_model_value_at (source_model, E_CAL_MODEL_TASKS_FIELD_URL, row));
+       set_due (model, comp_data, e_cal_model_util_get_value (values, E_CAL_MODEL_TASKS_FIELD_DUE));
+       set_geo (comp_data, e_cal_model_util_get_value (values, E_CAL_MODEL_TASKS_FIELD_GEO));
+       set_priority (comp_data, e_cal_model_util_get_value (values, E_CAL_MODEL_TASKS_FIELD_PRIORITY));
+       set_url (comp_data, e_cal_model_util_get_value (values, E_CAL_MODEL_TASKS_FIELD_URL));
 }
 
 static gint
@@ -973,7 +955,7 @@ cal_model_tasks_set_value_at (ETableModel *etm,
                break;
        }
 
-       commit_component_changes (comp_data);
+       e_cal_model_modify_component (E_CAL_MODEL (model), comp_data, E_CAL_OBJ_MOD_ALL);
 }
 
 static gboolean
@@ -1186,7 +1168,8 @@ e_cal_model_tasks_class_init (ECalModelTasksClass *class)
 
        cal_model_class = E_CAL_MODEL_CLASS (class);
        cal_model_class->get_color_for_component = cal_model_tasks_get_color_for_component;
-       cal_model_class->fill_component_from_model = cal_model_tasks_fill_component_from_model;
+       cal_model_class->store_values_from_model = cal_model_tasks_store_values_from_model;
+       cal_model_class->fill_component_from_values = cal_model_tasks_fill_component_from_values;
 
        g_object_class_install_property (
                object_class,
@@ -1261,13 +1244,20 @@ e_cal_model_tasks_init (ECalModelTasks *model)
 }
 
 ECalModel *
-e_cal_model_tasks_new (ESourceRegistry *registry)
+e_cal_model_tasks_new (ECalDataModel *data_model,
+                      ESourceRegistry *registry,
+                      EShell *shell)
 {
+       g_return_val_if_fail (E_IS_CAL_DATA_MODEL (data_model), NULL);
        g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
+       g_return_val_if_fail (E_IS_SHELL (shell), NULL);
 
        return g_object_new (
                E_TYPE_CAL_MODEL_TASKS,
-               "registry", registry, NULL);
+               "data-model", data_model,
+               "registry", registry,
+               "shell", shell,
+               NULL);
 }
 
 gboolean
@@ -1383,7 +1373,7 @@ e_cal_model_tasks_mark_comp_complete (ECalModelTasks *model,
 
        /*e_table_model_row_changed (E_TABLE_MODEL (model), model_row);*/
 
-       commit_component_changes (comp_data);
+       e_cal_model_modify_component (E_CAL_MODEL (model), comp_data, E_CAL_OBJ_MOD_ALL);
 }
 
 /**
@@ -1428,7 +1418,7 @@ e_cal_model_tasks_mark_comp_incomplete (ECalModelTasks *model,
 
        /*e_table_model_row_changed (E_TABLE_MODEL (model), model_row);*/
 
-       commit_component_changes (comp_data);
+       e_cal_model_modify_component (E_CAL_MODEL (model), comp_data, E_CAL_OBJ_MOD_ALL);
 }
 
 void
diff --git a/calendar/gui/e-cal-model-tasks.h b/calendar/gui/e-cal-model-tasks.h
index 2cf7977..0fa19ff 100644
--- a/calendar/gui/e-cal-model-tasks.h
+++ b/calendar/gui/e-cal-model-tasks.h
@@ -78,7 +78,9 @@ struct _ECalModelTasksClass {
 };
 
 GType          e_cal_model_tasks_get_type      (void);
-ECalModel *    e_cal_model_tasks_new           (ESourceRegistry *registry);
+ECalModel *    e_cal_model_tasks_new           (ECalDataModel *data_model,
+                                                ESourceRegistry *registry,
+                                                EShell *shell);
 gboolean       e_cal_model_tasks_get_highlight_due_today
                                                (ECalModelTasks *model);
 void           e_cal_model_tasks_set_highlight_due_today
diff --git a/calendar/gui/e-cal-model.c b/calendar/gui/e-cal-model.c
index a27bef9..3288600 100644
--- a/calendar/gui/e-cal-model.c
+++ b/calendar/gui/e-cal-model.c
@@ -33,12 +33,15 @@
 #include <e-util/e-util.h>
 #include <e-util/e-util-enumtypes.h>
 
+#include "dialogs/recur-comp.h"
+#include "dialogs/send-comp.h"
 #include "comp-util.h"
-#include "e-cal-model.h"
+#include "e-cal-data-model-subscriber.h"
+#include "e-cal-ops.h"
 #include "itip-utils.h"
 #include "misc.h"
 
-typedef struct _ClientData ClientData;
+#include "e-cal-model.h"
 
 struct _ECalModelComponentPrivate {
        GString *categories_str;
@@ -52,39 +55,19 @@ struct _ECalModelComponentPrivate {
        (G_TYPE_INSTANCE_GET_PRIVATE \
        ((obj), E_TYPE_CAL_MODEL_COMPONENT, ECalModelComponentPrivate))
 
-struct _ClientData {
-       volatile gint ref_count;
-       GWeakRef model;
-       ECalClient *client;
-
-       GMutex view_lock;
-       gboolean do_query;
-       ECalClientView *view;
-       GCancellable *cancellable;
-
-       gulong backend_died_handler_id;
-       gulong objects_added_handler_id;
-       gulong objects_modified_handler_id;
-       gulong objects_removed_handler_id;
-       gulong progress_handler_id;
-       gulong complete_handler_id;
-};
-
 struct _ECalModelPrivate {
+       ECalDataModel *data_model;
        ESourceRegistry *registry;
+       EShell *shell;
+       EClientCache *client_cache;
 
-       /* Queue of ClientData structs */
-       GQueue clients;
-       GMutex clients_lock;
-
-       /* The default client in the list */
-       ECalClient *default_client;
+       /* The default source uid of an ECalClient */
+       gchar *default_source_uid;
 
        /* Array for storing the objects. Each element is of type ECalModelComponent */
        GPtrArray *objects;
 
        icalcomponent_kind kind;
-       ECalModelFlags flags;
        icaltimezone *zone;
 
        /* The time range to display */
@@ -94,9 +77,6 @@ struct _ECalModelPrivate {
        /* The search regular expression */
        gchar *search_sexp;
 
-       /* The full regular expression, including time range */
-       gchar *full_sexp;
-
        /* The default category */
        gchar *default_category;
 
@@ -130,18 +110,6 @@ struct _ECalModelPrivate {
 
        /* Ask user to confirm before deleting components. */
        gboolean confirm_delete;
-
-       gboolean in_added;
-       gboolean in_modified;
-       gboolean in_removed;
-
-       GHashTable *notify_added;
-       GHashTable *notify_modified;
-       GHashTable *notify_removed;
-
-       GMutex notify_lock;
-
-       GCancellable *loading_clients;
 };
 
 typedef struct {
@@ -151,19 +119,17 @@ typedef struct {
 
 static const gchar *cal_model_get_color_for_component (ECalModel *model, ECalModelComponent *comp_data);
 
-static gboolean add_new_client (ECalModel *model, ECalClient *client, gboolean do_query);
-static void remove_client_objects (ECalModel *model, ClientData *client_data);
-static void remove_client (ECalModel *model, ClientData *client_data);
-static void redo_queries (ECalModel *model);
-
 enum {
        PROP_0,
+       PROP_CLIENT_CACHE,
        PROP_COMPRESS_WEEKEND,
        PROP_CONFIRM_DELETE,
-       PROP_DEFAULT_CLIENT,
+       PROP_DATA_MODEL,
        PROP_DEFAULT_REMINDER_INTERVAL,
        PROP_DEFAULT_REMINDER_UNITS,
+       PROP_DEFAULT_SOURCE_UID,
        PROP_REGISTRY,
+       PROP_SHELL,
        PROP_TIMEZONE,
        PROP_USE_24_HOUR_FORMAT,
        PROP_USE_DEFAULT_REMINDER,
@@ -185,236 +151,95 @@ enum {
        TIME_RANGE_CHANGED,
        ROW_APPENDED,
        COMPS_DELETED,
-       CAL_VIEW_PROGRESS,
-       CAL_VIEW_COMPLETE,
-       STATUS_MESSAGE,
        TIMEZONE_CHANGED,
+       OBJECT_CREATED,
        LAST_SIGNAL
 };
 
 /* Forward Declarations */
-static void    e_cal_model_table_model_init
-                                       (ETableModelInterface *iface);
+static void e_cal_model_table_model_init (ETableModelInterface *iface);
+static void e_cal_model_cal_data_model_subscriber_init (ECalDataModelSubscriberInterface *iface);
 
 static guint signals[LAST_SIGNAL];
 
-G_DEFINE_TYPE_WITH_CODE (
-       ECalModel,
-       e_cal_model,
-       G_TYPE_OBJECT,
-       G_IMPLEMENT_INTERFACE (
-               E_TYPE_EXTENSIBLE, NULL)
-       G_IMPLEMENT_INTERFACE (
-               E_TYPE_TABLE_MODEL,
-               e_cal_model_table_model_init))
-
-G_DEFINE_TYPE (
-       ECalModelComponent,
-       e_cal_model_component,
-       G_TYPE_OBJECT)
-
-static void
-client_data_backend_died_cb (ECalClient *client,
-                             ClientData *client_data)
-{
-       ECalModel *model;
-
-       model = g_weak_ref_get (&client_data->model);
-       if (model != NULL) {
-               e_cal_model_remove_client (model, client);
-               g_object_unref (model);
-       }
-}
+G_DEFINE_ABSTRACT_TYPE_WITH_CODE (ECalModel, e_cal_model, G_TYPE_OBJECT,
+       G_IMPLEMENT_INTERFACE (E_TYPE_EXTENSIBLE, NULL)
+       G_IMPLEMENT_INTERFACE (E_TYPE_TABLE_MODEL, e_cal_model_table_model_init)
+       G_IMPLEMENT_INTERFACE (E_TYPE_CAL_DATA_MODEL_SUBSCRIBER, e_cal_model_cal_data_model_subscriber_init))
 
-static ClientData *
-client_data_new (ECalModel *model,
-                 ECalClient *client,
-                 gboolean do_query)
-{
-       ClientData *client_data;
-       gulong handler_id;
-
-       client_data = g_slice_new0 (ClientData);
-       client_data->ref_count = 1;
-       g_weak_ref_set (&client_data->model, model);
-       client_data->client = g_object_ref (client);
-       client_data->do_query = do_query;
-
-       g_mutex_init (&client_data->view_lock);
-
-       handler_id = g_signal_connect (
-               client_data->client, "backend-died",
-               G_CALLBACK (client_data_backend_died_cb), client_data);
-       client_data->backend_died_handler_id = handler_id;
-
-       return client_data;
-}
+G_DEFINE_TYPE (ECalModelComponent, e_cal_model_component, G_TYPE_OBJECT)
 
 static void
-client_data_disconnect_view_handlers (ClientData *client_data)
+e_cal_model_component_set_icalcomponent (ECalModelComponent *comp_data,
+                                        ECalModel *model,
+                                        icalcomponent *icalcomp)
 {
-       /* This MUST be called with the view_lock acquired. */
-
-       g_return_if_fail (client_data->view != NULL);
-
-       if (client_data->objects_added_handler_id > 0) {
-               g_signal_handler_disconnect (
-                       client_data->view,
-                       client_data->objects_added_handler_id);
-               client_data->objects_added_handler_id = 0;
-       }
-
-       if (client_data->objects_modified_handler_id > 0) {
-               g_signal_handler_disconnect (
-                       client_data->view,
-                       client_data->objects_modified_handler_id);
-               client_data->objects_modified_handler_id = 0;
-       }
+       if (model != NULL)
+               g_return_if_fail (E_IS_CAL_MODEL (model));
+       g_return_if_fail (comp_data != NULL);
 
-       if (client_data->objects_removed_handler_id > 0) {
-               g_signal_handler_disconnect (
-                       client_data->view,
-                       client_data->objects_removed_handler_id);
-               client_data->objects_removed_handler_id = 0;
+       #define free_ptr(x) { \
+               if (x) { \
+                       g_free (x); \
+                       x = NULL; \
+               } \
        }
 
-       if (client_data->progress_handler_id > 0) {
-               g_signal_handler_disconnect (
-                       client_data->view,
-                       client_data->progress_handler_id);
-               client_data->progress_handler_id = 0;
-       }
+       if (comp_data->icalcomp)
+               icalcomponent_free (comp_data->icalcomp);
+       comp_data->icalcomp = icalcomp;
 
-       if (client_data->complete_handler_id > 0) {
-               g_signal_handler_disconnect (
-                       client_data->view,
-                       client_data->complete_handler_id);
-               client_data->complete_handler_id = 0;
-       }
-}
+       if (comp_data->priv->categories_str)
+               g_string_free (comp_data->priv->categories_str, TRUE);
+       comp_data->priv->categories_str = NULL;
 
-static ClientData *
-client_data_ref (ClientData *client_data)
-{
-       g_return_val_if_fail (client_data != NULL, NULL);
-       g_return_val_if_fail (client_data->ref_count > 0, NULL);
+       free_ptr (comp_data->dtstart);
+       free_ptr (comp_data->dtend);
+       free_ptr (comp_data->due);
+       free_ptr (comp_data->completed);
+       free_ptr (comp_data->created);
+       free_ptr (comp_data->lastmodified);
+       free_ptr (comp_data->color);
 
-       g_atomic_int_inc (&client_data->ref_count);
+       #undef free_ptr
 
-       return client_data;
+       if (comp_data->icalcomp && model)
+               e_cal_model_set_instance_times (comp_data, model->priv->zone);
 }
 
 static void
-client_data_unref (ClientData *client_data)
-{
-       g_return_if_fail (client_data != NULL);
-       g_return_if_fail (client_data->ref_count > 0);
-
-       if (g_atomic_int_dec_and_test (&client_data->ref_count)) {
-
-               g_signal_handler_disconnect (
-                       client_data->client,
-                       client_data->backend_died_handler_id);
-
-               if (client_data->view != NULL)
-                       client_data_disconnect_view_handlers (client_data);
-
-               g_weak_ref_set (&client_data->model, NULL);
-
-               g_clear_object (&client_data->client);
-               g_clear_object (&client_data->view);
-               g_clear_object (&client_data->cancellable);
-
-               g_mutex_clear (&client_data->view_lock);
-
-               g_slice_free (ClientData, client_data);
-       }
-}
-
-static GList *
-cal_model_clients_list (ECalModel *model)
-{
-       GList *list, *head;
-
-       g_mutex_lock (&model->priv->clients_lock);
-
-       head = g_queue_peek_head_link (&model->priv->clients);
-       list = g_list_copy_deep (head, (GCopyFunc) client_data_ref, NULL);
-
-       g_mutex_unlock (&model->priv->clients_lock);
-
-       return list;
-}
-
-static ClientData *
-cal_model_clients_lookup (ECalModel *model,
-                          ECalClient *client)
+e_cal_model_component_finalize (GObject *object)
 {
-       ClientData *client_data = NULL;
-       GList *list, *link;
-
-       list = cal_model_clients_list (model);
-
-       for (link = list; link != NULL; link = g_list_next (link)) {
-               ClientData *candidate = link->data;
+       ECalModelComponent *comp_data = E_CAL_MODEL_COMPONENT (object);
 
-               if (candidate->client == client) {
-                       client_data = client_data_ref (candidate);
-                       break;
-               }
+       if (comp_data->client) {
+               g_object_unref (comp_data->client);
+               comp_data->client = NULL;
        }
 
-       g_list_free_full (list, (GDestroyNotify) client_data_unref);
-
-       return client_data;
-}
-
-static ClientData *
-cal_model_clients_peek (ECalModel *model)
-{
-       ClientData *client_data;
+       e_cal_model_component_set_icalcomponent (comp_data, NULL, NULL);
 
-       g_mutex_lock (&model->priv->clients_lock);
-
-       client_data = g_queue_peek_head (&model->priv->clients);
-       if (client_data != NULL)
-               client_data_ref (client_data);
-
-       g_mutex_unlock (&model->priv->clients_lock);
-
-       return client_data;
+       /* Chain up to parent's finalize() method. */
+       G_OBJECT_CLASS (e_cal_model_component_parent_class)->finalize (object);
 }
 
-static ClientData *
-cal_model_clients_pop (ECalModel *model)
+/* Class initialization function for the calendar component object */
+static void
+e_cal_model_component_class_init (ECalModelComponentClass *class)
 {
-       ClientData *client_data;
-
-       g_mutex_lock (&model->priv->clients_lock);
-
-       client_data = g_queue_pop_head (&model->priv->clients);
+       GObjectClass *object_class;
 
-       g_mutex_unlock (&model->priv->clients_lock);
+       object_class = (GObjectClass *) class;
+       g_type_class_add_private (class, sizeof (ECalModelComponentPrivate));
 
-       return client_data;
+       object_class->finalize = e_cal_model_component_finalize;
 }
 
-static gboolean
-cal_model_clients_remove (ECalModel *model,
-                          ClientData *client_data)
+static void
+e_cal_model_component_init (ECalModelComponent *comp)
 {
-       gboolean removed = FALSE;
-
-       g_mutex_lock (&model->priv->clients_lock);
-
-       if (g_queue_remove (&model->priv->clients, client_data)) {
-               client_data_unref (client_data);
-               removed = TRUE;
-       }
-
-       g_mutex_unlock (&model->priv->clients_lock);
-
-       return removed;
+       comp->priv = E_CAL_MODEL_COMPONENT_GET_PRIVATE (comp);
+       comp->is_new_component = FALSE;
 }
 
 static gpointer
@@ -518,7 +343,7 @@ get_dtstart (ECalModel *model,
                    && e_cal_client_get_timezone_sync (comp_data->client, icaltime_get_tzid (tt_start), 
&zone, NULL, NULL))
                        got_zone = TRUE;
 
-               if (e_cal_model_get_flags (model) & E_CAL_MODEL_FLAGS_EXPAND_RECURRENCES) {
+               if (e_cal_data_model_get_expand_recurrences (priv->data_model)) {
                        if (got_zone) {
                                tt_start = icaltime_from_timet_with_zone (comp_data->instance_start, 
tt_start.is_date, zone);
                                if (priv->zone)
@@ -755,6 +580,20 @@ datetime_to_zone (ECalClient *client,
 }
 
 static void
+cal_model_set_data_model (ECalModel *model,
+                         ECalDataModel *data_model)
+{
+       g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model));
+       g_return_if_fail (model->priv->data_model == NULL);
+
+       /* Be aware of a circular dependency, once this @model is subscribed to
+          the @data_model, then the @data_model increases reference count
+          of the @model.
+       */
+       model->priv->data_model = g_object_ref (data_model);
+}
+
+static void
 cal_model_set_registry (ECalModel *model,
                         ESourceRegistry *registry)
 {
@@ -765,6 +604,25 @@ cal_model_set_registry (ECalModel *model,
 }
 
 static void
+cal_model_set_shell (ECalModel *model,
+                    EShell *shell)
+{
+       EClientCache *client_cache;
+
+       g_return_if_fail (E_IS_SHELL (shell));
+       g_return_if_fail (model->priv->shell == NULL);
+
+       model->priv->shell = g_object_ref (shell);
+
+       client_cache = e_shell_get_client_cache (shell);
+
+       g_return_if_fail (E_IS_CLIENT_CACHE (client_cache));
+       g_return_if_fail (model->priv->client_cache == NULL);
+
+       model->priv->client_cache = g_object_ref (client_cache);
+}
+
+static void
 cal_model_set_property (GObject *object,
                         guint property_id,
                         const GValue *value,
@@ -783,12 +641,18 @@ cal_model_set_property (GObject *object,
                                g_value_get_boolean (value));
                        return;
 
-               case PROP_DEFAULT_CLIENT:
-                       e_cal_model_set_default_client (
+               case PROP_DATA_MODEL:
+                       cal_model_set_data_model (
                                E_CAL_MODEL (object),
                                g_value_get_object (value));
                        return;
 
+               case PROP_DEFAULT_SOURCE_UID:
+                       e_cal_model_set_default_source_uid (
+                               E_CAL_MODEL (object),
+                               g_value_get_string (value));
+                       return;
+
                case PROP_DEFAULT_REMINDER_INTERVAL:
                        e_cal_model_set_default_reminder_interval (
                                E_CAL_MODEL (object),
@@ -807,6 +671,12 @@ cal_model_set_property (GObject *object,
                                g_value_get_object (value));
                        return;
 
+               case PROP_SHELL:
+                       cal_model_set_shell (
+                               E_CAL_MODEL (object),
+                               g_value_get_object (value));
+                       return;
+
                case PROP_TIMEZONE:
                        e_cal_model_set_timezone (
                                E_CAL_MODEL (object),
@@ -915,6 +785,13 @@ cal_model_get_property (GObject *object,
                         GParamSpec *pspec)
 {
        switch (property_id) {
+               case PROP_CLIENT_CACHE:
+                       g_value_set_object (
+                               value,
+                               e_cal_model_get_client_cache (
+                               E_CAL_MODEL (object)));
+                       return;
+
                case PROP_COMPRESS_WEEKEND:
                        g_value_set_boolean (
                                value,
@@ -929,10 +806,17 @@ cal_model_get_property (GObject *object,
                                E_CAL_MODEL (object)));
                        return;
 
-               case PROP_DEFAULT_CLIENT:
-                       g_value_take_object (
+               case PROP_DATA_MODEL:
+                       g_value_set_object (
+                               value,
+                               e_cal_model_get_data_model (
+                               E_CAL_MODEL (object)));
+                       return;
+
+               case PROP_DEFAULT_SOURCE_UID:
+                       g_value_set_string (
                                value,
-                               e_cal_model_ref_default_client (
+                               e_cal_model_get_default_source_uid (
                                E_CAL_MODEL (object)));
                        return;
 
@@ -957,6 +841,13 @@ cal_model_get_property (GObject *object,
                                E_CAL_MODEL (object)));
                        return;
 
+               case PROP_SHELL:
+                       g_value_set_object (
+                               value,
+                               e_cal_model_get_shell (
+                               E_CAL_MODEL (object)));
+                       return;
+
                case PROP_TIMEZONE:
                        g_value_set_pointer (
                                value,
@@ -1082,21 +973,13 @@ cal_model_dispose (GObject *object)
 
        priv = E_CAL_MODEL_GET_PRIVATE (object);
 
-       if (priv->registry != NULL) {
-               g_object_unref (priv->registry);
-               priv->registry = NULL;
-       }
+       g_clear_object (&priv->data_model);
+       g_clear_object (&priv->registry);
+       g_clear_object (&priv->shell);
+       g_clear_object (&priv->client_cache);
 
-       if (priv->loading_clients) {
-               g_cancellable_cancel (priv->loading_clients);
-               g_object_unref (priv->loading_clients);
-               priv->loading_clients = NULL;
-       }
-
-       while (!g_queue_is_empty (&priv->clients))
-               client_data_unref (g_queue_pop_head (&priv->clients));
-
-       priv->default_client = NULL;
+       g_free (priv->default_source_uid);
+       priv->default_source_uid = NULL;
 
        /* Chain up to parent's dispose() method. */
        G_OBJECT_CLASS (e_cal_model_parent_class)->dispose (object);
@@ -1110,11 +993,6 @@ cal_model_finalize (GObject *object)
 
        priv = E_CAL_MODEL_GET_PRIVATE (object);
 
-       g_mutex_clear (&priv->clients_lock);
-
-       g_free (priv->search_sexp);
-       g_free (priv->full_sexp);
-
        g_free (priv->default_category);
 
        for (ii = 0; ii < priv->objects->len; ii++) {
@@ -1129,12 +1007,6 @@ cal_model_finalize (GObject *object)
        }
        g_ptr_array_free (priv->objects, TRUE);
 
-       g_mutex_clear (&priv->notify_lock);
-
-       g_hash_table_destroy (priv->notify_added);
-       g_hash_table_destroy (priv->notify_modified);
-       g_hash_table_destroy (priv->notify_removed);
-
        /* Chain up to parent's finalize() method. */
        G_OBJECT_CLASS (e_cal_model_parent_class)->finalize (object);
 }
@@ -1230,80 +1102,211 @@ cal_model_row_count (ETableModel *etm)
        return priv->objects->len;
 }
 
+static const gchar *
+cal_model_kind_to_extension_name (ECalModel *model)
+{
+       g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
+
+       switch (model->priv->kind) {
+               case ICAL_VEVENT_COMPONENT:
+                       return E_SOURCE_EXTENSION_CALENDAR;
+               case ICAL_VJOURNAL_COMPONENT:
+                       return E_SOURCE_EXTENSION_MEMO_LIST;
+               case ICAL_VTODO_COMPONENT:
+                       return E_SOURCE_EXTENSION_TASK_LIST;
+               default:
+                       g_warn_if_reached ();
+                       break;
+       }
+
+       return NULL;
+}
+
+typedef struct {
+       ECalModel *model;
+       ETableModel *table_model;
+       GHashTable *values;
+       gboolean success;
+} CreateComponentData;
+
 static void
-cal_model_append_row (ETableModel *etm,
-                      ETableModel *source,
-                      gint row)
+create_component_data_free (gpointer ptr)
 {
-       ECalModelClass *model_class;
+       CreateComponentData *ccd = ptr;
+
+       if (ccd) {
+               GHashTableIter iter;
+               gpointer key, value;
+
+               g_hash_table_iter_init (&iter, ccd->values);
+               while (g_hash_table_iter_next (&iter, &key, &value)) {
+                       gint column = GPOINTER_TO_INT (key);
+
+                       e_table_model_free_value (ccd->table_model, column, value);
+               }
+
+               if (ccd->success)
+                       g_signal_emit (ccd->model, signals[ROW_APPENDED], 0);
+
+               g_clear_object (&ccd->model);
+               g_clear_object (&ccd->table_model);
+               g_hash_table_destroy (ccd->values);
+               g_free (ccd);
+       }
+}
+
+static void
+cal_model_create_component_from_values_thread (EAlertSinkThreadJobData *job_data,
+                                              gpointer user_data,
+                                              GCancellable *cancellable,
+                                              GError **error)
+{
+       CreateComponentData *ccd = user_data;
+       EClientCache *client_cache;
+       ESourceRegistry *registry;
+       ESource *source;
+       EClient *client;
        ECalModelComponent *comp_data;
-       ECalModel *model = (ECalModel *) etm;
-       gchar *uid = NULL;
-       GError *error = NULL;
+       const gchar *source_uid;
+       GError *local_error = NULL;
 
-       g_return_if_fail (E_IS_CAL_MODEL (model));
-       g_return_if_fail (E_IS_TABLE_MODEL (source));
+       g_return_if_fail (ccd != NULL);
 
-       comp_data = g_object_new (E_TYPE_CAL_MODEL_COMPONENT, NULL);
+       source_uid = e_cal_model_get_default_source_uid (ccd->model);
+       g_return_if_fail (source_uid != NULL);
 
-       comp_data->client = e_cal_model_ref_default_client (model);
+       client_cache = e_cal_model_get_client_cache (ccd->model);
+       registry = e_cal_model_get_registry (ccd->model);
 
-       if (comp_data->client == NULL) {
-               g_object_unref (comp_data);
+       source = e_source_registry_ref_source (registry, source_uid);
+       if (!source) {
+               g_set_error (&local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+                       _("Source with UID '%s' not found"), source_uid);
+               e_alert_sink_thread_job_set_alert_arg_0 (job_data, source_uid);
                return;
        }
 
-       comp_data->icalcomp = e_cal_model_create_component_with_defaults (model, FALSE);
+       e_alert_sink_thread_job_set_alert_arg_0 (job_data, e_source_get_display_name (source));
 
-       /* set values for our fields */
-       set_categories (comp_data, e_table_model_value_at (source, E_CAL_MODEL_FIELD_CATEGORIES, row));
-       set_classification (comp_data, e_table_model_value_at (source, E_CAL_MODEL_FIELD_CLASSIFICATION, 
row));
-       set_description (comp_data, e_table_model_value_at (source, E_CAL_MODEL_FIELD_DESCRIPTION, row));
-       set_summary (comp_data, e_table_model_value_at (source, E_CAL_MODEL_FIELD_SUMMARY, row));
+       client = e_client_cache_get_client_sync (client_cache, source,
+               cal_model_kind_to_extension_name (ccd->model), cancellable, &local_error);
+       g_clear_object (&source);
 
-       if (e_table_model_value_at (source, E_CAL_MODEL_FIELD_DTSTART, row)) {
-               set_dtstart (model, comp_data, e_table_model_value_at (source, E_CAL_MODEL_FIELD_DTSTART, 
row));
-       } else if (model->priv->get_default_time) {
-               time_t tt = model->priv->get_default_time (model, model->priv->get_default_time_user_data);
+       if (!client) {
+               e_util_propagate_open_source_job_error (job_data,
+                       cal_model_kind_to_extension_name (ccd->model), local_error, error);
+               return;
+       }
 
-               if (tt > 0) {
-                       struct icaltimetype itt = icaltime_from_timet_with_zone (tt, FALSE, 
e_cal_model_get_timezone (model));
-                       icalproperty *prop = icalcomponent_get_first_property (comp_data->icalcomp, 
ICAL_DTSTART_PROPERTY);
+       comp_data = g_object_new (E_TYPE_CAL_MODEL_COMPONENT, NULL);
+       comp_data->client = g_object_ref (client);
+       comp_data->icalcomp = e_cal_model_create_component_with_defaults_sync (ccd->model, comp_data->client, 
FALSE, cancellable, error);
 
-                       if (prop) {
-                               icalproperty_set_dtstart (prop, itt);
-                       } else {
-                               prop = icalproperty_new_dtstart (itt);
-                               icalcomponent_add_property (comp_data->icalcomp, prop);
+       if (comp_data->icalcomp) {
+               ECalModelClass *model_class;
+               gchar *uid = NULL;
+               gpointer dtstart;
+
+               /* set values for our fields */
+               set_categories (comp_data, e_cal_model_util_get_value (ccd->values, 
E_CAL_MODEL_FIELD_CATEGORIES));
+               set_classification (comp_data, e_cal_model_util_get_value (ccd->values, 
E_CAL_MODEL_FIELD_CLASSIFICATION));
+               set_description (comp_data, e_cal_model_util_get_value (ccd->values, 
E_CAL_MODEL_FIELD_DESCRIPTION));
+               set_summary (comp_data, e_cal_model_util_get_value (ccd->values, E_CAL_MODEL_FIELD_SUMMARY));
+
+               dtstart = e_cal_model_util_get_value (ccd->values, E_CAL_MODEL_FIELD_DTSTART);
+               if (dtstart) {
+                       set_dtstart (ccd->model, comp_data, dtstart);
+               } else if (ccd->model->priv->get_default_time) {
+                       time_t tt = ccd->model->priv->get_default_time (ccd->model, 
ccd->model->priv->get_default_time_user_data);
+
+                       if (tt > 0) {
+                               struct icaltimetype itt = icaltime_from_timet_with_zone (tt, FALSE, 
e_cal_model_get_timezone (ccd->model));
+                               icalproperty *prop = icalcomponent_get_first_property (comp_data->icalcomp, 
ICAL_DTSTART_PROPERTY);
+
+                               if (prop) {
+                                       icalproperty_set_dtstart (prop, itt);
+                               } else {
+                                       prop = icalproperty_new_dtstart (itt);
+                                       icalcomponent_add_property (comp_data->icalcomp, prop);
+                               }
                        }
                }
-       }
 
-       /* call the class' method for filling the component */
-       model_class = (ECalModelClass *) G_OBJECT_GET_CLASS (model);
-       if (model_class->fill_component_from_model != NULL) {
-               model_class->fill_component_from_model (model, comp_data, source, row);
+               /* call the class' method for filling the component */
+               model_class = E_CAL_MODEL_GET_CLASS (ccd->model);
+               if (model_class->fill_component_from_values != NULL) {
+                       model_class->fill_component_from_values (ccd->model, comp_data, ccd->values);
+               }
+
+               ccd->success = e_cal_client_create_object_sync (comp_data->client, comp_data->icalcomp, &uid, 
cancellable, error);
+
+               g_free (uid);
        }
 
-       e_cal_client_create_object_sync (
-               comp_data->client, comp_data->icalcomp, &uid, NULL, &error);
+       g_object_unref (comp_data);
+       g_object_unref (client);
+}
+
+static void
+cal_model_append_row (ETableModel *etm,
+                      ETableModel *source,
+                      gint row)
+{
+       ECalModelClass *model_class;
+       ECalModel *model = (ECalModel *) etm;
+       GHashTable *values;
+       GCancellable *cancellable;
+       CreateComponentData *ccd;
+       const gchar *description;
+       const gchar *alert_ident;
+
+       g_return_if_fail (E_IS_CAL_MODEL (model));
+       g_return_if_fail (E_IS_TABLE_MODEL (source));
 
-       if (error != NULL) {
-               g_warning (
-                       G_STRLOC ": Could not create the object! %s",
-                       error->message);
+       switch (e_cal_model_get_component_kind (model)) {
+               case ICAL_VEVENT_COMPONENT:
+                       description = _("Creating an event");
+                       alert_ident = "calendar:failed-create-event";
+                       break;
+               case ICAL_VJOURNAL_COMPONENT:
+                       description = _("Creating a memo");
+                       alert_ident = "calendar:failed-create-memo";
+                       break;
+               case ICAL_VTODO_COMPONENT:
+                       description = _("Creating a task");
+                       alert_ident = "calendar:failed-create-task";
+                       break;
+               default:
+                       g_warn_if_reached ();
+                       return;
+       }
 
-               /* FIXME: show error dialog */
-               g_error_free (error);
-       } else {
-               if (uid)
-                       icalcomponent_set_uid (comp_data->icalcomp, uid);
+       values = g_hash_table_new (g_direct_hash, g_direct_equal);
 
-               g_signal_emit (model, signals[ROW_APPENDED], 0);
+       /* store values for our fields */
+       e_cal_model_util_set_value (values, source, E_CAL_MODEL_FIELD_CATEGORIES, row);
+       e_cal_model_util_set_value (values, source, E_CAL_MODEL_FIELD_CLASSIFICATION, row);
+       e_cal_model_util_set_value (values, source, E_CAL_MODEL_FIELD_DESCRIPTION, row);
+       e_cal_model_util_set_value (values, source, E_CAL_MODEL_FIELD_SUMMARY, row);
+       e_cal_model_util_set_value (values, source, E_CAL_MODEL_FIELD_DTSTART, row);
+
+       /* call the class' method to store other values */
+       model_class = E_CAL_MODEL_GET_CLASS (model);
+       if (model_class->store_values_from_model != NULL) {
+               model_class->store_values_from_model (model, source, row, values);
        }
 
-       g_free (uid);
-       g_object_unref (comp_data);
+       ccd = g_new0 (CreateComponentData, 1);
+       ccd->model = g_object_ref (model);
+       ccd->table_model = g_object_ref (source);
+       ccd->values = values;
+       ccd->success = FALSE;
+
+       cancellable = e_cal_data_model_submit_thread_job (model->priv->data_model, description,
+               alert_ident, NULL, cal_model_create_component_from_values_thread,
+               ccd, create_component_data_free);
+
+       g_clear_object (&cancellable);
 }
 
 static gpointer
@@ -1418,7 +1421,7 @@ cal_model_set_value_at (ETableModel *etm,
        ECalModelPrivate *priv;
        ECalModelComponent *comp_data;
        ECalModel *model = (ECalModel *) etm;
-       GError *error = NULL;
+       ECalObjModType mod = E_CAL_OBJ_MOD_ALL;
 
        g_return_if_fail (E_IS_CAL_MODEL (model));
 
@@ -1448,19 +1451,10 @@ cal_model_set_value_at (ETableModel *etm,
                break;
        }
 
-       /* FIXME ask about mod type */
-       e_cal_client_modify_object_sync (
-               comp_data->client, comp_data->icalcomp,
-               CALOBJ_MOD_ALL, NULL, &error);
-
-       if (error != NULL) {
-               g_warning (
-                       G_STRLOC ": Could not modify the object! %s",
-                       error->message);
+       if (!recur_icalcomp_dialog (comp_data->client, comp_data->icalcomp, &mod, NULL, FALSE))
+               return;
 
-               /* FIXME Show error dialog */
-               g_error_free (error);
-       }
+       e_cal_ops_modify_component (model, comp_data->client, comp_data->icalcomp, mod, 
E_CAL_OPS_SEND_FLAG_DONT_SEND);
 }
 
 static gboolean
@@ -1671,6 +1665,197 @@ cal_model_value_to_string (ETableModel *etm,
        return g_strdup ("");
 }
 
+static gint
+e_cal_model_get_component_index (ECalModel *model,
+                                ECalClient *client,
+                                const ECalComponentId *id)
+{
+       gint ii;
+
+       for (ii = 0; ii < model->priv->objects->len; ii++) {
+               ECalModelComponent *comp_data = g_ptr_array_index (model->priv->objects, ii);
+
+               if (comp_data) {
+                       const gchar *uid;
+                       gchar *rid = NULL;
+                       struct icaltimetype icalrid;
+                       gboolean has_rid = (id->rid && *id->rid);
+
+                       uid = icalcomponent_get_uid (comp_data->icalcomp);
+                       icalrid = icalcomponent_get_recurrenceid (comp_data->icalcomp);
+                       if (!icaltime_is_null_time (icalrid))
+                               rid = icaltime_as_ical_string_r (icalrid);
+
+                       if (uid && *uid) {
+                               if ((!client || comp_data->client == client) && strcmp (id->uid, uid) == 0) {
+                                       if (has_rid) {
+                                               if (!(rid && *rid && strcmp (rid, id->rid) == 0)) {
+                                                       g_free (rid);
+                                                       continue;
+                                               }
+                                       }
+                                       g_free (rid);
+                                       return ii;
+                               }
+                       }
+
+                       g_free (rid);
+               }
+       }
+
+       return -1;
+}
+
+/* We do this check since the calendar items are downloaded from the server
+ * in the open_method, since the default timezone might not be set there. */
+static void
+ensure_dates_are_in_default_zone (ECalModel *model,
+                                  icalcomponent *icalcomp)
+{
+       icaltimetype dt;
+       icaltimezone *zone;
+
+       zone = e_cal_model_get_timezone (model);
+       if (!zone)
+               return;
+
+       dt = icalcomponent_get_dtstart (icalcomp);
+       if (dt.is_utc) {
+               dt = icaltime_convert_to_zone (dt, zone);
+               icalcomponent_set_dtstart (icalcomp, dt);
+       }
+
+       dt = icalcomponent_get_dtend (icalcomp);
+       if (dt.is_utc) {
+               dt = icaltime_convert_to_zone (dt, zone);
+               icalcomponent_set_dtend (icalcomp, dt);
+       }
+}
+
+static void
+cal_model_data_subscriber_component_added_or_modified (ECalDataModelSubscriber *subscriber,
+                                                      ECalClient *client,
+                                                      ECalComponent *comp,
+                                                      gboolean is_added)
+{
+       ECalModel *model;
+       ECalModelComponent *comp_data;
+       ETableModel *table_model;
+       ECalComponentId *id;
+       icalcomponent *icalcomp;
+       gint index;
+
+       model = E_CAL_MODEL (subscriber);
+
+       id = e_cal_component_get_id (comp);
+
+       index = e_cal_model_get_component_index (model, client, id);
+
+       e_cal_component_free_id (id);
+
+       if (index < 0 && !is_added)
+               return;
+
+       table_model = E_TABLE_MODEL (model);
+       icalcomp = icalcomponent_new_clone (e_cal_component_get_icalcomponent (comp));
+       ensure_dates_are_in_default_zone (model, icalcomp);
+
+       if (index < 0) {
+               e_table_model_pre_change (table_model);
+
+               comp_data = g_object_new (E_TYPE_CAL_MODEL_COMPONENT, NULL);
+               comp_data->is_new_component = FALSE;
+               comp_data->client = g_object_ref (client);
+               comp_data->icalcomp = icalcomp;
+               e_cal_model_set_instance_times (comp_data, model->priv->zone);
+               g_ptr_array_add (model->priv->objects, comp_data);
+
+               e_table_model_row_inserted (table_model, model->priv->objects->len - 1);
+       } else {
+               e_table_model_pre_change (table_model);
+
+               comp_data = g_ptr_array_index (model->priv->objects, index);
+               e_cal_model_component_set_icalcomponent (comp_data, model, icalcomp);
+
+               e_table_model_row_changed (table_model, index);
+       }
+}
+
+static void
+e_cal_model_data_subscriber_component_added (ECalDataModelSubscriber *subscriber,
+                                            ECalClient *client,
+                                            ECalComponent *comp)
+{
+       cal_model_data_subscriber_component_added_or_modified (subscriber, client, comp, TRUE);
+}
+
+static void
+e_cal_model_data_subscriber_component_modified (ECalDataModelSubscriber *subscriber,
+                                               ECalClient *client,
+                                               ECalComponent *comp)
+{
+       cal_model_data_subscriber_component_added_or_modified (subscriber, client, comp, FALSE);
+}
+
+static void
+e_cal_model_data_subscriber_component_removed (ECalDataModelSubscriber *subscriber,
+                                              ECalClient *client,
+                                              const gchar *uid,
+                                              const gchar *rid)
+{
+       ECalModel *model;
+       ECalModelComponent *comp_data;
+       ETableModel *table_model;
+       ECalComponentId id;
+       GSList *link;
+       gint index;
+
+       model = E_CAL_MODEL (subscriber);
+
+       id.uid = (gchar *) uid;
+       id.rid = (gchar *) rid;
+
+       index = e_cal_model_get_component_index (model, client, &id);
+
+       if (index < 0)
+               return;
+
+       table_model = E_TABLE_MODEL (model);
+       e_table_model_pre_change (table_model);
+
+       comp_data = g_ptr_array_remove_index (model->priv->objects, index);
+       if (!comp_data) {
+               e_table_model_no_change (table_model);
+               return;
+       }
+
+       link = g_slist_append (NULL, comp_data);
+       g_signal_emit (model, signals[COMPS_DELETED], 0, link);
+
+       g_slist_free (link);
+       g_object_unref (comp_data);
+
+       e_table_model_row_deleted (table_model, index);
+}
+
+static void
+e_cal_model_data_subscriber_freeze (ECalDataModelSubscriber *subscriber)
+{
+       /* No freeze/thaw, the ETableModel doesn't notify about changes when frozen */
+
+       /* ETableModel *table_model = E_TABLE_MODEL (subscriber);
+       e_table_model_freeze (table_model); */
+}
+
+static void
+e_cal_model_data_subscriber_thaw (ECalDataModelSubscriber *subscriber)
+{
+       /* No freeze/thaw, the ETableModel doesn't notify about changes when frozen */
+
+       /* ETableModel *table_model = E_TABLE_MODEL (subscriber);
+       e_table_model_thaw (table_model); */
+}
+
 static void
 e_cal_model_class_init (ECalModelClass *class)
 {
@@ -1686,7 +1871,27 @@ e_cal_model_class_init (ECalModelClass *class)
        object_class->finalize = cal_model_finalize;
 
        class->get_color_for_component = cal_model_get_color_for_component;
-       class->fill_component_from_model = NULL;
+
+       g_object_class_install_property (
+               object_class,
+               PROP_DATA_MODEL,
+               g_param_spec_object (
+                       "data-model",
+                       "Calendar Data Model",
+                       NULL,
+                       E_TYPE_CAL_DATA_MODEL,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT_ONLY));
+
+       g_object_class_install_property (
+               object_class,
+               PROP_CLIENT_CACHE,
+               g_param_spec_object (
+                       "client-cache",
+                       "Client Cache",
+                       NULL,
+                       E_TYPE_CLIENT_CACHE,
+                       G_PARAM_READABLE));
 
        g_object_class_install_property (
                object_class,
@@ -1710,16 +1915,6 @@ e_cal_model_class_init (ECalModelClass *class)
 
        g_object_class_install_property (
                object_class,
-               PROP_DEFAULT_CLIENT,
-               g_param_spec_object (
-                       "default-client",
-                       "Default ECalClient",
-                       NULL,
-                       E_TYPE_CAL_CLIENT,
-                       G_PARAM_READWRITE));
-
-       g_object_class_install_property (
-               object_class,
                PROP_DEFAULT_REMINDER_INTERVAL,
                g_param_spec_int (
                        "default-reminder-interval",
@@ -1743,6 +1938,16 @@ e_cal_model_class_init (ECalModelClass *class)
 
        g_object_class_install_property (
                object_class,
+               PROP_DEFAULT_SOURCE_UID,
+               g_param_spec_string (
+                       "default-source-uid",
+                       "Default source UID of an ECalClient",
+                       NULL,
+                       NULL,
+                       G_PARAM_READWRITE));
+
+       g_object_class_install_property (
+               object_class,
                PROP_REGISTRY,
                g_param_spec_object (
                        "registry",
@@ -1754,6 +1959,17 @@ e_cal_model_class_init (ECalModelClass *class)
 
        g_object_class_install_property (
                object_class,
+               PROP_SHELL,
+               g_param_spec_object (
+                       "shell",
+                       "Shell",
+                       "EShell",
+                       E_TYPE_SHELL,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT_ONLY));
+
+       g_object_class_install_property (
+               object_class,
                PROP_TIMEZONE,
                g_param_spec_pointer (
                        "timezone",
@@ -1955,40 +2171,6 @@ e_cal_model_class_init (ECalModelClass *class)
                G_TYPE_NONE, 1,
                G_TYPE_POINTER);
 
-       signals[CAL_VIEW_PROGRESS] = g_signal_new (
-               "cal_view_progress",
-               G_TYPE_FROM_CLASS (class),
-               G_SIGNAL_RUN_LAST,
-               G_STRUCT_OFFSET (ECalModelClass, cal_view_progress),
-               NULL, NULL,
-               e_marshal_VOID__STRING_INT_INT,
-               G_TYPE_NONE, 3,
-               G_TYPE_STRING,
-               G_TYPE_INT,
-               G_TYPE_INT);
-
-       signals[CAL_VIEW_COMPLETE] = g_signal_new (
-               "cal_view_complete",
-               G_TYPE_FROM_CLASS (class),
-               G_SIGNAL_RUN_LAST,
-               G_STRUCT_OFFSET (ECalModelClass, cal_view_complete),
-               NULL, NULL,
-               e_marshal_VOID__BOXED_INT,
-               G_TYPE_NONE, 2,
-               G_TYPE_ERROR,
-               G_TYPE_INT);
-
-       signals[STATUS_MESSAGE] = g_signal_new (
-               "status-message",
-               G_TYPE_FROM_CLASS (class),
-               G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-               G_STRUCT_OFFSET (ECalModelClass, status_message),
-               NULL, NULL,
-               e_marshal_VOID__STRING_DOUBLE,
-               G_TYPE_NONE, 2,
-               G_TYPE_STRING,
-               G_TYPE_DOUBLE);
-
        signals[TIMEZONE_CHANGED] = g_signal_new (
                "timezone-changed",
                G_TYPE_FROM_CLASS (class),
@@ -1999,6 +2181,15 @@ e_cal_model_class_init (ECalModelClass *class)
                G_TYPE_NONE, 2,
                G_TYPE_POINTER,
                G_TYPE_POINTER);
+
+       signals[OBJECT_CREATED] = g_signal_new (
+               "object-created",
+               G_TYPE_FROM_CLASS (class),
+               G_SIGNAL_RUN_LAST,
+               G_STRUCT_OFFSET (ECalModelClass, object_created),
+               NULL, NULL,
+               g_cclosure_marshal_VOID__OBJECT,
+               G_TYPE_NONE, 1, E_TYPE_CAL_CLIENT);
 }
 
 static void
@@ -2020,33 +2211,28 @@ e_cal_model_table_model_init (ETableModelInterface *iface)
 }
 
 static void
+e_cal_model_cal_data_model_subscriber_init (ECalDataModelSubscriberInterface *iface)
+{
+       iface->component_added = e_cal_model_data_subscriber_component_added;
+       iface->component_modified = e_cal_model_data_subscriber_component_modified;
+       iface->component_removed = e_cal_model_data_subscriber_component_removed;
+       iface->freeze = e_cal_model_data_subscriber_freeze;
+       iface->thaw = e_cal_model_data_subscriber_thaw;
+}
+
+static void
 e_cal_model_init (ECalModel *model)
 {
        model->priv = E_CAL_MODEL_GET_PRIVATE (model);
 
-       g_mutex_init (&model->priv->clients_lock);
-
        /* match none by default */
-       model->priv->start = -1;
-       model->priv->end = -1;
-       model->priv->search_sexp = NULL;
-       model->priv->full_sexp = g_strdup ("#f");
+       model->priv->start = (time_t) -1;
+       model->priv->end = (time_t) -1;
 
        model->priv->objects = g_ptr_array_new ();
        model->priv->kind = ICAL_NO_COMPONENT;
-       model->priv->flags = 0;
 
        model->priv->use_24_hour_format = TRUE;
-
-       model->priv->in_added = FALSE;
-       model->priv->in_modified = FALSE;
-       model->priv->in_removed = FALSE;
-       model->priv->notify_added = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, 
NULL);
-       model->priv->notify_modified = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, 
NULL);
-       model->priv->notify_removed = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, 
NULL);
-       g_mutex_init (&model->priv->notify_lock);
-
-       model->priv->loading_clients = g_cancellable_new ();
 }
 
 /* updates time in a component, and keeps the timezone used in it, if exists */
@@ -2123,7 +2309,7 @@ gboolean
 e_cal_model_test_row_editable (ECalModel *model,
                                gint row)
 {
-       gboolean readonly;
+       gboolean readonly = FALSE;
        ECalClient *client = NULL;
 
        if (row != -1) {
@@ -2134,13 +2320,44 @@ e_cal_model_test_row_editable (ECalModel *model,
                if (comp_data != NULL && comp_data->client != NULL)
                        client = g_object_ref (comp_data->client);
 
+               readonly = (client == NULL);
        } else {
-               client = e_cal_model_ref_default_client (model);
-       }
+               const gchar *source_uid;
+
+               source_uid = e_cal_model_get_default_source_uid (model);
+
+               /* if the source cannot be opened, then expect the client being writable;
+                  there will be shown an error if not, when saving changes anyway */
+               readonly = source_uid == NULL;
+
+               if (source_uid != NULL) {
+                       ESourceRegistry *registry = e_cal_model_get_registry (model);
+                       EClientCache *client_cache = e_cal_model_get_client_cache (model);
+                       ESource *source;
+
+                       source = e_source_registry_ref_source (registry, source_uid);
+                       if (source) {
+                               EClient *e_client;
+
+                               e_client = e_client_cache_ref_cached_client (client_cache, source,
+                                       cal_model_kind_to_extension_name (model));
+                               if (e_client) {
+                                       client = E_CAL_CLIENT (e_client);
+                               } else {
+                                       const gchar *parent_uid = e_source_get_parent (source);
+
+                                       /* There are couple known to be always read-only */
+                                       readonly = g_strcmp0 (parent_uid, "webcal-stub") == 0 ||
+                                                  g_strcmp0 (parent_uid, "weather-stub") == 0 ||
+                                                  g_strcmp0 (parent_uid, "contacts-stub") == 0;
+                               }
+                       }
 
-       readonly = (client == NULL);
+                       g_clear_object (&source);
+               }
+       }
 
-       if (!readonly)
+       if (!readonly && client)
                readonly = e_client_is_readonly (E_CLIENT (client));
 
        g_clear_object (&client);
@@ -2148,6 +2365,38 @@ e_cal_model_test_row_editable (ECalModel *model,
        return !readonly;
 }
 
+ESourceRegistry *
+e_cal_model_get_registry (ECalModel *model)
+{
+       g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
+
+       return model->priv->registry;
+}
+
+EShell *
+e_cal_model_get_shell (ECalModel *model)
+{
+       g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
+
+       return model->priv->shell;
+}
+
+ECalDataModel *
+e_cal_model_get_data_model (ECalModel *model)
+{
+       g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
+
+       return model->priv->data_model;
+}
+
+EClientCache *
+e_cal_model_get_client_cache (ECalModel *model)
+{
+       g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
+
+       return model->priv->client_cache;
+}
+
 gboolean
 e_cal_model_get_confirm_delete (ECalModel *model)
 {
@@ -2187,31 +2436,6 @@ e_cal_model_set_component_kind (ECalModel *model,
        model->priv->kind = kind;
 }
 
-ECalModelFlags
-e_cal_model_get_flags (ECalModel *model)
-{
-       g_return_val_if_fail (E_IS_CAL_MODEL (model), 0);
-
-       return model->priv->flags;
-}
-
-void
-e_cal_model_set_flags (ECalModel *model,
-                       ECalModelFlags flags)
-{
-       g_return_if_fail (E_IS_CAL_MODEL (model));
-
-       model->priv->flags = flags;
-}
-
-ESourceRegistry *
-e_cal_model_get_registry (ECalModel *model)
-{
-       g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
-
-       return model->priv->registry;
-}
-
 icaltimezone *
 e_cal_model_get_timezone (ECalModel *model)
 {
@@ -2237,7 +2461,6 @@ e_cal_model_set_timezone (ECalModel *model,
        /* the timezone affects the times shown for date fields,
         * so we need to redisplay everything */
        e_table_model_changed (E_TABLE_MODEL (model));
-       redo_queries (model);
 
        g_object_notify (G_OBJECT (model), "timezone");
        g_signal_emit (
@@ -2590,99 +2813,31 @@ e_cal_model_set_work_day_start_minute (ECalModel *model,
        g_object_notify (G_OBJECT (model), "work-day-start-minute");
 }
 
-ECalClient *
-e_cal_model_ref_default_client (ECalModel *model)
+const gchar *
+e_cal_model_get_default_source_uid (ECalModel *model)
 {
-       ClientData *client_data;
-       ECalClient *default_client = NULL;
-
        g_return_val_if_fail (model != NULL, NULL);
        g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
 
-       if (model->priv->default_client != NULL)
-               return g_object_ref (model->priv->default_client);
-
-       client_data = cal_model_clients_peek (model);
-       if (client_data != NULL) {
-               default_client = g_object_ref (client_data->client);
-               client_data_unref (client_data);
-       }
+       if (model->priv->default_source_uid && !model->priv->default_source_uid)
+               return NULL;
 
-       return default_client;
+       return model->priv->default_source_uid;
 }
 
 void
-e_cal_model_set_default_client (ECalModel *model,
-                                ECalClient *client)
+e_cal_model_set_default_source_uid (ECalModel *model,
+                                   const gchar *source_uid)
 {
-       ECalModelPrivate *priv;
-
        g_return_if_fail (E_IS_CAL_MODEL (model));
 
-       if (client != NULL)
-               g_return_if_fail (E_IS_CAL_CLIENT (client));
-
-       priv = model->priv;
-
-       if (priv->default_client == client)
+       if (g_strcmp0 (model->priv->default_source_uid, source_uid) == 0)
                return;
 
-       if (priv->default_client == NULL) {
-               ClientData *client_data;
-
-               client_data = cal_model_clients_lookup (
-                       model, priv->default_client);
-               if (client_data != NULL) {
-                       if (!client_data->do_query)
-                               remove_client (model, client_data);
-                       client_data_unref (client_data);
-               }
-       }
-
-       if (client != NULL) {
-               /* Make sure its in the model */
-               add_new_client (model, client, FALSE);
-
-               /* Store the default client */
-               priv->default_client = client;
-       } else {
-               priv->default_client = NULL;
-       }
-
-       g_object_notify (G_OBJECT (model), "default-client");
-}
-
-GList *
-e_cal_model_list_clients (ECalModel *model)
-{
-       GQueue results = G_QUEUE_INIT;
-       GList *list, *link;
-       ECalClient *default_client;
-
-       g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
-
-       default_client = model->priv->default_client;
-
-       list = cal_model_clients_list (model);
+       g_free (model->priv->default_source_uid);
+       model->priv->default_source_uid = g_strdup (source_uid);
 
-       for (link = list; link != NULL; link = g_list_next (link)) {
-               ClientData *client_data = link->data;
-               ECalClient *client;
-
-               client = client_data->client;
-
-               /* Exclude the default client if we're not querying it. */
-               if (client == default_client) {
-                       if (!client_data->do_query)
-                               continue;
-               }
-
-               g_queue_push_tail (&results, g_object_ref (client));
-       }
-
-       g_list_free_full (list, (GDestroyNotify) client_data_unref);
-
-       return g_queue_peek_head_link (&results);
+       g_object_notify (G_OBJECT (model), "default-source-uid");
 }
 
 static ECalModelComponent *
@@ -2726,1022 +2881,32 @@ search_by_id_and_client (ECalModelPrivate *priv,
        return NULL;
 }
 
-static void
-remove_all_for_id_and_client (ECalModel *model,
-                              ECalClient *client,
-                              const ECalComponentId *id)
-{
-       ECalModelComponent *comp_data;
-
-       while ((comp_data = search_by_id_and_client (model->priv, client, id))) {
-               gint pos;
-               GSList *list = NULL;
-
-               pos = get_position_in_array (model->priv->objects, comp_data);
-
-               if (!g_ptr_array_remove (model->priv->objects, comp_data))
-                       continue;
-
-               list = g_slist_append (list, comp_data);
-               g_signal_emit (model, signals[COMPS_DELETED], 0, list);
-
-               g_slist_free (list);
-               g_object_unref (comp_data);
-
-               e_table_model_pre_change (E_TABLE_MODEL (model));
-               e_table_model_row_deleted (E_TABLE_MODEL (model), pos);
-       }
-}
-
-typedef struct {
-       ECalClient *client;
-       ECalClientView *view;
-       ECalModel *model;
-       icalcomponent *icalcomp;
-} RecurrenceExpansionData;
-
-static void
-free_rdata (gpointer data)
-{
-       RecurrenceExpansionData *rdata = data;
-
-       if (!rdata)
-               return;
-
-       g_object_unref (rdata->client);
-       g_object_unref (rdata->view);
-       g_object_unref (rdata->model);
-       g_free (rdata);
-}
-
-static gboolean
-add_instance_cb (ECalComponent *comp,
-                 time_t instance_start,
-                 time_t instance_end,
-                 gpointer user_data)
-{
-       ECalModelComponent *comp_data;
-       ECalModelPrivate *priv;
-       RecurrenceExpansionData *rdata = user_data;
-       icaltimetype time;
-       ECalComponentDateTime datetime, to_set;
-       icaltimezone *zone = NULL;
-       ECalComponentId *id;
-
-       g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), TRUE);
-
-       priv = rdata->model->priv;
-
-       id = e_cal_component_get_id (comp);
-       remove_all_for_id_and_client (rdata->model, rdata->client, id);
-       e_cal_component_free_id (id);
-
-       e_table_model_pre_change (E_TABLE_MODEL (rdata->model));
-
-       /* set the right instance start date to component */
-       e_cal_component_get_dtstart (comp, &datetime);
-       if (datetime.tzid)
-               e_cal_client_get_timezone_sync (rdata->client, datetime.tzid, &zone, NULL, NULL);
-       time = icaltime_from_timet_with_zone (instance_start, FALSE, zone ? zone : priv->zone);
-       to_set.value = &time;
-       to_set.tzid = datetime.tzid;
-       e_cal_component_set_dtstart (comp, &to_set);
-       e_cal_component_free_datetime (&datetime);
-
-       /* set the right instance end date to component*/
-       e_cal_component_get_dtend (comp, &datetime);
-       zone = NULL;
-       if (datetime.tzid)
-               e_cal_client_get_timezone_sync (rdata->client, datetime.tzid, &zone, NULL, NULL);
-       time = icaltime_from_timet_with_zone (instance_end, FALSE, zone ? zone : priv->zone);
-       to_set.value = &time;
-       to_set.tzid = datetime.tzid;
-       e_cal_component_set_dtend (comp, &to_set);
-       e_cal_component_free_datetime (&datetime);
-
-       comp_data = g_object_new (E_TYPE_CAL_MODEL_COMPONENT, NULL);
-       comp_data->client = g_object_ref (rdata->client);
-       comp_data->icalcomp = icalcomponent_new_clone (e_cal_component_get_icalcomponent (comp));
-       comp_data->instance_start = instance_start;
-       comp_data->instance_end = instance_end;
-
-       g_ptr_array_add (priv->objects, comp_data);
-       e_table_model_row_inserted (E_TABLE_MODEL (rdata->model), priv->objects->len - 1);
-
-       return TRUE;
-}
-
-/* We do this check since the calendar items are downloaded from the server
- * in the open_method, since the default timezone might not be set there. */
-static void
-ensure_dates_are_in_default_zone (ECalModel *model,
-                                  icalcomponent *icalcomp)
-{
-       icaltimetype dt;
-       icaltimezone *zone;
-
-       zone = e_cal_model_get_timezone (model);
-       if (!zone)
-               return;
-
-       dt = icalcomponent_get_dtstart (icalcomp);
-       if (dt.is_utc) {
-               dt = icaltime_convert_to_zone (dt, zone);
-               icalcomponent_set_dtstart (icalcomp, dt);
-       }
-
-       dt = icalcomponent_get_dtend (icalcomp);
-       if (dt.is_utc) {
-               dt = icaltime_convert_to_zone (dt, zone);
-               icalcomponent_set_dtend (icalcomp, dt);
-       }
-}
-
-static gint
-place_master_object_first_cb (gconstpointer p1,
-                              gconstpointer p2)
-{
-       icalcomponent *c1 = (icalcomponent *) p1, *c2 = (icalcomponent *) p2;
-       const gchar *uid1, *uid2;
-       gint res;
-
-       g_return_val_if_fail (c1 != NULL, 0);
-       g_return_val_if_fail (c2 != NULL, 0);
-
-       uid1 = icalcomponent_get_uid (c1);
-       uid2 = icalcomponent_get_uid (c2);
-
-       res = g_strcmp0 (uid1, uid2);
-       if (res == 0) {
-               struct icaltimetype rid1, rid2;
-
-               rid1 = icalcomponent_get_recurrenceid (c1);
-               rid2 = icalcomponent_get_recurrenceid (c2);
-
-               if (icaltime_is_null_time (rid1)) {
-                       if (!icaltime_is_null_time (rid2))
-                               res = -1;
-               } else if (icaltime_is_null_time (rid2)) {
-                       res = 1;
-               } else {
-                       res = icaltime_compare (rid1, rid2);
-               }
-       }
-
-       return res;
-}
-
-static void
-process_event (ECalClientView *view,
-               const GSList *objects,
-               ECalModel *model,
-               void (*process_fn) (ECalClientView *view,
-                                   const GSList *objects,
-                                   ECalModel *model),
-               gboolean *in,
-               GHashTable *save_hash,
-               gpointer (*copy_fn) (gpointer data),
-               void (*free_fn) (gpointer data))
-{
-       gboolean skip = FALSE;
-       const GSList *l;
-
-       g_return_if_fail (save_hash != NULL);
-
-       g_mutex_lock (&model->priv->notify_lock);
-       if (*in) {
-               GSList *save_list = g_hash_table_lookup (save_hash, view);
-
-               skip = TRUE;
-               for (l = objects; l; l = l->next) {
-                       if (l->data)
-                               save_list = g_slist_append (save_list, copy_fn (l->data));
-               }
-
-               g_hash_table_insert (save_hash, g_object_ref (view), save_list);
-       } else {
-               *in = TRUE;
-       }
-
-       g_mutex_unlock (&model->priv->notify_lock);
-
-       if (skip)
-               return;
-
-       /* do it */
-       process_fn (view, objects, model);
-
-       g_mutex_lock (&model->priv->notify_lock);
-       while (g_hash_table_size (save_hash)) {
-               gpointer key = NULL, value = NULL;
-               GHashTableIter iter;
-               GSList *save_list;
-
-               g_hash_table_iter_init (&iter, save_hash);
-               if (!g_hash_table_iter_next (&iter, &key, &value)) {
-                       g_debug ("%s: Failed to get first item of the save_hash", G_STRFUNC);
-                       break;
-               }
-
-               save_list = value;
-               view = g_object_ref (key);
-
-               g_hash_table_remove (save_hash, view);
-
-               g_mutex_unlock (&model->priv->notify_lock);
-
-               /* do it */
-               process_fn (view, save_list, model);
-
-               for (l = save_list; l; l = l->next) {
-                       if (l->data) {
-                               free_fn (l->data);
-                       }
-               }
-               g_slist_free (save_list);
-               g_object_unref (view);
-
-               g_mutex_lock (&model->priv->notify_lock);
-       }
-
-       *in = FALSE;
-       g_mutex_unlock (&model->priv->notify_lock);
-}
-
-static void
-process_added (ECalClientView *view,
-               const GSList *objects,
-               ECalModel *model)
-{
-       ECalModelPrivate *priv;
-       const GSList *l;
-       GSList *copy;
-
-       priv = model->priv;
-
-       /* order matters, process master object first, then detached instances */
-       copy = g_slist_sort (g_slist_copy ((GSList *) objects), place_master_object_first_cb);
-
-       for (l = copy; l; l = l->next) {
-               ECalModelComponent *comp_data;
-               ECalComponentId *id;
-               ECalComponent *comp = e_cal_component_new ();
-               ECalClient *client = e_cal_client_view_get_client (view);
-
-               /* This will fail for alarm or VCalendar component */
-               if (!e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (l->data))) {
-                       g_object_unref (comp);
-                       continue;
-               }
-
-               id = e_cal_component_get_id (comp);
-
-               /* remove the components if they are already present and re-add them */
-               remove_all_for_id_and_client (model, client, id);
-
-               e_cal_component_free_id (id);
-               g_object_unref (comp);
-               ensure_dates_are_in_default_zone (model, l->data);
-
-               if (e_cal_util_component_has_recurrences (l->data) && (priv->flags & 
E_CAL_MODEL_FLAGS_EXPAND_RECURRENCES)) {
-                       ClientData *client_data;
-
-                       client_data = cal_model_clients_lookup (model, client);
-
-                       if (client_data != NULL) {
-                               RecurrenceExpansionData *rdata = g_new0 (RecurrenceExpansionData, 1);
-                               rdata->client = g_object_ref (client);
-                               rdata->view = g_object_ref (view);
-                               rdata->model = g_object_ref (model);
-
-                               e_cal_client_generate_instances_for_object (rdata->client, l->data, 
priv->start, priv->end, client_data->cancellable,
-                                                                           (ECalRecurInstanceFn) 
add_instance_cb, rdata, free_rdata);
-
-                               client_data_unref (client_data);
-                       }
-               } else {
-                       e_table_model_pre_change (E_TABLE_MODEL (model));
-
-                       comp_data = g_object_new (E_TYPE_CAL_MODEL_COMPONENT, NULL);
-                       comp_data->client = g_object_ref (client);
-                       comp_data->icalcomp = icalcomponent_new_clone (l->data);
-                       e_cal_model_set_instance_times (comp_data, priv->zone);
-
-                       g_ptr_array_add (priv->objects, comp_data);
-                       e_table_model_row_inserted (E_TABLE_MODEL (model), priv->objects->len - 1);
-               }
-       }
-
-       g_slist_free (copy);
-}
-
-static void
-process_modified (ECalClientView *view,
-                  const GSList *objects,
-                  ECalModel *model)
-{
-       ECalModelPrivate *priv;
-       const GSList *l;
-       GSList *list = NULL;
-
-       priv = model->priv;
-
-       /*  re-add only the recurrence objects */
-       for (l = objects; l != NULL; l = g_slist_next (l)) {
-               if (!e_cal_util_component_is_instance (l->data) && e_cal_util_component_has_recurrences 
(l->data) && (priv->flags & E_CAL_MODEL_FLAGS_EXPAND_RECURRENCES))
-                       list = g_slist_prepend (list, l->data);
-               else {
-                       gint pos;
-                       ECalModelComponent *comp_data;
-                       ECalComponentId *id;
-                       ECalComponent *comp = e_cal_component_new ();
-                       ECalClient *client = e_cal_client_view_get_client (view);
-
-                       if (!e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (l->data))) {
-                               g_object_unref (comp);
-                               continue;
-                       }
-
-                       e_table_model_pre_change (E_TABLE_MODEL (model));
-
-                       id = e_cal_component_get_id (comp);
-
-                       comp_data = search_by_id_and_client (priv, client, id);
-
-                       e_cal_component_free_id (id);
-                       g_object_unref (comp);
-
-                       if (!comp_data) {
-                               /* the modified component is not in the model yet, just skip it */
-                               continue;
-                       }
-
-                       if (comp_data->icalcomp)
-                               icalcomponent_free (comp_data->icalcomp);
-                       if (comp_data->dtstart) {
-                               g_free (comp_data->dtstart);
-                               comp_data->dtstart = NULL;
-                       }
-                       if (comp_data->dtend) {
-                               g_free (comp_data->dtend);
-                               comp_data->dtend = NULL;
-                       }
-                       if (comp_data->due) {
-                               g_free (comp_data->due);
-                               comp_data->due = NULL;
-                       }
-                       if (comp_data->completed) {
-                               g_free (comp_data->completed);
-                               comp_data->completed = NULL;
-                       }
-                       if (comp_data->created) {
-                               g_free (comp_data->created);
-                               comp_data->created = NULL;
-                       }
-                       if (comp_data->lastmodified) {
-                               g_free (comp_data->lastmodified);
-                               comp_data->lastmodified = NULL;
-                       }
-                       if (comp_data->color) {
-                               g_free (comp_data->color);
-                               comp_data->color = NULL;
-                       }
-
-                       comp_data->icalcomp = icalcomponent_new_clone (l->data);
-                       e_cal_model_set_instance_times (comp_data, priv->zone);
-
-                       pos = get_position_in_array (priv->objects, comp_data);
-
-                       e_table_model_row_changed (E_TABLE_MODEL (model), pos);
-               }
-       }
-
-       process_event (
-               view, list, model, process_added,
-               &model->priv->in_added,
-               model->priv->notify_added,
-               (gpointer (*)(gpointer)) icalcomponent_new_clone,
-               (void (*)(gpointer)) icalcomponent_free);
-
-       g_slist_free (list);
-}
-
-static void
-process_removed (ECalClientView *view,
-                 const GSList *ids,
-                 ECalModel *model)
-{
-       ECalModelPrivate *priv;
-       const GSList *l;
-
-       priv = model->priv;
-
-       for (l = ids; l; l = l->next) {
-               ECalModelComponent *comp_data = NULL;
-               ECalComponentId *id = l->data;
-               gint pos;
-
-               /* make sure we remove all objects with this UID */
-               while ((comp_data = search_by_id_and_client (priv, e_cal_client_view_get_client (view), id))) 
{
-                       GSList *l = NULL;
-
-                       pos = get_position_in_array (priv->objects, comp_data);
-
-                       if (!g_ptr_array_remove (priv->objects, comp_data))
-                               continue;
-
-                       l = g_slist_append (l, comp_data);
-                       g_signal_emit (model, signals[COMPS_DELETED], 0, l);
-
-                       g_slist_free (l);
-                       g_object_unref (comp_data);
-
-                       e_table_model_pre_change (E_TABLE_MODEL (model));
-                       e_table_model_row_deleted (E_TABLE_MODEL (model), pos);
-               }
-       }
-
-       /* to notify about changes, because in call of row_deleted there are still all events */
-       e_table_model_changed (E_TABLE_MODEL (model));
-}
-
-static gpointer
-copy_comp_id (gpointer id)
-{
-       ECalComponentId *comp_id = (ECalComponentId *) id, *copy;
-
-       g_return_val_if_fail (comp_id != NULL, NULL);
-
-       copy = g_new0 (ECalComponentId, 1);
-       copy->uid = g_strdup (comp_id->uid);
-       copy->rid = g_strdup (comp_id->rid);
-
-       return copy;
-}
-
-static void
-free_comp_id (gpointer id)
-{
-       ECalComponentId *comp_id = (ECalComponentId *) id;
-
-       g_return_if_fail (comp_id != NULL);
-
-       g_free (comp_id->uid);
-       g_free (comp_id->rid);
-       g_free (comp_id);
-}
-
-static void
-client_view_objects_added_cb (ECalClientView *view,
-                              const GSList *objects,
-                              GWeakRef *weak_ref_model)
-{
-       ECalModel *model;
-
-       model = g_weak_ref_get (weak_ref_model);
-
-       if (model != NULL) {
-               process_event (
-                       view, objects, model, process_added,
-                       &model->priv->in_added,
-                       model->priv->notify_added,
-                       (gpointer (*)(gpointer)) icalcomponent_new_clone,
-                       (void (*)(gpointer)) icalcomponent_free);
-               g_object_unref (model);
-       }
-}
-
-static void
-client_view_objects_modified_cb (ECalClientView *view,
-                                 const GSList *objects,
-                                 GWeakRef *weak_ref_model)
-{
-       ECalModel *model;
-
-       model = g_weak_ref_get (weak_ref_model);
-
-       if (model != NULL) {
-               process_event (
-                       view, objects, model, process_modified,
-                       &model->priv->in_modified,
-                       model->priv->notify_modified,
-                       (gpointer (*)(gpointer)) icalcomponent_new_clone,
-                       (void (*)(gpointer)) icalcomponent_free);
-               g_object_unref (model);
-       }
-}
-
-static void
-client_view_objects_removed_cb (ECalClientView *view,
-                                const GSList *ids,
-                                GWeakRef *weak_ref_model)
-{
-       ECalModel *model;
-
-       model = g_weak_ref_get (weak_ref_model);
-
-       if (model != NULL) {
-               process_event (
-                       view, ids, model, process_removed,
-                       &model->priv->in_removed,
-                       model->priv->notify_removed,
-                       copy_comp_id, free_comp_id);
-               g_object_unref (model);
-       }
-}
-
-static void
-client_view_progress_cb (ECalClientView *view,
-                         gint percent,
-                         const gchar *message,
-                         GWeakRef *weak_ref_model)
-{
-       ECalModel *model;
-
-       model = g_weak_ref_get (weak_ref_model);
-
-       if (model != NULL) {
-               ECalClient *client;
-               ECalClientSourceType source_type;
-
-               client = e_cal_client_view_get_client (view);
-               source_type = e_cal_client_get_source_type (client);
-
-               g_signal_emit (
-                       model, signals[CAL_VIEW_PROGRESS], 0,
-                       message, percent, source_type);
-
-               g_object_unref (model);
-       }
-}
-
-static void
-client_view_complete_cb (ECalClientView *view,
-                         const GError *error,
-                         GWeakRef *weak_ref_model)
-{
-       ECalModel *model;
-
-       model = g_weak_ref_get (weak_ref_model);
-
-       if (model != NULL) {
-               ECalClient *client;
-               ECalClientSourceType source_type;
-
-               client = e_cal_client_view_get_client (view);
-               source_type = e_cal_client_get_source_type (client);
-
-               g_signal_emit (
-                       model, signals[CAL_VIEW_COMPLETE], 0,
-                       error, source_type);
-
-               g_object_unref (model);
-       }
-}
-
-static void
-cal_model_get_view_cb (GObject *source_object,
-                       GAsyncResult *result,
-                       gpointer user_data)
-{
-       ClientData *client_data = user_data;
-       ECalClientView *view = NULL;
-       ECalModel *model = NULL;
-       GError *error = NULL;
-
-       e_cal_client_get_view_finish (
-               E_CAL_CLIENT (source_object), result, &view, &error);
-
-       /* Sanity check. */
-       g_return_if_fail (
-               ((view != NULL) && (error == NULL)) ||
-               ((view == NULL) && (error != NULL)));
-
-       /* Ignore cancellations. */
-       if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
-               g_error_free (error);
-               goto exit;
-       }
-
-       model = g_weak_ref_get (&client_data->model);
-
-       if (view != NULL && model != NULL) {
-               gulong handler_id;
-
-               g_mutex_lock (&client_data->view_lock);
-
-               client_data->view = g_object_ref (view);
-
-               handler_id = g_signal_connect_data (
-                       view, "objects-added",
-                       G_CALLBACK (client_view_objects_added_cb),
-                       e_weak_ref_new (model),
-                       (GClosureNotify) e_weak_ref_free, 0);
-               client_data->objects_added_handler_id = handler_id;
-
-               handler_id = g_signal_connect_data (
-                       view, "objects-modified",
-                       G_CALLBACK (client_view_objects_modified_cb),
-                       e_weak_ref_new (model),
-                       (GClosureNotify) e_weak_ref_free, 0);
-               client_data->objects_modified_handler_id = handler_id;
-
-               handler_id = g_signal_connect_data (
-                       view, "objects-removed",
-                       G_CALLBACK (client_view_objects_removed_cb),
-                       e_weak_ref_new (model),
-                       (GClosureNotify) e_weak_ref_free, 0);
-               client_data->objects_removed_handler_id = handler_id;
-
-               handler_id = g_signal_connect_data (
-                       view, "progress",
-                       G_CALLBACK (client_view_progress_cb),
-                       e_weak_ref_new (model),
-                       (GClosureNotify) e_weak_ref_free, 0);
-               client_data->progress_handler_id = handler_id;
-
-               handler_id = g_signal_connect_data (
-                       view, "complete",
-                       G_CALLBACK (client_view_complete_cb),
-                       e_weak_ref_new (model),
-                       (GClosureNotify) e_weak_ref_free, 0);
-               client_data->complete_handler_id = handler_id;
-
-               g_mutex_unlock (&client_data->view_lock);
-
-               e_cal_client_view_start (view, &error);
-
-               if (error != NULL) {
-                       g_warning (
-                               "%s: Failed to start view: %s",
-                               G_STRFUNC, error->message);
-                       g_error_free (error);
-               }
-
-       } else if (error != NULL) {
-               g_warning (
-                       "%s: Failed to get view: %s",
-                       G_STRFUNC, error->message);
-               g_error_free (error);
-       }
-
-exit:
-       g_clear_object (&model);
-       g_clear_object (&view);
-
-       client_data_unref (client_data);
-}
-
-static void
-update_e_cal_view_for_client (ECalModel *model,
-                              ClientData *client_data)
-{
-       ECalModelPrivate *priv;
-       GCancellable *cancellable;
-
-       priv = model->priv;
-
-       g_return_if_fail (model->priv->full_sexp != NULL);
-
-       /* free the previous view, if any */
-       g_mutex_lock (&client_data->view_lock);
-       if (client_data->view != NULL) {
-               client_data_disconnect_view_handlers (client_data);
-               g_clear_object (&client_data->view);
-       }
-       g_mutex_unlock (&client_data->view_lock);
-
-       /* Don't create the new query if we won't use it */
-       if (!client_data->do_query)
-               return;
-
-       /* prepare the view */
-
-       cancellable = g_cancellable_new ();
-
-       g_mutex_lock (&client_data->view_lock);
-
-       if (client_data->cancellable != NULL) {
-               g_cancellable_cancel (client_data->cancellable);
-               g_clear_object (&client_data->cancellable);
-       }
-
-       client_data->cancellable = g_object_ref (cancellable);
-
-       g_mutex_unlock (&client_data->view_lock);
-
-       e_cal_client_get_view (
-               client_data->client, priv->full_sexp,
-               cancellable, cal_model_get_view_cb,
-               client_data_ref (client_data));
-
-       g_object_unref (cancellable);
-}
-
 void
-e_cal_model_update_status_message (ECalModel *model,
-                                   const gchar *message,
-                                   gdouble percent)
-{
-       g_return_if_fail (model != NULL);
-
-       g_signal_emit (model, signals[STATUS_MESSAGE], 0, message, percent);
-}
-
-static gboolean
-add_new_client (ECalModel *model,
-                ECalClient *client,
-                gboolean do_query)
+e_cal_model_remove_all_objects (ECalModel *model)
 {
-       ClientData *client_data;
-       gboolean update_view = TRUE;
-
-       /* Look to see if we already have this client */
-       client_data = cal_model_clients_lookup (model, client);
-       if (client_data != NULL) {
-               if (client_data->do_query)
-                       update_view = FALSE;
-               else
-                       client_data->do_query = do_query;
-
-       } else {
-               client_data = client_data_new (model, client, do_query);
-
-               g_mutex_lock (&model->priv->clients_lock);
-               g_queue_push_tail (
-                       &model->priv->clients,
-                       client_data_ref (client_data));
-               g_mutex_unlock (&model->priv->clients_lock);
-       }
-
-       if (update_view)
-               update_e_cal_view_for_client (model, client_data);
-
-       client_data_unref (client_data);
-
-       return update_view;
-}
-
-/**
- * e_cal_model_add_client:
- * @model: an #ECalModel
- * @client: an #ECalClient
- *
- * Adds @client to @model and creates an internal #ECalClientView for it.
- *
- * If @model already has @client from a previous e_cal_model_add_client()
- * call (in other words, excluding e_cal_model_set_default_client()), then
- * the function does nothing and returns %FALSE.
- *
- * Returns: %TRUE if @client was added, %FALSE if @model already had it
- */
-gboolean
-e_cal_model_add_client (ECalModel *model,
-                        ECalClient *client)
-{
-       g_return_val_if_fail (E_IS_CAL_MODEL (model), FALSE);
-       g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
-
-       return add_new_client (model, client, TRUE);
-}
-
-static void
-remove_client_objects (ECalModel *model,
-                       ClientData *client_data)
-{
-       gint i;
-
-       /* remove all objects belonging to this client */
-       for (i = model->priv->objects->len; i > 0; i--) {
-               ECalModelComponent *comp_data = (ECalModelComponent *) g_ptr_array_index 
(model->priv->objects, i - 1);
-
-               g_return_if_fail (comp_data != NULL);
-
-               if (comp_data->client == client_data->client) {
-                       GSList *l = NULL;
-
-                       g_ptr_array_remove (model->priv->objects, comp_data);
-
-                       l = g_slist_append (l, comp_data);
-                       g_signal_emit (model, signals[COMPS_DELETED], 0, l);
-
-                       g_slist_free (l);
-                       g_object_unref (comp_data);
-
-                       e_table_model_pre_change (E_TABLE_MODEL (model));
-                       e_table_model_row_deleted (E_TABLE_MODEL (model), i - 1);
-               }
-       }
-
-       /* to notify about changes, because in call of row_deleted there are still all events */
-       e_table_model_changed (E_TABLE_MODEL (model));
-}
-
-static void
-remove_client (ECalModel *model,
-               ClientData *client_data)
-{
-       g_mutex_lock (&client_data->view_lock);
-       if (client_data->view != NULL)
-               client_data_disconnect_view_handlers (client_data);
-       g_mutex_unlock (&client_data->view_lock);
-
-       remove_client_objects (model, client_data);
-
-       /* If this is the default client and we were querying (so it
-        * was also a source), keep it around but don't query it */
-       if (model->priv->default_client == client_data->client && client_data->do_query) {
-               client_data->do_query = FALSE;
-
-               return;
-       }
-
-       if (model->priv->default_client == client_data->client)
-               model->priv->default_client = NULL;
-
-       cal_model_clients_remove (model, client_data);
-}
-
-/**
- * e_cal_model_remove_client
- * @model: an #ECalModel
- * @client: an #ECalClient
- *
- * Removes @client from @model along with its internal #ECalClientView.
- *
- * If @model does not have @client then the function does nothing and
- * returns %FALSE.
- *
- * Returns: %TRUE is @client was remove, %FALSE if @model did not have it
- */
-gboolean
-e_cal_model_remove_client (ECalModel *model,
-                           ECalClient *client)
-{
-       ClientData *client_data;
-       gboolean removed = FALSE;
-
-       g_return_val_if_fail (E_IS_CAL_MODEL (model), FALSE);
-       g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
-
-       client_data = cal_model_clients_lookup (model, client);
-       if (client_data != NULL) {
-               remove_client (model, client_data);
-               client_data_unref (client_data);
-               removed = TRUE;
-       }
-
-       return removed;
-}
-
-/**
- * e_cal_model_remove_all_clients
- */
-void
-e_cal_model_remove_all_clients (ECalModel *model)
-{
-       ClientData *client_data;
-
-       g_return_if_fail (E_IS_CAL_MODEL (model));
-
-       while ((client_data = cal_model_clients_pop (model)) != NULL) {
-               remove_client (model, client_data);
-               client_data_unref (client_data);
-       }
-}
-
-static GSList *
-get_objects_as_list (ECalModel *model)
-{
-       gint i;
-       GSList *l = NULL;
-       ECalModelPrivate *priv = model->priv;
+       ECalModelComponent *comp_data;
+       ETableModel *table_model;
+       GSList *link;
+       gint index;
 
-       for (i = 0; i < priv->objects->len; i++) {
-               ECalModelComponent *comp_data;
+       table_model = E_TABLE_MODEL (model);
+       for (index = model->priv->objects->len - 1; index >= 0; index--) {
+               e_table_model_pre_change (table_model);
 
-               comp_data = g_ptr_array_index (priv->objects, i);
-               if (comp_data == NULL) {
-                       g_warning ("comp_data is null\n");
+               comp_data = g_ptr_array_remove_index (model->priv->objects, index);
+               if (!comp_data) {
+                       e_table_model_no_change (table_model);
                        continue;
                }
 
-               l = g_slist_prepend (l, comp_data);
-       }
-
-       return l;
-}
-
-struct cc_data
-{
-       ECalModel *model;
-       EFlag *eflag;
-};
-
-static gboolean
-cleanup_content_cb (gpointer user_data)
-{
-       ECalModel *model;
-       ECalModelPrivate *priv;
-       GSList *slist;
-       gint len;
-       struct cc_data *data = user_data;
-
-       g_return_val_if_fail (data != NULL, FALSE);
-       g_return_val_if_fail (data->model != NULL, FALSE);
-       g_return_val_if_fail (data->eflag != NULL, FALSE);
-
-       model = data->model;
-       priv = model->priv;
-
-       g_return_val_if_fail (priv != NULL, FALSE);
-
-       e_table_model_pre_change (E_TABLE_MODEL (model));
-       len = priv->objects->len;
-
-       slist = get_objects_as_list (model);
-       g_ptr_array_set_size (priv->objects, 0);
-       g_signal_emit (model, signals[COMPS_DELETED], 0, slist);
-
-       e_table_model_rows_deleted (E_TABLE_MODEL (model), 0, len);
-
-       g_slist_foreach (slist, (GFunc) g_object_unref, NULL);
-       g_slist_free (slist);
-
-       e_flag_set (data->eflag);
-
-       return FALSE;
-}
-
-static void
-redo_queries (ECalModel *model)
-{
-       ECalModelPrivate *priv;
-       GList *list, *link;
-       struct cc_data data;
-
-       priv = model->priv;
-
-       if (priv->full_sexp)
-               g_free (priv->full_sexp);
-
-       if (priv->start != -1 && priv->end != -1) {
-               gchar *iso_start, *iso_end;
-               const gchar *default_tzloc = NULL;
-
-               iso_start = isodate_from_time_t (priv->start);
-               iso_end = isodate_from_time_t (priv->end);
-
-               if (priv->zone && priv->zone != icaltimezone_get_utc_timezone ())
-                       default_tzloc = icaltimezone_get_location (priv->zone);
-               if (!default_tzloc)
-                       default_tzloc = "";
-
-               if (priv->search_sexp) {
-                       priv->full_sexp = g_strdup_printf (
-                               "(and (occur-in-time-range? (make-time \"%s\") (make-time \"%s\") \"%s\") 
%s)",
-                               iso_start, iso_end, default_tzloc,
-                               priv->search_sexp ? priv->search_sexp : "");
-               } else {
-                       priv->full_sexp = g_strdup_printf (
-                               "(occur-in-time-range? (make-time \"%s\") (make-time \"%s\") \"%s\")",
-                               iso_start, iso_end, default_tzloc);
-               }
-
-               g_free (iso_start);
-               g_free (iso_end);
-       } else if (priv->search_sexp) {
-               priv->full_sexp = g_strdup (priv->search_sexp);
-       } else {
-               priv->full_sexp = g_strdup ("#f");
-       }
-
-       /* clean up the current contents, which should be done
-        * always from the main thread, because of gtk calls during removal */
-       data.model = model;
-       data.eflag = e_flag_new ();
-
-       if (!g_main_context_is_owner (g_main_context_default ())) {
-               /* function called from other than main thread */
-               e_named_timeout_add (10, cleanup_content_cb, &data);
-               e_flag_wait (data.eflag);
-       } else {
-               cleanup_content_cb (&data);
-       }
-
-       e_flag_free (data.eflag);
-
-       /* update the view for all clients */
+               link = g_slist_append (NULL, comp_data);
+               g_signal_emit (model, signals[COMPS_DELETED], 0, link);
 
-       list = cal_model_clients_list (model);
-
-       for (link = list; link != NULL; link = g_list_next (link)) {
-               ClientData *client_data = link->data;
+               g_slist_free (link);
+               g_object_unref (comp_data);
 
-               update_e_cal_view_for_client (model, client_data);
+               e_table_model_row_deleted (table_model, index);
        }
-
-       g_list_free_full (list, (GDestroyNotify) client_data_unref);
 }
 
 void
@@ -3769,6 +2934,7 @@ e_cal_model_set_time_range (ECalModel *model,
                             time_t end)
 {
        ECalModelPrivate *priv;
+       ECalDataModelSubscriber *subscriber;
 
        g_return_if_fail (model != NULL);
        g_return_if_fail (E_IS_CAL_MODEL (model));
@@ -3777,142 +2943,69 @@ e_cal_model_set_time_range (ECalModel *model,
 
        priv = model->priv;
 
+       if (start != (time_t) 0 && end != (time_t) 0) {
+               end = time_day_end_with_zone (end, priv->zone) - 1;
+       }
+
        if (priv->start == start && priv->end == end)
                return;
 
+       subscriber = E_CAL_DATA_MODEL_SUBSCRIBER (model);
        priv->start = start;
        priv->end = end;
 
        g_signal_emit (model, signals[TIME_RANGE_CHANGED], 0, start, end);
-       redo_queries (model);
-}
-
-const gchar *
-e_cal_model_get_search_query (ECalModel *model)
-{
-       ECalModelPrivate *priv;
-
-       g_return_val_if_fail (model != NULL, NULL);
-       g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
-
-       priv = model->priv;
-
-       return priv->search_sexp;
-}
-
-/**
- * e_cal_model_set_query
- */
-void
-e_cal_model_set_search_query (ECalModel *model,
-                              const gchar *sexp)
-{
-       ECalModelPrivate *priv;
-
-       g_return_if_fail (E_IS_CAL_MODEL (model));
-
-       priv = model->priv;
-
-       if (!strcmp (sexp ? sexp : "", priv->search_sexp ? priv->search_sexp : ""))
-               return;
-
-       if (priv->search_sexp)
-               g_free (priv->search_sexp);
-
-       if (!sexp || !*sexp)
-               priv->search_sexp = NULL;
-       else
-               priv->search_sexp = g_strdup (sexp);
-
-       redo_queries (model);
-}
-
-/**
- * e_cal_model_set_query
- */
-void
-e_cal_model_set_search_query_with_time_range (ECalModel *model,
-                                              const gchar *sexp,
-                                              time_t start,
-                                              time_t end)
-{
-       ECalModelPrivate *priv;
-       gboolean do_query = FALSE;
-
-       g_return_if_fail (E_IS_CAL_MODEL (model));
 
-       priv = model->priv;
-
-       if (strcmp (sexp ? sexp : "", priv->search_sexp ? priv->search_sexp : "")) {
-               if (priv->search_sexp)
-                       g_free (priv->search_sexp);
-
-               if (!sexp || !*sexp)
-                       priv->search_sexp = NULL;
-               else
-                       priv->search_sexp = g_strdup (sexp);
-               do_query = TRUE;
-       }
-
-       if (!(priv->start == start && priv->end == end)) {
-               priv->start = start;
-               priv->end = end;
-               do_query = TRUE;
-
-               g_signal_emit (model, signals[TIME_RANGE_CHANGED], 0, start, end);
-       }
-
-       if (do_query)
-               redo_queries (model);
+       e_cal_data_model_unsubscribe (model->priv->data_model, subscriber);
+       e_cal_model_remove_all_objects (model);
+       e_cal_data_model_subscribe (model->priv->data_model, subscriber, start, end);
 }
 
 /**
- * e_cal_model_create_component_with_defaults
+ * e_cal_model_create_component_with_defaults_sync
  */
 icalcomponent *
-e_cal_model_create_component_with_defaults (ECalModel *model,
-                                            gboolean all_day)
+e_cal_model_create_component_with_defaults_sync (ECalModel *model,
+                                                ECalClient *client,
+                                                gboolean all_day,
+                                                GCancellable *cancellable,
+                                                GError **error)
 {
-       ECalModelPrivate *priv;
        ECalComponent *comp;
        icalcomponent *icalcomp;
-       ECalClient *client;
 
        g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
 
-       priv = model->priv;
-
-       client = e_cal_model_ref_default_client (model);
-       if (client == NULL)
-               return icalcomponent_new (priv->kind);
-
-       switch (priv->kind) {
-       case ICAL_VEVENT_COMPONENT :
-               comp = cal_comp_event_new_with_defaults (
-                       client, all_day,
-                       e_cal_model_get_use_default_reminder (model),
-                       e_cal_model_get_default_reminder_interval (model),
-                       e_cal_model_get_default_reminder_units (model));
-               break;
-       case ICAL_VTODO_COMPONENT :
-               comp = cal_comp_task_new_with_defaults (client);
-               break;
-       case ICAL_VJOURNAL_COMPONENT :
-               comp = cal_comp_memo_new_with_defaults (client);
-               break;
-       default:
-               return NULL;
+       if (client) {
+               switch (model->priv->kind) {
+               case ICAL_VEVENT_COMPONENT :
+                       comp = cal_comp_event_new_with_defaults_sync (
+                               client, all_day,
+                               e_cal_model_get_use_default_reminder (model),
+                               e_cal_model_get_default_reminder_interval (model),
+                               e_cal_model_get_default_reminder_units (model),
+                               cancellable, error);
+                       break;
+               case ICAL_VTODO_COMPONENT :
+                       comp = cal_comp_task_new_with_defaults_sync (client, cancellable, error);
+                       break;
+               case ICAL_VJOURNAL_COMPONENT :
+                       comp = cal_comp_memo_new_with_defaults_sync (client, cancellable, error);
+                       break;
+               default:
+                       g_warn_if_reached ();
+                       return NULL;
+               }
        }
 
-       g_object_unref (client);
-
-       if (!comp)
-               return icalcomponent_new (priv->kind);
-
-       icalcomp = icalcomponent_new_clone (e_cal_component_get_icalcomponent (comp));
-       g_object_unref (comp);
+       if (comp) {
+               icalcomp = icalcomponent_new_clone (e_cal_component_get_icalcomponent (comp));
+               g_object_unref (comp);
+       } else {
+               icalcomp = icalcomponent_new (model->priv->kind);
+       }
 
-       /* make sure the component has an UID */
+       /* make sure the component has a UID */
        if (!icalcomponent_get_uid (icalcomp)) {
                gchar *uid;
 
@@ -4084,8 +3177,9 @@ e_cal_model_get_component_at (ECalModel *model,
 }
 
 ECalModelComponent *
-e_cal_model_get_component_for_uid (ECalModel *model,
-                                   const ECalComponentId *id)
+e_cal_model_get_component_for_client_and_uid (ECalModel *model,
+                                             ECalClient *client,
+                                             const ECalComponentId *id)
 {
        ECalModelPrivate *priv;
 
@@ -4093,7 +3187,7 @@ e_cal_model_get_component_for_uid (ECalModel *model,
 
        priv = model->priv;
 
-       return search_by_id_and_client (priv, NULL, id);
+       return search_by_id_and_client (priv, client, id);
 }
 
 /**
@@ -4137,89 +3231,6 @@ e_cal_model_date_value_to_string (ECalModel *model,
        return g_strdup (buffer);
 }
 
-/* FIXME is it still needed ?
-static ECellDateEditValue *
-copy_ecdv (ECellDateEditValue *ecdv)
-{
-       ECellDateEditValue *new_ecdv;
- *
-       new_ecdv = g_new0 (ECellDateEditValue, 1);
-       new_ecdv->tt = ecdv ? ecdv->tt : icaltime_null_time ();
-       new_ecdv->zone = ecdv ? ecdv->zone : NULL;
- *
-       return new_ecdv;
-} */
-
-static void e_cal_model_component_finalize (GObject *object);
-
-/* Class initialization function for the calendar component object */
-static void
-e_cal_model_component_class_init (ECalModelComponentClass *class)
-{
-       GObjectClass *object_class;
-
-       object_class = (GObjectClass *) class;
-       g_type_class_add_private (class, sizeof (ECalModelComponentPrivate));
-
-       object_class->finalize = e_cal_model_component_finalize;
-}
-
-static void
-e_cal_model_component_finalize (GObject *object)
-{
-       ECalModelComponent *comp_data = E_CAL_MODEL_COMPONENT (object);
-
-       if (comp_data->client) {
-               g_object_unref (comp_data->client);
-               comp_data->client = NULL;
-       }
-       if (comp_data->icalcomp) {
-               icalcomponent_free (comp_data->icalcomp);
-               comp_data->icalcomp = NULL;
-       }
-       if (comp_data->dtstart) {
-               g_free (comp_data->dtstart);
-               comp_data->dtstart = NULL;
-       }
-       if (comp_data->dtend) {
-               g_free (comp_data->dtend);
-               comp_data->dtend = NULL;
-       }
-       if (comp_data->due) {
-               g_free (comp_data->due);
-               comp_data->due = NULL;
-       }
-       if (comp_data->completed) {
-               g_free (comp_data->completed);
-               comp_data->completed = NULL;
-       }
-       if (comp_data->created) {
-               g_free (comp_data->created);
-               comp_data->created = NULL;
-       }
-       if (comp_data->lastmodified) {
-               g_free (comp_data->lastmodified);
-               comp_data->lastmodified = NULL;
-       }
-       if (comp_data->color) {
-               g_free (comp_data->color);
-               comp_data->color = NULL;
-       }
-
-       if (comp_data->priv->categories_str)
-               g_string_free (comp_data->priv->categories_str, TRUE);
-       comp_data->priv->categories_str = NULL;
-
-       /* Chain up to parent's finalize() method. */
-       G_OBJECT_CLASS (e_cal_model_component_parent_class)->finalize (object);
-}
-
-static void
-e_cal_model_component_init (ECalModelComponent *comp)
-{
-       comp->priv = E_CAL_MODEL_COMPONENT_GET_PRIVATE (comp);
-}
-
 /**
  * e_cal_model_generate_instances_sync
  *
@@ -4264,14 +3275,12 @@ void
 e_cal_model_set_instance_times (ECalModelComponent *comp_data,
                                 const icaltimezone *zone)
 {
-       struct icaltimetype start_time, end_time;
-       icalcomponent_kind kind;
+       if (icalcomponent_isa (comp_data->icalcomp) == ICAL_VEVENT_COMPONENT) {
+               struct icaltimetype start_time, end_time;
 
-       kind = icalcomponent_isa (comp_data->icalcomp);
-       start_time = icalcomponent_get_dtstart (comp_data->icalcomp);
-       end_time = icalcomponent_get_dtend (comp_data->icalcomp);
+               start_time = icalcomponent_get_dtstart (comp_data->icalcomp);
+               end_time = icalcomponent_get_dtend (comp_data->icalcomp);
 
-       if (kind == ICAL_VEVENT_COMPONENT) {
                if (start_time.is_date && icaltime_is_null_time (end_time)) {
                        /* If end_time is null and it's an all day event,
                         * just make start_time = end_time so that end_time
@@ -4291,55 +3300,8 @@ e_cal_model_set_instance_times (ECalModelComponent *comp_data,
                }
        }
 
-       if (start_time.zone)
-               zone = start_time.zone;
-       else {
-               icalparameter *param = NULL;
-               icalproperty *prop = icalcomponent_get_first_property (comp_data->icalcomp, 
ICAL_DTSTART_PROPERTY);
-
-              if (prop)        {
-                       param = icalproperty_get_first_parameter (prop, ICAL_TZID_PARAMETER);
-
-                       if (param) {
-                               const gchar *tzid = NULL;
-                               icaltimezone *st_zone = NULL;
-
-                               tzid = icalparameter_get_tzid (param);
-                               if (tzid)
-                                       e_cal_client_get_timezone_sync (comp_data->client, tzid, &st_zone, 
NULL, NULL);
-
-                               if (st_zone)
-                                       zone = st_zone;
-                       }
-              }
-       }
-
-       comp_data->instance_start = icaltime_as_timet_with_zone (start_time, zone);
-
-       if (end_time.zone)
-               zone = end_time.zone;
-       else {
-               icalparameter *param = NULL;
-               icalproperty *prop = icalcomponent_get_first_property (comp_data->icalcomp, 
ICAL_DTSTART_PROPERTY);
-
-              if (prop)        {
-                       param = icalproperty_get_first_parameter (prop, ICAL_TZID_PARAMETER);
-
-                       if (param) {
-                               const gchar *tzid = NULL;
-                               icaltimezone *end_zone = NULL;
-
-                               tzid = icalparameter_get_tzid (param);
-                               if (tzid)
-                                       e_cal_client_get_timezone_sync (comp_data->client, tzid, &end_zone, 
NULL, NULL);
-
-                               if (end_zone)
-                                       zone = end_zone;
-                       }
-              }
-
-       }
-       comp_data->instance_end = icaltime_as_timet_with_zone (end_time, zone);
+       cal_comp_get_instance_times (comp_data->client, comp_data->icalcomp, zone,
+               &comp_data->instance_start, NULL, &comp_data->instance_end, NULL, NULL);
 }
 
 /**
@@ -4357,3 +3319,49 @@ e_cal_model_set_default_time_func (ECalModel *model,
        model->priv->get_default_time = func;
        model->priv->get_default_time_user_data = user_data;
 }
+
+void
+e_cal_model_modify_component (ECalModel *model,
+                             ECalModelComponent *comp_data,
+                             ECalObjModType mod)
+{
+       g_return_if_fail (E_IS_CAL_MODEL (model));
+       g_return_if_fail (E_IS_CAL_MODEL_COMPONENT (comp_data));
+
+       e_cal_ops_modify_component (model, comp_data->client, comp_data->icalcomp, mod, 
E_CAL_OPS_SEND_FLAG_ASK);
+}
+
+void
+e_cal_model_util_set_value (GHashTable *values,
+                           ETableModel *table_model,
+                           gint column,
+                           gint row)
+{
+       gpointer value;
+
+       g_return_if_fail (values != NULL);
+
+       value = e_table_model_value_at (table_model, column, row);
+
+       g_hash_table_insert (values, GINT_TO_POINTER (column),
+               e_table_model_duplicate_value (table_model, column, value));
+}
+
+gpointer
+e_cal_model_util_get_value (GHashTable *values,
+                           gint column)
+{
+       g_return_val_if_fail (values != NULL, NULL);
+
+       return g_hash_table_lookup (values, GINT_TO_POINTER (column));
+}
+
+void
+e_cal_model_emit_object_created (ECalModel *model,
+                                ECalClient *where)
+{
+       g_return_if_fail (E_IS_CAL_MODEL (model));
+       g_return_if_fail (E_IS_CAL_CLIENT (where));
+
+       g_signal_emit (model, signals[OBJECT_CREATED], 0, where);
+}
diff --git a/calendar/gui/e-cal-model.h b/calendar/gui/e-cal-model.h
index 6711c81..f7a6351 100644
--- a/calendar/gui/e-cal-model.h
+++ b/calendar/gui/e-cal-model.h
@@ -28,6 +28,8 @@
 #include <libecal/libecal.h>
 
 #include <e-util/e-util.h>
+#include <shell/e-shell.h>
+#include <calendar/gui/e-cal-data-model.h>
 
 #include "e-cell-date-edit-text.h"
 
@@ -89,11 +91,6 @@ typedef enum {
        E_CAL_MODEL_FIELD_LAST
 } ECalModelField;
 
-typedef enum {
-       E_CAL_MODEL_FLAGS_INVALID = -1,
-       E_CAL_MODEL_FLAGS_EXPAND_RECURRENCES = 0x01
-} ECalModelFlags;
-
 typedef struct _ECalModel ECalModel;
 typedef struct _ECalModelClass ECalModelClass;
 typedef struct _ECalModelPrivate ECalModelPrivate;
@@ -109,6 +106,7 @@ struct _ECalModelComponent {
        icalcomponent *icalcomp;
        time_t instance_start;
        time_t instance_end;
+       gboolean is_new_component;
 
        /* Private data used by ECalModelCalendar and ECalModelTasks */
        /* keep these public to avoid many accessor functions */
@@ -144,11 +142,15 @@ struct _ECalModelClass {
        const gchar *   (*get_color_for_component)
                                                (ECalModel *model,
                                                 ECalModelComponent *comp_data);
-       void            (*fill_component_from_model)
+       void            (*store_values_from_model)
                                                (ECalModel *model,
-                                                ECalModelComponent *comp_data,
                                                 ETableModel *source_model,
-                                                gint row);
+                                                gint row,
+                                                GHashTable *values); /* column ID ~> value */
+       void            (*fill_component_from_values)
+                                               (ECalModel *model,
+                                                ECalModelComponent *comp_data,
+                                                GHashTable *values); /* column ID ~> value, populated by 
store_values_from_model() */
 
        /* Signals */
        void            (*time_range_changed)   (ECalModel *model,
@@ -157,25 +159,23 @@ struct _ECalModelClass {
        void            (*row_appended)         (ECalModel *model);
        void            (*comps_deleted)        (ECalModel *model,
                                                 gpointer list);
-       void            (*cal_view_progress)    (ECalModel *model,
-                                                const gchar *message,
-                                                gint progress,
-                                                ECalClientSourceType type);
-       void            (*cal_view_complete)    (ECalModel *model,
-                                                const GError *error,
-                                                ECalClientSourceType type);
-       void            (*status_message)       (ECalModel *model,
-                                                const gchar *message,
-                                                gdouble percent);
        void            (*timezone_changed)     (ECalModel *model,
                                                 icaltimezone *old_zone,
                                                 icaltimezone *new_zone);
+       void            (*object_created)       (ECalModel *model,
+                                                ECalClient *where);
 };
 
 typedef time_t (*ECalModelDefaultTimeFunc) (ECalModel *model, gpointer user_data);
 
 GType          e_cal_model_get_type            (void);
 GType          e_cal_model_component_get_type  (void);
+ECalDataModel *        e_cal_model_get_data_model      (ECalModel *model);
+ESourceRegistry *
+               e_cal_model_get_registry        (ECalModel *model);
+EShell *       e_cal_model_get_shell           (ECalModel *model);
+EClientCache * e_cal_model_get_client_cache    (ECalModel *model);
+const gchar *  e_cal_model_get_extension_name  (ECalModel *model);
 icalcomponent_kind
                e_cal_model_get_component_kind  (ECalModel *model);
 void           e_cal_model_set_component_kind  (ECalModel *model,
@@ -183,11 +183,6 @@ void               e_cal_model_set_component_kind  (ECalModel *model,
 gboolean       e_cal_model_get_confirm_delete  (ECalModel *model);
 void           e_cal_model_set_confirm_delete  (ECalModel *model,
                                                 gboolean confirm_delete);
-ECalModelFlags e_cal_model_get_flags           (ECalModel *model);
-void           e_cal_model_set_flags           (ECalModel *model,
-                                                ECalModelFlags flags);
-ESourceRegistry *
-               e_cal_model_get_registry        (ECalModel *model);
 icaltimezone * e_cal_model_get_timezone        (ECalModel *model);
 void           e_cal_model_set_timezone        (ECalModel *model,
                                                 icaltimezone *zone);
@@ -249,27 +244,24 @@ gint              e_cal_model_get_work_day_start_minute
 void           e_cal_model_set_work_day_start_minute
                                                (ECalModel *model,
                                                 gint work_day_start_minute);
-ECalClient *   e_cal_model_ref_default_client  (ECalModel *model);
-void           e_cal_model_set_default_client  (ECalModel *model,
-                                                ECalClient *client);
-GList *                e_cal_model_list_clients        (ECalModel *model);
-gboolean       e_cal_model_add_client          (ECalModel *model,
-                                                ECalClient *cal_client);
-gboolean       e_cal_model_remove_client       (ECalModel *model,
-                                                ECalClient *cal_client);
-void           e_cal_model_remove_all_clients  (ECalModel *model);
+const gchar *  e_cal_model_get_default_source_uid
+                                               (ECalModel *model);
+void           e_cal_model_set_default_source_uid
+                                               (ECalModel *model,
+                                                const gchar *source_uid);
+void           e_cal_model_remove_all_objects  (ECalModel *model);
 void           e_cal_model_get_time_range      (ECalModel *model,
                                                 time_t *start,
                                                 time_t *end);
 void           e_cal_model_set_time_range      (ECalModel *model,
                                                 time_t start,
                                                 time_t end);
-const gchar *  e_cal_model_get_search_query    (ECalModel *model);
-void           e_cal_model_set_search_query    (ECalModel *model,
-                                                const gchar *sexp);
-icalcomponent *        e_cal_model_create_component_with_defaults
+icalcomponent *        e_cal_model_create_component_with_defaults_sync
                                                (ECalModel *model,
-                                                gboolean all_day);
+                                                ECalClient *client,
+                                                gboolean all_day,
+                                                GCancellable *cancellable,
+                                                GError **error);
 gchar *                e_cal_model_get_attendees_status_info
                                                (ECalModel *model,
                                                 ECalComponent *comp,
@@ -287,8 +279,9 @@ ECalModelComponent *
                e_cal_model_get_component_at    (ECalModel *model,
                                                 gint row);
 ECalModelComponent *
-               e_cal_model_get_component_for_uid
+               e_cal_model_get_component_for_client_and_uid
                                                (ECalModel *model,
+                                                ECalClient *client,
                                                 const ECalComponentId *id);
 gchar *                e_cal_model_date_value_to_string (ECalModel *model,
                                                 gconstpointer value);
@@ -301,11 +294,6 @@ void               e_cal_model_generate_instances_sync
 GPtrArray *    e_cal_model_get_object_array    (ECalModel *model);
 void           e_cal_model_set_instance_times  (ECalModelComponent *comp_data,
                                                 const icaltimezone *zone);
-void           e_cal_model_set_search_query_with_time_range
-                                               (ECalModel *model,
-                                                const gchar *sexp,
-                                                time_t start,
-                                                time_t end);
 gboolean       e_cal_model_test_row_editable   (ECalModel *model,
                                                 gint row);
 void           e_cal_model_set_default_time_func
@@ -321,10 +309,19 @@ void              e_cal_model_update_comp_time    (ECalModel *model,
                                                                   struct icaltimetype v),
                                                 icalproperty * (*new_func) (struct icaltimetype v));
 
-void           e_cal_model_update_status_message
-                                               (ECalModel *model,
-                                                const gchar *message,
-                                                gdouble percent);
+void           e_cal_model_emit_object_created (ECalModel *model,
+                                                ECalClient *where);
+
+void           e_cal_model_modify_component    (ECalModel *model,
+                                                ECalModelComponent *comp_data,
+                                                ECalObjModType mod);
+
+void           e_cal_model_util_set_value      (GHashTable *values,
+                                                ETableModel *table_model,
+                                                gint column,
+                                                gint row);
+gpointer       e_cal_model_util_get_value      (GHashTable *values,
+                                                gint column);
 
 G_END_DECLS
 
diff --git a/calendar/gui/e-cal-ops.c b/calendar/gui/e-cal-ops.c
new file mode 100644
index 0000000..21554e6
--- /dev/null
+++ b/calendar/gui/e-cal-ops.c
@@ -0,0 +1,2090 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Milan Crha <mcrha redhat com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+
+#include <e-util/e-util.h>
+#include <shell/e-shell-view.h>
+
+#include "dialogs/comp-editor.h"
+#include "dialogs/event-editor.h"
+#include "dialogs/memo-editor.h"
+#include "dialogs/task-editor.h"
+#include "dialogs/send-comp.h"
+#include "comp-util.h"
+
+#include "e-cal-data-model.h"
+
+#include "e-cal-ops.h"
+
+static void
+cal_ops_manage_send_component (ECalModel *model,
+                              ECalClient *client,
+                              icalcomponent *icalcomp,
+                              ECalObjModType mod,
+                              ECalOpsSendFlags send_flags)
+{
+       ECalComponent *comp;
+       ESourceRegistry *registry;
+
+       g_return_if_fail (E_IS_CAL_MODEL (model));
+       g_return_if_fail (E_IS_CAL_CLIENT (client));
+       g_return_if_fail (icalcomp != NULL);
+
+       if ((send_flags & E_CAL_OPS_SEND_FLAG_DONT_SEND) != 0)
+               return;
+
+       comp = e_cal_component_new_from_icalcomponent (icalcomponent_new_clone (icalcomp));
+       if (!comp)
+               return;
+
+       registry = e_cal_model_get_registry (model);
+
+       if (itip_organizer_is_user (registry, comp, client)) {
+               gboolean strip_alarms = (send_flags & E_CAL_OPS_SEND_FLAG_STRIP_ALARMS) != 0;
+               gboolean only_new_attendees = (send_flags & E_CAL_OPS_SEND_FLAG_ONLY_NEW_ATTENDEES) != 0;
+               gboolean can_send = (send_flags & E_CAL_OPS_SEND_FLAG_SEND) != 0;
+
+               if (!can_send) /* E_CAL_OPS_SEND_FLAG_ASK */
+                       can_send = send_component_dialog (NULL, client, comp,
+                               (send_flags & E_CAL_OPS_SEND_FLAG_IS_NEW_COMPONENT) != 0,
+                               &strip_alarms, &only_new_attendees);
+
+               if (can_send)
+                       itip_send_component (model, E_CAL_COMPONENT_METHOD_REQUEST, comp, client,
+                               NULL, NULL, NULL, strip_alarms, only_new_attendees, mod == E_CAL_OBJ_MOD_ALL);
+       }
+
+       g_clear_object (&comp);
+}
+
+typedef struct {
+       ECalModel *model;
+       ECalClient *client;
+       icalcomponent *icalcomp;
+       ECalObjModType mod;
+       gchar *uid;
+       gchar *rid;
+       gboolean check_detached_instance;
+       ECalOpsCreateComponentFunc create_cb;
+       ECalOpsGetDefaultComponentFunc get_default_comp_cb;
+       gboolean all_day_default_comp;
+       gchar *for_client_uid;
+       gboolean is_modify;
+       ECalOpsSendFlags send_flags;
+       gpointer user_data;
+       GDestroyNotify user_data_free;
+       gboolean success;
+} BasicOperationData;
+
+static void
+basic_operation_data_free (gpointer ptr)
+{
+       BasicOperationData *bod = ptr;
+
+       if (bod) {
+               if (bod->success) {
+                       if (bod->create_cb && bod->uid && bod->icalcomp) {
+                               bod->create_cb (bod->model, bod->client, bod->icalcomp, bod->uid, 
bod->user_data);
+                               if (bod->user_data_free)
+                                       bod->user_data_free (bod->user_data);
+                       }
+
+                       if (bod->is_modify && bod->icalcomp && (bod->send_flags & 
E_CAL_OPS_SEND_FLAG_DONT_SEND) == 0) {
+                               cal_ops_manage_send_component (bod->model, bod->client, bod->icalcomp, 
bod->mod, bod->send_flags);
+                       }
+
+                       if (bod->get_default_comp_cb && bod->icalcomp) {
+                               bod->get_default_comp_cb (bod->model, bod->client, bod->icalcomp, 
bod->user_data);
+                               if (bod->user_data_free)
+                                       bod->user_data_free (bod->user_data);
+                       }
+               }
+
+               g_clear_object (&bod->model);
+               g_clear_object (&bod->client);
+               if (bod->icalcomp)
+                       icalcomponent_free (bod->icalcomp);
+               g_free (bod->for_client_uid);
+               g_free (bod->uid);
+               g_free (bod->rid);
+               g_free (bod);
+       }
+}
+
+static void
+cal_ops_create_component_thread (EAlertSinkThreadJobData *job_data,
+                                gpointer user_data,
+                                GCancellable *cancellable,
+                                GError **error)
+{
+       BasicOperationData *bod = user_data;
+
+       g_return_if_fail (bod != NULL);
+
+       bod->success = e_cal_client_create_object_sync (bod->client, bod->icalcomp, &bod->uid, cancellable, 
error);
+}
+
+/**
+ * e_cal_ops_create_component:
+ * @model: an #ECalModel
+ * @client: an #ECalClient
+ * @icalcomp: an #icalcomponent
+ * @callback: (allow none): a callback to be called on success
+ * @user_data: user data to be passed to @callback; ignored when @callback is #NULL
+ * @user_data_free: a function to free @user_data; ignored when @callback is #NULL
+ *
+ * Creates a new @icalcomp in the @client. The @callback, if not #NULL,
+ * is called with a new uid of the @icalcomp on sucessful component save.
+ * The @callback is called in the main thread.
+ *
+ * Since: 3.14
+ **/
+void
+e_cal_ops_create_component (ECalModel *model,
+                           ECalClient *client,
+                           icalcomponent *icalcomp,
+                           ECalOpsCreateComponentFunc callback,
+                           gpointer user_data,
+                           GDestroyNotify user_data_free)
+{
+       ECalDataModel *data_model;
+       ESource *source;
+       const gchar *description;
+       const gchar *alert_ident;
+       BasicOperationData *bod;
+       GCancellable *cancellable;
+
+       g_return_if_fail (E_IS_CAL_MODEL (model));
+       g_return_if_fail (E_IS_CAL_CLIENT (client));
+       g_return_if_fail (icalcomp != NULL);
+
+       switch (e_cal_client_get_source_type (client)) {
+               case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+                       description = _("Creating an event");
+                       alert_ident = "calendar:failed-create-event";
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+                       description = _("Creating a memo");
+                       alert_ident = "calendar:failed-create-memo";
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+                       description = _("Creating a task");
+                       alert_ident = "calendar:failed-create-task";
+                       break;
+               default:
+                       g_warn_if_reached ();
+                       return;
+       }
+
+       data_model = e_cal_model_get_data_model (model);
+       source = e_client_get_source (E_CLIENT (client));
+
+       bod = g_new0 (BasicOperationData, 1);
+       bod->model = g_object_ref (model);
+       bod->client = g_object_ref (client);
+       bod->icalcomp = icalcomponent_new_clone (icalcomp);
+       bod->create_cb = callback;
+       bod->user_data = user_data;
+       bod->user_data_free = user_data_free;
+
+       cancellable = e_cal_data_model_submit_thread_job (data_model, description, alert_ident,
+               e_source_get_display_name (source), cal_ops_create_component_thread,
+               bod, basic_operation_data_free);
+
+       g_clear_object (&cancellable);
+}
+
+static void
+cal_ops_modify_component_thread (EAlertSinkThreadJobData *job_data,
+                                gpointer user_data,
+                                GCancellable *cancellable,
+                                GError **error)
+{
+       BasicOperationData *bod = user_data;
+
+       g_return_if_fail (bod != NULL);
+
+       if (bod->mod == E_CAL_OBJ_MOD_ALL) {
+               ECalComponent *comp;
+
+               comp = e_cal_component_new_from_icalcomponent (icalcomponent_new_clone (bod->icalcomp));
+               if (comp && e_cal_component_has_recurrences (comp)) {
+                       if (!comp_util_sanitize_recurrence_master_sync (comp, bod->client, cancellable, 
error)) {
+                               g_object_unref (comp);
+                               return;
+                       }
+
+                       icalcomponent_free (bod->icalcomp);
+                       bod->icalcomp = icalcomponent_new_clone (e_cal_component_get_icalcomponent (comp));
+               }
+
+               g_clear_object (&comp);
+       }
+
+       bod->success = e_cal_client_modify_object_sync (bod->client, bod->icalcomp, bod->mod, cancellable, 
error);
+}
+
+/**
+ * e_cal_ops_modify_component:
+ * @model: an #ECalModel
+ * @client: an #ECalClient
+ * @icalcomp: an #icalcomponent
+ * @mod: a mode to use for modification of the component
+ * @send_flags: what to do when the modify succeeded and the component has attendees
+ *
+ * Saves changes of the @icalcomp into the @client using the @mod. The @send_flags influences
+ * what to do when the @icalcomp has attendees and the organizer is user. Only one of
+ * #E_CAL_OPS_SEND_FLAG_ASK, #E_CAL_OPS_SEND_FLAG_SEND, #E_CAL_OPS_SEND_FLAG_DONT_SEND
+ * can be used, while the ASK flag is the default.
+ *
+ * Since: 3.14
+ **/
+void
+e_cal_ops_modify_component (ECalModel *model,
+                           ECalClient *client,
+                           icalcomponent *icalcomp,
+                           ECalObjModType mod,
+                           ECalOpsSendFlags send_flags)
+{
+       ECalDataModel *data_model;
+       ESource *source;
+       const gchar *description;
+       const gchar *alert_ident;
+       BasicOperationData *bod;
+       GCancellable *cancellable;
+
+       g_return_if_fail (E_IS_CAL_MODEL (model));
+       g_return_if_fail (E_IS_CAL_CLIENT (client));
+       g_return_if_fail (icalcomp != NULL);
+
+       switch (e_cal_client_get_source_type (client)) {
+               case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+                       description = _("Modifying an event");
+                       alert_ident = "calendar:failed-modify-event";
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+                       description = _("Modifying a memo");
+                       alert_ident = "calendar:failed-modify-memo";
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+                       description = _("Modifying a task");
+                       alert_ident = "calendar:failed-modify-task";
+                       break;
+               default:
+                       g_warn_if_reached ();
+                       return;
+       }
+
+       data_model = e_cal_model_get_data_model (model);
+       source = e_client_get_source (E_CLIENT (client));
+
+       bod = g_new0 (BasicOperationData, 1);
+       bod->model = g_object_ref (model);
+       bod->client = g_object_ref (client);
+       bod->icalcomp = icalcomponent_new_clone (icalcomp);
+       bod->mod = mod;
+       bod->send_flags = send_flags;
+       bod->is_modify = TRUE;
+
+       cancellable = e_cal_data_model_submit_thread_job (data_model, description, alert_ident,
+               e_source_get_display_name (source), cal_ops_modify_component_thread,
+               bod, basic_operation_data_free);
+
+       g_clear_object (&cancellable);
+}
+
+static void
+cal_ops_remove_component_thread (EAlertSinkThreadJobData *job_data,
+                                gpointer user_data,
+                                GCancellable *cancellable,
+                                GError **error)
+{
+       BasicOperationData *bod = user_data;
+
+       g_return_if_fail (bod != NULL);
+
+       /* The check_detached_instance means to test whether the event is a detached instance,
+          then only that one is deleted, otherwise the master object is deleted */
+       if (bod->check_detached_instance && bod->mod == E_CAL_OBJ_MOD_THIS && bod->rid && *bod->rid) {
+               icalcomponent *icalcomp = NULL;
+               GError *local_error = NULL;
+
+               if (!e_cal_client_get_object_sync (bod->client, bod->uid, bod->rid, &icalcomp, cancellable, 
&local_error) &&
+                   g_error_matches (local_error, E_CAL_CLIENT_ERROR, E_CAL_CLIENT_ERROR_OBJECT_NOT_FOUND)) {
+                       g_free (bod->rid);
+                       bod->rid = NULL;
+                       bod->mod = E_CAL_OBJ_MOD_ALL;
+               }
+
+               g_clear_error (&local_error);
+               if (icalcomp)
+                       icalcomponent_free (icalcomp);
+       }
+
+       bod->success = e_cal_client_remove_object_sync (bod->client, bod->uid, bod->rid, bod->mod, 
cancellable, error);
+}
+
+/**
+ * e_cal_ops_remove_component:
+ * @model: an #ECalModel
+ * @client: an #ECalClient
+ * @uid: a UID of the component to remove
+ * @rid: (allow none): a recurrence ID of the component; can be #NULL
+ * @mod: a mode to use for the component removal
+ * @check_detached_instance: whether to test whether a detached instance is to be removed
+ *
+ * Removes component identified by @uid and @rid from the @client using mode @mod.
+ * The @check_detached_instance influences behaviour when removing only one instance.
+ * If set to #TRUE, then it is checked first whether the component to be removed is
+ * a detached instance. If it is, then only that one is removed (as requested), otherwise
+ * the master objects is removed. If the @check_detached_instance is set to #FALSE, then
+ * the removal is done exactly with the given values.
+ *
+ * Since: 3.14
+ **/
+void
+e_cal_ops_remove_component (ECalModel *model,
+                           ECalClient *client,
+                           const gchar *uid,
+                           const gchar *rid,
+                           ECalObjModType mod,
+                           gboolean check_detached_instance)
+{
+       ECalDataModel *data_model;
+       ESource *source;
+       const gchar *description;
+       const gchar *alert_ident;
+       BasicOperationData *bod;
+       GCancellable *cancellable;
+
+       g_return_if_fail (E_IS_CAL_MODEL (model));
+       g_return_if_fail (E_IS_CAL_CLIENT (client));
+       g_return_if_fail (uid != NULL);
+
+       switch (e_cal_client_get_source_type (client)) {
+               case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+                       description = _("Removing an event");
+                       alert_ident = "calendar:failed-remove-event";
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+                       description = _("Removing a memo");
+                       alert_ident = "calendar:failed-remove-memo";
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+                       description = _("Removing a task");
+                       alert_ident = "calendar:failed-remove-task";
+                       break;
+               default:
+                       g_warn_if_reached ();
+                       return;
+       }
+
+       data_model = e_cal_model_get_data_model (model);
+       source = e_client_get_source (E_CLIENT (client));
+
+       bod = g_new0 (BasicOperationData, 1);
+       bod->model = g_object_ref (model);
+       bod->client = g_object_ref (client);
+       bod->uid = g_strdup (uid);
+       bod->rid = g_strdup (rid);
+       bod->mod = mod;
+       bod->check_detached_instance = check_detached_instance;
+
+       cancellable = e_cal_data_model_submit_thread_job (data_model, description, alert_ident,
+               e_source_get_display_name (source), cal_ops_remove_component_thread,
+               bod, basic_operation_data_free);
+
+       g_clear_object (&cancellable);
+}
+
+static void
+cal_ops_delete_components_thread (EAlertSinkThreadJobData *job_data,
+                                 gpointer user_data,
+                                 GCancellable *cancellable,
+                                 GError **error)
+{
+       GSList *objects = user_data, *link;
+
+       for (link = objects; link && !g_cancellable_is_cancelled (cancellable); link = g_slist_next (link)) {
+               ECalModelComponent *comp_data = (ECalModelComponent *) link->data;
+               struct icaltimetype tt;
+               gchar *rid = NULL;
+
+               tt = icalcomponent_get_recurrenceid (comp_data->icalcomp);
+               if (icaltime_is_valid_time (tt) && !icaltime_is_null_time (tt))
+                       rid = icaltime_as_ical_string_r (tt);
+
+               if (!e_cal_client_remove_object_sync (
+                       comp_data->client, icalcomponent_get_uid (comp_data->icalcomp),
+                       rid, CALOBJ_MOD_THIS, cancellable, error)) {
+                       ESource *source = e_client_get_source (E_CLIENT (comp_data->client));
+                       e_alert_sink_thread_job_set_alert_arg_0 (job_data, e_source_get_display_name 
(source));
+                       /* Stop on the first error */
+                       g_free (rid);
+                       break;
+               }
+
+               g_free (rid);
+       }
+}
+
+/**
+ * e_cal_ops_delete_ecalmodel_components:
+ * @model: an #ECalModel
+ * @objects: a #GSList of an #ECalModelComponent objects to delete
+ *
+ * Deletes all components from their sources. The @objects should
+ * be part of @model.
+ *
+ * Since: 3.14
+ **/
+void
+e_cal_ops_delete_ecalmodel_components (ECalModel *model,
+                                      const GSList *objects)
+{
+       ECalDataModel *data_model;
+       GCancellable *cancellable;
+       const gchar *alert_ident;
+       gchar *description;
+       GSList *objects_copy;
+       gint nobjects;
+
+       g_return_if_fail (E_IS_CAL_MODEL (model));
+
+       if (!objects)
+               return;
+
+       objects_copy = g_slist_copy ((GSList *) objects);
+       g_slist_foreach (objects_copy, (GFunc) g_object_ref, NULL);
+       nobjects = g_slist_length (objects_copy);
+
+       switch (e_cal_model_get_component_kind (model)) {
+               case ICAL_VEVENT_COMPONENT:
+                       description = g_strdup_printf (ngettext ("Deleting an event", "Deleting %d events", 
nobjects), nobjects);
+                       alert_ident = "calendar:failed-remove-event";
+                       break;
+               case ICAL_VJOURNAL_COMPONENT:
+                       description = g_strdup_printf (ngettext ("Deleting a memo", "Deleting %d memos", 
nobjects), nobjects);
+                       alert_ident = "calendar:failed-remove-memo";
+                       break;
+               case ICAL_VTODO_COMPONENT:
+                       description = g_strdup_printf (ngettext ("Deleting a task", "Deleting %d tasks", 
nobjects), nobjects);
+                       alert_ident = "calendar:failed-remove-task";
+                       break;
+               default:
+                       g_warn_if_reached ();
+                       return;
+       }
+
+       data_model = e_cal_model_get_data_model (model);
+
+       cancellable = e_cal_data_model_submit_thread_job (data_model, description, alert_ident,
+               NULL, cal_ops_delete_components_thread, objects_copy, (GDestroyNotify) 
e_util_free_nullable_object_slist);
+
+       g_clear_object (&cancellable);
+       g_free (description);
+}
+
+static gboolean
+cal_ops_create_comp_with_new_uid_sync (ECalClient *cal_client,
+                                      icalcomponent *icalcomp,
+                                      GCancellable *cancellable,
+                                      GError **error)
+{
+       icalcomponent *clone;
+       gchar *uid;
+       gboolean success;
+
+       g_return_val_if_fail (E_IS_CAL_CLIENT (cal_client), FALSE);
+       g_return_val_if_fail (icalcomp != NULL, FALSE);
+
+
+       clone = icalcomponent_new_clone (icalcomp);
+
+       uid = e_cal_component_gen_uid ();
+       icalcomponent_set_uid (clone, uid);
+       g_free (uid);
+
+       success = e_cal_client_create_object_sync (cal_client, clone, NULL, cancellable, error);
+
+       icalcomponent_free (clone);
+
+       return success;
+}
+
+typedef struct {
+       ECalModel *model;
+       icalcomponent *icalcomp;
+       icalcomponent_kind kind;
+       const gchar *extension_name;
+       gboolean success;
+} PasteComponentsData;
+
+static void
+paste_components_data_free (gpointer ptr)
+{
+       PasteComponentsData *pcd = ptr;
+
+       if (pcd) {
+               if (pcd->model && pcd->success)
+                       g_signal_emit_by_name (pcd->model, "row-appended", 0);
+
+               g_clear_object (&pcd->model);
+               icalcomponent_free (pcd->icalcomp);
+               g_free (pcd);
+       }
+}
+
+static void
+cal_ops_update_components_thread (EAlertSinkThreadJobData *job_data,
+                                 gpointer user_data,
+                                 GCancellable *cancellable,
+                                 GError **error)
+{
+       PasteComponentsData *pcd = user_data;
+       EClient *client;
+       EClientCache *client_cache;
+       ECalClient *cal_client;
+       ESourceRegistry *registry;
+       ESource *source;
+       const gchar *uid;
+       gboolean success = TRUE, any_copied = FALSE;
+       GError *local_error = NULL;
+
+       g_return_if_fail (pcd != NULL);
+
+       uid = e_cal_model_get_default_source_uid (pcd->model);
+       g_return_if_fail (uid != NULL);
+
+       client_cache = e_cal_model_get_client_cache (pcd->model);
+       registry = e_cal_model_get_registry (pcd->model);
+
+       source = e_source_registry_ref_source (registry, uid);
+       if (!source) {
+               g_set_error (&local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+                       _("Source with UID '%s' not found"), uid);
+               e_alert_sink_thread_job_set_alert_arg_0 (job_data, uid);
+               return;
+       }
+
+       e_alert_sink_thread_job_set_alert_arg_0 (job_data, e_source_get_display_name (source));
+
+       client = e_client_cache_get_client_sync (client_cache, source, pcd->extension_name, cancellable, 
&local_error);
+       g_clear_object (&source);
+
+       if (!client) {
+               e_util_propagate_open_source_job_error (job_data, pcd->extension_name, local_error, error);
+               return;
+       }
+
+       cal_client = E_CAL_CLIENT (client);
+
+       if (icalcomponent_isa (pcd->icalcomp) == ICAL_VCALENDAR_COMPONENT &&
+           icalcomponent_get_first_component (pcd->icalcomp, pcd->kind) != NULL) {
+               icalcomponent *subcomp;
+
+               for (subcomp = icalcomponent_get_first_component (pcd->icalcomp, ICAL_VTIMEZONE_COMPONENT);
+                    subcomp && !g_cancellable_is_cancelled (cancellable);
+                    subcomp = icalcomponent_get_next_component (pcd->icalcomp, ICAL_VTIMEZONE_COMPONENT)) {
+                       icaltimezone *zone;
+
+                       zone = icaltimezone_new ();
+                       icaltimezone_set_component (zone, subcomp);
+                       if (!e_cal_client_add_timezone_sync (cal_client, zone, cancellable, error)) {
+                               icaltimezone_free (zone, 1);
+                               success = FALSE;
+                               break;
+                       }
+
+                       icaltimezone_free (zone, 1);
+               }
+
+               for (subcomp = icalcomponent_get_first_component (pcd->icalcomp, pcd->kind);
+                    subcomp && !g_cancellable_is_cancelled (cancellable) && success;
+                    subcomp = icalcomponent_get_next_component (pcd->icalcomp, pcd->kind)) {
+                       if (!cal_ops_create_comp_with_new_uid_sync (cal_client, subcomp, cancellable, error)) 
{
+                               success = FALSE;
+                               break;
+                       }
+
+                       any_copied = TRUE;
+               }
+       } else if (icalcomponent_isa (pcd->icalcomp) == pcd->kind) {
+               success = cal_ops_create_comp_with_new_uid_sync (cal_client, pcd->icalcomp, cancellable, 
error);
+               any_copied = success;
+       }
+
+       pcd->success = success && any_copied;
+
+       g_object_unref (client);
+}
+
+/**
+ * e_cal_ops_paste_components:
+ * @model: an #ECalModel
+ * @icalcompstr: a string representation of an iCalendar component
+ *
+ * Pastes components into the default source of the @model.
+ *
+ * Since: 3.14
+ **/
+void
+e_cal_ops_paste_components (ECalModel *model,
+                           const gchar *icalcompstr)
+{
+       ECalDataModel *data_model;
+       icalcomponent *icalcomp;
+       icalcomponent_kind kind;
+       gint ncomponents = 0;
+       GCancellable *cancellable;
+       const gchar *alert_ident;
+       const gchar *extension_name;
+       gchar *description;
+       PasteComponentsData *pcd;
+
+       g_return_if_fail (E_IS_CAL_MODEL (model));
+       g_return_if_fail (icalcompstr != NULL);
+
+       icalcomp = icalparser_parse_string (icalcompstr);
+       if (!icalcomp)
+               return;
+
+       kind = icalcomponent_isa (icalcomp);
+       if (kind != ICAL_VCALENDAR_COMPONENT &&
+           kind != e_cal_model_get_component_kind (model)) {
+               icalcomponent_free (icalcomp);
+               return;
+       }
+
+       switch (e_cal_model_get_component_kind (model)) {
+               case ICAL_VEVENT_COMPONENT:
+                       if (kind == ICAL_VCALENDAR_COMPONENT) {
+                               kind = ICAL_VEVENT_COMPONENT;
+                               ncomponents = icalcomponent_count_components (icalcomp, kind);
+                       } else if (kind == ICAL_VEVENT_COMPONENT) {
+                               ncomponents = 1;
+                       }
+
+                       if (ncomponents == 0)
+                               break;
+
+                       description = g_strdup_printf (ngettext ("Pasting an event", "Pasting %d events", 
ncomponents), ncomponents);
+                       alert_ident = "calendar:failed-create-event";
+                       extension_name = E_SOURCE_EXTENSION_CALENDAR;
+                       break;
+               case ICAL_VJOURNAL_COMPONENT:
+                       if (kind == ICAL_VCALENDAR_COMPONENT) {
+                               kind = ICAL_VJOURNAL_COMPONENT;
+                               ncomponents = icalcomponent_count_components (icalcomp, kind);
+                       } else if (kind == ICAL_VJOURNAL_COMPONENT) {
+                               ncomponents = 1;
+                       }
+
+                       if (ncomponents == 0)
+                               break;
+
+                       description = g_strdup_printf (ngettext ("Pasting a memo", "Pasting %d memos", 
ncomponents), ncomponents);
+                       alert_ident = "calendar:failed-create-memo";
+                       extension_name = E_SOURCE_EXTENSION_MEMO_LIST;
+                       break;
+               case ICAL_VTODO_COMPONENT:
+                       if (kind == ICAL_VCALENDAR_COMPONENT) {
+                               kind = ICAL_VTODO_COMPONENT;
+                               ncomponents = icalcomponent_count_components (icalcomp, kind);
+                       } else if (kind == ICAL_VTODO_COMPONENT) {
+                               ncomponents = 1;
+                       }
+
+                       if (ncomponents == 0)
+                               break;
+
+                       description = g_strdup_printf (ngettext ("Pasting a task", "Pasting %d tasks", 
ncomponents), ncomponents);
+                       alert_ident = "calendar:failed-create-task";
+                       extension_name = E_SOURCE_EXTENSION_TASK_LIST;
+                       break;
+               default:
+                       g_warn_if_reached ();
+                       break;
+       }
+
+       if (ncomponents == 0) {
+               icalcomponent_free (icalcomp);
+               return;
+       }
+
+       pcd = g_new0 (PasteComponentsData, 1);
+       pcd->model = g_object_ref (model);
+       pcd->icalcomp = icalcomp;
+       pcd->kind = kind;
+       pcd->extension_name = extension_name;
+       pcd->success = FALSE;
+
+       data_model = e_cal_model_get_data_model (model);
+
+       cancellable = e_cal_data_model_submit_thread_job (data_model, description, alert_ident,
+               NULL, cal_ops_update_components_thread, pcd, paste_components_data_free);
+
+       g_clear_object (&cancellable);
+       g_free (description);
+}
+
+typedef struct
+{
+       ECalClient *client;
+       icalcomponent *icalcomp;
+} SendComponentData;
+
+static void
+send_component_data_free (gpointer ptr)
+{
+       SendComponentData *scd = ptr;
+
+       if (scd) {
+               g_clear_object (&scd->client);
+               icalcomponent_free (scd->icalcomp);
+               g_free (scd);
+       }
+}
+
+static void
+cal_ops_send_component_thread (EAlertSinkThreadJobData *job_data,
+                              gpointer user_data,
+                              GCancellable *cancellable,
+                              GError **error)
+{
+       SendComponentData *scd = user_data;
+       icalcomponent *mod_comp = NULL;
+       GSList *users = NULL;
+
+       g_return_if_fail (scd != NULL);
+
+       e_cal_client_send_objects_sync (scd->client, scd->icalcomp,
+               &users, &mod_comp, cancellable, error);
+
+       if (mod_comp)
+               icalcomponent_free (mod_comp);
+
+       g_slist_free_full (users, g_free);
+}
+
+/**
+ * e_cal_ops_send_component:
+ * @model: an #ECalModel
+ * @client: an #ECalClient
+ * @icalcomp: an #icalcomponent
+ *
+ * Sends (calls e_cal_client_send_objects_sync()) on the given @client
+ * with the given @icalcomp in a dedicated thread.
+ *
+ * Since: 3.14
+ **/
+void
+e_cal_ops_send_component (ECalModel *model,
+                         ECalClient *client,
+                         icalcomponent *icalcomp)
+{
+       ECalDataModel *data_model;
+       ESource *source;
+       GCancellable *cancellable;
+       const gchar *alert_ident;
+       const gchar *description;
+       SendComponentData *scd;
+
+       g_return_if_fail (E_IS_CAL_MODEL (model));
+       g_return_if_fail (E_IS_CAL_CLIENT (client));
+       g_return_if_fail (icalcomp != NULL);
+
+       switch (e_cal_client_get_source_type (client)) {
+               case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+                       description = _("Updating an event");
+                       alert_ident = "calendar:failed-update-event";
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+                       description = _("Updating a memo");
+                       alert_ident = "calendar:failed-update-memo";
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+                       description = _("Updating a task");
+                       alert_ident = "calendar:failed-update-task";
+                       break;
+               default:
+                       g_warn_if_reached ();
+                       return;
+       }
+
+       scd = g_new0 (SendComponentData, 1);
+       scd->client = g_object_ref (client);
+       scd->icalcomp = icalcomponent_new_clone (icalcomp);
+
+       source = e_client_get_source (E_CLIENT (client));
+       data_model = e_cal_model_get_data_model (model);
+
+       cancellable = e_cal_data_model_submit_thread_job (data_model, description, alert_ident,
+               e_source_get_display_name (source), cal_ops_send_component_thread,
+               scd, send_component_data_free);
+
+       g_clear_object (&cancellable);
+}
+
+typedef struct {
+       ECalModel *model;
+       GList *clients;
+       icalcomponent_kind kind;
+       time_t older_than;
+} PurgeComponentsData;
+
+static void
+purge_components_data_free (gpointer ptr)
+{
+       PurgeComponentsData *pcd = ptr;
+
+       if (pcd) {
+               g_clear_object (&pcd->model);
+               g_list_free_full (pcd->clients, g_object_unref);
+               g_free (pcd);
+       }
+}
+
+struct purge_data {
+       GList *clients;
+       gboolean remove;
+       time_t older_than;
+};
+
+static gboolean
+ca_ops_purge_check_instance_cb (ECalComponent *comp,
+                               time_t instance_start,
+                               time_t instance_end,
+                               gpointer data)
+{
+       struct purge_data *pd = data;
+
+       if (instance_end >= pd->older_than)
+               pd->remove = FALSE;
+
+       return pd->remove;
+}
+
+static void
+cal_ops_purge_components_thread (EAlertSinkThreadJobData *job_data,
+                                gpointer user_data,
+                                GCancellable *cancellable,
+                                GError **error)
+{
+       PurgeComponentsData *pcd = user_data;
+       GList *clink;
+       gchar *sexp, *start, *end;
+       gboolean pushed_message = FALSE;
+       const gchar *display_name, *tzloc = NULL;
+       icaltimezone *zone;
+       icalcomponent_kind model_kind;
+
+       g_return_if_fail (pcd != NULL);
+
+       model_kind = e_cal_model_get_component_kind (pcd->model);
+       zone = e_cal_model_get_timezone (pcd->model);
+       if (zone && zone != icaltimezone_get_utc_timezone ())
+               tzloc = icaltimezone_get_location (zone);
+
+       start = isodate_from_time_t (0);
+       end = isodate_from_time_t (pcd->older_than);
+       sexp = g_strdup_printf (
+               "(occur-in-time-range? (make-time \"%s\") (make-time \"%s\") \"%s\")",
+               start, end, tzloc ? tzloc : "");
+       g_free (start);
+       g_free (end);
+
+       for (clink = pcd->clients; clink && !g_cancellable_is_cancelled (cancellable); clink = g_list_next 
(clink)) {
+               ECalClient *client = clink->data;
+               GSList *objects, *olink;
+               gint nobjects, ii, last_percent = 0;
+               gboolean success = TRUE;
+
+               if (!client || e_client_is_readonly (E_CLIENT (client)))
+                       continue;
+
+               display_name = e_source_get_display_name (e_client_get_source (E_CLIENT (client)));
+               e_alert_sink_thread_job_set_alert_arg_0 (job_data, display_name);
+
+               switch (model_kind) {
+                       case ICAL_VEVENT_COMPONENT:
+                               camel_operation_push_message (cancellable,
+                                       _("Getting events to purge in the calendar '%s'"), display_name);
+                               break;
+                       case ICAL_VJOURNAL_COMPONENT:
+                               camel_operation_push_message (cancellable,
+                                       _("Getting memos to purge in the memo list '%s'"), display_name);
+                               break;
+                       case ICAL_VTODO_COMPONENT:
+                               camel_operation_push_message (cancellable,
+                                       _("Getting tasks to purge in the task list '%s'"), display_name);
+                               break;
+                       default:
+                               g_warn_if_reached ();
+                               return;
+               }
+
+               pushed_message = TRUE;
+
+               if (!e_cal_client_get_object_list_sync (client, sexp, &objects, cancellable, error))
+                       break;
+
+               camel_operation_pop_message (cancellable);
+               pushed_message = FALSE;
+
+               if (!objects)
+                       continue;
+
+               switch (model_kind) {
+                       case ICAL_VEVENT_COMPONENT:
+                               camel_operation_push_message (cancellable,
+                                       _("Purging events in the calendar '%s'"), display_name);
+                               break;
+                       case ICAL_VJOURNAL_COMPONENT:
+                               camel_operation_push_message (cancellable,
+                                       _("Purging memos in the memo list '%s'"), display_name);
+                               break;
+                       case ICAL_VTODO_COMPONENT:
+                               camel_operation_push_message (cancellable,
+                                       _("Purging tasks in the task list '%s'"), display_name);
+                               break;
+                       default:
+                               g_warn_if_reached ();
+                               return;
+               }
+
+               pushed_message = TRUE;
+               nobjects = g_slist_length (objects);
+
+               for (olink = objects, ii = 0; olink; olink = g_slist_next (olink), ii++) {
+                       icalcomponent *icalcomp = olink->data;
+                       gboolean remove = TRUE;
+                       gint percent = 100 * (ii + 1) / nobjects;
+
+                       if (!e_cal_client_check_recurrences_no_master (client)) {
+                               struct purge_data pd;
+
+                               pd.remove = TRUE;
+                               pd.older_than = pcd->older_than;
+
+                               e_cal_client_generate_instances_for_object_sync (client, icalcomp,
+                                       pcd->older_than, G_MAXINT32, ca_ops_purge_check_instance_cb, &pd);
+
+                               remove = pd.remove;
+                       }
+
+                       if (remove) {
+                               const gchar *uid = icalcomponent_get_uid (icalcomp);
+
+                               if (e_cal_util_component_is_instance (icalcomp) ||
+                                   e_cal_util_component_has_recurrences (icalcomp)) {
+                                       gchar *rid = NULL;
+                                       struct icaltimetype recur_id;
+
+                                       recur_id = icalcomponent_get_recurrenceid (icalcomp);
+
+                                       if (!icaltime_is_null_time (recur_id))
+                                               rid = icaltime_as_ical_string_r (recur_id);
+
+                                       success = e_cal_client_remove_object_sync (client, uid, rid, 
E_CAL_OBJ_MOD_ALL, cancellable, error);
+
+                                       g_free (rid);
+                               } else {
+                                       success = e_cal_client_remove_object_sync (client, uid, NULL, 
E_CAL_OBJ_MOD_THIS, cancellable, error);
+                               }
+
+                               if (!success)
+                                       break;
+                       }
+
+                       if (percent != last_percent) {
+                               camel_operation_progress (cancellable, percent);
+                               last_percent = percent;
+                       }
+               }
+
+               g_slist_foreach (objects, (GFunc) icalcomponent_free, NULL);
+               g_slist_free (objects);
+
+               camel_operation_progress (cancellable, 0);
+               camel_operation_pop_message (cancellable);
+               pushed_message = FALSE;
+
+               if (!success)
+                       break;
+       }
+
+       if (pushed_message)
+               camel_operation_pop_message (cancellable);
+
+       g_free (sexp);
+}
+
+/**
+ * e_cal_ops_purge_components:
+ * @model: an #ECalModel instance
+ * @older_than: threshold for the purge operation
+ *
+ * Purges (removed) all components older than @older_than from all
+ * currently active clients in @model.
+ *
+ * Since: 3.14
+ **/
+void
+e_cal_ops_purge_components (ECalModel *model,
+                           time_t older_than)
+{
+       ECalDataModel *data_model;
+       GCancellable *cancellable;
+       const gchar *alert_ident;
+       const gchar *description;
+       PurgeComponentsData *pcd;
+
+       g_return_if_fail (E_IS_CAL_MODEL (model));
+
+       switch (e_cal_model_get_component_kind (model)) {
+               case ICAL_VEVENT_COMPONENT:
+                       description = _("Purging events");
+                       alert_ident = "calendar:failed-remove-event";
+                       break;
+               case ICAL_VJOURNAL_COMPONENT:
+                       description = _("Purging memos");
+                       alert_ident = "calendar:failed-remove-memo";
+                       break;
+               case ICAL_VTODO_COMPONENT:
+                       description = _("Purging tasks");
+                       alert_ident = "calendar:failed-remove-task";
+                       break;
+               default:
+                       g_warn_if_reached ();
+                       return;
+       }
+
+       data_model = e_cal_model_get_data_model (model);
+
+       pcd = g_new0 (PurgeComponentsData, 1);
+       pcd->model = g_object_ref (model);
+       pcd->clients = e_cal_data_model_get_clients (data_model);
+       pcd->kind = e_cal_model_get_component_kind (model);
+       pcd->older_than = older_than;
+
+       cancellable = e_cal_data_model_submit_thread_job (data_model, description, alert_ident,
+               NULL, cal_ops_purge_components_thread,
+               pcd, purge_components_data_free);
+
+       g_clear_object (&cancellable);
+}
+
+static void
+clients_list_free (gpointer ptr)
+{
+       g_list_free_full (ptr, g_object_unref);
+}
+
+static void
+cal_ops_delete_completed_thread (EAlertSinkThreadJobData *job_data,
+                                gpointer user_data,
+                                GCancellable *cancellable,
+                                GError **error)
+{
+       GList *clients = user_data, *link;
+
+       for (link = clients; link; link = g_list_next (link)) {
+               ECalClient *client = link->data;
+               GSList *objects = NULL, *olink;
+
+               if (!client ||
+                   e_client_is_readonly (E_CLIENT (client)))
+                       continue;
+
+               if (!e_cal_client_get_object_list_sync (client, "(is-completed?)", &objects, cancellable, 
error)) {
+                       ESource *source = e_client_get_source (E_CLIENT (client));
+                       e_alert_sink_thread_job_set_alert_arg_0 (job_data, e_source_get_display_name 
(source));
+                       break;
+               }
+
+               for (olink = objects; olink != NULL; olink = g_slist_next (olink)) {
+                       icalcomponent *icalcomp = olink->data;
+                       const gchar *uid;
+
+                       uid = icalcomponent_get_uid (icalcomp);
+
+                       if (!e_cal_client_remove_object_sync (client, uid, NULL, CALOBJ_MOD_THIS, 
cancellable, error)) {
+                               ESource *source = e_client_get_source (E_CLIENT (client));
+                               e_alert_sink_thread_job_set_alert_arg_0 (job_data, e_source_get_display_name 
(source));
+                               break;
+                       }
+               }
+
+               e_cal_client_free_icalcomp_slist (objects);
+
+               /* did not process all objects => an error occurred */
+               if (olink != NULL)
+                       break;
+       }
+}
+
+/**
+ * e_cal_ops_delete_completed_tasks:
+ * @model: an #ECalModel
+ *
+ * Deletes all completed tasks from all currently opened
+ * clients in @model.
+ *
+ * Since: 3.14
+ **/
+void
+e_cal_ops_delete_completed_tasks (ECalModel *model)
+{
+       ECalDataModel *data_model;
+       GCancellable *cancellable;
+       GList *clients;
+
+       g_return_if_fail (E_IS_CAL_MODEL (model));
+
+       data_model = e_cal_model_get_data_model (model);
+       clients = e_cal_data_model_get_clients (data_model);
+
+       if (!clients)
+               return;
+
+       if (e_cal_client_get_source_type (clients->data) != E_CAL_CLIENT_SOURCE_TYPE_TASKS) {
+               g_list_free_full (clients, g_object_unref);
+               g_warn_if_reached ();
+               return;
+       }
+
+       cancellable = e_cal_data_model_submit_thread_job (data_model, _("Expunging completed tasks"),
+               "calendar:failed-remove-task", NULL, cal_ops_delete_completed_thread,
+               clients, clients_list_free);
+
+       g_clear_object (&cancellable);
+}
+
+static ECalClient *
+cal_ops_open_client_sync (EAlertSinkThreadJobData *job_data,
+                         EShell *shell,
+                         const gchar *client_uid,
+                         const gchar *extension_name,
+                         GCancellable *cancellable,
+                         GError **error)
+{
+       ECalClient *cal_client = NULL;
+       ESourceRegistry *registry;
+       EClientCache *client_cache;
+       ESource *source;
+       EClient *client;
+
+       g_return_val_if_fail (E_IS_SHELL (shell), NULL);
+       g_return_val_if_fail (client_uid != NULL, NULL);
+       g_return_val_if_fail (extension_name != NULL, NULL);
+
+       registry = e_shell_get_registry (shell);
+       client_cache = e_shell_get_client_cache (shell);
+
+       source = e_source_registry_ref_source (registry, client_uid);
+       if (!source) {
+               g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+                       _("Source with UID '%s' not found"), client_uid);
+               e_alert_sink_thread_job_set_alert_arg_0 (job_data, client_uid);
+       } else {
+               client = e_client_cache_get_client_sync (client_cache, source, extension_name, cancellable, 
error);
+               if (client)
+                       cal_client = E_CAL_CLIENT (client);
+       }
+
+       g_clear_object (&source);
+
+       return cal_client;
+}
+
+static void
+cal_ops_get_default_component_thread (EAlertSinkThreadJobData *job_data,
+                                     gpointer user_data,
+                                     GCancellable *cancellable,
+                                     GError **error)
+{
+       BasicOperationData *bod = user_data;
+
+       g_return_if_fail (bod != NULL);
+
+       if (!bod->for_client_uid) {
+               ESourceRegistry *registry;
+               ESource *default_source = NULL;
+
+               registry = e_cal_model_get_registry (bod->model);
+
+               switch (e_cal_model_get_component_kind (bod->model)) {
+                       case ICAL_VEVENT_COMPONENT:
+                               default_source = e_source_registry_ref_default_calendar (registry);
+                               break;
+                       case ICAL_VJOURNAL_COMPONENT:
+                               default_source = e_source_registry_ref_default_memo_list (registry);
+                               break;
+                       case ICAL_VTODO_COMPONENT:
+                               default_source = e_source_registry_ref_default_task_list (registry);
+                               break;
+                       default:
+                               g_warn_if_reached ();
+                               return;
+               }
+
+               if (default_source)
+                       bod->for_client_uid = g_strdup (e_source_get_uid (default_source));
+
+               g_clear_object (&default_source);
+       }
+
+       if (bod->for_client_uid) {
+               const gchar *extension_name = NULL;
+
+               switch (e_cal_model_get_component_kind (bod->model)) {
+                       case ICAL_VEVENT_COMPONENT:
+                               extension_name = E_SOURCE_EXTENSION_CALENDAR;
+                               break;
+                       case ICAL_VJOURNAL_COMPONENT:
+                               extension_name = E_SOURCE_EXTENSION_MEMO_LIST;
+                               break;
+                       case ICAL_VTODO_COMPONENT:
+                               extension_name = E_SOURCE_EXTENSION_TASK_LIST;
+                               break;
+                       default:
+                               g_warn_if_reached ();
+                               return;
+               }
+
+               bod->client = cal_ops_open_client_sync (job_data,
+                       e_cal_model_get_shell (bod->model),
+                       bod->for_client_uid,
+                       extension_name,
+                       cancellable,
+                       error);
+       }
+
+       bod->icalcomp = e_cal_model_create_component_with_defaults_sync (bod->model, bod->client, 
bod->all_day_default_comp, cancellable, error);
+       bod->success = bod->icalcomp != NULL && !g_cancellable_is_cancelled (cancellable);
+}
+
+/**
+ * e_cal_ops_get_default_component:
+ * @model: an #ECalModel
+ * @for_client_uid: (allow none): a client UID to use for the new component; can be #NULL
+ * @all_day: whether the default event should be an all day event; this argument
+ *    is ignored for other than event @model-s
+ * @callback: a callback to be called when the operation succeeded
+ * @user_data: user data passed to @callback
+ * @user_data_free: (allow none): a function to free @user_data, or #NULL
+ *
+ * Creates a new component with default values as defined by the @client,
+ * or by the @model, if @client is #NULL. The @callback is called on success.
+ * The @callback is called in the main thread.
+ *
+ * Since: 3.14
+ **/
+void
+e_cal_ops_get_default_component (ECalModel *model,
+                                const gchar *for_client_uid,
+                                gboolean all_day,
+                                ECalOpsGetDefaultComponentFunc callback,
+                                gpointer user_data,
+                                GDestroyNotify user_data_free)
+{
+       ECalDataModel *data_model;
+       ESource *source = NULL;
+       const gchar *description;
+       const gchar *alert_ident;
+       BasicOperationData *bod;
+       GCancellable *cancellable;
+
+       g_return_if_fail (E_IS_CAL_MODEL (model));
+       g_return_if_fail (callback != NULL);
+
+       switch (e_cal_model_get_component_kind (model)) {
+               case ICAL_VEVENT_COMPONENT:
+                       description = _("Creating an event");
+                       alert_ident = "calendar:failed-create-event";
+                       break;
+               case ICAL_VJOURNAL_COMPONENT:
+                       description = _("Creating a memo");
+                       alert_ident = "calendar:failed-create-memo";
+                       break;
+               case ICAL_VTODO_COMPONENT:
+                       description = _("Creating a task");
+                       alert_ident = "calendar:failed-create-task";
+                       break;
+               default:
+                       g_warn_if_reached ();
+                       return;
+       }
+
+       data_model = e_cal_model_get_data_model (model);
+       if (for_client_uid) {
+               ESourceRegistry *registry;
+
+               registry = e_cal_model_get_registry (model);
+               source = e_source_registry_ref_source (registry, for_client_uid);
+       }
+
+       bod = g_new0 (BasicOperationData, 1);
+       bod->model = g_object_ref (model);
+       bod->client = NULL;
+       bod->icalcomp = NULL;
+       bod->for_client_uid = g_strdup (for_client_uid);
+       bod->all_day_default_comp = all_day;
+       bod->get_default_comp_cb = callback;
+       bod->user_data = user_data;
+       bod->user_data_free = user_data_free;
+
+       cancellable = e_cal_data_model_submit_thread_job (data_model, description, alert_ident,
+               source ? e_source_get_display_name (source) : "", cal_ops_get_default_component_thread,
+               bod, basic_operation_data_free);
+
+       g_clear_object (&cancellable);
+       g_clear_object (&source);
+}
+
+static void
+cal_ops_emit_model_object_created (CompEditor *editor,
+                                  ECalModel *model)
+{
+       g_return_if_fail (IS_COMP_EDITOR (editor));
+       g_return_if_fail (E_IS_CAL_MODEL (model));
+
+       e_cal_model_emit_object_created (model, comp_editor_get_client (editor));
+}
+
+typedef struct
+{
+       gboolean is_new_component;
+       EShell *shell;
+       ECalModel *model;
+       ECalClientSourceType source_type;
+       gboolean is_assigned;
+       gchar *extension_name;
+       gchar *for_client_uid;
+       ESource *default_source;
+       ECalClient *client;
+       ECalComponent *comp;
+
+       /* for events only */
+       time_t dtstart;
+       time_t dtend;
+       gboolean all_day;
+       gboolean use_default_reminder;
+       gint default_reminder_interval;
+       EDurationType default_reminder_units;
+} NewComponentData;
+
+static void
+new_component_data_free (gpointer ptr)
+{
+       NewComponentData *ncd = ptr;
+
+       if (ncd) {
+               /* successfully opened the default client */
+               if (ncd->client && ncd->comp) {
+                       CompEditor *editor = NULL;
+                       CompEditorFlags flags = 0;
+
+                       if (ncd->is_new_component) {
+                               flags |= COMP_EDITOR_NEW_ITEM;
+
+                               if (ncd->source_type == E_CAL_CLIENT_SOURCE_TYPE_EVENTS)
+                                       flags |= COMP_EDITOR_USER_ORG;
+                       } else {
+                               if (e_cal_component_has_attendees (ncd->comp))
+                                       ncd->is_assigned = TRUE;
+
+                               if (ncd->is_assigned && e_cal_component_has_organizer (ncd->comp)) {
+                                       ESourceRegistry *registry;
+
+                                       registry = e_cal_model_get_registry (ncd->model);
+                                       if (itip_organizer_is_user (registry, ncd->comp, ncd->client))
+                                               flags |= COMP_EDITOR_USER_ORG;
+
+                                       if (ncd->source_type == E_CAL_CLIENT_SOURCE_TYPE_EVENTS &&
+                                           (flags & COMP_EDITOR_USER_ORG) == 0 &&
+                                           itip_sentby_is_user (registry, ncd->comp, ncd->client))
+                                               flags |= COMP_EDITOR_USER_ORG;
+                               } else {
+                                       flags |= COMP_EDITOR_USER_ORG;
+                               }
+                       }
+
+                       if (ncd->is_assigned) {
+                               if (ncd->is_new_component)
+                                       flags |= COMP_EDITOR_USER_ORG;
+
+                               if (ncd->source_type == E_CAL_CLIENT_SOURCE_TYPE_EVENTS)
+                                       flags |= COMP_EDITOR_MEETING;
+                               else if (ncd->source_type == E_CAL_CLIENT_SOURCE_TYPE_MEMOS)
+                                       flags |= COMP_EDITOR_IS_SHARED;
+                               else if (ncd->source_type == E_CAL_CLIENT_SOURCE_TYPE_TASKS)
+                                       flags |= COMP_EDITOR_IS_ASSIGNED;
+                       }
+
+                       switch (ncd->source_type) {
+                               case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+                                       editor = event_editor_new (ncd->client, ncd->shell, flags);
+                                       if (ncd->is_new_component && ncd->model && ncd->dtstart > 0 && 
ncd->dtend > 0) {
+                                               ECalComponentDateTime dt;
+                                               struct icaltimetype itt;
+                                               icaltimezone *zone;
+
+                                               zone = e_cal_model_get_timezone (ncd->model);
+
+                                               dt.value = &itt;
+                                               if (ncd->all_day)
+                                                       dt.tzid = NULL;
+                                               else
+                                                       dt.tzid = icaltimezone_get_tzid (zone);
+
+                                               itt = icaltime_from_timet_with_zone (ncd->dtstart, FALSE, 
zone);
+                                               if (ncd->all_day) {
+                                                       itt.hour = itt.minute = itt.second = 0;
+                                                       itt.is_date = TRUE;
+                                               }
+                                               e_cal_component_set_dtstart (ncd->comp, &dt);
+
+                                               itt = icaltime_from_timet_with_zone (ncd->dtend, FALSE, zone);
+                                               if (ncd->all_day) {
+                                                       /* We round it up to the end of the day, unless it is
+                                                        * already set to midnight */
+                                                       if (itt.hour != 0 || itt.minute != 0 || itt.second != 
0) {
+                                                               icaltime_adjust (&itt, 1, 0, 0, 0);
+                                                       }
+                                                       itt.hour = itt.minute = itt.second = 0;
+                                                       itt.is_date = TRUE;
+                                               }
+                                               e_cal_component_set_dtend (ncd->comp, &dt);
+                                       }
+                                       e_cal_component_commit_sequence (ncd->comp);
+                                       break;
+                               case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+                                       editor = memo_editor_new (ncd->client, ncd->shell, flags);
+                                       break;
+                               case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+                                       editor = task_editor_new (ncd->client, ncd->shell, flags);
+                                       break;
+                               default:
+                                       g_warn_if_reached ();
+                                       break;
+                       }
+
+                       if (editor) {
+                               g_signal_connect (editor, "object-created",
+                                       G_CALLBACK (cal_ops_emit_model_object_created), ncd->model);
+
+                               g_object_set_data_full (G_OBJECT (editor), "e-cal-ops-model", g_object_ref 
(ncd->model), g_object_unref);
+
+                               comp_editor_edit_comp (editor, ncd->comp);
+                               gtk_window_present (GTK_WINDOW (editor));
+                       }
+               }
+
+               g_clear_object (&ncd->shell);
+               g_clear_object (&ncd->model);
+               g_clear_object (&ncd->default_source);
+               g_clear_object (&ncd->client);
+               g_clear_object (&ncd->comp);
+               g_free (ncd->extension_name);
+               g_free (ncd->for_client_uid);
+               g_free (ncd);
+       }
+}
+
+static void
+cal_ops_new_component_editor_thread (EAlertSinkThreadJobData *job_data,
+                                    gpointer user_data,
+                                    GCancellable *cancellable,
+                                    GError **error)
+{
+       NewComponentData *ncd = user_data;
+       GError *local_error = NULL;
+
+       g_return_if_fail (ncd != NULL);
+
+       if (ncd->for_client_uid) {
+               ncd->client = cal_ops_open_client_sync (job_data, ncd->shell, ncd->for_client_uid,
+                       ncd->extension_name, cancellable, &local_error);
+       }
+
+       if (!ncd->default_source && !ncd->client && !ncd->for_client_uid) {
+               const gchar *message;
+
+               switch (ncd->source_type) {
+                       case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+                               message = _("Default calendar not found");
+                               break;
+                       case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+                               message = _("Default memo list not found");
+                               break;
+                       case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+                               message = _("Default task list not found");
+                               break;
+                       default:
+                               g_warn_if_reached ();
+                               return;
+               }
+
+               g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, message);
+               return;
+       }
+
+       if (!ncd->client && !ncd->for_client_uid) {
+               EClient *client;
+               EClientCache *client_cache;
+
+               client_cache = e_shell_get_client_cache (ncd->shell);
+
+               client = e_client_cache_get_client_sync (client_cache, ncd->default_source, 
ncd->extension_name, cancellable, &local_error);
+               if (client)
+                       ncd->client = E_CAL_CLIENT (client);
+       }
+
+       if (ncd->client) {
+               switch (ncd->source_type) {
+                       case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+                               ncd->comp = cal_comp_event_new_with_current_time_sync (ncd->client,
+                                       ncd->all_day, ncd->use_default_reminder, 
ncd->default_reminder_interval,
+                                       ncd->default_reminder_units, cancellable, &local_error);
+                               break;
+                       case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+                               ncd->comp = cal_comp_memo_new_with_defaults_sync (ncd->client, cancellable, 
&local_error);
+                               break;
+                       case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+                               ncd->comp = cal_comp_task_new_with_defaults_sync (ncd->client, cancellable, 
&local_error);
+                               break;
+                       default:
+                               g_warn_if_reached ();
+                               return;
+               }
+       }
+
+       e_util_propagate_open_source_job_error (job_data, ncd->extension_name, local_error, error);
+}
+
+static void
+e_cal_ops_new_component_ex (EShellWindow *shell_window,
+                           ECalModel *model,
+                           ECalClientSourceType source_type,
+                           const gchar *for_client_uid,
+                           gboolean is_assigned,
+                           gboolean all_day,
+                           time_t dtstart,
+                           time_t dtend,
+                           gboolean use_default_reminder,
+                           gint default_reminder_interval,
+                           EDurationType default_reminder_units)
+{
+       ESourceRegistry *registry;
+       ESource *default_source, *for_client_source = NULL;
+       EShell *shell;
+       gchar *description = NULL, *alert_ident = NULL, *alert_arg_0 = NULL;
+       const gchar *source_display_name = ""; /* not NULL intentionally */
+       const gchar *extension_name;
+       NewComponentData *ncd;
+
+       if (shell_window) {
+               g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
+
+               shell = e_shell_window_get_shell (shell_window);
+       } else {
+               g_return_if_fail (E_IS_CAL_MODEL (model));
+
+               shell = e_cal_model_get_shell (model);
+       }
+
+       registry = e_shell_get_registry (shell);
+
+       switch (source_type) {
+               case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+                       extension_name = E_SOURCE_EXTENSION_CALENDAR;
+                       default_source = e_source_registry_ref_default_calendar (registry);
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+                       extension_name = E_SOURCE_EXTENSION_MEMO_LIST;
+                       default_source = e_source_registry_ref_default_memo_list (registry);
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+                       extension_name = E_SOURCE_EXTENSION_TASK_LIST;
+                       default_source = e_source_registry_ref_default_task_list (registry);
+                       break;
+               default:
+                       g_warn_if_reached ();
+                       return;
+       }
+
+       if (for_client_uid)
+               for_client_source = e_source_registry_ref_source (registry, for_client_uid);
+
+       ncd = g_new0 (NewComponentData, 1);
+       ncd->is_new_component = TRUE;
+       ncd->shell = g_object_ref (shell);
+       ncd->model = model ? g_object_ref (model) : NULL;
+       ncd->source_type = source_type;
+       ncd->for_client_uid = g_strdup (for_client_uid);
+       ncd->is_assigned = is_assigned;
+       ncd->extension_name = g_strdup (extension_name);
+       ncd->default_source = default_source ? g_object_ref (default_source) : NULL;
+       ncd->client = NULL;
+       ncd->comp = NULL;
+       ncd->dtstart = dtstart;
+       ncd->dtend = dtend;
+       ncd->all_day = all_day;
+       ncd->use_default_reminder = use_default_reminder;
+       ncd->default_reminder_interval = default_reminder_interval;
+       ncd->default_reminder_units = default_reminder_units;
+
+       if (for_client_source)
+               source_display_name = e_source_get_display_name (for_client_source);
+       else if (default_source)
+               source_display_name = e_source_get_display_name (default_source);
+
+       g_warn_if_fail (e_util_get_open_source_job_info (extension_name,
+               source_display_name, &description, &alert_ident, &alert_arg_0));
+
+       if (shell_window) {
+               EShellView *shell_view;
+               EActivity *activity;
+
+               shell_view = e_shell_window_get_shell_view (shell_window,
+                       e_shell_window_get_active_view (shell_window));
+
+               activity = e_shell_view_submit_thread_job (
+                       shell_view, description, alert_ident, alert_arg_0,
+                       cal_ops_new_component_editor_thread, ncd, new_component_data_free);
+
+               g_clear_object (&activity);
+       } else {
+               GCancellable *cancellable;
+               ECalDataModel *data_model;
+
+               data_model = e_cal_model_get_data_model (model);
+
+               cancellable = e_cal_data_model_submit_thread_job (data_model, description, alert_ident, 
alert_arg_0,
+                       cal_ops_new_component_editor_thread, ncd, new_component_data_free);
+
+               g_clear_object (&cancellable);
+       }
+
+       g_clear_object (&default_source);
+       g_clear_object (&for_client_source);
+       g_free (description);
+       g_free (alert_ident);
+       g_free (alert_arg_0);
+}
+
+/**
+ * e_cal_ops_new_component_editor:
+ * @shell_window: an #EShellWindow
+ * @source_type: a source type of the new component
+ * @for_client_uid: (allow none): a client UID to use for the new component; can be #NULL
+ * @is_assigned: whether the new component should be assigned
+ *
+ * Creates a new component either for an #ECalClient with UID @for_client_uid, or
+ * for a default source of the @source_type, with prefilled values as provided
+ * by the #ECalClient. Use e_cal_ops_new_event_editor() for events with
+ * predefined alarms.
+ *
+ * Since: 3.14
+ **/
+void
+e_cal_ops_new_component_editor (EShellWindow *shell_window,
+                               ECalClientSourceType source_type,
+                               const gchar *for_client_uid,
+                               gboolean is_assigned)
+{
+       e_cal_ops_new_component_ex (shell_window, NULL, source_type, for_client_uid, is_assigned, FALSE, 0, 
0, FALSE, 0, E_DURATION_MINUTES);
+}
+
+/**
+ * e_cal_ops_new_event_editor:
+ * @shell_window: an #EShellWindow
+ * @source_type: a source type of the new component
+ * @for_client_uid: (allow none): a client UID to use for the new component; can be #NULL
+ * @is_meeting: whether the new event should be a meeting
+ * @all_day: whether the new event should be an all day event
+ * @use_default_reminder: whether a default reminder should be added,
+ *    if #FALSE, then the next two reminded arguments are ignored
+ * @default_reminder_interval: reminder interval for the default reminder
+ * @default_reminder_units: reminder uints for the default reminder
+ *
+ * This is a fine-grained version of e_cal_ops_new_component_editor(), suitable
+ * for events with predefined alarms. The e_cal_ops_new_component_editor()
+ * accepts events as well.
+ *
+ * Since: 3.14
+ **/
+void
+e_cal_ops_new_event_editor (EShellWindow *shell_window,
+                           const gchar *for_client_uid,
+                           gboolean is_meeting,
+                           gboolean all_day,
+                           gboolean use_default_reminder,
+                           gint default_reminder_interval,
+                           EDurationType default_reminder_units)
+{
+       e_cal_ops_new_component_ex (shell_window, NULL, E_CAL_CLIENT_SOURCE_TYPE_EVENTS, for_client_uid, 
is_meeting,
+               all_day, 0, 0, use_default_reminder, default_reminder_interval, default_reminder_units);
+}
+
+/**
+ * e_cal_ops_new_component_editor_from_model:
+ * @model: an #ECalModel
+ * @for_client_uid: (allow none): a client UID to use for the new component; can be #NULL
+ * @dtstart: a DTSTART to use, for events; less than or equal to 0 to ignore
+ * @dtend: a DTEND to use, for events; less than or equal to 0 to ignore
+ * @is_assigned: whether the new component should be assigned
+ * @all_day: whether the new component should be an all day event
+ *
+ * Creates a new component either for an #ECalClient with UID @for_client_uid, or
+ * for a default source of the source type as defined by @model, with prefilled
+ * values as provided by the #ECalClient. The @all_day is used only for events
+ * source type.
+ *
+ * Since: 3.14
+ **/
+void
+e_cal_ops_new_component_editor_from_model (ECalModel *model,
+                                          const gchar *for_client_uid,
+                                          time_t dtstart,
+                                          time_t dtend,
+                                          gboolean is_assigned,
+                                          gboolean all_day)
+{
+       ECalClientSourceType source_type;
+
+       g_return_if_fail (E_IS_CAL_MODEL (model));
+
+       switch (e_cal_model_get_component_kind (model)) {
+               case ICAL_VEVENT_COMPONENT:
+                       source_type = E_CAL_CLIENT_SOURCE_TYPE_EVENTS;
+                       break;
+               case ICAL_VJOURNAL_COMPONENT:
+                       source_type = E_CAL_CLIENT_SOURCE_TYPE_MEMOS;
+                       break;
+               case ICAL_VTODO_COMPONENT:
+                       source_type = E_CAL_CLIENT_SOURCE_TYPE_TASKS;
+                       break;
+               default:
+                       g_warn_if_reached ();
+                       return;
+       }
+
+       if (!for_client_uid)
+               for_client_uid = e_cal_model_get_default_source_uid (model);
+
+       if (for_client_uid && !for_client_uid)
+               for_client_uid = NULL;
+
+       e_cal_ops_new_component_ex (NULL, model, source_type, for_client_uid, is_assigned, all_day, dtstart, 
dtend,
+               e_cal_model_get_use_default_reminder (model),
+               e_cal_model_get_default_reminder_interval (model),
+               e_cal_model_get_default_reminder_units (model));
+}
+
+/**
+ * e_cal_ops_open_component_in_editor_sync:
+ * @model: an #ECalModel instance
+ * @client: an #ECalClient, to which the component belongs
+ * @icalcomp: an #icalcomponent to open in an editor
+ *
+ * Opens a component @icalcomp, which belongs to a @client, in
+ * a component editor. This is done synchronously.
+ *
+ * Since: 3.14
+ **/
+void
+e_cal_ops_open_component_in_editor_sync (ECalModel *model,
+                                        ECalClient *client,
+                                        icalcomponent *icalcomp)
+{
+       NewComponentData *ncd;
+       ECalComponent *comp;
+       CompEditor *editor;
+
+       g_return_if_fail (E_IS_CAL_MODEL (model));
+       g_return_if_fail (E_IS_CAL_CLIENT (client));
+       g_return_if_fail (icalcomp != NULL);
+
+       editor = comp_editor_find_instance (icalcomponent_get_uid (icalcomp));
+       if (editor) {
+               gtk_window_present (GTK_WINDOW (editor));
+               return;
+       }
+
+       comp = e_cal_component_new_from_icalcomponent (icalcomponent_new_clone (icalcomp));
+       g_return_if_fail (comp != NULL);
+
+       ncd = g_new0 (NewComponentData, 1);
+       ncd->is_new_component = FALSE;
+       ncd->shell = g_object_ref (e_cal_model_get_shell (model));
+       ncd->model = g_object_ref (model);
+       ncd->source_type = e_cal_client_get_source_type (client);
+       ncd->is_assigned = FALSE; /* will be figured out later */
+       ncd->extension_name = NULL;
+       ncd->for_client_uid = NULL;
+       ncd->default_source = NULL;
+       ncd->client = g_object_ref (client);
+       ncd->comp = comp;
+
+       /* This opens the editor */
+       new_component_data_free (ncd);
+}
+
+typedef struct
+{
+       EShell *shell;
+       ECalModel *model;
+       ESource *destination;
+       ECalClient *destination_client;
+       ECalClientSourceType source_type;
+       GHashTable *icalcomps_by_source;
+       gboolean is_move;
+       gint nobjects;
+} TransferComponentsData;
+
+static void
+transfer_components_free_icalcomps_slist (gpointer ptr)
+{
+       GSList *icalcomps = ptr;
+
+       g_slist_free_full (icalcomps, (GDestroyNotify) icalcomponent_free);
+}
+
+static void
+transfer_components_data_free (gpointer ptr)
+{
+       TransferComponentsData *tcd = ptr;
+
+       if (tcd) {
+               if (tcd->destination_client)
+                       e_cal_model_emit_object_created (tcd->model, tcd->destination_client);
+
+               g_clear_object (&tcd->shell);
+               g_clear_object (&tcd->model);
+               g_clear_object (&tcd->destination);
+               g_clear_object (&tcd->destination_client);
+               g_hash_table_destroy (tcd->icalcomps_by_source);
+               g_free (tcd);
+       }
+}
+
+static void
+transfer_components_thread (EAlertSinkThreadJobData *job_data,
+                           gpointer user_data,
+                           GCancellable *cancellable,
+                           GError **error)
+{
+       TransferComponentsData *tcd = user_data;
+       const gchar *extension_name;
+       EClient *from_client = NULL, *to_client = NULL;
+       ECalClient *from_cal_client = NULL, *to_cal_client = NULL;
+       EClientCache *client_cache;
+       GHashTableIter iter;
+       gpointer key, value;
+       gint nobjects, ii = 0, last_percent = 0;
+       GSList *link;
+       gboolean success = TRUE;
+
+       g_return_if_fail (tcd != NULL);
+
+       switch (tcd->source_type) {
+               case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+                       extension_name = E_SOURCE_EXTENSION_CALENDAR;
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+                       extension_name = E_SOURCE_EXTENSION_MEMO_LIST;
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+                       extension_name = E_SOURCE_EXTENSION_TASK_LIST;
+                       break;
+               default:
+                       g_warn_if_reached ();
+                       return;
+       }
+
+       client_cache = e_shell_get_client_cache (tcd->shell);
+
+       to_client = e_util_open_client_sync (job_data, client_cache, extension_name, tcd->destination, 
cancellable, error);
+       if (!to_client)
+               goto out;
+
+       to_cal_client = E_CAL_CLIENT (to_client);
+
+       if (e_client_is_readonly (E_CLIENT (to_client))) {
+               g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_READ_ONLY, _("Destination is read only"));
+               goto out;
+       }
+
+       nobjects = tcd->nobjects;
+
+       g_hash_table_iter_init (&iter, tcd->icalcomps_by_source);
+       while (g_hash_table_iter_next (&iter, &key, &value)) {
+               ESource *source = key;
+               GSList *icalcomps = value;
+
+               from_client = e_util_open_client_sync (job_data, client_cache, extension_name, source, 
cancellable, error);
+               if (!from_client) {
+                       success = FALSE;
+                       goto out;
+               }
+
+               from_cal_client = E_CAL_CLIENT (from_client);
+
+               for (link = icalcomps; link && !g_cancellable_is_cancelled (cancellable); link = g_slist_next 
(link), ii++) {
+                       gint percent = 100 * (ii + 1) / nobjects;
+                       icalcomponent *icalcomp = link->data;
+
+                       if (!cal_comp_transfer_item_to_sync (from_cal_client, to_cal_client, icalcomp, 
!tcd->is_move, cancellable, error)) {
+                               success = FALSE;
+                               break;
+                       }
+
+                       if (percent != last_percent) {
+                               camel_operation_progress (cancellable, percent);
+                               last_percent = percent;
+                       }
+               }
+
+               g_clear_object (&from_client);
+       }
+
+       if (success && ii > 0)
+               tcd->destination_client = g_object_ref (to_client);
+
+ out:
+       g_clear_object (&from_client);
+       g_clear_object (&to_client);
+}
+
+/**
+ * e_cal_ops_transfer_components:
+ * @shell_view: an #EShellView
+ * @model: an #ECalModel, where to notify about created objects
+ * @source_type: a source type of the @destination and the sources
+ * @icalcomps_by_source: a hash table of #ESource to #GSList of icalcomponent to transfer
+ * @destination: a destination #ESource
+ * @icalcomps: a #GSList of icalcomponent-s to transfer
+ * @is_move: whether the transfer is move (%TRUE) or copy (%FALSE)
+ *
+ * Transfers (copies or moves, as set by @is_move) all @icalcomps from the @source
+ * to the @destination of type @source type (calendar/memo list/task list).
+ *
+ * Since: 3.14
+ **/
+void
+e_cal_ops_transfer_components (EShellView *shell_view,
+                              ECalModel *model,
+                              ECalClientSourceType source_type,
+                              GHashTable *icalcomps_by_source,
+                              ESource *destination,
+                              gboolean is_move)
+{
+       gint nobjects;
+       gchar *description;
+       const gchar *alert_ident;
+       TransferComponentsData *tcd;
+       GHashTableIter iter;
+       gpointer key, value;
+       EActivity *activity;
+
+       g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
+       g_return_if_fail (E_IS_CAL_MODEL (model));
+       g_return_if_fail (icalcomps_by_source != NULL);
+       g_return_if_fail (E_IS_SOURCE (destination));
+
+       nobjects = 0;
+       g_hash_table_iter_init (&iter, icalcomps_by_source);
+       while (g_hash_table_iter_next (&iter, &key, &value)) {
+               ESource *source = key;
+               GSList *icalcomps = value;
+
+               if (!e_source_equal (source, destination))
+                       nobjects += g_slist_length (icalcomps);
+       }
+
+       switch (source_type) {
+               case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+                       description = g_strdup_printf (is_move ?
+                               ngettext ("Moving an event", "Moving %d events", nobjects) :
+                               ngettext ("Copying an event", "Copying %d events", nobjects),
+                               nobjects);
+                       alert_ident = is_move ? "calendar:failed-move-event" : "calendar:failed-copy-event";
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+                       description = g_strdup_printf (is_move ?
+                               ngettext ("Moving an memo", "Moving %d memos", nobjects) :
+                               ngettext ("Copying an memo", "Copying %d memos", nobjects),
+                               nobjects);
+                       alert_ident = is_move ? "calendar:failed-move-memo" : "calendar:failed-copy-memo";
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+                       description = g_strdup_printf (is_move ?
+                               ngettext ("Moving an task", "Moving %d tasks", nobjects) :
+                               ngettext ("Copying an task", "Copying %d tasks", nobjects),
+                               nobjects);
+                       alert_ident = is_move ? "calendar:failed-move-task" : "calendar:failed-copy-task";
+                       break;
+               default:
+                       g_warn_if_reached ();
+                       return;
+       }
+
+       tcd = g_new0 (TransferComponentsData, 1);
+       tcd->shell = g_object_ref (e_shell_window_get_shell (e_shell_view_get_shell_window (shell_view)));
+       tcd->model = g_object_ref (model);
+       tcd->icalcomps_by_source = g_hash_table_new_full ((GHashFunc) e_source_hash, (GEqualFunc) 
e_source_equal,
+               g_object_unref, transfer_components_free_icalcomps_slist);
+       tcd->destination = g_object_ref (destination);
+       tcd->source_type = source_type;
+       tcd->is_move = is_move;
+       tcd->nobjects = nobjects;
+       tcd->destination_client = NULL;
+
+       g_hash_table_iter_init (&iter, icalcomps_by_source);
+       while (g_hash_table_iter_next (&iter, &key, &value)) {
+               ESource *source = key;
+               GSList *icalcomps = value;
+
+               if (!e_source_equal (source, destination)) {
+                       GSList *link;
+
+                       icalcomps = g_slist_copy (icalcomps);
+                       for (link = icalcomps; link; link = g_slist_next (link)) {
+                               link->data = icalcomponent_new_clone (link->data);
+                       }
+
+                       g_hash_table_insert (tcd->icalcomps_by_source, g_object_ref (source), icalcomps);
+               }
+       }
+
+       activity = e_shell_view_submit_thread_job (shell_view, description, alert_ident,
+               e_source_get_display_name (destination), transfer_components_thread, tcd,
+               transfer_components_data_free);
+
+       g_clear_object (&activity);
+       g_free (description);
+}
diff --git a/calendar/gui/e-cal-ops.h b/calendar/gui/e-cal-ops.h
new file mode 100644
index 0000000..6434144
--- /dev/null
+++ b/calendar/gui/e-cal-ops.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Milan Crha <mcrha redhat com>
+ */
+
+#ifndef E_CAL_OPS_H
+#define E_CAL_OPS_H
+
+#include <libecal/libecal.h>
+#include <shell/e-shell-window.h>
+#include <shell/e-shell-view.h>
+#include <calendar/gui/e-cal-model.h>
+
+typedef void (* ECalOpsCreateComponentFunc)    (ECalModel *model,
+                                                ECalClient *client,
+                                                icalcomponent *original_icalcomp,
+                                                const gchar *new_uid,
+                                                gpointer user_data);
+typedef void (* ECalOpsGetDefaultComponentFunc)        (ECalModel *model,
+                                                ECalClient *client,
+                                                icalcomponent *default_component,
+                                                gpointer user_data);
+
+typedef enum {
+       E_CAL_OPS_SEND_FLAG_ASK                 = 0,
+       E_CAL_OPS_SEND_FLAG_SEND                = 1 << 0,
+       E_CAL_OPS_SEND_FLAG_DONT_SEND           = 1 << 1,
+       E_CAL_OPS_SEND_FLAG_IS_NEW_COMPONENT    = 1 << 2,
+       E_CAL_OPS_SEND_FLAG_ONLY_NEW_ATTENDEES  = 1 << 3,
+       E_CAL_OPS_SEND_FLAG_STRIP_ALARMS        = 1 << 4
+} ECalOpsSendFlags;
+
+void   e_cal_ops_create_component              (ECalModel *model,
+                                                ECalClient *client,
+                                                icalcomponent *icalcomp,
+                                                ECalOpsCreateComponentFunc callback,
+                                                gpointer user_data,
+                                                GDestroyNotify user_data_free);
+void   e_cal_ops_modify_component              (ECalModel *model,
+                                                ECalClient *client,
+                                                icalcomponent *icalcomp,
+                                                ECalObjModType mod,
+                                                ECalOpsSendFlags send_flags);
+void   e_cal_ops_remove_component              (ECalModel *model,
+                                                ECalClient *client,
+                                                const gchar *uid,
+                                                const gchar *rid,
+                                                ECalObjModType mod,
+                                                gboolean check_detached_instance);
+void   e_cal_ops_delete_ecalmodel_components   (ECalModel *model,
+                                                const GSList *objects); /* data is 'ECalModelComponent *' */
+void   e_cal_ops_paste_components              (ECalModel *model,
+                                                const gchar *icalcompstr);
+void   e_cal_ops_send_component                (ECalModel *model,
+                                                ECalClient *client,
+                                                icalcomponent *icalcomp);
+void   e_cal_ops_purge_components              (ECalModel *model,
+                                                time_t older_than);
+void   e_cal_ops_delete_completed_tasks        (ECalModel *model);
+void   e_cal_ops_get_default_component         (ECalModel *model,
+                                                const gchar *for_client_uid,
+                                                gboolean all_day,
+                                                ECalOpsGetDefaultComponentFunc callback,
+                                                gpointer user_data,
+                                                GDestroyNotify user_data_free);
+
+void   e_cal_ops_new_component_editor          (EShellWindow *shell_window,
+                                                ECalClientSourceType source_type,
+                                                const gchar *for_client_uid,
+                                                gboolean is_assigned);
+void   e_cal_ops_new_event_editor              (EShellWindow *shell_window,
+                                                const gchar *for_client_uid,
+                                                gboolean is_meeting,
+                                                gboolean all_day,
+                                                gboolean use_default_reminder,
+                                                gint default_reminder_interval,
+                                                EDurationType default_reminder_units);
+void   e_cal_ops_new_component_editor_from_model
+                                               (ECalModel *model,
+                                                const gchar *for_client_uid,
+                                                time_t dtstart,
+                                                time_t dtend,
+                                                gboolean is_assigned,
+                                                gboolean all_day);
+void   e_cal_ops_open_component_in_editor_sync (ECalModel *model,
+                                                ECalClient *client,
+                                                icalcomponent *icalcomp);
+
+void   e_cal_ops_transfer_components           (EShellView *shell_view,
+                                                ECalModel *model,
+                                                ECalClientSourceType source_type,
+                                                GHashTable *icalcomps_by_source, /* ESource ~> 
GSList{icalcomponent} */
+                                                ESource *destination,
+                                                gboolean is_move);
+
+#endif /* E_CAL_OPS_H */
diff --git a/calendar/gui/e-calendar-view.c b/calendar/gui/e-calendar-view.c
index 686327a..33f3fc6 100644
--- a/calendar/gui/e-calendar-view.c
+++ b/calendar/gui/e-calendar-view.c
@@ -35,13 +35,16 @@
 
 #include "comp-util.h"
 #include "ea-calendar.h"
+#include "e-cal-ops.h"
 #include "e-cal-model-calendar.h"
 #include "e-calendar-view.h"
+#include "e-day-view.h"
+#include "e-month-view.h"
+#include "e-cal-list-view.h"
 #include "ea-cal-view.h"
 #include "itip-utils.h"
 #include "dialogs/comp-editor-util.h"
 #include "dialogs/delete-comp.h"
-#include "dialogs/delete-error.h"
 #include "dialogs/event-editor.h"
 #include "dialogs/send-comp.h"
 #include "dialogs/cancel-comp.h"
@@ -56,13 +59,9 @@
        ((obj), E_TYPE_CALENDAR_VIEW, ECalendarViewPrivate))
 
 struct _ECalendarViewPrivate {
-       /* The GnomeCalendar we are associated to */
-       GnomeCalendar *calendar;
-
        /* The calendar model we are monitoring */
        ECalModel *model;
 
-       gchar *default_category;
        gint time_divisions;
        GSList *selected_cut_list;
 
@@ -92,8 +91,8 @@ enum {
        TIMEZONE_CHANGED,
        EVENT_CHANGED,
        EVENT_ADDED,
-       USER_CREATED,
        OPEN_EVENT,
+       MOVE_VIEW_RANGE,
        LAST_SIGNAL
 };
 
@@ -166,7 +165,6 @@ calendar_view_delete_event (ECalendarView *cal_view,
        ECalComponentVType vtype;
        ESourceRegistry *registry;
        gboolean delete = TRUE;
-       GError *error = NULL;
 
        if (!is_comp_data_valid (event))
                return;
@@ -189,29 +187,13 @@ calendar_view_delete_event (ECalendarView *cal_view,
 
                delete = prompt_retract_dialog (comp, &retract_comment, GTK_WIDGET (cal_view), &retract);
                if (retract) {
-                       GSList *users = NULL;
-                       icalcomponent *icalcomp = NULL, *mod_comp = NULL;
+                       icalcomponent *icalcomp;
 
-                       calendar_view_add_retract_data (
-                               comp, retract_comment, CALOBJ_MOD_ALL);
+                       calendar_view_add_retract_data (comp, retract_comment, CALOBJ_MOD_ALL);
                        icalcomp = e_cal_component_get_icalcomponent (comp);
                        icalcomponent_set_method (icalcomp, ICAL_METHOD_CANCEL);
-                       e_cal_client_send_objects_sync (
-                               event->comp_data->client, icalcomp,
-                               &users, &mod_comp, NULL, &error);
-                       if (error != NULL) {
-                               delete_error_dialog (error, E_CAL_COMPONENT_EVENT);
-                               g_clear_error (&error);
-                       } else {
-
-                               if (mod_comp)
-                                       icalcomponent_free (mod_comp);
 
-                               if (users) {
-                                       g_slist_foreach (users, (GFunc) g_free, NULL);
-                                       g_slist_free (users);
-                               }
-                       }
+                       e_cal_ops_send_component (model, event->comp_data->client, icalcomp);
                }
        } else if (e_cal_model_get_confirm_delete (model))
                delete = delete_component_dialog (
@@ -226,10 +208,9 @@ calendar_view_delete_event (ECalendarView *cal_view,
                    && cancel_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (cal_view)),
                                                event->comp_data->client,
                                                comp, TRUE))
-                       itip_send_comp (
-                               registry, E_CAL_COMPONENT_METHOD_CANCEL,
+                       itip_send_component (model, E_CAL_COMPONENT_METHOD_CANCEL,
                                comp, event->comp_data->client, NULL, NULL,
-                               NULL, TRUE, FALSE);
+                               NULL, TRUE, FALSE, FALSE);
 
                e_cal_component_get_uid (comp, &uid);
                if (!uid || !*uid) {
@@ -237,15 +218,12 @@ calendar_view_delete_event (ECalendarView *cal_view,
                        return;
                }
                rid = e_cal_component_get_recurid_as_string (comp);
-               if (e_cal_util_component_is_instance (event->comp_data->icalcomp) || 
e_cal_util_component_has_recurrences (event->comp_data->icalcomp))
-                       e_cal_client_remove_object_sync (
-                               event->comp_data->client, uid,
-                               rid, CALOBJ_MOD_ALL, NULL, &error);
+               if (e_cal_util_component_is_instance (event->comp_data->icalcomp) ||
+                   e_cal_util_component_has_recurrences (event->comp_data->icalcomp))
+                       e_cal_ops_remove_component (model, event->comp_data->client, uid, rid, 
E_CAL_OBJ_MOD_ALL, FALSE);
                else
-                       e_cal_client_remove_object_sync (event->comp_data->client, uid, NULL, 
CALOBJ_MOD_THIS, NULL, &error);
+                       e_cal_ops_remove_component (model, event->comp_data->client, uid, NULL, 
E_CAL_OBJ_MOD_THIS, FALSE);
 
-               delete_error_dialog (error, E_CAL_COMPONENT_EVENT);
-               g_clear_error (&error);
                g_free (rid);
        }
 
@@ -362,26 +340,11 @@ calendar_view_dispose (GObject *object)
                g_object_unref (keyboard);
        }
 
-       g_clear_object (&priv->calendar);
-
        /* Chain up to parent's dispose() method. */
        G_OBJECT_CLASS (e_calendar_view_parent_class)->dispose (object);
 }
 
 static void
-calendar_view_finalize (GObject *object)
-{
-       ECalendarViewPrivate *priv;
-
-       priv = E_CALENDAR_VIEW_GET_PRIVATE (object);
-
-       g_free (priv->default_category);
-
-       /* Chain up to parent's finalize() method. */
-       G_OBJECT_CLASS (e_calendar_view_parent_class)->finalize (object);
-}
-
-static void
 calendar_view_constructed (GObject *object)
 {
        /* Do this after calendar_view_init() so extensions can query
@@ -482,10 +445,6 @@ calendar_view_cut_clipboard (ESelectable *selectable)
        if (!selected)
                return;
 
-#if 0  /* KILL-BONOBO */
-       e_calendar_view_set_status_message (cal_view, _("Deleting selected objects"), -1);
-#endif
-
        e_selectable_copy_clipboard (selectable);
 
        for (l = selected; l != NULL; l = g_list_next (l)) {
@@ -494,10 +453,6 @@ calendar_view_cut_clipboard (ESelectable *selectable)
                priv->selected_cut_list = g_slist_prepend (priv->selected_cut_list, g_object_ref 
(event->comp_data));
        }
 
-#if 0  /* KILL-BONOBO */
-       e_calendar_view_set_status_message (cal_view, NULL, -1);
-#endif
-
        g_list_free (selected);
 }
 
@@ -614,45 +569,301 @@ calendar_view_copy_clipboard (ESelectable *selectable)
        g_list_free (selected);
 }
 
-static gboolean
-clipboard_get_calendar_data (ECalendarView *cal_view,
-                             const gchar *text,
-                             GSList **copied_list)
+static void
+calendar_view_component_created_cb (ECalModel *model,
+                                   ECalClient *client,
+                                   icalcomponent *original_icalcomp,
+                                   const gchar *new_uid,
+                                   gpointer user_data)
+{
+       gboolean strip_alarms = TRUE;
+       ECalComponent *comp;
+       ESourceRegistry *registry;
+       GtkWidget *toplevel = user_data;
+
+       comp = e_cal_component_new_from_icalcomponent (icalcomponent_new_clone (original_icalcomp));
+       g_return_if_fail (comp != NULL);
+
+       registry = e_cal_model_get_registry (model);
+
+       if (new_uid)
+               e_cal_component_set_uid (comp, new_uid);
+
+       if ((itip_organizer_is_user (registry, comp, client) ||
+            itip_sentby_is_user (registry, comp, client)) &&
+            send_component_dialog ((GtkWindow *) toplevel, client, comp, TRUE, &strip_alarms, NULL)) {
+               itip_send_component (model, E_CAL_COMPONENT_METHOD_REQUEST,
+                       comp, client, NULL, NULL, NULL, strip_alarms, FALSE, FALSE);
+       }
+
+       g_object_unref (comp);
+}
+
+static void
+e_calendar_view_add_event_sync (ECalModel *model,
+                               ECalClient *client,
+                               time_t dtstart,
+                               icaltimezone *default_zone,
+                               icalcomponent *icalcomp,
+                               gboolean all_day,
+                               gboolean is_day_view,
+                               gint time_division,
+                               GtkWidget *top_level)
+{
+       ECalComponent *comp;
+       struct icaltimetype itime, old_dtstart, old_dtend;
+       time_t tt_start, tt_end, new_dtstart = 0;
+       struct icaldurationtype ic_dur, ic_oneday;
+       gchar *uid;
+       gint start_offset, end_offset;
+       gboolean all_day_event = FALSE;
+
+       start_offset = 0;
+       end_offset = 0;
+
+       old_dtstart = icalcomponent_get_dtstart (icalcomp);
+       tt_start = icaltime_as_timet (old_dtstart);
+       old_dtend = icalcomponent_get_dtend (icalcomp);
+       tt_end = icaltime_as_timet (old_dtend);
+       ic_dur = icaldurationtype_from_int (tt_end - tt_start);
+
+       if (icaldurationtype_as_int (ic_dur) > 60 *60 *24) {
+               /* This is a long event */
+               start_offset = old_dtstart.hour * 60 + old_dtstart.minute;
+               end_offset = old_dtstart.hour * 60 + old_dtend.minute;
+       }
+
+       ic_oneday = icaldurationtype_null_duration ();
+       ic_oneday.days = 1;
+
+       if (is_day_view) {
+               if (start_offset == 0 && end_offset == 0 && all_day)
+                       all_day_event = TRUE;
+
+               if (all_day_event) {
+                       ic_dur = ic_oneday;
+               } else if (icaldurationtype_as_int (ic_dur) >= 60 *60 *24 && !all_day) {
+                       /* copy & paste from top canvas to main canvas */
+                       ic_dur = icaldurationtype_from_int (time_division * 60);
+               }
+
+               if (all_day)
+                       new_dtstart = dtstart + start_offset * 60;
+               else
+                       new_dtstart = dtstart;
+       } else {
+               if (old_dtstart.is_date && old_dtend.is_date
+                       && memcmp (&ic_dur, &ic_oneday, sizeof (ic_dur)) == 0) {
+                       all_day_event = TRUE;
+                       new_dtstart = dtstart;
+               } else {
+                       icaltimetype new_time = icaltime_from_timet_with_zone (dtstart, FALSE, default_zone);
+
+                       new_time.hour = old_dtstart.hour;
+                       new_time.minute = old_dtstart.minute;
+                       new_time.second = old_dtstart.second;
+
+                       new_dtstart = icaltime_as_timet_with_zone (new_time, old_dtstart.zone ? 
old_dtstart.zone : default_zone);
+               }
+       }
+
+       itime = icaltime_from_timet_with_zone (new_dtstart, FALSE, old_dtstart.zone ? old_dtstart.zone : 
default_zone);
+       /* set the timezone properly */
+       itime.zone = old_dtstart.zone ? old_dtstart.zone : default_zone;
+       if (all_day_event)
+               itime.is_date = TRUE;
+       icalcomponent_set_dtstart (icalcomp, itime);
+
+       itime.is_date = FALSE;
+       itime = icaltime_add (itime, ic_dur);
+       if (all_day_event)
+               itime.is_date = TRUE;
+       icalcomponent_set_dtend (icalcomp, itime);
+
+       /* The new uid stuff can go away once we actually set it in the backend */
+       uid = e_cal_component_gen_uid ();
+       comp = e_cal_component_new ();
+       e_cal_component_set_icalcomponent (
+               comp, icalcomponent_new_clone (icalcomp));
+       e_cal_component_set_uid (comp, uid);
+       g_free (uid);
+
+       e_cal_component_commit_sequence (comp);
+
+       e_cal_ops_create_component (model, client, e_cal_component_get_icalcomponent (comp),
+               calendar_view_component_created_cb, g_object_ref (top_level), g_object_unref);
+
+       g_object_unref (comp);
+}
+
+typedef struct {
+       ECalendarView *cal_view;
+       GSList *selected_cut_list; /* ECalModelComponent * */
+       GSList *copied_uids; /* gchar * */
+       gchar *ical_str;
+       time_t selection_start;
+       time_t selection_end;
+       gboolean is_day_view;
+       gint time_division;
+       GtkWidget *top_level;
+       gboolean success;
+       ECalClient *client;
+} PasteClipboardData;
+
+static void
+paste_clipboard_data_free (gpointer ptr)
+{
+       PasteClipboardData *pcd = ptr;
+
+       if (pcd) {
+               if (pcd->success && pcd->copied_uids && pcd->selected_cut_list) {
+                       ECalModel *model;
+                       ESourceRegistry *registry;
+                       GSList *link;
+
+                       model = e_calendar_view_get_model (pcd->cal_view);
+                       registry = e_cal_model_get_registry (model);
+
+                       for (link = pcd->selected_cut_list; link != NULL; link = g_slist_next (link)) {
+                               ECalModelComponent *comp_data = (ECalModelComponent *) link->data;
+                               ECalComponent *comp;
+                               const gchar *uid;
+                               GSList *found = NULL;
+
+                               /* Remove them one by one after ensuring it has been copied to the 
destination successfully */
+                               found = g_slist_find_custom (pcd->copied_uids, icalcomponent_get_uid 
(comp_data->icalcomp), (GCompareFunc) strcmp);
+                               if (!found)
+                                       continue;
+
+                               g_free (found->data);
+                               pcd->copied_uids = g_slist_delete_link (pcd->copied_uids, found);
+
+                               comp = e_cal_component_new ();
+                               e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone 
(comp_data->icalcomp));
+
+                               if ((itip_organizer_is_user (registry, comp, comp_data->client) ||
+                                   itip_sentby_is_user (registry, comp, comp_data->client))
+                                   && cancel_component_dialog ((GtkWindow *) pcd->top_level, 
comp_data->client, comp, TRUE))
+                                       itip_send_component (model, E_CAL_COMPONENT_METHOD_CANCEL,
+                                               comp, comp_data->client, NULL, NULL, NULL, TRUE, FALSE, TRUE);
+
+                               e_cal_component_get_uid (comp, &uid);
+                               if (e_cal_component_is_instance (comp)) {
+                                       gchar *rid = NULL;
+
+                                       /* when cutting detached instances, only cut that instance */
+                                       rid = e_cal_component_get_recurid_as_string (comp);
+                                       e_cal_ops_remove_component (model, comp_data->client, uid, rid, 
E_CAL_OBJ_MOD_THIS, TRUE);
+                                       g_free (rid);
+                               } else {
+                                       e_cal_ops_remove_component (model, comp_data->client, uid, NULL, 
E_CAL_OBJ_MOD_ALL, FALSE);
+                               }
+
+                               g_object_unref (comp);
+                       }
+               }
+
+               if (pcd->success && pcd->client) {
+                       ECalModel *model;
+
+                       model = e_calendar_view_get_model (pcd->cal_view);
+                       e_cal_model_emit_object_created (model, pcd->client);
+               }
+
+               g_clear_object (&pcd->cal_view);
+               g_clear_object (&pcd->top_level);
+               g_clear_object (&pcd->client);
+               g_slist_free_full (pcd->selected_cut_list, g_object_unref);
+               g_slist_free_full (pcd->copied_uids, g_free);
+               g_free (pcd->ical_str);
+               g_free (pcd);
+       }
+}
+
+static void
+cal_view_paste_clipboard_thread (EAlertSinkThreadJobData *job_data,
+                                gpointer user_data,
+                                GCancellable *cancellable,
+                                GError **error)
 {
+       PasteClipboardData *pcd = user_data;
        icalcomponent *icalcomp;
        icalcomponent_kind kind;
-       time_t selected_time_start, selected_time_end;
        icaltimezone *default_zone;
-       ECalClient *client;
-       gboolean in_top_canvas, ret = FALSE;
+       ECalModel *model;
+       ESourceRegistry *registry;
+       ESource *source, *default_source;
+       EClientCache *client_cache;
+       EClient *e_client;
+       ECalClient *client = NULL;
+       const gchar *message;
+       const gchar *extension_name;
+       guint copied_components = 1;
+       gboolean all_day;
+       GError *local_error = NULL;
+
+       g_return_if_fail (pcd != NULL);
+
+       icalcomp = icalparser_parse_string (pcd->ical_str);
+       if (!icalcomp) {
+               g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
+                       _("Pasted text doesn't contain valid iCalendar data"));
+               return;
+       }
 
-       g_return_val_if_fail (E_IS_CALENDAR_VIEW (cal_view), FALSE);
+       model = e_calendar_view_get_model (pcd->cal_view);
+       registry = e_cal_model_get_registry (model);
 
-       if (!text || !*text)
-               return FALSE;
+       switch (e_cal_model_get_component_kind (model)) {
+               case ICAL_VEVENT_COMPONENT:
+                       default_source = e_source_registry_ref_default_calendar (registry);
+                       extension_name = E_SOURCE_EXTENSION_CALENDAR;
+                       message = _("Default calendar not found");
+                       break;
+               case ICAL_VJOURNAL_COMPONENT:
+                       default_source = e_source_registry_ref_default_memo_list (registry);
+                       extension_name = E_SOURCE_EXTENSION_MEMO_LIST;
+                       message = _("Default memo list not found");
+                       break;
+               case ICAL_VTODO_COMPONENT:
+                       default_source = e_source_registry_ref_default_task_list (registry);
+                       extension_name = E_SOURCE_EXTENSION_TASK_LIST;
+                       message = _("Default task list not found");
+                       break;
+               default:
+                       g_warn_if_reached ();
+                       goto out;
+       }
 
-       icalcomp = icalparser_parse_string (text);
-       if (!icalcomp)
-               return FALSE;
+       source = e_source_registry_ref_source (registry, e_cal_model_get_default_source_uid (model));
+       if (!source) {
+               source = default_source;
+               default_source = NULL;
+       }
 
-       /* check the type of the component */
-       /* FIXME An error dialog if we return? */
-       kind = icalcomponent_isa (icalcomp);
-       if (kind != ICAL_VCALENDAR_COMPONENT && kind != ICAL_VEVENT_COMPONENT)
-               return FALSE;
+       if (!source) {
+               const gchar *default_source_uid = e_cal_model_get_default_source_uid (model);
 
-       default_zone = e_cal_model_get_timezone (cal_view->priv->model);
-       client = e_cal_model_ref_default_client (cal_view->priv->model);
+               e_alert_sink_thread_job_set_alert_arg_0 (job_data, default_source_uid ? default_source_uid : 
"");
+               g_set_error_literal (&local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, message);
 
-#if 0  /* KILL-BONOBO */
-       e_calendar_view_set_status_message (cal_view, _("Updating objects"), -1);
-#endif
-       e_calendar_view_get_selected_time_range (cal_view, &selected_time_start, &selected_time_end);
+               return;
+       }
 
-       if ((selected_time_end - selected_time_start) == 60 * 60 * 24)
-               in_top_canvas = TRUE;
-       else
-               in_top_canvas = FALSE;
+       e_alert_sink_thread_job_set_alert_arg_0 (job_data, e_source_get_display_name (source));
+       client_cache = e_cal_model_get_client_cache (model);
+
+       e_client = e_client_cache_get_client_sync (client_cache, source, extension_name, cancellable, 
&local_error);
+       if (!e_client) {
+               e_util_propagate_open_source_job_error (job_data, extension_name, local_error, error);
+               goto out;
+       }
+
+       client = E_CAL_CLIENT (e_client);
+       kind = icalcomponent_isa (icalcomp);
+       default_zone = e_cal_model_get_timezone (model);
+       all_day = pcd->selection_end - pcd->selection_start == 60 * 60 * 24;
+       copied_components = 0;
 
        if (kind == ICAL_VCALENDAR_COMPONENT) {
                icalcomponent *subcomp;
@@ -662,28 +873,13 @@ clipboard_get_calendar_data (ECalendarView *cal_view,
                     subcomp;
                     subcomp = icalcomponent_get_next_component (icalcomp, ICAL_VTIMEZONE_COMPONENT)) {
                        icaltimezone *zone;
-                       GError *error = NULL;
 
                        zone = icaltimezone_new ();
                        icaltimezone_set_component (zone, subcomp);
-                       e_cal_client_add_timezone_sync (
-                               client, zone, NULL, &error);
-                       if (error != NULL) {
-                               icalproperty *tzidprop;
-                               const gchar *tzid;
-
-                               tzidprop = icalcomponent_get_first_property (
-                                       subcomp, ICAL_TZID_PROPERTY);
-                               if (tzidprop != NULL)
-                                       tzid = icalproperty_get_tzid (tzidprop);
-                               else
-                                       tzid = "???";
-
-                               g_warning (
-                                       "%s: Add zone '%s' failed. %s",
-                                       G_STRFUNC, tzid, error->message);
-
-                               g_error_free (error);
+
+                       if (!e_cal_client_add_timezone_sync (client, zone, cancellable, error)) {
+                               icaltimezone_free (zone, 1);
+                               goto out;
                        }
 
                        icaltimezone_free (zone, 1);
@@ -698,28 +894,33 @@ clipboard_get_calendar_data (ECalendarView *cal_view,
                                        icalproperty_remove_parameter_by_name (icalprop, 
"X-EVOLUTION-ENDDATE");
                        }
 
-                       ret = e_calendar_view_add_event (cal_view, client, selected_time_start, default_zone, 
subcomp, in_top_canvas);
-                       if (!ret)
-                               break;
+                       e_calendar_view_add_event_sync (model, client, pcd->selection_start, default_zone, 
subcomp, all_day,
+                               pcd->is_day_view, pcd->time_division, pcd->top_level);
 
-                       if (copied_list)
-                               *copied_list = g_slist_prepend (*copied_list, g_strdup (icalcomponent_get_uid 
(subcomp)));
+                       copied_components++;
+                       if (pcd->selected_cut_list)
+                               pcd->copied_uids = g_slist_prepend (pcd->copied_uids, g_strdup 
(icalcomponent_get_uid (subcomp)));
                }
+       } else if (kind == e_cal_model_get_component_kind (model)) {
+               e_calendar_view_add_event_sync (model, client, pcd->selection_start, default_zone, icalcomp, 
all_day,
+                       pcd->is_day_view, pcd->time_division, pcd->top_level);
 
-               icalcomponent_free (icalcomp);
-       } else {
-               ret = e_calendar_view_add_event (cal_view, client, selected_time_start, default_zone, 
icalcomp, in_top_canvas);
-               if (ret && copied_list)
-                       *copied_list = g_slist_prepend (*copied_list, g_strdup (icalcomponent_get_uid 
(icalcomp)));
+               copied_components++;
+               if (pcd->selected_cut_list)
+                       pcd->copied_uids = g_slist_prepend (pcd->copied_uids, g_strdup (icalcomponent_get_uid 
(icalcomp)));
        }
 
-       g_object_unref (client);
+       pcd->success = !g_cancellable_is_cancelled (cancellable);
+       pcd->client = g_object_ref (client);
 
-       return ret;
+ out:
+       if (!copied_components && !g_cancellable_is_cancelled (cancellable) && error && !*error)
+               g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, _("No suitable component 
found"));
 
-#if 0  /* KILL-BONOBO */
-       e_calendar_view_set_status_message (cal_view, NULL, -1);
-#endif
+       icalcomponent_free (icalcomp);
+       g_clear_object (&source);
+       g_clear_object (&default_source);
+       g_clear_object (&client);
 }
 
 static void
@@ -727,15 +928,11 @@ calendar_view_paste_clipboard (ESelectable *selectable)
 {
        ECalModel *model;
        ECalendarView *cal_view;
-       ECalendarViewPrivate *priv;
-       ESourceRegistry *registry;
        GtkClipboard *clipboard;
 
        cal_view = E_CALENDAR_VIEW (selectable);
-       priv = cal_view->priv;
 
        model = e_calendar_view_get_model (cal_view);
-       registry = e_cal_model_get_registry (model);
 
        clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
 
@@ -750,86 +947,48 @@ calendar_view_paste_clipboard (ESelectable *selectable)
 
        /* Paste iCalendar data into the view. */
        } else if (e_clipboard_wait_is_calendar_available (clipboard)) {
-               gchar *calendar_source;
-               GSList *copied_list = NULL, *l;
-
-               calendar_source = e_clipboard_wait_for_calendar (clipboard);
-
-               if (priv->selected_cut_list)
-                       clipboard_get_calendar_data (cal_view, calendar_source, &copied_list);
-               else
-                       clipboard_get_calendar_data (cal_view, calendar_source, NULL);
-
-               if (copied_list && priv->selected_cut_list) {
-                       for (l = priv->selected_cut_list; l != NULL; l = l->next) {
-                               ECalComponent *comp;
-                               ECalModelComponent *comp_data = (ECalModelComponent *) l->data;
-                               const gchar *uid;
-                               GError *error = NULL;
-                               GSList *found = NULL;
-
-                               /* Remove them one by one after ensuring it has been copied to the 
destination successfully */
-                               found = g_slist_find_custom (copied_list, icalcomponent_get_uid 
(comp_data->icalcomp), (GCompareFunc) strcmp);
-                               if (!found)
-                                       continue;
-
-                               g_free (found->data);
-                               copied_list = g_slist_delete_link (copied_list, found);
-
-                               comp = e_cal_component_new ();
-                               e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone 
(comp_data->icalcomp));
-
-                               if ((itip_organizer_is_user (registry, comp, comp_data->client) ||
-                                                       itip_sentby_is_user (registry, comp, 
comp_data->client))
-                                               && cancel_component_dialog ((GtkWindow *) 
gtk_widget_get_toplevel (GTK_WIDGET (cal_view)),
-                                                       comp_data->client, comp, TRUE))
-                                       itip_send_comp (
-                                               registry,
-                                               E_CAL_COMPONENT_METHOD_CANCEL,
-                                               comp, comp_data->client,
-                                               NULL, NULL, NULL, TRUE, FALSE);
-
-                               e_cal_component_get_uid (comp, &uid);
-                               if (e_cal_component_is_instance (comp)) {
-                                       gchar *rid = NULL;
-                                       icalcomponent *icalcomp;
-
-                                       /* when cutting detached instances, only cut that instance */
-                                       rid = e_cal_component_get_recurid_as_string (comp);
-                                       e_cal_client_get_object_sync (
-                                               comp_data->client, uid, rid,
-                                               &icalcomp, NULL, NULL);
-                                       if (icalcomp != NULL) {
-                                               e_cal_client_remove_object_sync (
-                                                       comp_data->client, uid, rid,
-                                                       CALOBJ_MOD_THIS, NULL, &error);
-                                               icalcomponent_free (icalcomp);
-                                       } else {
-                                               e_cal_client_remove_object_sync (
-                                                       comp_data->client, uid, NULL,
-                                                       CALOBJ_MOD_ALL, NULL, &error);
-                                       }
-                                       g_free (rid);
-                               } else {
-                                       e_cal_client_remove_object_sync (
-                                               comp_data->client, uid, NULL,
-                                               CALOBJ_MOD_ALL, NULL, &error);
-                               }
-                               delete_error_dialog (error, E_CAL_COMPONENT_EVENT);
-
-                               g_clear_error (&error);
-                               g_object_unref (comp);
-                       }
-               }
-
-               if (priv->selected_cut_list) {
-                       g_slist_foreach (priv->selected_cut_list, (GFunc) g_object_unref, NULL);
-                       g_slist_free (priv->selected_cut_list);
+               PasteClipboardData *pcd;
+               ECalDataModel *data_model;
+               GCancellable *cancellable;
+               const gchar *alert_ident = NULL;
+
+               switch (e_cal_model_get_component_kind (model)) {
+                       case ICAL_VEVENT_COMPONENT:
+                               alert_ident = "calendar:failed-create-event";
+                               break;
+                       case ICAL_VJOURNAL_COMPONENT:
+                               alert_ident = "calendar:failed-create-memo";
+                               break;
+                       case ICAL_VTODO_COMPONENT:
+                               alert_ident = "calendar:failed-create-task";
+                               break;
+                       default:
+                               g_warn_if_reached ();
+                               return;
                }
-               priv->selected_cut_list = NULL;
-
-               g_free (calendar_source);
 
+               pcd = g_new0 (PasteClipboardData, 1);
+               pcd->cal_view = g_object_ref (cal_view);
+               pcd->selected_cut_list = cal_view->priv->selected_cut_list;
+               cal_view->priv->selected_cut_list = NULL;
+               pcd->copied_uids = NULL; /* gchar * */
+               pcd->ical_str = e_clipboard_wait_for_calendar (clipboard);
+               g_warn_if_fail (e_calendar_view_get_selected_time_range (cal_view, &pcd->selection_start, 
&pcd->selection_end));
+               pcd->is_day_view = E_IS_DAY_VIEW (cal_view);
+               if (pcd->is_day_view)
+                       pcd->time_division = e_calendar_view_get_time_divisions (cal_view);
+               pcd->top_level = gtk_widget_get_toplevel (GTK_WIDGET (cal_view));
+               if (pcd->top_level)
+                       g_object_ref (pcd->top_level);
+               pcd->success = FALSE;
+               pcd->client = NULL;
+
+               data_model = e_cal_model_get_data_model (model);
+
+               cancellable = e_cal_data_model_submit_thread_job (data_model, _("Pasting iCalendar data"), 
alert_ident,
+                       NULL, cal_view_paste_clipboard_thread, pcd, paste_clipboard_data_free);
+
+               g_clear_object (&cancellable);
        }
 }
 
@@ -869,19 +1028,18 @@ e_calendar_view_class_init (ECalendarViewClass *class)
        object_class->set_property = calendar_view_set_property;
        object_class->get_property = calendar_view_get_property;
        object_class->dispose = calendar_view_dispose;
-       object_class->finalize = calendar_view_finalize;
        object_class->constructed = calendar_view_constructed;
 
        class->selection_changed = NULL;
        class->selected_time_changed = NULL;
        class->event_changed = NULL;
        class->event_added = NULL;
-       class->user_created = NULL;
 
        class->get_selected_events = NULL;
        class->get_selected_time_range = NULL;
        class->set_selected_time_range = NULL;
        class->get_visible_time_range = NULL;
+       class->precalc_visible_time_range = NULL;
        class->update_query = NULL;
        class->open_event = e_calendar_view_open_event;
        class->paste_text = NULL;
@@ -990,15 +1148,6 @@ e_calendar_view_class_init (ECalendarViewClass *class)
                G_TYPE_NONE, 1,
                G_TYPE_POINTER);
 
-       signals[USER_CREATED] = g_signal_new (
-               "user-created",
-               G_TYPE_FROM_CLASS (class),
-               G_SIGNAL_RUN_LAST,
-               G_STRUCT_OFFSET (ECalendarViewClass, user_created),
-               NULL, NULL,
-               g_cclosure_marshal_VOID__OBJECT,
-               G_TYPE_NONE, 1, G_TYPE_OBJECT);
-
        signals[OPEN_EVENT] = g_signal_new (
                "open-event",
                G_TYPE_FROM_CLASS (class),
@@ -1008,6 +1157,15 @@ e_calendar_view_class_init (ECalendarViewClass *class)
                g_cclosure_marshal_VOID__VOID,
                G_TYPE_NONE, 0);
 
+       signals[MOVE_VIEW_RANGE] = g_signal_new (
+               "move-view-range",
+               G_TYPE_FROM_CLASS (object_class),
+               G_SIGNAL_RUN_LAST,
+               G_STRUCT_OFFSET (ECalendarViewClass, move_view_range),
+               NULL, NULL,
+               NULL, /* default marshal */
+               G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT64);
+
        /* Key bindings */
 
        binding_set = gtk_binding_set_by_class (class);
@@ -1059,174 +1217,6 @@ e_calendar_view_popup_event (ECalendarView *calendar_view,
        g_signal_emit (calendar_view, signals[POPUP_EVENT], 0, button_event);
 }
 
-gboolean
-e_calendar_view_add_event (ECalendarView *cal_view,
-                           ECalClient *client,
-                           time_t dtstart,
-                           icaltimezone *default_zone,
-                           icalcomponent *icalcomp,
-                           gboolean in_top_canvas)
-{
-       ECalModel *model;
-       ECalComponent *comp;
-       ESourceRegistry *registry;
-       struct icaltimetype itime, old_dtstart, old_dtend;
-       time_t tt_start, tt_end, new_dtstart = 0;
-       struct icaldurationtype ic_dur, ic_oneday;
-       gchar *uid;
-       gint start_offset, end_offset;
-       gboolean all_day_event = FALSE;
-       GnomeCalendarViewType view_type;
-       gboolean ret = TRUE;
-       GError *error = NULL;
-
-       model = e_calendar_view_get_model (cal_view);
-       registry = e_cal_model_get_registry (model);
-
-       start_offset = 0;
-       end_offset = 0;
-
-       old_dtstart = icalcomponent_get_dtstart (icalcomp);
-       tt_start = icaltime_as_timet (old_dtstart);
-       old_dtend = icalcomponent_get_dtend (icalcomp);
-       tt_end = icaltime_as_timet (old_dtend);
-       ic_dur = icaldurationtype_from_int (tt_end - tt_start);
-
-       if (icaldurationtype_as_int (ic_dur) > 60 *60 *24) {
-               /* This is a long event */
-               start_offset = old_dtstart.hour * 60 + old_dtstart.minute;
-               end_offset = old_dtstart.hour * 60 + old_dtend.minute;
-       }
-
-       ic_oneday = icaldurationtype_null_duration ();
-       ic_oneday.days = 1;
-
-       view_type = gnome_calendar_get_view (cal_view->priv->calendar);
-
-       switch (view_type) {
-       case GNOME_CAL_DAY_VIEW:
-       case GNOME_CAL_WORK_WEEK_VIEW:
-               if (start_offset == 0 && end_offset == 0 && in_top_canvas)
-                       all_day_event = TRUE;
-
-               if (all_day_event) {
-                       ic_dur = ic_oneday;
-               } else if (icaldurationtype_as_int (ic_dur) >= 60 *60 *24
-                               && !in_top_canvas) {
-                       /* copy & paste from top canvas to main canvas */
-                       gint time_divisions;
-
-                       time_divisions = e_calendar_view_get_time_divisions (cal_view);
-                       ic_dur = icaldurationtype_from_int (time_divisions * 60);
-               }
-
-               if (in_top_canvas)
-                       new_dtstart = dtstart + start_offset * 60;
-               else
-                       new_dtstart = dtstart;
-               break;
-       case GNOME_CAL_WEEK_VIEW:
-       case GNOME_CAL_MONTH_VIEW:
-       case GNOME_CAL_LIST_VIEW:
-               if (old_dtstart.is_date && old_dtend.is_date
-                       && memcmp (&ic_dur, &ic_oneday, sizeof (ic_dur)) == 0) {
-                       all_day_event = TRUE;
-                       new_dtstart = dtstart;
-               } else {
-                       icaltimetype new_time = icaltime_from_timet_with_zone (dtstart, FALSE, default_zone);
-
-                       new_time.hour = old_dtstart.hour;
-                       new_time.minute = old_dtstart.minute;
-                       new_time.second = old_dtstart.second;
-
-                       new_dtstart = icaltime_as_timet_with_zone (new_time, old_dtstart.zone ? 
old_dtstart.zone : default_zone);
-               }
-               break;
-       default:
-               g_return_val_if_reached (FALSE);
-       }
-
-       itime = icaltime_from_timet_with_zone (new_dtstart, FALSE, old_dtstart.zone ? old_dtstart.zone : 
default_zone);
-       /* set the timezone properly */
-       itime.zone = old_dtstart.zone ? old_dtstart.zone : default_zone;
-       if (all_day_event)
-               itime.is_date = TRUE;
-       icalcomponent_set_dtstart (icalcomp, itime);
-
-       itime.is_date = FALSE;
-       itime = icaltime_add (itime, ic_dur);
-       if (all_day_event)
-               itime.is_date = TRUE;
-       icalcomponent_set_dtend (icalcomp, itime);
-
-       /* FIXME The new uid stuff can go away once we actually set it in the backend */
-       uid = e_cal_component_gen_uid ();
-       comp = e_cal_component_new ();
-       e_cal_component_set_icalcomponent (
-               comp, icalcomponent_new_clone (icalcomp));
-       e_cal_component_set_uid (comp, uid);
-       g_free (uid);
-
-       e_cal_component_commit_sequence (comp);
-
-       uid = NULL;
-       e_cal_client_create_object_sync (
-               client, e_cal_component_get_icalcomponent (comp),
-               &uid, NULL, &error);
-       if (error == NULL) {
-               gboolean strip_alarms = TRUE;
-
-               if (uid) {
-                       e_cal_component_set_uid (comp, uid);
-                       g_free (uid);
-               }
-
-               if ((itip_organizer_is_user (registry, comp, client) ||
-                    itip_sentby_is_user (registry, comp, client)) &&
-                       send_component_dialog (
-                               (GtkWindow *) gtk_widget_get_toplevel (
-                                       GTK_WIDGET (cal_view)),
-                               client, comp, TRUE, &strip_alarms, NULL)) {
-                       itip_send_comp (
-                               registry, E_CAL_COMPONENT_METHOD_REQUEST,
-                               comp, client, NULL, NULL, NULL, strip_alarms,
-                               FALSE);
-               }
-       } else {
-               g_message (
-                       "%s: Could not create the object! %s",
-                       G_STRFUNC, error->message);
-               g_error_free (error);
-               ret = FALSE;
-       }
-
-       g_object_unref (comp);
-       return ret;
-}
-
-GnomeCalendar *
-e_calendar_view_get_calendar (ECalendarView *cal_view)
-{
-       g_return_val_if_fail (E_IS_CALENDAR_VIEW (cal_view), NULL);
-
-       return cal_view->priv->calendar;
-}
-
-void
-e_calendar_view_set_calendar (ECalendarView *cal_view,
-                              GnomeCalendar *calendar)
-{
-       g_return_if_fail (E_IS_CALENDAR_VIEW (cal_view));
-
-       if (calendar)
-               g_object_ref (calendar);
-
-       if (cal_view->priv->calendar)
-               g_object_unref (cal_view->priv->calendar);
-
-       cal_view->priv->calendar = calendar;
-}
-
 ECalModel *
 e_calendar_view_get_model (ECalendarView *cal_view)
 {
@@ -1260,32 +1250,6 @@ e_calendar_view_set_timezone (ECalendarView *cal_view,
                old_zone, zone);
 }
 
-const gchar *
-e_calendar_view_get_default_category (ECalendarView *cal_view)
-{
-       g_return_val_if_fail (E_IS_CALENDAR_VIEW (cal_view), NULL);
-
-       return cal_view->priv->default_category;
-}
-
-/**
- * e_calendar_view_set_default_category
- * @cal_view: A calendar view.
- * @category: Default category name or NULL for no category.
- *
- * Sets the default category that will be used when creating new calendar
- * components from the given calendar view.
- */
-void
-e_calendar_view_set_default_category (ECalendarView *cal_view,
-                                      const gchar *category)
-{
-       g_return_if_fail (E_IS_CALENDAR_VIEW (cal_view));
-
-       g_free (cal_view->priv->default_category);
-       cal_view->priv->default_category = g_strdup (category);
-}
-
 GtkTargetList *
 e_calendar_view_get_copy_target_list (ECalendarView *cal_view)
 {
@@ -1385,6 +1349,25 @@ e_calendar_view_get_visible_time_range (ECalendarView *cal_view,
 }
 
 void
+e_calendar_view_precalc_visible_time_range (ECalendarView *cal_view,
+                                           time_t in_start_time,
+                                           time_t in_end_time,
+                                           time_t *out_start_time,
+                                           time_t *out_end_time)
+{
+       ECalendarViewClass *class;
+
+       g_return_if_fail (E_IS_CALENDAR_VIEW (cal_view));
+
+       /* Not all views implement this, so return silently. */
+       class = E_CALENDAR_VIEW_GET_CLASS (cal_view);
+       if (class->precalc_visible_time_range == NULL)
+               return;
+
+       class->precalc_visible_time_range (cal_view, in_start_time, in_end_time, out_start_time, 
out_end_time);
+}
+
+void
 e_calendar_view_update_query (ECalendarView *cal_view)
 {
        ECalendarViewClass *class;
@@ -1400,132 +1383,19 @@ e_calendar_view_update_query (ECalendarView *cal_view)
 void
 e_calendar_view_delete_selected_occurrence (ECalendarView *cal_view)
 {
-       GList *selected;
-       ECalModel *model;
-       ECalComponent *comp;
        ECalendarViewEvent *event;
-       ECalComponentVType vtype;
-       ESourceRegistry *registry;
-       gboolean delete = TRUE;
-       GError *error = NULL;
-
-       model = e_calendar_view_get_model (cal_view);
-       registry = e_cal_model_get_registry (model);
+       GList *selected;
 
        selected = e_calendar_view_get_selected_events (cal_view);
        if (!selected)
                return;
-       event = (ECalendarViewEvent *) selected->data;
-       if (!is_comp_data_valid (event))
-               return;
 
-       comp = e_cal_component_new ();
-       e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (event->comp_data->icalcomp));
-       vtype = e_cal_component_get_vtype (comp);
-
-       /*FIXME Retract should be moved to Groupwise features plugin */
-       if (calendar_view_check_for_retract (comp, event->comp_data->client)) {
-               gchar *retract_comment = NULL;
-               gboolean retract = FALSE;
-
-               delete = prompt_retract_dialog (comp, &retract_comment, GTK_WIDGET (cal_view), &retract);
-               if (retract) {
-                       GSList *users = NULL;
-                       icalcomponent *icalcomp = NULL, *mod_comp = NULL;
-
-                       calendar_view_add_retract_data (
-                               comp, retract_comment, CALOBJ_MOD_THIS);
-                       icalcomp = e_cal_component_get_icalcomponent (comp);
-                       icalcomponent_set_method (icalcomp, ICAL_METHOD_CANCEL);
-                       e_cal_client_send_objects_sync (
-                               event->comp_data->client, icalcomp,
-                               &users, &mod_comp, NULL, &error);
-                       if (error != NULL) {
-                               delete_error_dialog (error, E_CAL_COMPONENT_EVENT);
-                               g_clear_error (&error);
-                       } else {
-                               if (mod_comp)
-                                       icalcomponent_free (mod_comp);
-                               if (users) {
-                                       g_slist_foreach (users, (GFunc) g_free, NULL);
-                                       g_slist_free (users);
-                               }
-                       }
-               }
-       } else if (e_cal_model_get_confirm_delete (model))
-               delete = delete_component_dialog (
-                       comp, FALSE, 1, vtype, GTK_WIDGET (cal_view));
-
-       if (delete) {
-               const gchar *uid;
-               gchar *rid = NULL;
-               ECalComponentDateTime dt;
-               icaltimezone *zone = NULL;
-               gboolean is_instance = FALSE;
-
-               e_cal_component_get_uid (comp, &uid);
-               e_cal_component_get_dtstart (comp, &dt);
-               is_instance = e_cal_component_is_instance (comp);
-
-               if (dt.tzid) {
-                       GError *error = NULL;
-
-                       e_cal_client_get_timezone_sync (event->comp_data->client, dt.tzid, &zone, NULL, 
&error);
-                       if (error != NULL) {
-                               zone = e_calendar_view_get_timezone (cal_view);
-                               g_clear_error (&error);
-                       }
-               } else
-                       zone = e_calendar_view_get_timezone (cal_view);
-
-               if (is_instance)
-                       rid = e_cal_component_get_recurid_as_string (comp);
-
-               e_cal_component_free_datetime (&dt);
-
-               if ((itip_organizer_is_user (registry, comp, event->comp_data->client) ||
-                    itip_sentby_is_user (registry, comp, event->comp_data->client))
-                               && cancel_component_dialog ((GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET 
(cal_view)),
-                                       event->comp_data->client,
-                                       comp, TRUE) && !e_cal_client_check_save_schedules 
(event->comp_data->client)) {
-                       if (!e_cal_component_is_instance (comp)) {
-                               ECalComponentRange range;
-
-                               /* set the recurrence ID of the object we send */
-                               range.type = E_CAL_COMPONENT_RANGE_SINGLE;
-                               e_cal_component_get_dtstart (comp, &range.datetime);
-                               range.datetime.value->is_date = 1;
-                               e_cal_component_set_recurid (comp, &range);
-
-                               e_cal_component_free_datetime (&range.datetime);
-                       }
-
-                       itip_send_comp (
-                               registry, E_CAL_COMPONENT_METHOD_CANCEL,
-                               comp, event->comp_data->client, NULL, NULL,
-                               NULL, TRUE, FALSE);
-               }
-
-               if (is_instance)
-                       e_cal_client_remove_object_sync (event->comp_data->client, uid, rid, CALOBJ_MOD_THIS, 
NULL, &error);
-               else {
-                       struct icaltimetype instance_rid;
-
-                       instance_rid = icaltime_from_timet_with_zone (
-                               event->comp_data->instance_start,
-                               TRUE, zone ? zone : icaltimezone_get_utc_timezone ());
-                       e_cal_util_remove_instances (event->comp_data->icalcomp, instance_rid, 
CALOBJ_MOD_THIS);
-                       e_cal_client_modify_object_sync (event->comp_data->client, 
event->comp_data->icalcomp, CALOBJ_MOD_THIS, NULL, &error);
-               }
-
-               delete_error_dialog (error, E_CAL_COMPONENT_EVENT);
-               g_clear_error (&error);
-               g_free (rid);
+       event = (ECalendarViewEvent *) selected->data;
+       if (is_comp_data_valid (event)) {
+               calendar_view_delete_event (cal_view, event);
        }
 
-       /* free memory */
        g_list_free (selected);
-       g_object_unref (comp);
 }
 
 void
@@ -1544,99 +1414,6 @@ e_calendar_view_open_event (ECalendarView *cal_view)
 }
 
 /**
- * e_calendar_view_new_appointment_for
- * @cal_view: A calendar view.
- * @dtstart: A Unix time_t that marks the beginning of the appointment.
- * @dtend: A Unix time_t that marks the end of the appointment.
- * @all_day: If TRUE, the dtstart and dtend are expanded to cover
- * the entire day, and the event is set to TRANSPARENT.
- * @meeting: Whether the appointment is a meeting or not.
- *
- * Opens an event editor dialog for a new appointment.
- */
-void
-e_calendar_view_new_appointment_for (ECalendarView *cal_view,
-                                     time_t dtstart,
-                                     time_t dtend,
-                                     gboolean all_day,
-                                     gboolean meeting)
-{
-       ECalendarViewPrivate *priv;
-       struct icaltimetype itt;
-       ECalComponentDateTime dt;
-       ECalComponent *comp;
-       icalcomponent *icalcomp;
-       ECalComponentTransparency transparency;
-       ECalClient *default_client = NULL;
-       gpointer parent;
-       guint32 flags = 0;
-
-       g_return_if_fail (E_IS_CALENDAR_VIEW (cal_view));
-
-       parent = gtk_widget_get_toplevel (GTK_WIDGET (cal_view));
-       parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
-
-       priv = cal_view->priv;
-
-       default_client = e_cal_model_ref_default_client (priv->model);
-       g_return_if_fail (default_client != NULL);
-
-       dt.value = &itt;
-       if (all_day)
-               dt.tzid = NULL;
-       else
-               dt.tzid = icaltimezone_get_tzid (e_cal_model_get_timezone (cal_view->priv->model));
-
-       icalcomp = e_cal_model_create_component_with_defaults (priv->model, all_day);
-       comp = e_cal_component_new ();
-       e_cal_component_set_icalcomponent (comp, icalcomp);
-
-       /* DTSTART, DTEND */
-       itt = icaltime_from_timet_with_zone (dtstart, FALSE, e_cal_model_get_timezone 
(cal_view->priv->model));
-       if (all_day) {
-               itt.hour = itt.minute = itt.second = 0;
-               itt.is_date = TRUE;
-       }
-       e_cal_component_set_dtstart (comp, &dt);
-
-       itt = icaltime_from_timet_with_zone (dtend, FALSE, e_cal_model_get_timezone (cal_view->priv->model));
-       if (all_day) {
-               /* We round it up to the end of the day, unless it is
-                * already set to midnight */
-               if (itt.hour != 0 || itt.minute != 0 || itt.second != 0) {
-                       icaltime_adjust (&itt, 1, 0, 0, 0);
-               }
-               itt.hour = itt.minute = itt.second = 0;
-               itt.is_date = TRUE;
-       }
-       e_cal_component_set_dtend (comp, &dt);
-
-       /* TRANSPARENCY */
-       transparency = all_day ? E_CAL_COMPONENT_TRANSP_TRANSPARENT
-               : E_CAL_COMPONENT_TRANSP_OPAQUE;
-       e_cal_component_set_transparency (comp, transparency);
-
-       /* CATEGORY */
-       e_cal_component_set_categories (comp, priv->default_category);
-
-       /* edit the object */
-       e_cal_component_commit_sequence (comp);
-
-       flags |= COMP_EDITOR_NEW_ITEM;
-       if (meeting) {
-               flags |= COMP_EDITOR_MEETING;
-               flags |= COMP_EDITOR_USER_ORG;
-       }
-
-       e_calendar_view_open_event_with_flags (
-               cal_view, default_client, icalcomp, flags);
-
-       g_object_unref (comp);
-
-       g_object_unref (default_client);
-}
-
-/**
  * e_calendar_view_new_appointment_full
  * @cal_view: an #ECalendarView
  * @all_day: Whether create all day event or not.
@@ -1708,7 +1485,9 @@ e_calendar_view_new_appointment_full (ECalendarView *cal_view,
                dtend = dtstart + (time_div * 60);
        }
 
-       e_calendar_view_new_appointment_for (cal_view, dtstart, dtend, all_day, meeting);
+       e_cal_ops_new_component_editor_from_model (
+               e_calendar_view_get_model (cal_view), NULL,
+               dtstart, dtend, meeting, all_day);
 }
 
 void
@@ -1724,7 +1503,7 @@ static void
 object_created_cb (CompEditor *ce,
                    ECalendarView *cal_view)
 {
-       e_calendar_view_emit_user_created (cal_view, comp_editor_get_client (ce));
+       e_cal_model_emit_object_created (e_calendar_view_get_model (cal_view), comp_editor_get_client (ce));
 }
 
 CompEditor *
@@ -1807,106 +1586,6 @@ e_calendar_view_edit_appointment (ECalendarView *cal_view,
        e_calendar_view_open_event_with_flags (cal_view, client, icalcomp, flags);
 }
 
-void
-e_calendar_view_modify_and_send (ECalendarView *cal_view,
-                                 ECalComponent *comp,
-                                 ECalClient *client,
-                                 CalObjModType mod,
-                                 GtkWindow *toplevel,
-                                 gboolean new)
-{
-       ECalModel *model;
-       ESourceRegistry *registry;
-       gboolean only_new_attendees = FALSE;
-       gboolean strip_alarms = TRUE;
-
-       if (e_calendar_view_modify (cal_view, comp, client, mod)) {
-               model = e_calendar_view_get_model (cal_view);
-               registry = e_cal_model_get_registry (model);
-
-               if ((itip_organizer_is_user (registry, comp, client) ||
-                    itip_sentby_is_user (registry, comp, client)) &&
-                   send_component_dialog (toplevel, client, comp, new, &strip_alarms, &only_new_attendees))
-                       e_calendar_view_send (cal_view, comp, client, mod, toplevel, strip_alarms, 
only_new_attendees);
-       }
-}
-
-gboolean
-e_calendar_view_modify (ECalendarView *cal_view,
-                        ECalComponent *comp,
-                        ECalClient *client,
-                        CalObjModType mod)
-{
-       GError *error = NULL;
-       gboolean ret;
-
-       g_return_val_if_fail (E_IS_CALENDAR_VIEW (cal_view), FALSE);
-
-       e_cal_component_commit_sequence (comp);
-
-       ret = e_cal_client_modify_object_sync (
-               client, e_cal_component_get_icalcomponent (comp),
-               mod, NULL, &error);
-
-       if (error != NULL) {
-               g_message (
-                       G_STRLOC ": Could not update the object! %s",
-                       error->message);
-
-               g_error_free (error);
-       }
-
-       return ret;
-}
-
-void
-e_calendar_view_send (ECalendarView *cal_view,
-                      ECalComponent *comp,
-                      ECalClient *client,
-                      CalObjModType mod,
-                      GtkWindow *toplevel,
-                      gboolean strip_alarms,
-                      gboolean only_new_attendees)
-{
-       ESourceRegistry *registry;
-       ECalModel *model;
-       ECalComponent *send_comp = NULL;
-
-       if (!itip_component_has_recipients (comp))
-               return;
-
-       if (mod == CALOBJ_MOD_ALL && e_cal_component_is_instance (comp)) {
-               /* Ensure we send the master object, not the instance only */
-               icalcomponent *icalcomp = NULL;
-               const gchar *uid = NULL;
-
-               e_cal_component_get_uid (comp, &uid);
-               e_cal_client_get_object_sync (
-                       client, uid, NULL, &icalcomp, NULL, NULL);
-               if (icalcomp != NULL) {
-                       send_comp = e_cal_component_new ();
-                       if (!e_cal_component_set_icalcomponent (send_comp, icalcomp)) {
-                               icalcomponent_free (icalcomp);
-                               g_object_unref (send_comp);
-                               send_comp = NULL;
-                       } else if (only_new_attendees) {
-                               /* copy new-attendees information too if required for later use */
-                               comp_editor_copy_new_attendees (send_comp, comp);
-                       }
-               }
-       }
-
-       model = e_calendar_view_get_model (cal_view);
-       registry = e_cal_model_get_registry (model);
-       itip_send_comp (
-               registry, E_CAL_COMPONENT_METHOD_REQUEST,
-               send_comp ? send_comp : comp, client, NULL,
-               NULL, NULL, strip_alarms, only_new_attendees);
-
-       if (send_comp)
-               g_object_unref (send_comp);
-}
-
 static void
 tooltip_ungrab (ECalendarView *view,
                guint32 event_time)
@@ -2340,15 +2019,22 @@ e_calendar_view_get_icalcomponent_summary (ECalClient *client,
        return summary;
 }
 
+/* A callback for e_cal_ops_create_component(), whose @user_data is an ECalendarView instance */
 void
-e_calendar_view_emit_user_created (ECalendarView *cal_view,
-                                   ECalClient *where_was_created)
+e_calendar_view_component_created_cb (ECalModel *model,
+                                     ECalClient *client,
+                                     icalcomponent *original_icalcomp,
+                                     const gchar *new_uid,
+                                     gpointer user_data)
 {
+       ECalendarView *cal_view = user_data;
+
        g_return_if_fail (E_IS_CALENDAR_VIEW (cal_view));
 
-       g_signal_emit (cal_view, signals[USER_CREATED], 0, where_was_created);
+       e_cal_model_emit_object_created (model, client);
 }
 
+
 void
 draw_curved_rectangle (cairo_t *cr,
                        gdouble x0,
@@ -2487,3 +2173,110 @@ e_calendar_view_is_editing (ECalendarView *cal_view)
 
        return is_editing;
 }
+
+/* Returns text description of the current view. */
+gchar *
+e_calendar_view_get_description_text (ECalendarView *cal_view)
+{
+       time_t start_time, end_time;
+       struct tm start_tm, end_tm;
+       struct icaltimetype start_tt, end_tt;
+       icaltimezone *zone;
+       gchar buffer[1024] = { 0 };
+       gchar end_buffer[512] = { 0 };
+
+       g_return_val_if_fail (E_IS_CALENDAR_VIEW (cal_view), NULL);
+
+       if (!e_calendar_view_get_visible_time_range (cal_view, &start_time, &end_time))
+               return NULL;
+
+       zone = e_cal_model_get_timezone (cal_view->priv->model);
+
+       start_tt = icaltime_from_timet_with_zone (start_time, FALSE, zone);
+       start_tm.tm_year = start_tt.year - 1900;
+       start_tm.tm_mon = start_tt.month - 1;
+       start_tm.tm_mday = start_tt.day;
+       start_tm.tm_hour = start_tt.hour;
+       start_tm.tm_min = start_tt.minute;
+       start_tm.tm_sec = start_tt.second;
+       start_tm.tm_isdst = -1;
+       start_tm.tm_wday = time_day_of_week (start_tt.day, start_tt.month - 1, start_tt.year);
+
+       /* Subtract one from end_time so we don't get an extra day. */
+       end_tt = icaltime_from_timet_with_zone (end_time - 1, FALSE, zone);
+       end_tm.tm_year = end_tt.year - 1900;
+       end_tm.tm_mon = end_tt.month - 1;
+       end_tm.tm_mday = end_tt.day;
+       end_tm.tm_hour = end_tt.hour;
+       end_tm.tm_min = end_tt.minute;
+       end_tm.tm_sec = end_tt.second;
+       end_tm.tm_isdst = -1;
+       end_tm.tm_wday = time_day_of_week (end_tt.day, end_tt.month - 1, end_tt.year);
+
+       if (E_IS_MONTH_VIEW (cal_view) || E_IS_CAL_LIST_VIEW (cal_view)) {
+               if (start_tm.tm_year == end_tm.tm_year) {
+                       if (start_tm.tm_mon == end_tm.tm_mon) {
+                               e_utf8_strftime (buffer, sizeof (buffer),
+                                       "%d", &start_tm);
+                               e_utf8_strftime (end_buffer, sizeof (end_buffer),
+                                       _("%d %b %Y"), &end_tm);
+                               strcat (buffer, " - ");
+                               strcat (buffer, end_buffer);
+                       } else {
+                               e_utf8_strftime (buffer, sizeof (buffer),
+                                       _("%d %b"), &start_tm);
+                               e_utf8_strftime (end_buffer, sizeof (end_buffer),
+                                       _("%d %b %Y"), &end_tm);
+                               strcat (buffer, " - ");
+                               strcat (buffer, end_buffer);
+                       }
+               } else {
+                       e_utf8_strftime (
+                               buffer, sizeof (buffer),
+                               _("%d %b %Y"), &start_tm);
+                       e_utf8_strftime (
+                               end_buffer, sizeof (end_buffer),
+                               _("%d %b %Y"), &end_tm);
+                       strcat (buffer, " - ");
+                       strcat (buffer, end_buffer);
+               }
+       } else {
+               if (start_tm.tm_year == end_tm.tm_year &&
+                       start_tm.tm_mon == end_tm.tm_mon &&
+                       start_tm.tm_mday == end_tm.tm_mday) {
+                       e_utf8_strftime (
+                               buffer, sizeof (buffer),
+                               _("%A %d %b %Y"), &start_tm);
+               } else if (start_tm.tm_year == end_tm.tm_year) {
+                       e_utf8_strftime (
+                               buffer, sizeof (buffer),
+                               _("%a %d %b"), &start_tm);
+                       e_utf8_strftime (
+                               end_buffer, sizeof (end_buffer),
+                               _("%a %d %b %Y"), &end_tm);
+                       strcat (buffer, " - ");
+                       strcat (buffer, end_buffer);
+               } else {
+                       e_utf8_strftime (
+                               buffer, sizeof (buffer),
+                               _("%a %d %b %Y"), &start_tm);
+                       e_utf8_strftime (
+                               end_buffer, sizeof (end_buffer),
+                               _("%a %d %b %Y"), &end_tm);
+                       strcat (buffer, " - ");
+                       strcat (buffer, end_buffer);
+               }
+       }
+
+       return g_strdup (buffer);
+}
+
+void
+e_calendar_view_move_view_range (ECalendarView *cal_view,
+                                ECalendarViewMoveType mode_type,
+                                time_t exact_date)
+{
+       g_return_if_fail (E_IS_CALENDAR_VIEW (cal_view));
+
+       g_signal_emit (cal_view, signals[MOVE_VIEW_RANGE], 0, mode_type, (gint64) exact_date);
+}
diff --git a/calendar/gui/e-calendar-view.h b/calendar/gui/e-calendar-view.h
index 857ef04..faa36f2 100644
--- a/calendar/gui/e-calendar-view.h
+++ b/calendar/gui/e-calendar-view.h
@@ -26,7 +26,6 @@
 #include <libecal/libecal.h>
 
 #include "e-cal-model.h"
-#include "gnome-cal.h"
 #include "dialogs/comp-editor.h"
 
 /* Standard GObject macros */
@@ -127,6 +126,13 @@ typedef enum {
        EDIT_EVENT_FORCE_APPOINTMENT
 } EEditEventMode;
 
+typedef enum {
+       E_CALENDAR_VIEW_MOVE_PREVIOUS,
+       E_CALENDAR_VIEW_MOVE_NEXT,
+       E_CALENDAR_VIEW_MOVE_TO_TODAY,
+       E_CALENDAR_VIEW_MOVE_TO_EXACT_DAY
+} ECalendarViewMoveType;
+
 struct _ECalendarViewClass {
        GtkTableClass parent_class;
 
@@ -142,8 +148,9 @@ struct _ECalendarViewClass {
                                                 ECalendarViewEvent *event);
        void            (*event_added)          (ECalendarView *day_view,
                                                 ECalendarViewEvent *event);
-       void            (*user_created)         (ECalendarView *cal_view,
-                                                ECalClient *where_was_created);
+       void            (*move_view_range)      (ECalendarView *cal_view,
+                                                ECalendarViewMoveType move_type,
+                                                gint64 exact_date);
 
        /* Virtual methods */
        GList *         (*get_selected_events)  (ECalendarView *cal_view);
@@ -159,33 +166,27 @@ struct _ECalendarViewClass {
                                                (ECalendarView *cal_view,
                                                 time_t *start_time,
                                                 time_t *end_time);
+       void            (*precalc_visible_time_range)
+                                               (ECalendarView *cal_view,
+                                                time_t in_start_time,
+                                                time_t in_end_time,
+                                                time_t *out_start_time,
+                                                time_t *out_end_time);
        void            (*update_query)         (ECalendarView *cal_view);
        void            (*open_event)           (ECalendarView *cal_view);
        void            (*paste_text)           (ECalendarView *cal_view);
 };
 
 GType          e_calendar_view_get_type        (void);
-GnomeCalendar *        e_calendar_view_get_calendar    (ECalendarView *cal_view);
-void           e_calendar_view_set_calendar    (ECalendarView *cal_view,
-                                                GnomeCalendar *calendar);
 ECalModel *    e_calendar_view_get_model       (ECalendarView *cal_view);
 icaltimezone * e_calendar_view_get_timezone    (ECalendarView *cal_view);
 void           e_calendar_view_set_timezone    (ECalendarView *cal_view,
                                                 icaltimezone *zone);
-const gchar *  e_calendar_view_get_default_category
-                                               (ECalendarView *cal_view);
-void           e_calendar_view_set_default_category
-                                               (ECalendarView *cal_view,
-                                                const gchar *category);
 gint           e_calendar_view_get_time_divisions
                                                (ECalendarView *cal_view);
 void           e_calendar_view_set_time_divisions
                                                (ECalendarView *cal_view,
                                                 gint time_divisions);
-void           e_calendar_view_set_status_message
-                                               (ECalendarView *cal_view,
-                                                const gchar *message,
-                                                gint percent);
 GtkTargetList *        e_calendar_view_get_copy_target_list
                                                (ECalendarView *cal_view);
 GtkTargetList *        e_calendar_view_get_paste_target_list
@@ -205,6 +206,12 @@ gboolean   e_calendar_view_get_visible_time_range
                                                (ECalendarView *cal_view,
                                                 time_t *start_time,
                                                 time_t *end_time);
+void           e_calendar_view_precalc_visible_time_range
+                                               (ECalendarView *cal_view,
+                                                time_t in_start_time,
+                                                time_t in_end_time,
+                                                time_t *out_start_time,
+                                                time_t *out_end_time);
 void           e_calendar_view_update_query    (ECalendarView *cal_view);
 
 void           e_calendar_view_delete_selected_occurrence
@@ -218,18 +225,12 @@ CompEditor *      e_calendar_view_open_event_with_flags
 void           e_calendar_view_popup_event     (ECalendarView *cal_view,
                                                 GdkEvent *button_event);
 
-gboolean       e_calendar_view_add_event       (ECalendarView *cal_view,
+void           e_calendar_view_add_event       (ECalendarView *cal_view,
                                                 ECalClient *client,
                                                 time_t dtstart,
                                                 icaltimezone *default_zone,
                                                 icalcomponent *icalcomp,
                                                 gboolean in_top_canvas);
-void           e_calendar_view_new_appointment_for
-                                               (ECalendarView *cal_view,
-                                                time_t dtstart,
-                                                time_t dtend,
-                                                gboolean all_day,
-                                                gboolean meeting);
 void           e_calendar_view_new_appointment_full
                                                (ECalendarView *cal_view,
                                                 gboolean all_day,
@@ -242,23 +243,11 @@ void              e_calendar_view_edit_appointment
                                                 icalcomponent *icalcomp,
                                                 EEditEventMode mode);
 void           e_calendar_view_open_event      (ECalendarView *cal_view);
-void           e_calendar_view_modify_and_send (ECalendarView *cal_view,
-                                                ECalComponent *comp,
-                                                ECalClient *client,
-                                                CalObjModType mod,
-                                                GtkWindow *toplevel,
-                                                gboolean new);
-gboolean       e_calendar_view_modify          (ECalendarView *cal_view,
-                                                ECalComponent *comp,
-                                                ECalClient *client,
-                                                CalObjModType mod);
-void           e_calendar_view_send            (ECalendarView *cal_view,
-                                                ECalComponent *comp,
-                                                ECalClient *client,
-                                                CalObjModType mod,
-                                                GtkWindow *toplevel,
-                                                gboolean strip_alarms,
-                                                gboolean only_new_attendees);
+gchar *                e_calendar_view_get_description_text
+                                               (ECalendarView *cal_view);
+void           e_calendar_view_move_view_range (ECalendarView *cal_view,
+                                                ECalendarViewMoveType mode_type,
+                                                time_t exact_date);
 gboolean       e_calendar_view_get_tooltips    (const ECalendarViewEventData *data);
 
 void           e_calendar_view_move_tip        (GtkWidget *widget,
@@ -270,9 +259,12 @@ const gchar *      e_calendar_view_get_icalcomponent_summary
                                                 icalcomponent *icalcomp,
                                                 gboolean *free_text);
 
-void           e_calendar_view_emit_user_created
-                                               (ECalendarView *cal_view,
-                                                ECalClient *where_was_created);
+void           e_calendar_view_component_created_cb
+                                               (ECalModel *model,
+                                                ECalClient *client,
+                                                icalcomponent *original_icalcomp,
+                                                const gchar *new_uid,
+                                                gpointer user_data);
 
 void           draw_curved_rectangle           (cairo_t *cr,
                                                 gdouble x0,
diff --git a/calendar/gui/e-day-view.c b/calendar/gui/e-day-view.c
index 9950da6..b6d602d 100644
--- a/calendar/gui/e-day-view.c
+++ b/calendar/gui/e-day-view.c
@@ -36,7 +36,6 @@
 #include "libgnomecanvas/libgnomecanvas.h"
 
 #include "dialogs/delete-comp.h"
-#include "dialogs/delete-error.h"
 #include "dialogs/send-comp.h"
 #include "dialogs/cancel-comp.h"
 #include "dialogs/recur-comp.h"
@@ -46,6 +45,7 @@
 
 #include "calendar-config.h"
 #include "comp-util.h"
+#include "e-cal-ops.h"
 #include "e-cal-model-calendar.h"
 #include "e-day-view-layout.h"
 #include "e-day-view-main-item.h"
@@ -339,7 +339,8 @@ static void e_day_view_foreach_event_with_uid (EDayView *day_view,
 static void e_day_view_free_events (EDayView *day_view);
 static void e_day_view_free_event_array (EDayView *day_view,
                                         GArray *array);
-static gint e_day_view_add_event (ESourceRegistry *registry,
+static void e_day_view_add_event (ESourceRegistry *registry,
+                                ECalClient *client,
                                 ECalComponent *comp,
                                 time_t   start,
                                 time_t   end,
@@ -462,6 +463,11 @@ static time_t e_day_view_find_work_week_start      (EDayView       *day_view,
 static void e_day_view_recalc_work_week                (EDayView       *day_view);
 static void e_day_view_recalc_work_week_days_shown     (EDayView       *day_view);
 
+static void e_day_view_precalc_visible_time_range (ECalendarView *cal_view,
+                                                  time_t in_start_time,
+                                                  time_t in_end_time,
+                                                  time_t *out_start_time,
+                                                  time_t *out_end_time);
 static void e_day_view_queue_layout (EDayView *day_view);
 static void e_day_view_cancel_layout (EDayView *day_view);
 static gboolean e_day_view_layout_timeout_cb (gpointer data);
@@ -648,52 +654,62 @@ day_view_get_selected_time_range (ECalendarView *cal_view,
        return TRUE;
 }
 
-static gboolean
-e_day_view_add_new_event_in_selected_range (EDayView *day_view,
-                                            GdkEventKey *key_event)
+typedef struct {
+       EDayView *day_view;
+       GdkEventKey *key_event;
+       time_t dtstart, dtend;
+       gboolean in_top_canvas;
+       gboolean paste_clipboard;
+} NewEventInRangeData;
+
+static void
+new_event_in_rage_data_free (gpointer ptr)
 {
-       icalcomponent *icalcomp;
-       ECalClient *client;
-       ECalModel *model;
+       NewEventInRangeData *ned = ptr;
+
+       if (ned) {
+               g_clear_object (&ned->day_view);
+               g_free (ned->key_event);
+               g_free (ned);
+       }
+}
+
+static void
+day_view_new_event_in_selected_range_cb (ECalModel *model,
+                                        ECalClient *client,
+                                        icalcomponent *default_component,
+                                        gpointer user_data)
+{
+       NewEventInRangeData *ned = user_data;
        ECalComponent *comp = NULL;
        gint day, event_num;
-       time_t dtstart, dtend;
        ECalComponentDateTime start_dt, end_dt;
        struct icaltimetype start_tt, end_tt;
        const gchar *uid;
        AddEventData add_event_data;
        ESourceRegistry *registry;
-       gboolean success = FALSE;
+       icaltimezone *zone;
 
-       model = e_calendar_view_get_model (E_CALENDAR_VIEW (day_view));
-
-       registry = e_cal_model_get_registry (model);
-       client = e_cal_model_ref_default_client (model);
+       g_return_if_fail (ned != NULL);
+       g_return_if_fail (E_IS_CAL_MODEL (model));
+       g_return_if_fail (E_IS_CAL_CLIENT (client));
+       g_return_if_fail (default_component != NULL);
 
        /* Check if the client is read only */
        if (e_client_is_readonly (E_CLIENT (client)))
-               goto exit;
-
-       icalcomp = e_cal_model_create_component_with_defaults (model, day_view->selection_in_top_canvas);
-       if (!icalcomp)
-               goto exit;
-
-       uid = icalcomponent_get_uid (icalcomp);
-
-       comp = e_cal_component_new ();
-       e_cal_component_set_icalcomponent (comp, icalcomp);
+               return;
 
-       day_view_get_selected_time_range ((ECalendarView *) day_view, &dtstart, &dtend);
+       registry = e_cal_model_get_registry (model);
+       zone = e_cal_model_get_timezone (model);
+       uid = icalcomponent_get_uid (default_component);
 
-       start_tt = icaltime_from_timet_with_zone (
-               dtstart, FALSE,
-               e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view)));
+       comp = e_cal_component_new_from_icalcomponent (icalcomponent_new_clone (default_component));
+       g_return_if_fail (comp != NULL);
 
-       end_tt = icaltime_from_timet_with_zone (
-               dtend, FALSE,
-               e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view)));
+       start_tt = icaltime_from_timet_with_zone (ned->dtstart, FALSE, zone);
+       end_tt = icaltime_from_timet_with_zone (ned->dtend, FALSE, zone);
 
-       if (day_view->selection_in_top_canvas) {
+       if (ned->in_top_canvas) {
                start_dt.tzid = NULL;
                start_tt.is_date = 1;
                end_tt.is_date = 1;
@@ -701,7 +717,7 @@ e_day_view_add_new_event_in_selected_range (EDayView *day_view,
                /* Editor default in day/work-week view - top canvas */
                e_cal_component_set_transparency (comp, E_CAL_COMPONENT_TRANSP_TRANSPARENT);
        } else {
-               start_dt.tzid = icaltimezone_get_tzid (e_calendar_view_get_timezone (E_CALENDAR_VIEW 
(day_view)));
+               start_dt.tzid = icaltimezone_get_tzid (zone);
 
                /* Editor default in day/work-week view - main canvas */
                e_cal_component_set_transparency (comp, E_CAL_COMPONENT_TRANSP_OPAQUE);
@@ -713,32 +729,77 @@ e_day_view_add_new_event_in_selected_range (EDayView *day_view,
        e_cal_component_set_dtstart (comp, &start_dt);
        e_cal_component_set_dtend (comp, &end_dt);
 
-       e_cal_component_set_categories (
-               comp, e_calendar_view_get_default_category (E_CALENDAR_VIEW (day_view)));
-
        /* We add the event locally and start editing it. We don't send it
         * to the server until the user finishes editing it. */
-       add_event_data.day_view = day_view;
+       add_event_data.day_view = ned->day_view;
        add_event_data.comp_data = NULL;
-       e_day_view_add_event (registry, comp, dtstart, dtend, &add_event_data);
-       e_day_view_check_layout (day_view);
-       gtk_widget_queue_draw (day_view->top_canvas);
-       gtk_widget_queue_draw (day_view->main_canvas);
+       e_day_view_add_event (registry, client, comp, ned->dtstart, ned->dtend, &add_event_data);
+       e_day_view_check_layout (ned->day_view);
+       gtk_widget_queue_draw (ned->day_view->top_canvas);
+       gtk_widget_queue_draw (ned->day_view->main_canvas);
 
-       if (!e_day_view_find_event_from_uid (day_view, client, uid, NULL, &day, &event_num)) {
+       if (!e_day_view_find_event_from_uid (ned->day_view, client, uid, NULL, &day, &event_num)) {
                g_warning ("Couldn't find event to start editing.\n");
-               goto exit;
-       }
+       } else {
+               e_day_view_start_editing_event (ned->day_view, day, event_num, ned->key_event);
 
-       e_day_view_start_editing_event (day_view, day, event_num, key_event);
+               if (ned->paste_clipboard) {
+                       EDayViewEvent *event;
 
-       success = TRUE;
+                       g_clear_object (&comp);
 
-exit:
+                       if (ned->day_view->editing_event_day == E_DAY_VIEW_LONG_EVENT) {
+                               if (!is_array_index_in_bounds (ned->day_view->long_events, 
ned->day_view->editing_event_num))
+                                       goto out;
+
+                               event = &g_array_index (ned->day_view->long_events,
+                                                       EDayViewEvent,
+                                                       ned->day_view->editing_event_num);
+                       } else {
+                               if (!is_array_index_in_bounds 
(ned->day_view->events[ned->day_view->editing_event_day], ned->day_view->editing_event_num))
+                                       goto out;
+
+                               event = &g_array_index 
(ned->day_view->events[ned->day_view->editing_event_day],
+                                                       EDayViewEvent,
+                                                       ned->day_view->editing_event_num);
+                       }
+
+                       if (event->canvas_item &&
+                           E_IS_TEXT (event->canvas_item) &&
+                           E_TEXT (event->canvas_item)->editing) {
+                               e_text_paste_clipboard (E_TEXT (event->canvas_item));
+                       }
+               }
+       }
+
+ out:
        g_clear_object (&comp);
-       g_clear_object (&client);
+}
+
+static void
+e_day_view_add_new_event_in_selected_range (EDayView *day_view,
+                                            GdkEventKey *key_event,
+                                           gboolean paste_clipboard)
+{
+       NewEventInRangeData *ned;
+       ECalModel *model;
+       const gchar *source_uid;
+
+       ned = g_new0 (NewEventInRangeData, 1);
+       ned->day_view = g_object_ref (day_view);
+       if (key_event) {
+               ned->key_event = g_new0 (GdkEventKey, 1);
+               *ned->key_event = *key_event;
+       }
+       day_view_get_selected_time_range (E_CALENDAR_VIEW (day_view), &ned->dtstart, &ned->dtend);
+       ned->in_top_canvas = day_view->selection_in_top_canvas;
+       ned->paste_clipboard = paste_clipboard;
 
-       return success;
+       model = e_calendar_view_get_model (E_CALENDAR_VIEW (day_view));
+       source_uid = e_cal_model_get_default_source_uid (model);
+
+       e_cal_ops_get_default_component  (model, source_uid, ned->in_top_canvas,
+               day_view_new_event_in_selected_range_cb, ned, new_event_in_rage_data_free);
 }
 
 static void
@@ -1761,6 +1822,8 @@ day_view_set_selected_time_range (ECalendarView *cal_view,
                gtk_widget_queue_draw (day_view->top_canvas);
                gtk_widget_queue_draw (day_view->top_dates_canvas);
                gtk_widget_queue_draw (day_view->main_canvas);
+
+               e_day_view_ensure_rows_visible (day_view, day_view->selection_start_row, 
day_view->selection_end_row);
        }
 }
 
@@ -1797,9 +1860,10 @@ day_view_paste_text (ECalendarView *cal_view)
 
        day_view = E_DAY_VIEW (cal_view);
 
-       if (day_view->editing_event_num == -1 &&
-           !e_day_view_add_new_event_in_selected_range (day_view, NULL))
+       if (day_view->editing_event_num == -1) {
+               e_day_view_add_new_event_in_selected_range (day_view, NULL, TRUE);
                return;
+       }
 
        if (day_view->editing_event_day == E_DAY_VIEW_LONG_EVENT) {
                if (!is_array_index_in_bounds (day_view->long_events, day_view->editing_event_num))
@@ -1856,6 +1920,7 @@ e_day_view_class_init (EDayViewClass *class)
        view_class->get_selected_time_range = day_view_get_selected_time_range;
        view_class->set_selected_time_range = day_view_set_selected_time_range;
        view_class->get_visible_time_range = day_view_get_visible_time_range;
+       view_class->precalc_visible_time_range = e_day_view_precalc_visible_time_range;
        view_class->paste_text = day_view_paste_text;
 
        /* XXX Should these be constructor properties? */
@@ -2309,6 +2374,52 @@ e_day_view_init (EDayView *day_view)
 }
 
 static void
+e_day_view_precalc_visible_time_range (ECalendarView *cal_view,
+                                      time_t in_start_time,
+                                      time_t in_end_time,
+                                      time_t *out_start_time,
+                                      time_t *out_end_time)
+{
+       EDayView *day_view;
+       gint days_shown;
+       time_t lower;
+       icaltimezone *zone;
+
+       g_return_if_fail (E_IS_DAY_VIEW (cal_view));
+       g_return_if_fail (out_start_time != NULL);
+       g_return_if_fail (out_end_time != NULL);
+
+       day_view = E_DAY_VIEW (cal_view);
+       days_shown = e_day_view_get_days_shown (day_view);
+       zone = e_calendar_view_get_timezone (cal_view);
+
+       /* Calculate the first day that should be shown, based on start_time
+        * and the days_shown setting. If we are showing 1 day it is just the
+        * start of the day given by start_time, otherwise it is the previous
+        * work-week start day. */
+       if (!e_day_view_get_work_week_view (day_view)) {
+               lower = time_day_begin_with_zone (in_start_time, zone);
+       } else {
+               lower = e_day_view_find_work_week_start (day_view, in_start_time);
+       }
+
+       /* See if we need to change the days shown. */
+       if (lower == day_view->lower) {
+               *out_start_time = day_view->lower;
+               *out_end_time = day_view->upper;
+       } else {
+               gint day;
+
+               *out_start_time = lower;
+               *out_end_time = lower;
+
+               for (day = 1; day <= days_shown; day++) {
+                       *out_end_time = time_add_day_with_zone (*out_end_time, 1, zone);
+               }
+       }
+}
+
+static void
 time_range_changed_cb (ECalModel *model,
                        time_t start_time,
                        time_t end_time,
@@ -2393,7 +2504,7 @@ process_component (EDayView *day_view,
        add_event_data.day_view = day_view;
        add_event_data.comp_data = comp_data;
        e_day_view_add_event (
-               registry, comp, comp_data->instance_start,
+               registry, comp_data->client, comp, comp_data->instance_start,
                comp_data->instance_end, &add_event_data);
 
        g_object_unref (comp);
@@ -3867,10 +3978,9 @@ e_day_view_on_top_canvas_button_press (GtkWidget *widget,
                                day_view_set_selected_time_range ((ECalendarView *) day_view, dtstart, dtend);
                        }
 
-                       e_calendar_view_new_appointment_for (
-                               E_CALENDAR_VIEW (day_view),
-                               dtstart, dtend, TRUE,
-                               calendar_config_get_prefer_meeting ());
+                       e_cal_ops_new_component_editor_from_model (
+                               e_calendar_view_get_model (E_CALENDAR_VIEW (day_view)), NULL,
+                               dtstart, dtend, calendar_config_get_prefer_meeting (), TRUE);
                        return TRUE;
                }
 
@@ -4031,10 +4141,9 @@ e_day_view_on_main_canvas_button_press (GtkWidget *widget,
                                dtend = day_view->before_click_dtend;
                                day_view_set_selected_time_range ((ECalendarView *) day_view, dtstart, dtend);
                        }
-                       e_calendar_view_new_appointment_for (
-                               E_CALENDAR_VIEW (day_view),
-                               dtstart, dtend, FALSE,
-                               calendar_config_get_prefer_meeting ());
+                       e_cal_ops_new_component_editor_from_model (
+                               e_calendar_view_get_model (E_CALENDAR_VIEW (day_view)), NULL,
+                               dtstart, dtend, calendar_config_get_prefer_meeting (), FALSE);
                        return TRUE;
                }
 
@@ -5049,8 +5158,7 @@ e_day_view_finish_long_event_resize (EDayView *day_view)
        ECalModel *model;
        ECalClient *client;
        ESourceRegistry *registry;
-       CalObjModType mod = CALOBJ_MOD_ALL;
-       GtkWindow *toplevel;
+       ECalObjModType mod = E_CAL_OBJ_MOD_ALL;
        gint is_date;
 
        model = e_calendar_view_get_model (E_CALENDAR_VIEW (day_view));
@@ -5120,10 +5228,7 @@ e_day_view_finish_long_event_resize (EDayView *day_view)
                        goto out;
                }
 
-               if (mod == CALOBJ_MOD_ALL)
-                       comp_util_sanitize_recurrence_master (comp, client);
-
-               if (mod == CALOBJ_MOD_THIS) {
+               if (mod == E_CAL_OBJ_MOD_THIS) {
                        /* set the correct DTSTART/DTEND on the individual recurrence */
                        if (day_view->resize_drag_pos == E_CALENDAR_VIEW_POS_TOP_EDGE) {
                                *date.value = icaltime_from_timet_with_zone (
@@ -5141,17 +5246,14 @@ e_day_view_finish_long_event_resize (EDayView *day_view)
                        e_cal_component_set_rrule_list (comp, NULL);
                        e_cal_component_set_exdate_list (comp, NULL);
                        e_cal_component_set_exrule_list (comp, NULL);
-
-                       e_cal_component_commit_sequence (comp);
                }
        } else if (e_cal_component_is_instance (comp))
-               mod = CALOBJ_MOD_THIS;
+               mod = E_CAL_OBJ_MOD_THIS;
 
-       toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (day_view)));
+       e_cal_component_commit_sequence (comp);
 
-       e_calendar_view_modify_and_send (
-               E_CALENDAR_VIEW (day_view),
-               comp, client, mod, toplevel, TRUE);
+       e_cal_ops_modify_component (model, client, e_cal_component_get_icalcomponent (comp),
+               mod, E_CAL_OPS_SEND_FLAG_ASK | E_CAL_OPS_SEND_FLAG_IS_NEW_COMPONENT);
 
  out:
        day_view->resize_drag_pos = E_CALENDAR_VIEW_POS_NONE;
@@ -5173,10 +5275,9 @@ e_day_view_finish_resize (EDayView *day_view)
        ECalModel *model;
        ECalClient *client;
        ESourceRegistry *registry;
-       CalObjModType mod = CALOBJ_MOD_ALL;
+       ECalObjModType mod = E_CAL_OBJ_MOD_ALL;
        GtkWindow *toplevel;
        GtkResponseType send = GTK_RESPONSE_NO;
-       gboolean modified;
        gboolean only_new_attendees = FALSE;
        gboolean strip_alarms = TRUE;
 
@@ -5261,10 +5362,7 @@ e_day_view_finish_resize (EDayView *day_view)
                        goto out;
                }
 
-               if (mod == CALOBJ_MOD_ALL)
-                       comp_util_sanitize_recurrence_master (comp, client);
-
-               if (mod == CALOBJ_MOD_THIS) {
+               if (mod == E_CAL_OBJ_MOD_THIS) {
                        /* set the correct DTSTART/DTEND on the individual recurrence */
                        if (day_view->resize_drag_pos == E_CALENDAR_VIEW_POS_TOP_EDGE) {
                                *date.value = icaltime_from_timet_with_zone (
@@ -5284,16 +5382,14 @@ e_day_view_finish_resize (EDayView *day_view)
                        e_cal_component_set_exrule_list (comp, NULL);
                }
        } else if (e_cal_component_is_instance (comp))
-               mod = CALOBJ_MOD_THIS;
+               mod = E_CAL_OBJ_MOD_THIS;
 
        e_cal_component_commit_sequence (comp);
 
-       modified = e_calendar_view_modify (E_CALENDAR_VIEW (day_view), comp, client, mod);
-
-       if (modified && send == GTK_RESPONSE_YES)
-               e_calendar_view_send (
-                               E_CALENDAR_VIEW (day_view),
-                               comp, client, mod, toplevel, strip_alarms, only_new_attendees);
+       e_cal_ops_modify_component (model, client, e_cal_component_get_icalcomponent (comp), mod,
+               (send == GTK_RESPONSE_YES ? E_CAL_OPS_SEND_FLAG_SEND : E_CAL_OPS_SEND_FLAG_DONT_SEND) |
+               (strip_alarms ? E_CAL_OPS_SEND_FLAG_STRIP_ALARMS : 0) |
+               (only_new_attendees ? E_CAL_OPS_SEND_FLAG_ONLY_NEW_ATTENDEES : 0));
 
  out:
        g_object_unref (comp);
@@ -5381,8 +5477,9 @@ e_day_view_free_event_array (EDayView *day_view,
 }
 
 /* This adds one event to the view, adding it to the appropriate array. */
-static gboolean
+static void
 e_day_view_add_event (ESourceRegistry *registry,
+                     ECalClient *client,
                       ECalComponent *comp,
                       time_t start,
                       time_t end,
@@ -5394,6 +5491,7 @@ e_day_view_add_event (ESourceRegistry *registry,
        gint days_shown;
        struct icaltimetype start_tt, end_tt;
        AddEventData *add_event_data;
+       icaltimezone *zone;
 
        add_event_data = data;
 
@@ -5406,23 +5504,20 @@ e_day_view_add_event (ESourceRegistry *registry,
        }*/
 
        /* Check that the event times are valid. */
-       g_return_val_if_fail (start <= end, TRUE);
-       g_return_val_if_fail (start < add_event_data->day_view->upper, TRUE);
-       g_return_val_if_fail (end > add_event_data->day_view->lower, TRUE);
+       g_return_if_fail (start <= end);
+       g_return_if_fail (start < add_event_data->day_view->upper);
+       g_return_if_fail (end > add_event_data->day_view->lower);
 
-       start_tt = icaltime_from_timet_with_zone (
-               start, FALSE,
-               e_calendar_view_get_timezone (E_CALENDAR_VIEW (add_event_data->day_view)));
-       end_tt = icaltime_from_timet_with_zone (
-               end, FALSE,
-               e_calendar_view_get_timezone (E_CALENDAR_VIEW (add_event_data->day_view)));
+       zone = e_calendar_view_get_timezone (E_CALENDAR_VIEW (add_event_data->day_view));
+       start_tt = icaltime_from_timet_with_zone (start, FALSE, zone);
+       end_tt = icaltime_from_timet_with_zone (end, FALSE, zone);
 
        if (add_event_data->comp_data) {
                event.comp_data = g_object_ref (add_event_data->comp_data);
        } else {
                event.comp_data = g_object_new (E_TYPE_CAL_MODEL_COMPONENT, NULL);
-
-               event.comp_data->client = e_cal_model_ref_default_client (e_calendar_view_get_model 
(E_CALENDAR_VIEW (add_event_data->day_view)));
+               event.comp_data->is_new_component = TRUE;
+               event.comp_data->client = g_object_ref (client);
                e_cal_component_abort_sequence (comp);
                event.comp_data->icalcomp = icalcomponent_new_clone (e_cal_component_get_icalcomponent 
(comp));
        }
@@ -5447,9 +5542,7 @@ e_day_view_add_event (ESourceRegistry *registry,
        event.num_columns = 0;
 
        event.different_timezone = FALSE;
-       if (!cal_comp_util_compare_event_timezones (comp,
-                                                   event.comp_data->client,
-                                                   e_calendar_view_get_timezone (E_CALENDAR_VIEW 
(add_event_data->day_view))))
+       if (!cal_comp_util_compare_event_timezones (comp, event.comp_data->client, zone))
                event.different_timezone = TRUE;
 
        if (!e_cal_component_has_attendees (comp) ||
@@ -5482,7 +5575,7 @@ e_day_view_add_event (ESourceRegistry *registry,
                        g_array_append_val (add_event_data->day_view->events[day], event);
                        add_event_data->day_view->events_sorted[day] = FALSE;
                        add_event_data->day_view->need_layout[day] = TRUE;
-                       return TRUE;
+                       return;
                }
        }
 
@@ -5491,7 +5584,7 @@ e_day_view_add_event (ESourceRegistry *registry,
        g_array_append_val (add_event_data->day_view->long_events, event);
        add_event_data->day_view->long_events_sorted = FALSE;
        add_event_data->day_view->long_events_need_layout = TRUE;
-       return TRUE;
+       return;
 }
 
 /* This lays out the short (less than 1 day) events in the columns.
@@ -6128,7 +6221,9 @@ e_day_view_do_key_press (GtkWidget *widget,
                return FALSE;
        }
 
-       return e_day_view_add_new_event_in_selected_range (day_view, event);
+       e_day_view_add_new_event_in_selected_range (day_view, event, FALSE);
+
+       return TRUE;
 }
 
 /* Select the time that begins a work day*/
@@ -6688,7 +6783,7 @@ e_day_view_cursor_key_left (EDayView *day_view,
                             GdkEventKey *event)
 {
        if (day_view->selection_start_day == 0) {
-               gnome_calendar_previous (e_calendar_view_get_calendar (E_CALENDAR_VIEW (day_view)));
+               e_calendar_view_move_view_range (E_CALENDAR_VIEW (day_view), E_CALENDAR_VIEW_MOVE_PREVIOUS, 
0);
        } else {
                day_view->selection_start_day--;
                day_view->selection_end_day--;
@@ -6711,7 +6806,7 @@ e_day_view_cursor_key_right (EDayView *day_view,
        days_shown = e_day_view_get_days_shown (day_view);
 
        if (day_view->selection_end_day == days_shown - 1) {
-               gnome_calendar_next (e_calendar_view_get_calendar (E_CALENDAR_VIEW (day_view)));
+               e_calendar_view_move_view_range (E_CALENDAR_VIEW (day_view), E_CALENDAR_VIEW_MOVE_NEXT, 0);
        } else {
                day_view->selection_start_day++;
                day_view->selection_end_day++;
@@ -7275,8 +7370,7 @@ e_day_view_change_event_time (EDayView *day_view,
        ECalModel *model;
        ECalClient *client;
        ESourceRegistry *registry;
-       CalObjModType mod = CALOBJ_MOD_ALL;
-       GtkWindow *toplevel;
+       ECalObjModType mod = E_CAL_OBJ_MOD_ALL;
 
        day = day_view->editing_event_day;
        event_num = day_view->editing_event_num;
@@ -7336,25 +7430,19 @@ e_day_view_change_event_time (EDayView *day_view,
                        goto out;
                }
 
-               if (mod == CALOBJ_MOD_ALL)
-                       comp_util_sanitize_recurrence_master (comp, client);
-
-               if (mod == CALOBJ_MOD_THIS) {
+               if (mod == E_CAL_OBJ_MOD_THIS) {
                        e_cal_component_set_rdate_list (comp, NULL);
                        e_cal_component_set_rrule_list (comp, NULL);
                        e_cal_component_set_exdate_list (comp, NULL);
                        e_cal_component_set_exrule_list (comp, NULL);
                }
        } else if (e_cal_component_is_instance (comp))
-               mod = CALOBJ_MOD_THIS;
-
-       toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (day_view)));
+               mod = E_CAL_OBJ_MOD_THIS;
 
        e_cal_component_commit_sequence (comp);
 
-       e_calendar_view_modify_and_send (
-               E_CALENDAR_VIEW (day_view),
-               comp, client, mod, toplevel, TRUE);
+       e_cal_ops_modify_component (model, client, e_cal_component_get_icalcomponent (comp),
+               mod, E_CAL_OPS_SEND_FLAG_ASK | E_CAL_OPS_SEND_FLAG_IS_NEW_COMPONENT);
 
 out:
        g_object_unref (comp);
@@ -7554,7 +7642,7 @@ e_day_view_on_editing_stopped (EDayView *day_view,
        e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (event->comp_data->icalcomp));
 
        client = event->comp_data->client;
-       on_server = cal_comp_is_on_server (comp, client);
+       on_server = !event->comp_data->is_new_component;
 
        if (string_is_empty (text) && !on_server) {
                const gchar *uid;
@@ -7587,40 +7675,20 @@ e_day_view_on_editing_stopped (EDayView *day_view,
                e_cal_component_commit_sequence (comp);
 
                if (!on_server) {
-                       gchar *uid = NULL;
-                       GError *error = NULL;
-
-                       e_cal_client_create_object_sync (
-                               client, icalcomp, &uid, NULL, &error);
-
-                       if (error != NULL) {
-                               uid = NULL;
-                               g_warning (
-                                       "%s: Could not create the object! %s",
-                                       G_STRFUNC, error->message);
-                               g_error_free (error);
-                       } else {
-                               icalcomponent_set_uid (icalcomp, uid);
-                               e_calendar_view_emit_user_created (
-                                       E_CALENDAR_VIEW (day_view), client);
-                       }
-
-                       g_free (uid);
+                       e_cal_ops_create_component (e_calendar_view_get_model (E_CALENDAR_VIEW (day_view)), 
client, icalcomp,
+                               e_calendar_view_component_created_cb, g_object_ref (day_view), 
g_object_unref);
 
                        /* we remove the object since we either got the update from the server or failed */
                        e_day_view_remove_event_cb (day_view, day, event_num, NULL);
                } else {
-                       CalObjModType mod = CALOBJ_MOD_ALL;
-                       GtkWindow *toplevel;
+                       ECalObjModType mod = E_CAL_OBJ_MOD_ALL;
+
                        if (e_cal_component_has_recurrences (comp)) {
                                if (!recur_component_dialog (client, comp, &mod, NULL, FALSE)) {
                                        goto out;
                                }
 
-                               if (mod == CALOBJ_MOD_ALL)
-                                       comp_util_sanitize_recurrence_master (comp, client);
-
-                               if (mod == CALOBJ_MOD_THIS) {
+                               if (mod == E_CAL_OBJ_MOD_THIS) {
                                        ECalComponentDateTime olddt, dt;
                                        icaltimetype itt;
 
@@ -7668,14 +7736,10 @@ e_day_view_on_editing_stopped (EDayView *day_view,
                                        e_cal_component_commit_sequence (comp);
                                }
                        } else if (e_cal_component_is_instance (comp))
-                               mod = CALOBJ_MOD_THIS;
-
-                       /* FIXME When sending here, what exactly should we send? */
-                       toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (day_view)));
+                               mod = E_CAL_OBJ_MOD_THIS;
 
-                       e_calendar_view_modify_and_send (
-                               E_CALENDAR_VIEW (day_view),
-                               comp, client, mod, toplevel, FALSE);
+                       e_cal_ops_modify_component (e_calendar_view_get_model (E_CALENDAR_VIEW (day_view)),
+                               client, e_cal_component_get_icalcomponent (comp), mod, 
E_CAL_OPS_SEND_FLAG_ASK);
                }
 
        }
@@ -8761,7 +8825,6 @@ e_day_view_on_top_canvas_drag_data_received (GtkWidget *widget,
        gint format, length;
        gint days_shown;
        GtkResponseType send = GTK_RESPONSE_NO;
-       gboolean modified;
        gboolean only_new_attendees = FALSE;
        gboolean strip_alarms = TRUE;
 
@@ -8790,7 +8853,7 @@ e_day_view_on_top_canvas_drag_data_received (GtkWidget *widget,
                        x, y, &day,
                        NULL);
                if (pos != E_CALENDAR_VIEW_POS_OUTSIDE) {
-                       CalObjModType mod = CALOBJ_MOD_ALL;
+                       ECalObjModType mod = E_CAL_OBJ_MOD_ALL;
                        ECalClient *client;
                        GtkWindow *toplevel;
 
@@ -8920,24 +8983,21 @@ e_day_view_on_top_canvas_drag_data_received (GtkWidget *widget,
                                        return;
                                }
 
-                               if (mod == CALOBJ_MOD_ALL)
-                                       comp_util_sanitize_recurrence_master (comp, client);
-
-                               if (mod == CALOBJ_MOD_THIS) {
+                               if (mod == E_CAL_OBJ_MOD_THIS) {
                                        e_cal_component_set_rdate_list (comp, NULL);
                                        e_cal_component_set_rrule_list (comp, NULL);
                                        e_cal_component_set_exdate_list (comp, NULL);
                                        e_cal_component_set_exrule_list (comp, NULL);
                                }
                        } else if (e_cal_component_is_instance (comp))
-                               mod = CALOBJ_MOD_THIS;
+                               mod = E_CAL_OBJ_MOD_THIS;
 
-                       modified = e_calendar_view_modify (E_CALENDAR_VIEW (day_view), comp, client, mod);
+                       e_cal_component_commit_sequence (comp);
 
-                       if (modified && send == GTK_RESPONSE_YES)
-                               e_calendar_view_send (
-                                       E_CALENDAR_VIEW (day_view),
-                                       comp, client, mod, toplevel, strip_alarms, only_new_attendees);
+                       e_cal_ops_modify_component (model, client, e_cal_component_get_icalcomponent (comp), 
mod,
+                               (send == GTK_RESPONSE_YES ? E_CAL_OPS_SEND_FLAG_SEND : 
E_CAL_OPS_SEND_FLAG_DONT_SEND) |
+                               (strip_alarms ? E_CAL_OPS_SEND_FLAG_STRIP_ALARMS : 0) |
+                               (only_new_attendees ? E_CAL_OPS_SEND_FLAG_ONLY_NEW_ATTENDEES : 0));
 
                        g_object_unref (comp);
 
@@ -8946,14 +9006,9 @@ e_day_view_on_top_canvas_drag_data_received (GtkWidget *widget,
        }
 
        if (length >= 0 && format == 8 && !drag_from_same_window) {
-               ECalClient *client;
-
                /* We are dragging between different window */
-
                icalcomponent *icalcomp;
                icalcomponent_kind kind;
-               time_t dtstart;
-               icaltimezone *default_zone;
 
                pos = e_day_view_convert_position_in_top_canvas (
                        day_view,
@@ -8966,49 +9021,14 @@ e_day_view_on_top_canvas_drag_data_received (GtkWidget *widget,
                if (!icalcomp)
                        goto error;
 
-               default_zone = e_cal_model_get_timezone (model);
-
                /* check the type of the component */
                kind = icalcomponent_isa (icalcomp);
+               icalcomponent_free (icalcomp);
+
                if (kind != ICAL_VCALENDAR_COMPONENT && kind != ICAL_VEVENT_COMPONENT)
                        goto error;
 
-               dtstart = day_view->day_starts[day];
-
-               client = e_cal_model_ref_default_client (model);
-
-               if (kind == ICAL_VCALENDAR_COMPONENT) {
-                       icalcomponent_kind child_kind;
-                       icalcomponent *subcomp;
-
-                       subcomp = icalcomponent_get_first_component (icalcomp, ICAL_ANY_COMPONENT);
-                       while (subcomp) {
-                               child_kind = icalcomponent_isa (subcomp);
-                               if (child_kind == ICAL_VEVENT_COMPONENT)
-                                       e_calendar_view_add_event (
-                                               E_CALENDAR_VIEW (day_view), client, dtstart,
-                                               default_zone, subcomp, TRUE);
-                               else if (child_kind == ICAL_VTIMEZONE_COMPONENT) {
-                                       icaltimezone *zone;
-
-                                       zone = icaltimezone_new ();
-                                       icaltimezone_set_component (zone, subcomp);
-                                       e_cal_client_add_timezone_sync (client, zone, NULL, NULL);
-
-                                       icaltimezone_free (zone, 1);
-                               }
-
-                               subcomp = icalcomponent_get_next_component (
-                                       icalcomp, ICAL_ANY_COMPONENT);
-                       }
-
-                       icalcomponent_free (icalcomp);
-
-               } else {
-                       e_calendar_view_add_event (E_CALENDAR_VIEW (day_view), client, dtstart, default_zone, 
icalcomp, TRUE);
-               }
-
-               g_object_unref (client);
+               e_cal_ops_paste_components (model, (const gchar *) data);
 
                gtk_drag_finish (context, TRUE, TRUE, time);
                return;
@@ -9044,7 +9064,6 @@ e_day_view_on_main_canvas_drag_data_received (GtkWidget *widget,
        const guchar *data;
        gint format, length;
        GtkResponseType send = GTK_RESPONSE_NO;
-       gboolean modified;
        gboolean only_new_attendees = FALSE;
        gboolean strip_alarms = TRUE;
 
@@ -9078,7 +9097,7 @@ e_day_view_on_main_canvas_drag_data_received (GtkWidget *widget,
                        x, y, &day,
                        &row, NULL);
                if (pos != E_CALENDAR_VIEW_POS_OUTSIDE) {
-                       CalObjModType mod = CALOBJ_MOD_ALL;
+                       ECalObjModType mod = E_CAL_OBJ_MOD_ALL;
                        ECalClient *client;
                        GtkWindow *toplevel;
 
@@ -9181,24 +9200,21 @@ e_day_view_on_main_canvas_drag_data_received (GtkWidget *widget,
                                        return;
                                }
 
-                               if (mod == CALOBJ_MOD_ALL)
-                                       comp_util_sanitize_recurrence_master (comp, client);
-
-                               if (mod == CALOBJ_MOD_THIS) {
+                               if (mod == E_CAL_OBJ_MOD_THIS) {
                                        e_cal_component_set_rdate_list (comp, NULL);
                                        e_cal_component_set_rrule_list (comp, NULL);
                                        e_cal_component_set_exdate_list (comp, NULL);
                                        e_cal_component_set_exrule_list (comp, NULL);
                                }
                        } else if (e_cal_component_is_instance (comp))
-                               mod = CALOBJ_MOD_THIS;
+                               mod = E_CAL_OBJ_MOD_THIS;
 
-                       modified = e_calendar_view_modify (E_CALENDAR_VIEW (day_view), comp, client, mod);
+                       e_cal_component_commit_sequence (comp);
 
-                       if (modified && send == GTK_RESPONSE_YES)
-                               e_calendar_view_send (
-                                       E_CALENDAR_VIEW (day_view),
-                                       comp, client, mod, toplevel, strip_alarms, only_new_attendees);
+                       e_cal_ops_modify_component (model, client, e_cal_component_get_icalcomponent (comp), 
mod,
+                               (send == GTK_RESPONSE_YES ? E_CAL_OPS_SEND_FLAG_SEND : 
E_CAL_OPS_SEND_FLAG_DONT_SEND) |
+                               (strip_alarms ? E_CAL_OPS_SEND_FLAG_STRIP_ALARMS : 0) |
+                               (only_new_attendees ? E_CAL_OPS_SEND_FLAG_ONLY_NEW_ATTENDEES : 0));
 
                        g_object_unref (comp);
 
@@ -9207,14 +9223,9 @@ e_day_view_on_main_canvas_drag_data_received (GtkWidget *widget,
        }
 
        if (length >= 0 && format == 8 && !drag_from_same_window) {
-               ECalClient *client;
-
                /* We are dragging between different window */
-
                icalcomponent *icalcomp;
                icalcomponent_kind kind;
-               time_t dtstart;
-               icaltimezone *default_zone;
 
                pos = e_day_view_convert_position_in_main_canvas (
                        day_view,
@@ -9227,49 +9238,14 @@ e_day_view_on_main_canvas_drag_data_received (GtkWidget *widget,
                if (!icalcomp)
                        goto error;
 
-               default_zone = e_cal_model_get_timezone (model);
-
                /* check the type of the component */
                kind = icalcomponent_isa (icalcomp);
+               icalcomponent_free (icalcomp);
+
                if (kind != ICAL_VCALENDAR_COMPONENT && kind != ICAL_VEVENT_COMPONENT)
                        goto error;
 
-               dtstart = e_day_view_convert_grid_position_to_time (day_view, day, row);
-
-               client = e_cal_model_ref_default_client (model);
-
-               if (kind == ICAL_VCALENDAR_COMPONENT) {
-                       icalcomponent_kind child_kind;
-                       icalcomponent *subcomp;
-
-                       subcomp = icalcomponent_get_first_component (icalcomp, ICAL_ANY_COMPONENT);
-                       while (subcomp) {
-                               child_kind = icalcomponent_isa (subcomp);
-                               if (child_kind == ICAL_VEVENT_COMPONENT)
-                                       e_calendar_view_add_event (
-                                               E_CALENDAR_VIEW (day_view), client, dtstart,
-                                               default_zone, subcomp, FALSE);
-                               else if (child_kind == ICAL_VTIMEZONE_COMPONENT) {
-                                       icaltimezone *zone;
-
-                                       zone = icaltimezone_new ();
-                                       icaltimezone_set_component (zone, subcomp);
-                                       e_cal_client_add_timezone_sync (client, zone, NULL, NULL);
-
-                                       icaltimezone_free (zone, 1);
-                               }
-
-                               subcomp = icalcomponent_get_next_component (
-                                       icalcomp, ICAL_ANY_COMPONENT);
-                       }
-
-                       icalcomponent_free (icalcomp);
-
-               } else {
-                       e_calendar_view_add_event (E_CALENDAR_VIEW (day_view), client, dtstart, default_zone, 
icalcomp, FALSE);
-               }
-
-               g_object_unref (client);
+               e_cal_ops_paste_components (model, (const gchar *) data);
 
                gtk_drag_finish (context, TRUE, TRUE, time);
                return;
diff --git a/calendar/gui/e-day-view.h b/calendar/gui/e-day-view.h
index f6f187e..1e7eafb 100644
--- a/calendar/gui/e-day-view.h
+++ b/calendar/gui/e-day-view.h
@@ -28,7 +28,6 @@
 #include <libgnomecanvas/libgnomecanvas.h>
 
 #include "e-calendar-view.h"
-#include "gnome-cal.h"
 
 /*
  * EDayView - displays the Day & Work-Week views of the calendar.
diff --git a/calendar/gui/e-memo-table.c b/calendar/gui/e-memo-table.c
index 146a63b..38ae982 100644
--- a/calendar/gui/e-memo-table.c
+++ b/calendar/gui/e-memo-table.c
@@ -37,9 +37,9 @@
 #include <glib/gstdio.h>
 
 #include "dialogs/delete-comp.h"
-#include "dialogs/delete-error.h"
 #include "dialogs/memo-editor.h"
 #include "e-cal-model-memos.h"
+#include "e-cal-ops.h"
 #include "e-calendar-view.h"
 #include "e-cell-date-edit-text.h"
 #include "print.h"
@@ -68,7 +68,6 @@ enum {
 enum {
        OPEN_COMPONENT,
        POPUP_EVENT,
-       STATUS_MESSAGE,
        LAST_SIGNAL
 };
 
@@ -110,16 +109,6 @@ memo_table_emit_popup_event (EMemoTable *memo_table,
        g_signal_emit (memo_table, signal_id, 0, event);
 }
 
-static void
-memo_table_emit_status_message (EMemoTable *memo_table,
-                                const gchar *message,
-                                gdouble percent)
-{
-       guint signal_id = signals[STATUS_MESSAGE];
-
-       g_signal_emit (memo_table, signal_id, 0, message, percent);
-}
-
 /* Returns the current time, for the ECellDateEdit items.
  * FIXME: Should probably use the timezone of the item rather than the
  * current timezone, though that may be difficult to get from here. */
@@ -151,51 +140,14 @@ memo_table_get_current_time (ECellDateEdit *ecde,
        return tmp_tm;
 }
 
-static void
-memo_table_model_cal_view_progress_cb (EMemoTable *memo_table,
-                                       const gchar *message,
-                                       gint progress,
-                                       ECalClientSourceType type)
-{
-       gdouble percent = (gdouble) progress;
-
-       memo_table_emit_status_message (memo_table, message, percent);
-}
-
-static void
-memo_table_model_cal_view_complete_cb (EMemoTable *memo_table,
-                                       const GError *error,
-                                       ECalClientSourceType type)
-{
-       memo_table_emit_status_message (memo_table, NULL, -1.0);
-}
-
 /* Deletes all of the selected components in the table */
 static void
 delete_selected_components (EMemoTable *memo_table)
 {
-       GSList *objs, *l;
-       const gchar *status_message;
+       GSList *objs;
 
        objs = e_memo_table_get_selected (memo_table);
-
-       status_message = _("Deleting selected objects");
-       memo_table_emit_status_message (memo_table, status_message, -1.0);
-
-       for (l = objs; l; l = l->next) {
-               ECalModelComponent *comp_data = (ECalModelComponent *) l->data;
-               GError *error = NULL;
-
-               e_cal_client_remove_object_sync (
-                       comp_data->client,
-                       icalcomponent_get_uid (comp_data->icalcomp),
-                       NULL, CALOBJ_MOD_THIS, NULL, &error);
-               delete_error_dialog (error, E_CAL_COMPONENT_JOURNAL);
-               g_clear_error (&error);
-       }
-
-       memo_table_emit_status_message (memo_table, NULL, -1.0);
-
+       e_cal_ops_delete_ecalmodel_components (memo_table->priv->model, objs);
        g_slist_free (objs);
 }
 
@@ -206,16 +158,6 @@ memo_table_set_model (EMemoTable *memo_table,
        g_return_if_fail (memo_table->priv->model == NULL);
 
        memo_table->priv->model = g_object_ref (model);
-
-       g_signal_connect_swapped (
-               model, "cal-view-progress",
-               G_CALLBACK (memo_table_model_cal_view_progress_cb),
-               memo_table);
-
-       g_signal_connect_swapped (
-               model, "cal-view-complete",
-               G_CALLBACK (memo_table_model_cal_view_complete_cb),
-               memo_table);
 }
 
 static void
@@ -841,117 +783,6 @@ memo_table_copy_clipboard (ESelectable *selectable)
        memo_table->tmp_vcal = NULL;
 }
 
-/* Helper for memo_table_paste_clipboard() */
-static void
-clipboard_get_calendar_data (EMemoTable *memo_table,
-                             const gchar *text)
-{
-       icalcomponent *icalcomp;
-       gchar *uid;
-       ECalComponent *comp;
-       ECalClient *client;
-       ECalModel *model;
-       icalcomponent_kind kind;
-       const gchar *status_message;
-
-       g_return_if_fail (E_IS_MEMO_TABLE (memo_table));
-
-       if (!text || !*text)
-               return;
-
-       icalcomp = icalparser_parse_string (text);
-       if (!icalcomp)
-               return;
-
-       /* check the type of the component */
-       kind = icalcomponent_isa (icalcomp);
-       if (kind != ICAL_VCALENDAR_COMPONENT &&
-           kind != ICAL_VEVENT_COMPONENT &&
-           kind != ICAL_VTODO_COMPONENT &&
-           kind != ICAL_VJOURNAL_COMPONENT) {
-               return;
-       }
-
-       model = e_memo_table_get_model (memo_table);
-       client = e_cal_model_ref_default_client (model);
-
-       status_message = _("Updating objects");
-       memo_table_emit_status_message (memo_table, status_message, -1.0);
-
-       if (kind == ICAL_VCALENDAR_COMPONENT) {
-               icalcomponent_kind child_kind;
-               icalcomponent *subcomp;
-               icalcomponent *vcal_comp;
-
-               vcal_comp = icalcomp;
-               subcomp = icalcomponent_get_first_component (
-                       vcal_comp, ICAL_ANY_COMPONENT);
-               while (subcomp) {
-                       child_kind = icalcomponent_isa (subcomp);
-                       if (child_kind == ICAL_VEVENT_COMPONENT ||
-                           child_kind == ICAL_VTODO_COMPONENT ||
-                           child_kind == ICAL_VJOURNAL_COMPONENT) {
-                               ECalComponent *tmp_comp;
-                               GError *error = NULL;
-
-                               uid = e_cal_component_gen_uid ();
-                               tmp_comp = e_cal_component_new ();
-                               e_cal_component_set_icalcomponent (
-                                       tmp_comp,
-                                       icalcomponent_new_clone (subcomp));
-                               e_cal_component_set_uid (tmp_comp, uid);
-                               g_free (uid);
-                               uid = NULL;
-
-                               /* FIXME Should we convert start/due/complete
-                                *       times?  Also, need error handling.*/
-                               e_cal_client_create_object_sync (
-                                       client,
-                                       e_cal_component_get_icalcomponent (tmp_comp),
-                                       NULL, NULL, &error);
-
-                               g_object_unref (tmp_comp);
-
-                               if (error != NULL) {
-                                       g_warning (
-                                               "%s: Failed to create object: %s",
-                                               G_STRFUNC, error->message);
-                                       g_error_free (error);
-                               }
-                       }
-                       subcomp = icalcomponent_get_next_component (
-                               vcal_comp, ICAL_ANY_COMPONENT);
-               }
-       } else {
-               GError *error = NULL;
-
-               comp = e_cal_component_new ();
-               e_cal_component_set_icalcomponent (comp, icalcomp);
-               uid = e_cal_component_gen_uid ();
-               e_cal_component_set_uid (comp, (const gchar *) uid);
-               g_free (uid);
-               uid = NULL;
-
-               e_cal_client_create_object_sync (
-                       client,
-                       e_cal_component_get_icalcomponent (comp),
-                       NULL, NULL, &error);
-
-               g_object_unref (comp);
-
-               if (error != NULL) {
-                       g_warning (
-                               "%s: Failed to create object: %s",
-                               G_STRFUNC, error->message);
-                       g_error_free (error);
-               }
-       }
-
-       memo_table_emit_status_message (memo_table, NULL, -1.0);
-
-       g_object_unref (client);
-}
-
 static void
 memo_table_paste_clipboard (ESelectable *selectable)
 {
@@ -985,11 +816,14 @@ memo_table_paste_clipboard (ESelectable *selectable)
 
        /* Paste iCalendar data into the table. */
        } else if (e_clipboard_wait_is_calendar_available (clipboard)) {
-               gchar *calendar_source;
+               ECalModel *model;
+               gchar *ical_str;
+
+               model = e_memo_table_get_model (memo_table);
 
-               calendar_source = e_clipboard_wait_for_calendar (clipboard);
-               clipboard_get_calendar_data (memo_table, calendar_source);
-               g_free (calendar_source);
+               ical_str = e_clipboard_wait_for_calendar (clipboard);
+               e_cal_ops_paste_components (model, ical_str);
+               g_free (ical_str);
        }
 }
 
@@ -1154,16 +988,6 @@ e_memo_table_class_init (EMemoTableClass *class)
                g_cclosure_marshal_VOID__BOXED,
                G_TYPE_NONE, 1,
                GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
-
-       signals[STATUS_MESSAGE] = g_signal_new (
-               "status-message",
-               G_TYPE_FROM_CLASS (class),
-               G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-               G_STRUCT_OFFSET (EMemoTableClass, status_message),
-               NULL, NULL,
-               e_marshal_VOID__STRING_DOUBLE,
-               G_TYPE_NONE, 2,
-               G_TYPE_STRING, G_TYPE_DOUBLE);
 }
 
 static void
diff --git a/calendar/gui/e-memo-table.h b/calendar/gui/e-memo-table.h
index 7c76000..8bbdf36 100644
--- a/calendar/gui/e-memo-table.h
+++ b/calendar/gui/e-memo-table.h
@@ -81,9 +81,6 @@ struct _EMemoTableClass {
                                                 ECalModelComponent *comp_data);
        void    (*popup_event)                  (EMemoTable *memo_table,
                                                 GdkEvent *event);
-       void    (*status_message)               (EMemoTable *memo_table,
-                                                const gchar *message,
-                                                gdouble percent);
 };
 
 GType          e_memo_table_get_type           (void);
diff --git a/calendar/gui/e-task-table.c b/calendar/gui/e-task-table.c
index 036d643..e7af495 100644
--- a/calendar/gui/e-task-table.c
+++ b/calendar/gui/e-task-table.c
@@ -39,9 +39,9 @@
 
 #include "calendar-config.h"
 #include "dialogs/delete-comp.h"
-#include "dialogs/delete-error.h"
 #include "dialogs/task-editor.h"
 #include "e-cal-model-tasks.h"
+#include "e-cal-ops.h"
 #include "e-calendar-view.h"
 #include "e-cell-date-edit-text.h"
 #include "print.h"
@@ -76,7 +76,6 @@ enum {
 enum {
        OPEN_COMPONENT,
        POPUP_EVENT,
-       STATUS_MESSAGE,
        LAST_SIGNAL
 };
 
@@ -122,16 +121,6 @@ task_table_emit_popup_event (ETaskTable *task_table,
        g_signal_emit (task_table, signal_id, 0, event);
 }
 
-static void
-task_table_emit_status_message (ETaskTable *task_table,
-                                const gchar *message,
-                                gdouble percent)
-{
-       guint signal_id = signals[STATUS_MESSAGE];
-
-       g_signal_emit (task_table, signal_id, 0, message, percent);
-}
-
 static gint
 task_table_percent_compare_cb (gconstpointer a,
                                gconstpointer b,
@@ -243,51 +232,14 @@ task_table_status_compare_cb (gconstpointer a,
        return (status_a < status_b) ? -1 : (status_a > status_b);
 }
 
-static void
-task_table_model_cal_view_progress_cb (ETaskTable *task_table,
-                                       const gchar *message,
-                                       gint progress,
-                                       ECalClientSourceType type)
-{
-       gdouble percent = (gdouble) progress;
-
-       task_table_emit_status_message (task_table, message, percent);
-}
-
-static void
-task_table_model_cal_view_complete_cb (ETaskTable *task_table,
-                                       const GError *error,
-                                       ECalClientSourceType type)
-{
-       task_table_emit_status_message (task_table, NULL, -1.0);
-}
-
 /* Deletes all of the selected components in the table */
 static void
 delete_selected_components (ETaskTable *task_table)
 {
-       GSList *objs, *l;
-       const gchar *status_message;
+       GSList *objs;
 
        objs = e_task_table_get_selected (task_table);
-
-       status_message = _("Deleting selected objects");
-       task_table_emit_status_message (task_table, status_message, -1.0);
-
-       for (l = objs; l; l = l->next) {
-               ECalModelComponent *comp_data = (ECalModelComponent *) l->data;
-               GError *error = NULL;
-
-               e_cal_client_remove_object_sync (
-                       comp_data->client,
-                       icalcomponent_get_uid (comp_data->icalcomp),
-                       NULL, CALOBJ_MOD_THIS, NULL, &error);
-               delete_error_dialog (error, E_CAL_COMPONENT_TODO);
-               g_clear_error (&error);
-       }
-
-       task_table_emit_status_message (task_table, NULL, -1.0);
-
+       e_cal_ops_delete_ecalmodel_components (task_table->priv->model, objs);
        g_slist_free (objs);
 }
 
@@ -309,16 +261,6 @@ task_table_set_model (ETaskTable *task_table,
 
        task_table->priv->model = g_object_ref (model);
 
-       g_signal_connect_swapped (
-               model, "cal-view-progress",
-               G_CALLBACK (task_table_model_cal_view_progress_cb),
-               task_table);
-
-       g_signal_connect_swapped (
-               model, "cal-view-complete",
-               G_CALLBACK (task_table_model_cal_view_complete_cb),
-               task_table);
-
        /* redraw on drawing options change */
        task_table->priv->notify_highlight_due_today_id = e_signal_connect_notify (
                model, "notify::highlight-due-today",
@@ -1039,6 +981,9 @@ task_table_update_actions (ESelectable *selectable,
        for (iter = list; iter != NULL && sources_are_editable; iter = iter->next) {
                ECalModelComponent *comp_data = iter->data;
 
+               if (!comp_data)
+                       continue;
+
                sources_are_editable = sources_are_editable &&
                        !e_client_is_readonly (E_CLIENT (comp_data->client));
        }
@@ -1158,110 +1103,12 @@ static void
 clipboard_get_calendar_data (ETaskTable *task_table,
                              const gchar *text)
 {
-       icalcomponent *icalcomp;
-       gchar *uid;
-       ECalComponent *comp;
-       ECalModel *model;
-       ECalClient *client;
-       icalcomponent_kind kind;
-       const gchar *status_message;
-
        g_return_if_fail (E_IS_TASK_TABLE (task_table));
 
        if (!text || !*text)
                return;
 
-       icalcomp = icalparser_parse_string (text);
-       if (!icalcomp)
-               return;
-
-       /* check the type of the component */
-       kind = icalcomponent_isa (icalcomp);
-       if (kind != ICAL_VCALENDAR_COMPONENT &&
-           kind != ICAL_VEVENT_COMPONENT &&
-           kind != ICAL_VTODO_COMPONENT &&
-           kind != ICAL_VJOURNAL_COMPONENT) {
-               return;
-       }
-
-       model = e_task_table_get_model (task_table);
-       client = e_cal_model_ref_default_client (model);
-
-       status_message = _("Updating objects");
-       task_table_emit_status_message (task_table, status_message, -1.0);
-
-       if (kind == ICAL_VCALENDAR_COMPONENT) {
-               icalcomponent_kind child_kind;
-               icalcomponent *subcomp;
-               icalcomponent *vcal_comp;
-
-               vcal_comp = icalcomp;
-               subcomp = icalcomponent_get_first_component (
-                       vcal_comp, ICAL_ANY_COMPONENT);
-               while (subcomp) {
-                       child_kind = icalcomponent_isa (subcomp);
-                       if (child_kind == ICAL_VEVENT_COMPONENT ||
-                           child_kind == ICAL_VTODO_COMPONENT ||
-                           child_kind == ICAL_VJOURNAL_COMPONENT) {
-                               ECalComponent *tmp_comp;
-                               GError *error = NULL;
-
-                               uid = e_cal_component_gen_uid ();
-                               tmp_comp = e_cal_component_new ();
-                               e_cal_component_set_icalcomponent (
-                                       tmp_comp,
-                                       icalcomponent_new_clone (subcomp));
-                               e_cal_component_set_uid (tmp_comp, uid);
-                               g_free (uid);
-                               uid = NULL;
-
-                               /* FIXME should we convert start/due/complete
-                                * times?  Also, need error handling. */
-                               e_cal_client_create_object_sync (
-                                       client,
-                                       e_cal_component_get_icalcomponent (tmp_comp),
-                                       NULL, NULL, &error);
-
-                               if (error != NULL) {
-                                       g_warning (
-                                               "%s: Failed to create object: %s",
-                                               G_STRFUNC, error->message);
-                                       g_error_free (error);
-                               }
-
-                               g_object_unref (tmp_comp);
-                       }
-                       subcomp = icalcomponent_get_next_component (
-                               vcal_comp, ICAL_ANY_COMPONENT);
-               }
-       } else {
-               GError *error = NULL;
-
-               comp = e_cal_component_new ();
-               e_cal_component_set_icalcomponent (comp, icalcomp);
-               uid = e_cal_component_gen_uid ();
-               e_cal_component_set_uid (comp, (const gchar *) uid);
-               g_free (uid);
-               uid = NULL;
-
-               e_cal_client_create_object_sync (
-                       client,
-                       e_cal_component_get_icalcomponent (comp),
-                       NULL, NULL, &error);
-
-               if (error != NULL) {
-                       g_warning (
-                               "%s: Failed to create object: %s",
-                               G_STRFUNC, error->message);
-                       g_error_free (error);
-               }
-
-               g_object_unref (comp);
-       }
-
-       task_table_emit_status_message (task_table, NULL, -1.0);
-
-       g_object_unref (client);
+       e_cal_ops_paste_components (e_task_table_get_model (task_table), text);
 }
 
 static void
@@ -1394,7 +1241,6 @@ task_table_delete_selection (ESelectable *selectable)
        ECalComponent *comp = NULL;
        gboolean delete = TRUE;
        gint n_selected;
-       GError *error = NULL;
 
        task_table = E_TASK_TABLE (selectable);
        model = e_task_table_get_model (task_table);
@@ -1424,30 +1270,16 @@ task_table_delete_selection (ESelectable *selectable)
                        comp, &retract_comment,
                        GTK_WIDGET (task_table), &retract);
                if (retract) {
-                       GSList *users = NULL;
-                       icalcomponent *icalcomp = NULL, *mod_comp = NULL;
+                       icalcomponent *icalcomp = NULL;
 
                        add_retract_data (comp, retract_comment);
                        icalcomp = e_cal_component_get_icalcomponent (comp);
                        icalcomponent_set_method (icalcomp, ICAL_METHOD_CANCEL);
-                       e_cal_client_send_objects_sync (
-                               comp_data->client, icalcomp,
-                               &users, &mod_comp, NULL, &error);
-                       if (error != NULL) {
-                               delete_error_dialog (error, E_CAL_COMPONENT_TODO);
-                               g_clear_error (&error);
-                       } else {
-
-                               if (mod_comp)
-                                       icalcomponent_free (mod_comp);
-
-                               if (users) {
-                                       g_slist_foreach (users, (GFunc) g_free, NULL);
-                                       g_slist_free (users);
-                               }
-                       }
 
+                       e_cal_ops_send_component (model, comp_data->client, icalcomp);
                }
+
+               g_free (retract_comment);
        } else if (e_cal_model_get_confirm_delete (model))
                delete = delete_component_dialog (
                        comp, FALSE, n_selected,
@@ -1544,16 +1376,6 @@ e_task_table_class_init (ETaskTableClass *class)
                g_cclosure_marshal_VOID__BOXED,
                G_TYPE_NONE, 1,
                GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
-
-       signals[STATUS_MESSAGE] = g_signal_new (
-               "status-message",
-               G_TYPE_FROM_CLASS (class),
-               G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-               G_STRUCT_OFFSET (ETaskTableClass, status_message),
-               NULL, NULL,
-               e_marshal_VOID__STRING_DOUBLE,
-               G_TYPE_NONE, 2,
-               G_TYPE_STRING, G_TYPE_DOUBLE);
 }
 
 static void
@@ -1713,14 +1535,16 @@ hide_completed_rows_ready (GObject *source_object,
                            gpointer user_data)
 {
        ECalModel *model = user_data;
+       ECalClient *cal_client;
        GSList *m, *objects;
        gboolean changed = FALSE;
        gint pos;
        GPtrArray *comp_objects;
        GError *error = NULL;
 
-       e_cal_client_get_object_list_finish (
-               E_CAL_CLIENT (source_object), result, &objects, &error);
+       cal_client = E_CAL_CLIENT (source_object);
+
+       e_cal_client_get_object_list_finish (cal_client, result, &objects, &error);
 
        if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
                g_error_free (error);
@@ -1753,17 +1577,16 @@ hide_completed_rows_ready (GObject *source_object,
                        comp, icalcomponent_new_clone (m->data));
                id = e_cal_component_get_id (comp);
 
-               comp_data = e_cal_model_get_component_for_uid (model, id);
+               comp_data = e_cal_model_get_component_for_client_and_uid (model, cal_client, id);
                if (comp_data != NULL) {
                        e_table_model_pre_change (E_TABLE_MODEL (model));
                        pos = get_position_in_array (
                                comp_objects, comp_data);
+                       if (g_ptr_array_remove (comp_objects, comp_data))
+                               g_object_unref (comp_data);
                        e_table_model_row_deleted (
                                E_TABLE_MODEL (model), pos);
                        changed = TRUE;
-
-                       if (g_ptr_array_remove (comp_objects, comp_data))
-                               g_object_unref (comp_data);
                }
                e_cal_component_free_id (id);
                g_object_unref (comp);
@@ -1783,14 +1606,16 @@ show_completed_rows_ready (GObject *source_object,
                            GAsyncResult *result,
                            gpointer user_data)
 {
-       ECalClient *client;
+       ECalClient *cal_client;
        ECalModel *model = user_data;
        GSList *m, *objects;
        GPtrArray *comp_objects;
        GError *error = NULL;
 
-       e_cal_client_get_object_list_finish (
-               E_CAL_CLIENT (source_object), result, &objects, &error);
+       cal_client = E_CAL_CLIENT (source_object);
+       g_return_if_fail (cal_client != NULL);
+
+       e_cal_client_get_object_list_finish (cal_client, result, &objects, &error);
 
        if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
                g_error_free (error);
@@ -1811,9 +1636,6 @@ show_completed_rows_ready (GObject *source_object,
                return;
        }
 
-       client = E_CAL_CLIENT (source_object);
-       g_return_if_fail (client != NULL);
-
        comp_objects = e_cal_model_get_object_array (model);
        g_return_if_fail (comp_objects != NULL);
 
@@ -1826,11 +1648,11 @@ show_completed_rows_ready (GObject *source_object,
                        comp, icalcomponent_new_clone (m->data));
                id = e_cal_component_get_id (comp);
 
-               if (!(e_cal_model_get_component_for_uid (model, id))) {
+               if (!(e_cal_model_get_component_for_client_and_uid (model, cal_client, id))) {
                        e_table_model_pre_change (E_TABLE_MODEL (model));
                        comp_data = g_object_new (
                                E_TYPE_CAL_MODEL_COMPONENT, NULL);
-                       comp_data->client = g_object_ref (client);
+                       comp_data->client = g_object_ref (cal_client);
                        comp_data->icalcomp =
                                icalcomponent_new_clone (m->data);
                        e_cal_model_set_instance_times (
@@ -1896,6 +1718,7 @@ e_task_table_process_completed_tasks (ETaskTable *task_table,
                                       gboolean config_changed)
 {
        ECalModel *model;
+       ECalDataModel *data_model;
        GList *client_list;
        GCancellable *cancellable;
        gchar *hide_sexp, *show_sexp;
@@ -1909,6 +1732,7 @@ e_task_table_process_completed_tasks (ETaskTable *task_table,
        cancellable = task_table->priv->completed_cancellable;
 
        model = e_task_table_get_model (task_table);
+       data_model = e_cal_model_get_data_model (model);
        hide_sexp = calendar_config_get_hide_completed_tasks_sexp (TRUE);
        show_sexp = calendar_config_get_hide_completed_tasks_sexp (FALSE);
 
@@ -1916,7 +1740,7 @@ e_task_table_process_completed_tasks (ETaskTable *task_table,
        if (!(hide_sexp && show_sexp))
                show_sexp = g_strdup ("(is-completed?)");
 
-       client_list = e_cal_model_list_clients (model);
+       client_list = e_cal_data_model_get_clients (data_model);
 
        /* Delete rows from model */
        if (hide_sexp) {
diff --git a/calendar/gui/e-task-table.h b/calendar/gui/e-task-table.h
index 8709c92..09e68c1 100644
--- a/calendar/gui/e-task-table.h
+++ b/calendar/gui/e-task-table.h
@@ -79,9 +79,6 @@ struct _ETaskTableClass {
                                                 ECalModelComponent *comp_data);
        void    (*popup_event)                  (ETaskTable *task_table,
                                                 GdkEvent *event);
-       void    (*status_message)               (ETaskTable *task_table,
-                                                const gchar *message,
-                                                gdouble percent);
 };
 
 GType          e_task_table_get_type           (void);
diff --git a/calendar/gui/e-week-view-event-item.c b/calendar/gui/e-week-view-event-item.c
index 59358ca..f94081f 100644
--- a/calendar/gui/e-week-view-event-item.c
+++ b/calendar/gui/e-week-view-event-item.c
@@ -157,10 +157,7 @@ week_view_event_item_double_click (EWeekViewEventItem *event_item,
                if (editing && event &&
                        editing->comp_data == event->comp_data &&
                        is_comp_data_valid (editing) &&
-                       (!event->comp_data ||
-                        !is_icalcomp_on_the_server (
-                               event->comp_data->icalcomp,
-                               event->comp_data->client)))
+                       (!event->comp_data || event->comp_data->is_new_component))
                        return TRUE;
        }
 
diff --git a/calendar/gui/e-week-view.c b/calendar/gui/e-week-view.c
index 1c5a189..408cf23 100644
--- a/calendar/gui/e-week-view.c
+++ b/calendar/gui/e-week-view.c
@@ -36,7 +36,6 @@
 #include <libgnomecanvas/libgnomecanvas.h>
 
 #include "dialogs/delete-comp.h"
-#include "dialogs/delete-error.h"
 #include "dialogs/send-comp.h"
 #include "dialogs/cancel-comp.h"
 #include "dialogs/recur-comp.h"
@@ -45,6 +44,7 @@
 #include "calendar-config.h"
 #include "comp-util.h"
 #include "e-cal-model-calendar.h"
+#include "e-cal-ops.h"
 #include "e-week-view-event-item.h"
 #include "e-week-view-layout.h"
 #include "e-week-view-main-item.h"
@@ -140,11 +140,12 @@ static void e_week_view_update_selection (EWeekView *week_view,
                                          gint day);
 
 static void e_week_view_free_events (EWeekView *week_view);
-static gboolean e_week_view_add_event (ECalComponent *comp,
-                                      time_t     start,
-                                      time_t     end,
-                                      gboolean prepend,
-                                      gpointer   data);
+static void e_week_view_add_event (ECalClient *client,
+                                  ECalComponent *comp,
+                                  time_t start,
+                                  time_t end,
+                                  gboolean prepend,
+                                  gpointer data);
 static void e_week_view_check_layout (EWeekView *week_view);
 static void e_week_view_ensure_events_sorted (EWeekView *week_view);
 static void e_week_view_reshape_events (EWeekView *week_view);
@@ -238,7 +239,7 @@ week_view_process_component (EWeekView *week_view,
        /* Add the object */
        add_event_data.week_view = week_view;
        add_event_data.comp_data = comp_data;
-       e_week_view_add_event (comp, comp_data->instance_start, comp_data->instance_end, FALSE, 
&add_event_data);
+       e_week_view_add_event (comp_data->client, comp, comp_data->instance_start, comp_data->instance_end, 
FALSE, &add_event_data);
 
        g_object_unref (comp);
        g_free (rid);
@@ -374,6 +375,67 @@ week_view_model_rows_inserted_cb (EWeekView *week_view,
 }
 
 static void
+e_week_view_precalc_visible_time_range (ECalendarView *cal_view,
+                                       time_t in_start_time,
+                                       time_t in_end_time,
+                                       time_t *out_start_time,
+                                       time_t *out_end_time)
+{
+       EWeekView *week_view;
+       GDate date, base_date;
+       GDateWeekday weekday;
+       GDateWeekday display_start_day;
+       guint day_offset, week_start_offset;
+       gint num_days;
+       icaltimezone *zone;
+
+       g_return_if_fail (E_IS_WEEK_VIEW (cal_view));
+       g_return_if_fail (out_start_time != NULL);
+       g_return_if_fail (out_end_time != NULL);
+
+       week_view = E_WEEK_VIEW (cal_view);
+       zone = e_calendar_view_get_timezone (cal_view);
+
+       time_to_gdate_with_zone (&date, in_start_time, e_calendar_view_get_timezone (E_CALENDAR_VIEW 
(week_view)));
+
+       weekday = g_date_get_weekday (&date);
+       display_start_day = e_week_view_get_display_start_day (week_view);
+
+       /* Convert it to an offset from the start of the display. */
+       week_start_offset = e_weekday_get_days_between (display_start_day, weekday);
+
+       /* Set the day_offset to the result, so we move back to the
+        * start of the week. */
+       day_offset = week_start_offset;
+
+       /* Calculate the base date, i.e. the first day shown when the
+        * scrollbar adjustment value is 0. */
+       base_date = date;
+       g_date_subtract_days (&base_date, day_offset);
+
+       num_days = e_week_view_get_weeks_shown (week_view) * 7;
+
+       /* See if we need to update the first day shown. */
+       if (!g_date_valid (&week_view->priv->first_day_shown)
+           || g_date_compare (&week_view->priv->first_day_shown, &base_date)) {
+               gint day;
+
+               in_start_time = time_add_day_with_zone (in_start_time, -((gint) day_offset), zone);
+               in_start_time = time_day_begin_with_zone (in_start_time, zone);
+
+               *out_start_time = in_start_time;
+               *out_end_time = in_start_time;
+
+               for (day = 1; day <= num_days; day++) {
+                       *out_end_time = time_add_day_with_zone (*out_end_time, 1, zone);
+               }
+       } else {
+               *out_start_time = week_view->day_starts[0];
+               *out_end_time = week_view->day_starts[num_days];
+       }
+}
+
+static void
 week_view_time_range_changed_cb (EWeekView *week_view,
                                  time_t start_time,
                                  time_t end_time,
@@ -562,105 +624,140 @@ get_string_width (PangoLayout *layout,
        return width;
 }
 
-static gboolean
-e_week_view_add_new_event_in_selected_range (EWeekView *week_view,
-                                             const gchar *initial_text)
+typedef struct {
+       EWeekView *week_view;
+       time_t dtstart, dtend;
+       gchar *initial_text;
+       gboolean paste_clipboard;
+} NewEventInRangeData;
+
+static void
+new_event_in_rage_data_free (gpointer ptr)
 {
-       ECalClient *client;
-       ECalModel *model;
+       NewEventInRangeData *ned = ptr;
+
+       if (ned) {
+               g_clear_object (&ned->week_view);
+               g_free (ned->initial_text);
+               g_free (ned);
+       }
+}
+
+static void
+week_view_new_event_in_selected_range_cb (ECalModel *model,
+                                         ECalClient *client,
+                                         icalcomponent *default_component,
+                                         gpointer user_data)
+{
+       NewEventInRangeData *ned = user_data;
        ECalComponent *comp = NULL;
-       icalcomponent *icalcomp;
        gint event_num;
        ECalComponentDateTime date;
        struct icaltimetype itt;
-       time_t dtstart, dtend;
        const gchar *uid;
        AddEventData add_event_data;
        EWeekViewEvent *wvevent;
        EWeekViewEventSpan *span;
-       gboolean success = FALSE;
-
-       model = e_calendar_view_get_model (E_CALENDAR_VIEW (week_view));
-       client = e_cal_model_ref_default_client (model);
+       icaltimezone *zone;
 
        /* Check if the client is read only */
        if (e_client_is_readonly (E_CLIENT (client)))
                goto exit;
 
        /* Add a new event covering the selected range. */
-       icalcomp = e_cal_model_create_component_with_defaults (e_calendar_view_get_model (E_CALENDAR_VIEW 
(week_view)), TRUE);
-       if (!icalcomp)
-               goto exit;
-       uid = icalcomponent_get_uid (icalcomp);
-
-       comp = e_cal_component_new ();
-       e_cal_component_set_icalcomponent (comp, icalcomp);
+       comp = e_cal_component_new_from_icalcomponent (icalcomponent_new_clone (default_component));
+       g_return_if_fail (comp != NULL);
 
-       dtstart = week_view->day_starts[week_view->selection_start_day];
-       dtend = week_view->day_starts[week_view->selection_end_day + 1];
+       uid = icalcomponent_get_uid (default_component);
 
        date.value = &itt;
        date.tzid = NULL;
 
+       zone = e_cal_model_get_timezone (model);
+
        /* We use DATE values now, so we don't need the timezone. */
        /*date.tzid = icaltimezone_get_tzid (e_calendar_view_get_timezone (E_CALENDAR_VIEW (week_view)));*/
 
-       *date.value = icaltime_from_timet_with_zone (dtstart, TRUE,
-                                                    e_calendar_view_get_timezone (E_CALENDAR_VIEW 
(week_view)));
+       *date.value = icaltime_from_timet_with_zone (ned->dtstart, TRUE, zone);
        e_cal_component_set_dtstart (comp, &date);
 
-       *date.value = icaltime_from_timet_with_zone (dtend, TRUE,
-                                                    e_calendar_view_get_timezone (E_CALENDAR_VIEW 
(week_view)));
+       *date.value = icaltime_from_timet_with_zone (ned->dtend, TRUE, zone);
        e_cal_component_set_dtend (comp, &date);
 
        /* Editor default in week/month view */
        e_cal_component_set_transparency (comp, E_CAL_COMPONENT_TRANSP_TRANSPARENT);
 
-       e_cal_component_set_categories (
-               comp, e_calendar_view_get_default_category (E_CALENDAR_VIEW (week_view)));
-
        /* We add the event locally and start editing it. We don't send it
         * to the server until the user finishes editing it. */
-       add_event_data.week_view = week_view;
+       add_event_data.week_view = ned->week_view;
        add_event_data.comp_data = NULL;
-       e_week_view_add_event (comp, dtstart, dtend, TRUE, &add_event_data);
-       e_week_view_check_layout (week_view);
-       gtk_widget_queue_draw (week_view->main_canvas);
+       e_week_view_add_event (client, comp, ned->dtstart, ned->dtend, TRUE, &add_event_data);
+       e_week_view_check_layout (ned->week_view);
+       gtk_widget_queue_draw (ned->week_view->main_canvas);
 
-       if (!e_week_view_find_event_from_uid (week_view, client, uid, NULL, &event_num)) {
+       if (!e_week_view_find_event_from_uid (ned->week_view, client, uid, NULL, &event_num)) {
                g_warning ("Couldn't find event to start editing.\n");
                goto exit;
        }
 
-       if (!is_array_index_in_bounds (week_view->events, event_num))
+       if (!is_array_index_in_bounds (ned->week_view->events, event_num))
                goto exit;
 
-       wvevent = &g_array_index (week_view->events, EWeekViewEvent,
-                                 event_num);
+       wvevent = &g_array_index (ned->week_view->events, EWeekViewEvent, event_num);
 
-       if (!is_array_index_in_bounds (week_view->spans, wvevent->spans_index + 0))
+       if (!is_array_index_in_bounds (ned->week_view->spans, wvevent->spans_index + 0))
                goto exit;
 
-       span = &g_array_index (week_view->spans, EWeekViewEventSpan,
-                              wvevent->spans_index + 0);
+       span = &g_array_index (ned->week_view->spans, EWeekViewEventSpan, wvevent->spans_index + 0);
 
        /* If the event can't be fit on the screen, don't try to edit it. */
        if (!span->text_item) {
-               e_week_view_foreach_event_with_uid (week_view, uid,
-                               e_week_view_remove_event_cb, NULL);
+               e_week_view_foreach_event_with_uid (ned->week_view, uid, e_week_view_remove_event_cb, NULL);
                goto exit;
        }
 
-       e_week_view_start_editing_event (
-               week_view, event_num, 0, (gchar *) initial_text);
+       e_week_view_start_editing_event (ned->week_view, event_num, 0, ned->initial_text);
 
-       success = TRUE;
+       if (ned->paste_clipboard) {
+               wvevent = &g_array_index (ned->week_view->events, EWeekViewEvent, 
ned->week_view->editing_event_num);
+
+               if (!is_array_index_in_bounds (ned->week_view->spans, wvevent->spans_index + 
ned->week_view->editing_span_num))
+                       return;
+
+               span = &g_array_index (ned->week_view->spans, EWeekViewEventSpan, wvevent->spans_index + 
ned->week_view->editing_span_num);
+
+               if (span->text_item &&
+                   E_IS_TEXT (span->text_item) &&
+                   E_TEXT (span->text_item)->editing) {
+                       e_text_paste_clipboard (E_TEXT (span->text_item));
+               }
+       }
 
-exit:
+ exit:
        g_clear_object (&comp);
-       g_clear_object (&client);
+}
+
+static void
+e_week_view_add_new_event_in_selected_range (EWeekView *week_view,
+                                             const gchar *initial_text,
+                                            gboolean paste_clipboard)
+{
+       NewEventInRangeData *ned;
+       ECalModel *model;
+       const gchar *source_uid;
+
+       ned = g_new0 (NewEventInRangeData, 1);
+       ned->week_view = g_object_ref (week_view);
+       ned->initial_text = g_strdup (initial_text);
+       ned->dtstart = week_view->day_starts[week_view->selection_start_day];
+       ned->dtend = week_view->day_starts[week_view->selection_end_day + 1];
+       ned->paste_clipboard = paste_clipboard;
 
-       return success;
+       model = e_calendar_view_get_model (E_CALENDAR_VIEW (week_view));
+       source_uid = e_cal_model_get_default_source_uid (model);
+
+       e_cal_ops_get_default_component  (model, source_uid, TRUE,
+               week_view_new_event_in_selected_range_cb, ned, new_event_in_rage_data_free);
 }
 
 static void
@@ -1381,9 +1478,10 @@ week_view_paste_text (ECalendarView *cal_view)
 
        week_view = E_WEEK_VIEW (cal_view);
 
-       if (week_view->editing_event_num == -1 &&
-           !e_week_view_add_new_event_in_selected_range (week_view, NULL))
+       if (week_view->editing_event_num == -1) {
+               e_week_view_add_new_event_in_selected_range (week_view, NULL, TRUE);
                return;
+       }
 
        if (!is_array_index_in_bounds (week_view->events, week_view->editing_event_num))
                return;
@@ -1495,6 +1593,7 @@ e_week_view_class_init (EWeekViewClass *class)
        view_class->get_selected_time_range = week_view_get_selected_time_range;
        view_class->set_selected_time_range = week_view_set_selected_time_range;
        view_class->get_visible_time_range = week_view_get_visible_time_range;
+       view_class->precalc_visible_time_range = e_week_view_precalc_visible_time_range;
        view_class->paste_text = week_view_paste_text;
 
        class->cursor_key_up = week_view_cursor_key_up;
@@ -3028,8 +3127,9 @@ e_week_view_free_events (EWeekView *week_view)
 }
 
 /* This adds one event to the view, adding it to the appropriate array. */
-static gboolean
-e_week_view_add_event (ECalComponent *comp,
+static void
+e_week_view_add_event (ECalClient *client,
+                      ECalComponent *comp,
                        time_t start,
                        time_t end,
                        gboolean prepend,
@@ -3046,9 +3146,9 @@ e_week_view_add_event (ECalComponent *comp,
        /* Check that the event times are valid. */
        num_days = e_week_view_get_weeks_shown (add_event_data->week_view) * 7;
 
-       g_return_val_if_fail (start <= end, TRUE);
-       g_return_val_if_fail (start < add_event_data->week_view->day_starts[num_days], TRUE);
-       g_return_val_if_fail (end > add_event_data->week_view->day_starts[0], TRUE);
+       g_return_if_fail (start <= end);
+       g_return_if_fail (start < add_event_data->week_view->day_starts[num_days]);
+       g_return_if_fail (end > add_event_data->week_view->day_starts[0]);
 
        start_tt = icaltime_from_timet_with_zone (
                start, FALSE,
@@ -3061,8 +3161,8 @@ e_week_view_add_event (ECalComponent *comp,
                event.comp_data = g_object_ref (add_event_data->comp_data);
        } else {
                event.comp_data = g_object_new (E_TYPE_CAL_MODEL_COMPONENT, NULL);
-
-               event.comp_data->client = e_cal_model_ref_default_client (e_calendar_view_get_model 
(E_CALENDAR_VIEW (add_event_data->week_view)));
+               event.comp_data->is_new_component = TRUE;
+               event.comp_data->client = g_object_ref (client);
                e_cal_component_abort_sequence (comp);
                event.comp_data->icalcomp = icalcomponent_new_clone (e_cal_component_get_icalcomponent 
(comp));
        }
@@ -3094,8 +3194,6 @@ e_week_view_add_event (ECalComponent *comp,
                g_array_append_val (add_event_data->week_view->events, event);
        add_event_data->week_view->events_sorted = FALSE;
        add_event_data->week_view->events_need_layout = TRUE;
-
-       return TRUE;
 }
 
 /* This lays out the events, or reshapes them, as necessary. */
@@ -3896,7 +3994,7 @@ e_week_view_on_text_item_event (GnomeCanvasItem *item,
 
                /* if we started to editing new item on the canvas, then do not open editing dialog until 
it's saved,
                 * because the save of the event recalculates event numbers and you can edit different one */
-               if (!is_icalcomp_on_the_server (event->comp_data->icalcomp, event->comp_data->client))
+               if (event->comp_data->is_new_component)
                        return TRUE;
 
                e_calendar_view_edit_appointment (
@@ -4203,8 +4301,7 @@ e_week_view_change_event_time (EWeekView *week_view,
        ECalComponentDateTime date;
        struct icaltimetype itt;
        ECalClient *client;
-       CalObjModType mod = CALOBJ_MOD_ALL;
-       GtkWindow *toplevel;
+       ECalObjModType mod = E_CAL_OBJ_MOD_ALL;
 
        event_num = week_view->editing_event_num;
 
@@ -4254,25 +4351,20 @@ e_week_view_change_event_time (EWeekView *week_view,
                        goto out;
                }
 
-               if (mod == CALOBJ_MOD_ALL)
-                       comp_util_sanitize_recurrence_master (comp, client);
-
-               if (mod == CALOBJ_MOD_THIS) {
+               if (mod == E_CAL_OBJ_MOD_THIS) {
                        e_cal_component_set_rdate_list (comp, NULL);
                        e_cal_component_set_rrule_list (comp, NULL);
                        e_cal_component_set_exdate_list (comp, NULL);
                        e_cal_component_set_exrule_list (comp, NULL);
                }
        } else if (e_cal_component_is_instance (comp))
-               mod = CALOBJ_MOD_THIS;
-
-       toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (week_view)));
+               mod = E_CAL_OBJ_MOD_THIS;
 
        e_cal_component_commit_sequence (comp);
 
-       e_calendar_view_modify_and_send (
-               E_CALENDAR_VIEW (week_view),
-               comp, client, mod, toplevel, TRUE);
+       e_cal_ops_modify_component (e_calendar_view_get_model (E_CALENDAR_VIEW (week_view)),
+               client, e_cal_component_get_icalcomponent (comp),
+               mod, E_CAL_OPS_SEND_FLAG_ASK | E_CAL_OPS_SEND_FLAG_IS_NEW_COMPONENT);
 
 out:
        g_object_unref (comp);
@@ -4359,7 +4451,7 @@ e_week_view_on_editing_stopped (EWeekView *week_view,
        e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (event->comp_data->icalcomp));
 
        client = event->comp_data->client;
-       on_server = cal_comp_is_on_server (comp, client);
+       on_server = !event->comp_data->is_new_component;
 
        if (string_is_empty (text) && !on_server) {
                e_cal_component_get_uid (comp, &uid);
@@ -4395,45 +4487,20 @@ e_week_view_on_editing_stopped (EWeekView *week_view,
                e_cal_component_commit_sequence (comp);
 
                if (!on_server) {
-                       gchar *uid = NULL;
-                       GError *error = NULL;
-
-                       e_cal_client_create_object_sync (
-                               client, icalcomp, &uid, NULL, &error);
-
-                       if (error != NULL) {
-                               g_warning (
-                                       G_STRLOC ": Could not create the object! %s",
-                                       error->message);
-                               uid = NULL;
-                       } else {
-                               if (uid)
-                                       icalcomponent_set_uid (icalcomp, uid);
-
-                               e_calendar_view_emit_user_created (
-                                       E_CALENDAR_VIEW (week_view), client);
-                       }
-
-                       g_free (uid);
-
-                       if (error != NULL)
-                               g_error_free (error);
+                       e_cal_ops_create_component (e_calendar_view_get_model (E_CALENDAR_VIEW (week_view)), 
client, icalcomp,
+                               e_calendar_view_component_created_cb, g_object_ref (week_view), 
g_object_unref);
 
                        /* we remove the object since we either got the update from the server or failed */
                        e_week_view_remove_event_cb (week_view, event_num, NULL);
                } else {
-                       CalObjModType mod = CALOBJ_MOD_ALL;
-                       GtkWindow *toplevel;
+                       ECalObjModType mod = E_CAL_OBJ_MOD_ALL;
 
                        if (e_cal_component_has_recurrences (comp)) {
                                if (!recur_component_dialog (client, comp, &mod, NULL, FALSE)) {
                                        goto out;
                                }
 
-                               if (mod == CALOBJ_MOD_ALL)
-                                       comp_util_sanitize_recurrence_master (comp, client);
-
-                               if (mod == CALOBJ_MOD_THIS) {
+                               if (mod == E_CAL_OBJ_MOD_THIS) {
                                        ECalComponentDateTime dt;
                                        struct icaltimetype tt;
                                        gchar *tzid;
@@ -4480,18 +4547,13 @@ e_week_view_on_editing_stopped (EWeekView *week_view,
                                        e_cal_component_set_rrule_list (comp, NULL);
                                        e_cal_component_set_exdate_list (comp, NULL);
                                        e_cal_component_set_exrule_list (comp, NULL);
-
-                                       e_cal_component_commit_sequence (comp);
                                }
                        } else if (e_cal_component_is_instance (comp))
-                               mod = CALOBJ_MOD_THIS;
-
-                       /* FIXME When sending here, what exactly should we send? */
-                       toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (week_view)));
+                               mod = E_CAL_OBJ_MOD_THIS;
 
-                       e_calendar_view_modify_and_send (
-                               E_CALENDAR_VIEW (week_view),
-                               comp, client, mod, toplevel, FALSE);
+                       e_cal_component_commit_sequence (comp);
+                       e_cal_ops_modify_component (e_calendar_view_get_model (E_CALENDAR_VIEW (week_view)),
+                               client, e_cal_component_get_icalcomponent (comp), mod, 
E_CAL_OPS_SEND_FLAG_ASK);
                }
        }
 
@@ -4676,7 +4738,6 @@ e_week_view_do_key_press (GtkWidget *widget,
        gchar *initial_text;
        guint keyval;
        gboolean stop_emission;
-       gboolean ret_val;
 
        g_return_val_if_fail (widget != NULL, FALSE);
        g_return_val_if_fail (E_IS_WEEK_VIEW (widget), FALSE);
@@ -4762,12 +4823,12 @@ e_week_view_do_key_press (GtkWidget *widget,
        } else
                initial_text = e_utf8_from_gtk_event_key (widget, event->keyval, event->string);
 
-       ret_val = e_week_view_add_new_event_in_selected_range (week_view, initial_text);
+       e_week_view_add_new_event_in_selected_range (week_view, initial_text, FALSE);
 
        if (initial_text)
                g_free (initial_text);
 
-       return ret_val;
+       return TRUE;
 }
 
 static gint
@@ -4821,17 +4882,10 @@ e_week_view_jump_to_button_item (EWeekView *week_view,
                                  GnomeCanvasItem *item)
 {
        gint day;
-       GnomeCalendar *calendar;
 
        for (day = 0; day < E_WEEK_VIEW_MAX_WEEKS * 7; ++day) {
                if (item == week_view->jump_buttons[day]) {
-                       calendar = e_calendar_view_get_calendar (E_CALENDAR_VIEW (week_view));
-                       if (calendar)
-                               gnome_calendar_dayjump
-                                       (calendar,
-                                        week_view->day_starts[day]);
-                       else
-                               g_warning ("Calendar not set");
+                       e_calendar_view_move_view_range (E_CALENDAR_VIEW (week_view), 
E_CALENDAR_VIEW_MOVE_TO_EXACT_DAY, week_view->day_starts[day]);
                        return;
                }
        }
diff --git a/calendar/gui/e-week-view.h b/calendar/gui/e-week-view.h
index ee67592..d120645 100644
--- a/calendar/gui/e-week-view.h
+++ b/calendar/gui/e-week-view.h
@@ -26,7 +26,6 @@
 #include <libgnomecanvas/libgnomecanvas.h>
 
 #include "e-calendar-view.h"
-#include "gnome-cal.h"
 
 /*
  * EWeekView - displays the Week & Month views of the calendar.
diff --git a/calendar/gui/ea-cal-view.c b/calendar/gui/ea-cal-view.c
index de3d805..1fc0d70 100644
--- a/calendar/gui/ea-cal-view.c
+++ b/calendar/gui/ea-cal-view.c
@@ -27,6 +27,7 @@
 #include "ea-calendar-helpers.h"
 #include "e-day-view.h"
 #include "e-week-view.h"
+#include "e-cal-ops.h"
 #include "dialogs/goto-dialog.h"
 #include <glib/gi18n.h>
 
@@ -41,7 +42,7 @@ static void ea_cal_view_event_added_cb (ECalendarView *cal_view,
                                         gpointer data);
 
 static gboolean idle_dates_changed (gpointer data);
-static void ea_cal_view_dates_change_cb (GnomeCalendar *gcal, gpointer data);
+static void ea_cal_model_time_range_changed_cb (ECalModel *model, time_t start, time_t end, gpointer data);
 
 static void atk_action_interface_init (AtkActionIface *iface);
 static gboolean action_interface_do_action (AtkAction *action, gint i);
@@ -102,7 +103,7 @@ ea_cal_view_real_initialize (AtkObject *accessible,
                              gpointer data)
 {
        ECalendarView *cal_view;
-       GnomeCalendar *gcal;
+       ECalModel *model;
        static AtkRole role = ATK_ROLE_INVALID;
 
        g_return_if_fail (EA_IS_CAL_VIEW (accessible));
@@ -126,13 +127,13 @@ ea_cal_view_real_initialize (AtkObject *accessible,
                cal_view, "event_added",
                G_CALLBACK (ea_cal_view_event_added_cb), NULL);
 
-       /* listen for date changes of calendar */
-       gcal = e_calendar_view_get_calendar (cal_view);
+       /* listen for date changes */
+       model = e_calendar_view_get_model (cal_view);
 
-       if (gcal)
-               g_signal_connect (
-                       gcal, "dates_shown_changed",
-                       G_CALLBACK (ea_cal_view_dates_change_cb), accessible);
+       if (model)
+               g_signal_connect_after (
+                       model, "time-range-changed",
+                       G_CALLBACK (ea_cal_model_time_range_changed_cb), accessible);
 }
 
 static AtkObject *
@@ -267,8 +268,10 @@ idle_dates_changed (gpointer data)
 }
 
 static void
-ea_cal_view_dates_change_cb (GnomeCalendar *gcal,
-                             gpointer data)
+ea_cal_model_time_range_changed_cb (ECalModel *model,
+                                   time_t start,
+                                   time_t end,
+                                   gpointer data)
 {
        g_idle_add (idle_dates_changed, data);
 }
@@ -317,35 +320,25 @@ action_interface_do_action (AtkAction *action,
                return FALSE;
 
        cal_view = E_CALENDAR_VIEW (widget);
-        switch (index) {
-        case 0:
-                /* New Appointment */
-                e_calendar_view_new_appointment (cal_view);
-                break;
-        case 1:
-                /* New All Day Event */
-                e_calendar_view_get_selected_time_range (cal_view,
-                                                    &dtstart, &dtend);
-                e_calendar_view_new_appointment_for (cal_view,
-                                                dtstart, dtend, TRUE, FALSE);
-                break;
-        case 2:
-                /* New Meeting */
-                e_calendar_view_get_selected_time_range (cal_view,
-                                                    &dtstart, &dtend);
-                e_calendar_view_new_appointment_for (cal_view,
-                                                dtstart, dtend, FALSE, TRUE);
-                break;
-#if 0  /* FIXME Have to go through GnomeCalendar */
-        case 3:
-                /* Go to today */
-                break;
-                calendar_goto_today (e_calendar_view_get_calendar (cal_view));
-        case 4:
-                /* Go to date */
-                goto_dialog (e_calendar_view_get_calendar (cal_view));
-                break;
-#endif
+       switch (index) {
+       case 0:
+               /* New Appointment */
+               e_calendar_view_new_appointment (cal_view);
+               break;
+       case 1:
+               /* New All Day Event */
+               e_calendar_view_get_selected_time_range (cal_view, &dtstart, &dtend);
+               e_cal_ops_new_component_editor_from_model (
+                       e_calendar_view_get_model (cal_view), NULL,
+                       dtstart, dtend, FALSE, TRUE);
+               break;
+       case 2:
+               /* New Meeting */
+               e_calendar_view_get_selected_time_range (cal_view, &dtstart, &dtend);
+               e_cal_ops_new_component_editor_from_model (
+                       e_calendar_view_get_model (cal_view), NULL,
+                       dtstart, dtend, TRUE, FALSE);
+               break;
         default:
                 return_value = FALSE;
                 break;
diff --git a/calendar/gui/ea-calendar.c b/calendar/gui/ea-calendar.c
index 824edb7..4250062 100644
--- a/calendar/gui/ea-calendar.c
+++ b/calendar/gui/ea-calendar.c
@@ -34,7 +34,6 @@
 #include "calendar/gui/ea-day-view-main-item.h"
 #include "calendar/gui/ea-week-view.h"
 #include "calendar/gui/ea-week-view-main-item.h"
-#include "calendar/gui/ea-gnome-calendar.h"
 
 EA_FACTORY_GOBJECT (
        EA_TYPE_DAY_VIEW_MAIN_ITEM,
@@ -42,7 +41,6 @@ EA_FACTORY_GOBJECT (
 EA_FACTORY_GOBJECT (
        EA_TYPE_WEEK_VIEW_MAIN_ITEM,
        ea_week_view_main_item, ea_week_view_main_item_new)
-EA_FACTORY (EA_TYPE_GNOME_CALENDAR, ea_gnome_calendar, ea_gnome_calendar_new)
 
 static gboolean ea_calendar_focus_watcher (GSignalInvocationHint *ihint,
                                            guint n_param_values,
@@ -53,7 +51,7 @@ static gpointer e_text_type, pixbuf_type, e_day_view_type, e_week_view_type;
 static gpointer e_day_view_main_item_type, e_week_view_main_item_type;
 
 void
-gnome_calendar_a11y_init (void)
+e_calendar_a11y_init (void)
 {
        /* we only add focus watcher when accessibility is enabled
         */
@@ -64,8 +62,6 @@ gnome_calendar_a11y_init (void)
                gnome_canvas = gnome_canvas_new ();
                gtk_widget_destroy (gnome_canvas);
 
-               EA_SET_FACTORY (gnome_calendar_get_type (), ea_gnome_calendar);
-
                /* force loading some types */
                e_text_type = g_type_class_ref (E_TYPE_TEXT);
                pixbuf_type = g_type_class_ref (GNOME_TYPE_CANVAS_PIXBUF);
diff --git a/calendar/gui/ea-calendar.h b/calendar/gui/ea-calendar.h
index c94be35..c3564c8 100644
--- a/calendar/gui/ea-calendar.h
+++ b/calendar/gui/ea-calendar.h
@@ -26,7 +26,7 @@
 #ifndef _EA_CALENDAR_H__
 #define _EA_CALENDAR_H__
 
-void gnome_calendar_a11y_init (void);
+void e_calendar_a11y_init (void);
 void e_day_view_main_item_a11y_init (void);
 void e_week_view_main_item_a11y_init (void);
 
diff --git a/calendar/gui/ea-day-view-main-item.c b/calendar/gui/ea-day-view-main-item.c
index 9396eef..d34f626 100644
--- a/calendar/gui/ea-day-view-main-item.c
+++ b/calendar/gui/ea-day-view-main-item.c
@@ -46,7 +46,7 @@ static AtkObject * ea_day_view_main_item_get_parent (AtkObject *accessible);
 static gint ea_day_view_main_item_get_index_in_parent (AtkObject *accessible);
 
 /* callbacks */
-static void ea_day_view_main_item_dates_change_cb (GnomeCalendar *gcal, gpointer data);
+static void ea_day_view_main_item_time_range_changed_cb (ECalModel *model, time_t start, time_t end, 
gpointer data);
 static void ea_day_view_main_item_time_change_cb (EDayView *day_view, gpointer data);
 
 /* component interface */
@@ -187,7 +187,7 @@ AtkObject *
 ea_day_view_main_item_new (GObject *obj)
 {
        AtkObject *accessible;
-       GnomeCalendar *gcal;
+       ECalModel *model;
        EDayViewMainItem *main_item;
        EDayView *day_view;
 
@@ -216,11 +216,11 @@ ea_day_view_main_item_new (GObject *obj)
                accessible);
 
        /* listen for date changes of calendar */
-       gcal = e_calendar_view_get_calendar (E_CALENDAR_VIEW (day_view));
-       if (gcal)
-               g_signal_connect (
-                       gcal, "dates_shown_changed",
-                       G_CALLBACK (ea_day_view_main_item_dates_change_cb),
+       model = e_calendar_view_get_model (E_CALENDAR_VIEW (day_view));
+       if (model)
+               g_signal_connect_after (
+                       model, "time-range-changed",
+                       G_CALLBACK (ea_day_view_main_item_time_range_changed_cb),
                        accessible);
 
        return accessible;
@@ -373,12 +373,14 @@ ea_day_view_main_item_get_index_in_parent (AtkObject *accessible)
 /* callbacks */
 
 static void
-ea_day_view_main_item_dates_change_cb (GnomeCalendar *gcal,
-                                       gpointer data)
+ea_day_view_main_item_time_range_changed_cb (ECalModel *model,
+                                            time_t start,
+                                            time_t end,
+                                            gpointer data)
 {
        EaDayViewMainItem *ea_main_item;
 
-       g_return_if_fail (GNOME_IS_CALENDAR (gcal));
+       g_return_if_fail (E_IS_CAL_MODEL (model));
        g_return_if_fail (data);
        g_return_if_fail (EA_IS_DAY_VIEW_MAIN_ITEM (data));
 
diff --git a/calendar/gui/ea-day-view.c b/calendar/gui/ea-day-view.c
index 7af286e..3331148 100644
--- a/calendar/gui/ea-day-view.c
+++ b/calendar/gui/ea-day-view.c
@@ -27,7 +27,6 @@
 #include "ea-cal-view-event.h"
 
 #include "ea-calendar-helpers.h"
-#include "ea-gnome-calendar.h"
 #include <glib/gi18n.h>
 
 static const gchar * ea_day_view_get_name (AtkObject *accessible);
@@ -82,9 +81,7 @@ static const gchar *
 ea_day_view_get_name (AtkObject *accessible)
 {
        EDayView *day_view;
-       GnomeCalendar *gcal;
-       const gchar *label_text;
-       GnomeCalendarViewType view_type;
+       gchar *label_text;
        GtkWidget *widget;
        gint n_events;
        gchar *event_str, *name_str;
@@ -96,9 +93,8 @@ ea_day_view_get_name (AtkObject *accessible)
                return NULL;
 
        day_view = E_DAY_VIEW (widget);
-       gcal = e_calendar_view_get_calendar (E_CALENDAR_VIEW (day_view));
 
-       label_text = ea_gnome_calendar_get_label_description (gcal);
+       label_text = e_calendar_view_get_description_text (E_CALENDAR_VIEW (day_view));
 
        n_events = atk_object_get_n_accessible_children (accessible);
        /* the child main item is always there */
@@ -117,8 +113,7 @@ ea_day_view_get_name (AtkObject *accessible)
                10th - July 14th, 2006." or "Day View: Thursday July 13th, 2006." */
                event_str = g_strdup (_("It has no events."));
 
-       view_type = gnome_calendar_get_view (gcal);
-       if (view_type == GNOME_CAL_WORK_WEEK_VIEW)
+       if (e_day_view_get_work_week_view (day_view))
                /* To translators: First %s is the week, for example "July 10th -
                July 14th, 2006". Second %s is the number of events in this work
                week, for example "It has %d event/events." or  "It has no events." */
@@ -136,6 +131,7 @@ ea_day_view_get_name (AtkObject *accessible)
        ATK_OBJECT_CLASS (parent_class)->set_name (accessible, name_str);
        g_free (name_str);
        g_free (event_str);
+       g_free (label_text);
 
        return accessible->name;
 }
@@ -157,13 +153,7 @@ ea_day_view_get_description (AtkObject *accessible)
        if (accessible->description)
                return accessible->description;
        else {
-               GnomeCalendar *gcal;
-               GnomeCalendarViewType view_type;
-
-               gcal = e_calendar_view_get_calendar (E_CALENDAR_VIEW (day_view));
-               view_type = gnome_calendar_get_view (gcal);
-
-               if (view_type == GNOME_CAL_WORK_WEEK_VIEW)
+               if (e_day_view_get_work_week_view (day_view))
                        return _("calendar view for a work week");
                else
                        return _("calendar view for one or more days");
diff --git a/calendar/gui/ea-week-view-main-item.c b/calendar/gui/ea-week-view-main-item.c
index 96ed04e..468c000 100644
--- a/calendar/gui/ea-week-view-main-item.c
+++ b/calendar/gui/ea-week-view-main-item.c
@@ -50,8 +50,10 @@ static gint  ea_week_view_main_item_get_index_in_parent
                                                (AtkObject *accessible);
 
 /* callbacks */
-static void    ea_week_view_main_item_dates_change_cb
-                                               (GnomeCalendar *gcal,
+static void    ea_week_view_main_item_time_range_changed_cb
+                                               (ECalModel *model,
+                                                time_t start,
+                                                time_t end,
                                                 gpointer data);
 static void    ea_week_view_main_item_time_change_cb
                                                (EWeekView *week_view,
@@ -217,7 +219,7 @@ AtkObject *
 ea_week_view_main_item_new (GObject *obj)
 {
        AtkObject *accessible;
-       GnomeCalendar *gcal;
+       ECalModel *model;
        EWeekViewMainItem *main_item;
        EWeekView *week_view;
 
@@ -246,11 +248,11 @@ ea_week_view_main_item_new (GObject *obj)
                accessible);
 
        /* listen for date changes of calendar */
-       gcal = e_calendar_view_get_calendar (E_CALENDAR_VIEW (week_view));
-       if (gcal)
+       model = e_calendar_view_get_model (E_CALENDAR_VIEW (week_view));
+       if (model)
                g_signal_connect (
-                       gcal, "dates_shown_changed",
-                       G_CALLBACK (ea_week_view_main_item_dates_change_cb),
+                       model, "time-range-changed",
+                       G_CALLBACK (ea_week_view_main_item_time_range_changed_cb),
                        accessible);
 
        return accessible;
@@ -400,12 +402,14 @@ ea_week_view_main_item_get_index_in_parent (AtkObject *accessible)
 /* callbacks */
 
 static void
-ea_week_view_main_item_dates_change_cb (GnomeCalendar *gcal,
-                                        gpointer data)
+ea_week_view_main_item_time_range_changed_cb (ECalModel *model,
+                                             time_t start,
+                                             time_t end,
+                                             gpointer data)
 {
        EaWeekViewMainItem *ea_main_item;
 
-       g_return_if_fail (GNOME_IS_CALENDAR (gcal));
+       g_return_if_fail (E_IS_CAL_MODEL (model));
        g_return_if_fail (data);
        g_return_if_fail (EA_IS_WEEK_VIEW_MAIN_ITEM (data));
 
diff --git a/calendar/gui/ea-week-view.c b/calendar/gui/ea-week-view.c
index 593cb8b..0946950 100644
--- a/calendar/gui/ea-week-view.c
+++ b/calendar/gui/ea-week-view.c
@@ -29,7 +29,7 @@
 
 #include "ea-cal-view-event.h"
 #include "ea-calendar-helpers.h"
-#include "ea-gnome-calendar.h"
+#include "e-month-view.h"
 
 static const gchar * ea_week_view_get_name (AtkObject *accessible);
 static const gchar * ea_week_view_get_description (AtkObject *accessible);
@@ -84,9 +84,7 @@ static const gchar *
 ea_week_view_get_name (AtkObject *accessible)
 {
        EWeekView *week_view;
-       GnomeCalendar *gcal;
-       const gchar *label_text;
-       GnomeCalendarViewType view_type;
+       gchar *label_text;
        GtkWidget *widget;
        gint n_events;
        gchar *event_str, *name_str;
@@ -98,9 +96,8 @@ ea_week_view_get_name (AtkObject *accessible)
                return NULL;
 
        week_view = E_WEEK_VIEW (widget);
-       gcal = e_calendar_view_get_calendar (E_CALENDAR_VIEW (week_view));
 
-       label_text = ea_gnome_calendar_get_label_description (gcal);
+       label_text = e_calendar_view_get_description_text (E_CALENDAR_VIEW (week_view));
 
        n_events = atk_object_get_n_accessible_children (accessible);
        /* the child main item is always there */
@@ -112,9 +109,7 @@ ea_week_view_get_name (AtkObject *accessible)
        else
                event_str = g_strdup (_("It has no events."));
 
-       view_type = gnome_calendar_get_view (gcal);
-
-       if (view_type == GNOME_CAL_MONTH_VIEW)
+       if (E_IS_MONTH_VIEW (week_view))
                name_str = g_strdup_printf (
                        _("Month View: %s. %s"),
                        label_text, event_str);
@@ -127,6 +122,7 @@ ea_week_view_get_name (AtkObject *accessible)
        ATK_OBJECT_CLASS (parent_class)->set_name (accessible, name_str);
        g_free (name_str);
        g_free (event_str);
+       g_free (label_text);
 
        return accessible->name;
 }
@@ -148,13 +144,7 @@ ea_week_view_get_description (AtkObject *accessible)
        if (accessible->description)
                return accessible->description;
        else {
-               GnomeCalendar *gcal;
-               GnomeCalendarViewType view_type;
-
-               gcal = e_calendar_view_get_calendar (E_CALENDAR_VIEW (week_view));
-               view_type = gnome_calendar_get_view (gcal);
-
-               if (view_type == GNOME_CAL_MONTH_VIEW)
+               if (E_IS_MONTH_VIEW (week_view))
                        return _("calendar view for a month");
                else
                        return _("calendar view for one or more weeks");
@@ -188,12 +178,14 @@ ea_week_view_get_n_children (AtkObject *accessible)
 
                event = &g_array_index (week_view->events,
                                        EWeekViewEvent, event_index);
-               span = &g_array_index (week_view->spans, EWeekViewEventSpan,
-                                      event->spans_index + 0);
+               if (event->spans_index >= 0 && event->spans_index < week_view->spans->len) {
+                       span = &g_array_index (week_view->spans, EWeekViewEventSpan,
+                                              event->spans_index + 0);
 
-               /* at least one of the event spans is visible, count it */
-               if (span->text_item)
-                       ++count;
+                       /* at least one of the event spans is visible, count it */
+                       if (span->text_item)
+                               ++count;
+               }
        }
 
        /* add the number of visible jump buttons */
@@ -250,6 +242,10 @@ ea_week_view_ref_child (AtkObject *accessible,
 
                event = &g_array_index (week_view->events,
                                        EWeekViewEvent, event_index);
+
+               if (event->spans_index < 0 || !week_view->spans || event->spans_index >= 
week_view->spans->len)
+                       continue;
+
                span = &g_array_index (week_view->spans, EWeekViewEventSpan,
                                       event->spans_index + span_num);
 
diff --git a/calendar/gui/itip-utils.c b/calendar/gui/itip-utils.c
index 7190c05..78b22fa 100644
--- a/calendar/gui/itip-utils.c
+++ b/calendar/gui/itip-utils.c
@@ -426,11 +426,11 @@ itip_get_comp_attendee (ESourceRegistry *registry,
 
                        return user_email;
                }
-
-               g_free (address);
-               address = NULL;
        }
 
+       g_free (address);
+       address = NULL;
+
        extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY;
        list = e_source_registry_list_enabled (registry, extension_name);
 
@@ -1124,37 +1124,34 @@ comp_description (ECalComponent *comp,
 }
 
 static gboolean
-comp_server_send (ECalComponentItipMethod method,
-                  ECalComponent *comp,
-                  ECalClient *cal_client,
-                  icalcomponent *zones,
-                  GSList **users)
+comp_server_send_sync (ECalComponentItipMethod method,
+                      ECalComponent *comp,
+                      ECalClient *cal_client,
+                      icalcomponent *zones,
+                      GSList **users,
+                      GCancellable *cancellable,
+                      GError **error)
 {
        icalcomponent *top_level, *returned_icalcomp = NULL;
        gboolean retval = TRUE;
-       GError *error = NULL;
+       GError *local_error = NULL;
 
        top_level = comp_toplevel_with_zones (method, comp, cal_client, zones);
-       d (printf ("itip-utils.c: comp_server_send: calling e_cal_send_objects... \n"));
+       d (printf ("itip-utils.c: comp_server_send_sync: calling e_cal_send_objects... \n"));
 
        e_cal_client_send_objects_sync (
                cal_client, top_level, users,
-               &returned_icalcomp, NULL, &error);
-
-       if (g_error_matches (error, E_CAL_CLIENT_ERROR, E_CAL_CLIENT_ERROR_OBJECT_ID_ALREADY_EXISTS)) {
-               e_notice (
-                       NULL, GTK_MESSAGE_ERROR,
-                       _("Unable to book a resource, the "
-                       "new event collides with some other."));
-               g_error_free (error);
+               &returned_icalcomp, cancellable, &local_error);
+
+       if (g_error_matches (local_error, E_CAL_CLIENT_ERROR, E_CAL_CLIENT_ERROR_OBJECT_ID_ALREADY_EXISTS)) {
+               g_propagate_error (error, g_error_new (local_error->domain, local_error->code,
+                       _("Unable to book a resource, the new event collides with some other.")));
+               g_clear_error (&local_error);
                retval = FALSE;
 
-       } else if (error != NULL) {
-               e_notice (
-                       NULL, GTK_MESSAGE_ERROR,
-                       _("Unable to book a resource, error: %s"),
-                       error->message);
-               g_error_free (error);
+       } else if (local_error != NULL) {
+               g_prefix_error (&local_error, "%s", _("Unable to book a resource, error: "));
+               g_propagate_error (error, local_error);
                retval = FALSE;
        }
 
@@ -1672,18 +1669,90 @@ setup_from (ECalComponentItipMethod method,
        g_object_unref (registry);
 }
 
-gboolean
-itip_send_comp (ESourceRegistry *registry,
-                ECalComponentItipMethod method,
-                ECalComponent *send_comp,
-                ECalClient *cal_client,
-                icalcomponent *zones,
-                GSList *attachments_list,
-                GSList *users,
-                gboolean strip_alarms,
-                gboolean only_new_attendees)
+typedef struct {
+       ESourceRegistry *registry;
+       ECalComponentItipMethod method;
+       ECalComponent *send_comp;
+       ECalClient *cal_client;
+       icalcomponent *zones;
+       GSList *attachments_list;
+       GSList *users;
+       gboolean strip_alarms;
+       gboolean only_new_attendees;
+       gboolean ensure_master_object;
+
+       gboolean finished;
+       gboolean success;
+} ItipSendComponentData;
+
+static void
+itip_send_component_data_free (ItipSendComponentData *isc)
+{
+       if (isc) {
+               g_clear_object (&isc->registry);
+               g_clear_object (&isc->send_comp);
+               g_clear_object (&isc->cal_client);
+               if (isc->zones)
+                       icalcomponent_free (isc->zones);
+               g_slist_free_full (isc->attachments_list, g_object_unref); /* CamelMimePart */
+               g_slist_free_full (isc->users, g_free);
+               g_free (isc);
+       }
+}
+
+static void
+itip_send_component_begin (ItipSendComponentData *isc,
+                          GCancellable *cancellable,
+                          GError **error)
+{
+       g_return_if_fail (isc != NULL);
+
+       isc->finished = FALSE;
+
+       if (isc->method != E_CAL_COMPONENT_METHOD_PUBLISH && e_cal_client_check_save_schedules 
(isc->cal_client)) {
+               isc->success = TRUE;
+               isc->finished = TRUE;
+               return;
+       }
+
+       if (isc->ensure_master_object && e_cal_component_is_instance (isc->send_comp)) {
+               /* Ensure we send the master object, not the instance only */
+               icalcomponent *icalcomp = NULL;
+               const gchar *uid = NULL;
+
+               e_cal_component_get_uid (isc->send_comp, &uid);
+               if (e_cal_client_get_object_sync (isc->cal_client, uid, NULL, &icalcomp, cancellable, NULL) 
&& icalcomp) {
+                       ECalComponent *send_comp;
+
+                       send_comp = e_cal_component_new_from_icalcomponent (icalcomp);
+                       if (send_comp) {
+                               g_object_unref (isc->send_comp);
+                               isc->send_comp = send_comp;
+                       }
+               }
+       }
+
+       /* Give the server a chance to manipulate the comp */
+       if (isc->method != E_CAL_COMPONENT_METHOD_PUBLISH) {
+               d (printf ("itip-utils.c: itip_send_component_begin: calling comp_server_send_sync... \n"));
+               if (!comp_server_send_sync (isc->method, isc->send_comp, isc->cal_client, isc->zones, 
&isc->users, cancellable, error)) {
+                       isc->success = FALSE;
+                       isc->finished = TRUE;
+                       return;
+               }
+       }
+
+       /* check whether backend could handle sending requests/updates */
+       if (isc->method != E_CAL_COMPONENT_METHOD_PUBLISH &&
+           e_client_check_capability (E_CLIENT (isc->cal_client), CAL_STATIC_CAPABILITY_CREATE_MESSAGES)) {
+               isc->success = TRUE;
+               isc->finished = TRUE;
+       }
+}
+
+static void
+itip_send_component_finish (ItipSendComponentData *isc)
 {
-       EShell *shell;
        GSettings *settings;
        EMsgComposer *composer;
        EComposerHeaderTable *table;
@@ -1694,83 +1763,58 @@ itip_send_comp (ESourceRegistry *registry,
        gchar *ical_string = NULL;
        gchar *content_type = NULL;
        gchar *subject = NULL;
-       gboolean use_24_hour_format;
-       gboolean retval = FALSE;
+       gboolean use_24hour_format;
 
-       g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE);
+       g_return_if_fail (isc != NULL);
 
-       /* FIXME Pass this in. */
-       shell = e_shell_get_default ();
-
-       settings = g_settings_new ("org.gnome.evolution.calendar");
+       if (isc->finished)
+               return;
 
-       use_24_hour_format =
-               g_settings_get_boolean (settings, "use-24hour-format");
+       isc->success = FALSE;
 
+       settings = g_settings_new ("org.gnome.evolution.calendar");
+       use_24hour_format = g_settings_get_boolean (settings, "use-24hour-format");
        g_object_unref (settings);
 
        default_zone = calendar_config_get_icaltimezone ();
 
-       /* check whether backend could handle auto-saving requests/updates */
-       if (method != E_CAL_COMPONENT_METHOD_PUBLISH && e_cal_client_check_save_schedules (cal_client))
-               return TRUE;
-
-       /* Give the server a chance to manipulate the comp */
-       if (method != E_CAL_COMPONENT_METHOD_PUBLISH) {
-               d (printf ("itip-utils.c: itip_send_comp: calling comp_server_send... \n"));
-               if (!comp_server_send (method, send_comp, cal_client, zones, &users))
-                       goto cleanup;
-       }
-
-       /* check whether backend could handle sending requests/updates */
-       if (method != E_CAL_COMPONENT_METHOD_PUBLISH &&
-               e_client_check_capability (
-                       E_CLIENT (cal_client),
-               CAL_STATIC_CAPABILITY_CREATE_MESSAGES)) {
-               if (users) {
-                       g_slist_foreach (users, (GFunc) g_free, NULL);
-                       g_slist_free (users);
-               }
-               return TRUE;
-       }
-
        /* Tidy up the comp */
        comp = comp_compliant (
-               registry, method, send_comp, cal_client,
-               zones, default_zone, strip_alarms);
+               isc->registry, isc->method, isc->send_comp, isc->cal_client,
+               isc->zones, default_zone, isc->strip_alarms);
 
        if (comp == NULL)
                goto cleanup;
 
        /* Recipients */
        destinations = comp_to_list (
-               registry, method, comp, users, FALSE,
-               only_new_attendees ? g_object_get_data (
-               G_OBJECT (send_comp), "new-attendees") : NULL);
-       if (method != E_CAL_COMPONENT_METHOD_PUBLISH) {
+               isc->registry, isc->method, comp, isc->users, FALSE,
+               isc->only_new_attendees ? g_object_get_data (
+               G_OBJECT (isc->send_comp), "new-attendees") : NULL);
+       if (isc->method != E_CAL_COMPONENT_METHOD_PUBLISH) {
                if (destinations == NULL) {
                        /* We sent them all via the server */
-                       retval = TRUE;
+                       isc->success = TRUE;
                        goto cleanup;
                }
        }
 
        /* Subject information */
-       subject = comp_subject (registry, method, comp);
+       subject = comp_subject (isc->registry, isc->method, comp);
 
-       composer = e_msg_composer_new (shell);
+       composer = e_msg_composer_new (e_shell_get_default ());
        table = e_msg_composer_get_header_table (composer);
 
-       setup_from (method, send_comp, cal_client, table);
+       setup_from (isc->method, isc->send_comp, isc->cal_client, table);
        e_composer_header_table_set_subject (table, subject);
        e_composer_header_table_set_destinations_to (table, destinations);
 
        e_destination_freev (destinations);
 
        /* Content type */
-       content_type = comp_content_type (comp, method);
+       content_type = comp_content_type (comp, isc->method);
 
-       top_level = comp_toplevel_with_zones (method, comp, cal_client, zones);
+       top_level = comp_toplevel_with_zones (isc->method, comp, isc->cal_client, isc->zones);
        ical_string = icalcomponent_as_ical_string_r (top_level);
 
        if (e_cal_component_get_vtype (comp) == E_CAL_COMPONENT_EVENT) {
@@ -1782,10 +1826,9 @@ itip_send_comp (ESourceRegistry *registry,
                gchar *body;
 
                filename = comp_filename (comp);
-               description = comp_description (comp, use_24_hour_format);
+               description = comp_description (comp, use_24hour_format);
 
-               body = camel_text_to_html (
-                       description, CAMEL_MIME_FILTER_TOHTML_PRE, 0);
+               body = camel_text_to_html (description, CAMEL_MIME_FILTER_TOHTML_PRE, 0);
                e_msg_composer_set_body_text (composer, body, TRUE);
                g_free (body);
 
@@ -1804,31 +1847,160 @@ itip_send_comp (ESourceRegistry *registry,
                g_free (description);
        }
 
-       append_cal_attachments (composer, comp, attachments_list);
+       append_cal_attachments (composer, comp, isc->attachments_list);
 
-       if ((method == E_CAL_COMPONENT_METHOD_PUBLISH) && !users)
+       if (isc->method == E_CAL_COMPONENT_METHOD_PUBLISH && !isc->users)
                gtk_widget_show (GTK_WIDGET (composer));
        else
                e_msg_composer_send (composer);
 
-       retval = TRUE;
+       isc->success = TRUE;
 
-cleanup:
-       if (comp != NULL)
-               g_object_unref (comp);
+ cleanup:
+       g_clear_object (&comp);
        if (top_level != NULL)
                icalcomponent_free (top_level);
+       g_free (content_type);
+       g_free (subject);
+       g_free (ical_string);
+}
+
+static void
+itip_send_component_finish_and_free (gpointer ptr)
+{
+       ItipSendComponentData *isc = ptr;
+
+       if (isc) {
+               itip_send_component_finish (isc);
+               itip_send_component_data_free (isc);
+       }
+}
+
+static void
+itip_send_component_thread (EAlertSinkThreadJobData *job_data,
+                           gpointer user_data,
+                           GCancellable *cancellable,
+                           GError **error)
+{
+       ItipSendComponentData *isc = user_data;
+
+       g_return_if_fail (isc != NULL);
 
+       itip_send_component_begin (isc, cancellable, error);
+}
+
+void
+itip_send_component (ECalModel *model,
+                    ECalComponentItipMethod method,
+                    ECalComponent *send_comp,
+                    ECalClient *cal_client,
+                    icalcomponent *zones,
+                    GSList *attachments_list,
+                    GSList *users,
+                    gboolean strip_alarms,
+                    gboolean only_new_attendees,
+                    gboolean ensure_master_object)
+{
+       ESourceRegistry *registry;
+       ECalDataModel *data_model;
+       ESource *source;
+       const gchar *alert_ident;
+       const gchar *description;
+       GCancellable *cancellable;
+       ItipSendComponentData *isc;
+
+       g_return_if_fail (E_IS_CAL_MODEL (model));
+       g_return_if_fail (E_IS_CAL_CLIENT (cal_client));
+
+       switch (e_cal_client_get_source_type (cal_client)) {
+               case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+                       description = _("Sending an event");
+                       alert_ident = "calendar:failed-send-event";
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+                       description = _("Sending a memo");
+                       alert_ident = "calendar:failed-send-memo";
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+                       description = _("Sending a task");
+                       alert_ident = "calendar:failed-send-task";
+                       break;
+               default:
+                       g_warn_if_reached ();
+                       break;
+       }
+
+       registry = e_cal_model_get_registry (model);
+       data_model = e_cal_model_get_data_model (model);
+       source = e_client_get_source (E_CLIENT (cal_client));
+
+       isc = g_new0 (ItipSendComponentData, 1);
+       isc->registry = g_object_ref (registry);
+       isc->method = method;
+       isc->send_comp = g_object_ref (send_comp);
+       isc->cal_client = g_object_ref (cal_client);
+       if (zones) {
+               isc->zones = icalcomponent_new_clone (zones);
+       }
+       if (attachments_list) {
+               isc->attachments_list = g_slist_copy (attachments_list);
+               g_slist_foreach (isc->attachments_list, (GFunc) g_object_ref, NULL);
+       }
        if (users) {
-               g_slist_foreach (users, (GFunc) g_free, NULL);
-               g_slist_free (users);
+               GSList *link;
+
+               isc->users = g_slist_copy (users);
+               for (link = isc->users; link; link = g_slist_next (link)) {
+                       link->data = g_strdup (link->data);
+               }
        }
+       isc->strip_alarms = strip_alarms;
+       isc->only_new_attendees = only_new_attendees;
+       isc->ensure_master_object = ensure_master_object;
+       isc->success = FALSE;
+       isc->finished = FALSE;
 
-       g_free (content_type);
-       g_free (subject);
-       g_free (ical_string);
+       cancellable = e_cal_data_model_submit_thread_job (data_model, description, alert_ident,
+               e_source_get_display_name (source), itip_send_component_thread,
+               isc, itip_send_component_finish_and_free);
 
-       return retval;
+       g_clear_object (&cancellable);
+}
+
+gboolean
+itip_send_comp_sync (ESourceRegistry *registry,
+                    ECalComponentItipMethod method,
+                    ECalComponent *send_comp,
+                    ECalClient *cal_client,
+                    icalcomponent *zones,
+                    GSList *attachments_list,
+                    GSList *users,
+                    gboolean strip_alarms,
+                    gboolean only_new_attendees,
+                    GCancellable *cancellable,
+                    GError **error)
+{
+       ItipSendComponentData isc;
+
+       isc.registry = registry;
+       isc.method = method;
+       isc.send_comp = send_comp;
+       isc.cal_client = cal_client;
+       isc.zones = zones;
+       isc.attachments_list = attachments_list;
+       isc.users = users;
+       isc.strip_alarms = strip_alarms;
+       isc.only_new_attendees = only_new_attendees;
+
+       isc.finished = FALSE;
+       isc.success = FALSE;
+
+       itip_send_component_begin (&isc, cancellable, error);
+       itip_send_component_finish (&isc);
+
+       g_slist_free_full (isc.users, g_free);
+
+       return isc.success;
 }
 
 gboolean
diff --git a/calendar/gui/itip-utils.h b/calendar/gui/itip-utils.h
index 3136c31..841e66e 100644
--- a/calendar/gui/itip-utils.h
+++ b/calendar/gui/itip-utils.h
@@ -22,6 +22,7 @@
 #include <libical/ical.h>
 #include <string.h>
 #include <libecal/libecal.h>
+#include <calendar/gui/e-cal-model.h>
 
 G_BEGIN_DECLS
 
@@ -68,15 +69,27 @@ const gchar *       itip_strip_mailto               (const gchar *address);
 gchar *                itip_get_comp_attendee          (ESourceRegistry *registry,
                                                 ECalComponent *comp,
                                                 ECalClient *cal_client);
-gboolean       itip_send_comp                  (ESourceRegistry *registry,
+gboolean       itip_send_comp_sync             (ESourceRegistry *registry,
                                                 ECalComponentItipMethod method,
-                                                ECalComponent *comp,
+                                                ECalComponent *send_comp,
+                                                ECalClient *cal_client,
+                                                icalcomponent *zones,
+                                                GSList *attachments_list,
+                                                GSList *users,
+                                                gboolean strip_alarms,
+                                                gboolean only_new_attendees,
+                                                GCancellable *cancellable,
+                                                GError **error);
+void           itip_send_component             (ECalModel *model,
+                                                ECalComponentItipMethod method,
+                                                ECalComponent *send_comp,
                                                 ECalClient *cal_client,
                                                 icalcomponent *zones,
                                                 GSList *attachments_list,
                                                 GSList *users,
                                                 gboolean strip_alarms,
-                                                gboolean only_new_attendees);
+                                                gboolean only_new_attendees,
+                                                gboolean ensure_master_object);
 gboolean       itip_publish_begin              (ECalComponent *pub_comp,
                                                 ECalClient *cal_client,
                                                 gboolean cloned,
diff --git a/calendar/gui/print.c b/calendar/gui/print.c
index 6546688..7c02004 100644
--- a/calendar/gui/print.c
+++ b/calendar/gui/print.c
@@ -44,7 +44,6 @@
 #include "e-week-view.h"
 #include "e-week-view-layout.h"
 #include "e-task-table.h"
-#include "gnome-cal.h"
 
 #include "art/jump.xpm"
 
@@ -59,7 +58,9 @@ struct PrintCompItem {
 };
 
 struct PrintCalItem {
-       GnomeCalendar *gcal;
+       ECalendarView *cal_view;
+       ETable *tasks_table;
+       EPrintView print_view_type;
        time_t start;
 };
 
@@ -769,7 +770,7 @@ calc_small_month_width (GtkPrintContext *context,
 */
 static void
 print_month_small (GtkPrintContext *context,
-                   GnomeCalendar *gcal,
+                   ECalModel *model,
                    time_t month,
                    gdouble x1,
                    gdouble y1,
@@ -782,7 +783,6 @@ print_month_small (GtkPrintContext *context,
 {
        icaltimezone *zone;
        PangoFontDescription *font, *font_bold, *font_normal;
-       ECalModel *model;
        time_t now, next;
        gint x, y;
        gint day;
@@ -797,7 +797,6 @@ print_month_small (GtkPrintContext *context,
        gboolean week_numbers;
        cairo_t *cr;
 
-       model = gnome_calendar_get_model (gcal);
        zone = e_cal_model_get_timezone (model);
 
        week_numbers = get_show_week_numbers ();
@@ -924,7 +923,7 @@ print_month_small (GtkPrintContext *context,
 
                                /* this is a slow messy way to do this ... but easy ... */
                                e_cal_model_generate_instances_sync (
-                                       gnome_calendar_get_model (gcal), now,
+                                       model, now,
                                        time_day_end_with_zone (now, zone),
                                        instance_cb, &found);
 
@@ -1017,7 +1016,7 @@ bound_text (GtkPrintContext *context,
 /* Draw the borders, lines, and times down the left of the day view. */
 static void
 print_day_background (GtkPrintContext *context,
-                      GnomeCalendar *gcal,
+                      ECalModel *model,
                       time_t whence,
                       struct pdinfo *pdi,
                       gdouble left,
@@ -1025,7 +1024,6 @@ print_day_background (GtkPrintContext *context,
                       gdouble top,
                       gdouble bottom)
 {
-       ECalModel *model;
        PangoFontDescription *font_hour, *font_minute;
        gdouble yinc, y;
        gdouble width = DAY_VIEW_TIME_COLUMN_WIDTH;
@@ -1037,7 +1035,6 @@ print_day_background (GtkPrintContext *context,
        gdouble hour_minute_x, hour_minute_width;
        cairo_t *cr;
 
-       model = gnome_calendar_get_model (gcal);
        use_24_hour = e_cal_model_get_use_24_hour_format (model);
 
        /* Fill the time column in light-gray. */
@@ -1545,14 +1542,13 @@ print_day_event (GtkPrintContext *context,
 
 static void
 print_day_details (GtkPrintContext *context,
-                   GnomeCalendar *gcal,
+                   ECalModel *model,
                    time_t whence,
                    gdouble left,
                    gdouble right,
                    gdouble top,
                    gdouble bottom)
 {
-       ECalModel *model;
        icaltimezone *zone;
        EDayViewEvent *event;
        PangoFontDescription *font;
@@ -1565,7 +1561,6 @@ print_day_details (GtkPrintContext *context,
 #define LONG_DAY_EVENTS_TOP_SPACING 4
 #define LONG_DAY_EVENTS_BOTTOM_SPACING 2
 
-       model = gnome_calendar_get_model (gcal);
        zone = e_cal_model_get_timezone (model);
 
        start = time_day_begin_with_zone (whence, zone);
@@ -1699,7 +1694,7 @@ print_day_details (GtkPrintContext *context,
 
        /* Draw the borders, lines, and times down the left. */
        print_day_background (
-               context, gcal, whence, &pdi,
+               context, model, whence, &pdi,
                left, right, top, bottom);
        /* Now adjust to get rid of the time column. */
        left += DAY_VIEW_TIME_COLUMN_WIDTH;
@@ -2149,7 +2144,7 @@ print_week_summary_cb (ECalComponent *comp,
 
 static void
 print_week_summary (GtkPrintContext *context,
-                    GnomeCalendar *gcal,
+                    ECalModel *model,
                     time_t whence,
                     gboolean multi_week_view,
                     gint weeks_shown,
@@ -2169,9 +2164,7 @@ print_week_summary (GtkPrintContext *context,
        GArray *spans;
        PangoFontDescription *font, *font_background;
        gdouble cell_width, cell_height;
-       ECalModel *model;
 
-       model = gnome_calendar_get_model (gcal);
        zone = e_cal_model_get_timezone (model);
 
        psi.days_shown = weeks_shown * 7;
@@ -2267,7 +2260,9 @@ print_week_summary (GtkPrintContext *context,
 
 static void
 print_month_summary (GtkPrintContext *context,
-                     GnomeCalendar *gcal,
+                     ECalModel *model,
+                    ECalendarView *calendar_view,
+                    EPrintView print_view_type,
                      time_t whence,
                      gdouble left,
                      gdouble right,
@@ -2279,7 +2274,6 @@ print_month_summary (GtkPrintContext *context,
        struct tm tm;
        struct icaltimetype tt;
        gchar buffer[100];
-       ECalModel *model;
        PangoFontDescription *font;
        gboolean compress_weekend;
        gint columns, col, month, weeks;
@@ -2287,23 +2281,18 @@ print_month_summary (GtkPrintContext *context,
        gint wday;
        gdouble font_size, cell_width, x1, x2, y1, y2;
 
-       model = gnome_calendar_get_model (gcal);
        zone = e_cal_model_get_timezone (model);
        weekday = e_cal_model_get_week_start_day (model);
        compress_weekend = e_cal_model_get_compress_weekend (model);
 
        date = 0;
        weeks = 6;
-       if (gnome_calendar_get_view (gcal) == GNOME_CAL_MONTH_VIEW) {
-               GnomeCalendarViewType view_type;
-               ECalendarView *calendar_view;
+       if (print_view_type == E_PRINT_VIEW_MONTH) {
                EWeekView *week_view;
                GDate first_day_shown;
                gboolean multi_week_view;
                gint weeks_shown;
 
-               view_type = gnome_calendar_get_view (gcal);
-               calendar_view = gnome_calendar_get_calendar_view (gcal, view_type);
                week_view = E_WEEK_VIEW (calendar_view);
                weeks_shown = e_week_view_get_weeks_shown (week_view);
                multi_week_view = e_week_view_get_multi_week_view (week_view);
@@ -2374,14 +2363,14 @@ print_month_summary (GtkPrintContext *context,
 
        top = y2;
        print_week_summary (
-               context, gcal, date, TRUE, weeks, month,
+               context, model, date, TRUE, weeks, month,
                MONTH_NORMAL_FONT_SIZE, MONTH_NORMAL_FONT_SIZE,
                left, right, top, bottom);
 }
 
 static void
 print_todo_details (GtkPrintContext *context,
-                    GnomeCalendar *gcal,
+                   ETable *tasks_table,
                     time_t start,
                     time_t end,
                     gdouble left,
@@ -2392,18 +2381,14 @@ print_todo_details (GtkPrintContext *context,
        PangoFontDescription *font_summary;
        gdouble y, yend, x, xend;
        struct icaltimetype *tt;
-       GtkWidget *task_table;
-       ETable *table;
        ECalModel *model;
        gint rows, row;
        cairo_t *cr;
 
        /* We get the tasks directly from the TaskPad ETable. This means we
         * get them filtered & sorted for free. */
-       task_table = gnome_calendar_get_task_table (gcal);
-       table = E_TABLE (task_table);
-       g_return_if_fail (table != NULL);
-       model = e_task_table_get_model (E_TASK_TABLE (task_table));
+       g_return_if_fail (tasks_table != NULL);
+       model = e_task_table_get_model (E_TASK_TABLE (tasks_table));
 
        font_summary = get_font_for_size (12, PANGO_WEIGHT_NORMAL);
 
@@ -2427,7 +2412,7 @@ print_todo_details (GtkPrintContext *context,
                ECalComponentText summary;
                gint model_row;
 
-               model_row = e_table_view_to_model_row (table, row);
+               model_row = e_table_view_to_model_row (tasks_table, row);
                comp_data = e_cal_model_get_component_at (model, model_row);
                if (!comp_data)
                        continue;
@@ -2485,7 +2470,8 @@ print_todo_details (GtkPrintContext *context,
 
 static void
 print_day_view (GtkPrintContext *context,
-                GnomeCalendar *gcal,
+               ECalendarView *cal_view,
+                ETable *tasks_table,
                 time_t date)
 {
        ECalModel *model;
@@ -2497,7 +2483,7 @@ print_day_view (GtkPrintContext *context,
        gdouble width, height;
        struct tm tm;
 
-       model = gnome_calendar_get_model (gcal);
+       model = e_calendar_view_get_model (cal_view);
        zone = e_cal_model_get_timezone (model);
 
        setup = gtk_print_context_get_page_setup (context);
@@ -2512,13 +2498,13 @@ print_day_view (GtkPrintContext *context,
 
                /* Print the main view with all the events in. */
                print_day_details (
-                       context, gcal, date,
+                       context, model, date,
                        0.0, todo - 2.0, HEADER_HEIGHT + 4,
                        height);
 
                 /* Print the TaskPad down the right. */
                print_todo_details (
-                       context, gcal, 0, INT_MAX,
+                       context, tasks_table, 0, INT_MAX,
                        todo, width, HEADER_HEIGHT + 4,
                        height);
 
@@ -2533,13 +2519,13 @@ print_day_view (GtkPrintContext *context,
                        SMALL_MONTH_SPACING;
 
                print_month_small (
-                       context, gcal, date,
+                       context, model, date,
                        l, 2, l + small_month_width + week_numbers_inc, HEADER_HEIGHT + 2,
                        DATE_MONTH | DATE_YEAR, date, date, FALSE);
 
                l += SMALL_MONTH_SPACING + small_month_width + week_numbers_inc;
                print_month_small (
-                       context, gcal,
+                       context, model,
                        time_add_month_with_zone (date, 1, zone),
                        l, 2, l + small_month_width + week_numbers_inc, HEADER_HEIGHT + 2,
                        DATE_MONTH | DATE_YEAR, 0, 0, FALSE);
@@ -2569,7 +2555,7 @@ print_day_view (GtkPrintContext *context,
 
 static void
 print_work_week_background (GtkPrintContext *context,
-                            GnomeCalendar *gcal,
+                            ECalModel *model,
                             time_t whence,
                             struct pdinfo *pdi,
                             gdouble left,
@@ -2577,7 +2563,6 @@ print_work_week_background (GtkPrintContext *context,
                             gdouble top,
                             gdouble bottom)
 {
-       ECalModel *model;
        PangoFontDescription *font_hour, *font_minute;
        gdouble yinc, y;
        gdouble width = DAY_VIEW_TIME_COLUMN_WIDTH;
@@ -2591,7 +2576,6 @@ print_work_week_background (GtkPrintContext *context,
        gdouble hour_minute_xl, hour_minute_xr;
        cairo_t *cr;
 
-       model = gnome_calendar_get_model (gcal);
        use_24_hour = e_cal_model_get_use_24_hour_format (model);
 
        /* Fill the left time column in light-gray. */
@@ -2725,7 +2709,7 @@ print_work_week_background (GtkPrintContext *context,
 
 static void
 print_work_week_day_details (GtkPrintContext *context,
-                             GnomeCalendar *gcal,
+                             ECalModel *model,
                              time_t whence,
                              gdouble left,
                              gdouble right,
@@ -2733,7 +2717,6 @@ print_work_week_day_details (GtkPrintContext *context,
                              gdouble bottom,
                              struct pdinfo *_pdi)
 {
-       ECalModel *model;
        icaltimezone *zone;
        EDayViewEvent *event;
        PangoFontDescription *font;
@@ -2746,7 +2729,6 @@ print_work_week_day_details (GtkPrintContext *context,
 #define LONG_DAY_EVENTS_TOP_SPACING 4
 #define LONG_DAY_EVENTS_BOTTOM_SPACING 2
 
-       model = gnome_calendar_get_model (gcal);
        zone = e_cal_model_get_timezone (model);
 
        start = time_day_begin_with_zone (whence, zone);
@@ -2931,7 +2913,7 @@ print_work_week_view_cb (ECalComponent *comp,
 
 static void
 print_work_week_view (GtkPrintContext *context,
-                      GnomeCalendar *gcal,
+                      ECalendarView *cal_view,
                       time_t date)
 {
        GtkPageSetup *setup;
@@ -2948,7 +2930,7 @@ print_work_week_view (GtkPrintContext *context,
        gdouble day_width, day_x;
        ECalModel *model;
 
-       model = gnome_calendar_get_model (gcal);
+       model = e_calendar_view_get_model (cal_view);
        zone = e_cal_model_get_timezone (model);
 
        setup = gtk_print_context_get_page_setup (context);
@@ -2971,7 +2953,7 @@ print_work_week_view (GtkPrintContext *context,
        e_cal_model_generate_instances_sync (model, start, end, print_work_week_view_cb, &pdi);
 
        print_work_week_background (
-               context, gcal, date, &pdi, 0.0, width,
+               context, model, date, &pdi, 0.0, width,
                HEADER_HEIGHT + DAY_VIEW_ROW_HEIGHT + LONG_EVENT_OFFSET,
                height);
 
@@ -2982,13 +2964,13 @@ print_work_week_view (GtkPrintContext *context,
                SMALL_MONTH_SPACING;
 
        print_month_small (
-               context, gcal, start,
+               context, model, start,
                l, 4, l + small_month_width + weeknum_inc, HEADER_HEIGHT + 4,
                DATE_MONTH | DATE_YEAR, start, end, FALSE);
 
        l += SMALL_MONTH_SPACING + small_month_width + weeknum_inc;
        print_month_small (
-               context, gcal,
+               context, model,
                time_add_month_with_zone (start, 1, zone),
                l, 4, l + small_month_width + weeknum_inc, HEADER_HEIGHT + 4,
                DATE_MONTH | DATE_YEAR, 0, 0, FALSE);
@@ -3027,7 +3009,7 @@ print_work_week_view (GtkPrintContext *context,
                        HEADER_HEIGHT + 4, HEADER_HEIGHT + 4 + 18);
 
                print_work_week_day_details (
-                       context, gcal, when,
+                       context, model, when,
                        day_x, day_x + day_width,
                        HEADER_HEIGHT, height, &pdi);
                when = time_add_day_with_zone (when, 1, zone);
@@ -3036,7 +3018,7 @@ print_work_week_view (GtkPrintContext *context,
 
 static void
 print_week_view (GtkPrintContext *context,
-                 GnomeCalendar *gcal,
+                 ECalendarView *cal_view,
                  time_t date)
 {
        GtkPageSetup *setup;
@@ -3057,7 +3039,7 @@ print_week_view (GtkPrintContext *context,
        small_month_width = calc_small_month_width (context, HEADER_HEIGHT);
        week_numbers_inc = get_show_week_numbers () ? small_month_width / 7.0 : 0;
 
-       model = gnome_calendar_get_model (gcal);
+       model = e_calendar_view_get_model (cal_view);
        zone = e_cal_model_get_timezone (model);
 
        convert_timet_to_struct_tm (date, zone, &tm);
@@ -3077,7 +3059,7 @@ print_week_view (GtkPrintContext *context,
 
        /* Print the main week view. */
        print_week_summary (
-               context, gcal, when, FALSE, 1, 0,
+               context, model, when, FALSE, 1, 0,
                WEEK_EVENT_FONT_SIZE, WEEK_SMALL_FONT_SIZE,
                0.0, width,
                HEADER_HEIGHT + 20, height);
@@ -3096,14 +3078,14 @@ print_week_view (GtkPrintContext *context,
        l = width - SMALL_MONTH_PAD - (small_month_width + week_numbers_inc) * 2
                - SMALL_MONTH_SPACING;
        print_month_small (
-               context, gcal, when,
+               context, model, when,
                l, 4, l + small_month_width + week_numbers_inc, HEADER_HEIGHT + 10,
                DATE_MONTH | DATE_YEAR, when,
                time_add_week_with_zone (when, 1, zone), FALSE);
 
        l += SMALL_MONTH_SPACING + small_month_width + week_numbers_inc;
        print_month_small (
-               context, gcal,
+               context, model,
                time_add_month_with_zone (when, 1, zone),
                l, 4, l + small_month_width + week_numbers_inc, HEADER_HEIGHT + 10,
                DATE_MONTH | DATE_YEAR, when,
@@ -3127,7 +3109,8 @@ print_week_view (GtkPrintContext *context,
 
 static void
 print_month_view (GtkPrintContext *context,
-                  GnomeCalendar *gcal,
+                  ECalendarView *cal_view,
+                 EPrintView print_view_type,
                   time_t date)
 {
        ECalModel *model;
@@ -3138,7 +3121,7 @@ print_month_view (GtkPrintContext *context,
        gdouble l, week_numbers_inc, small_month_width;
        struct tm tm;
 
-       model = gnome_calendar_get_model (gcal);
+       model = e_calendar_view_get_model (cal_view);
        zone = e_cal_model_get_timezone (model);
 
        setup = gtk_print_context_get_page_setup (context);
@@ -3149,7 +3132,7 @@ print_month_view (GtkPrintContext *context,
        week_numbers_inc = get_show_week_numbers () ? small_month_width / 7.0 : 0;
 
        /* Print the main month view. */
-       print_month_summary (context, gcal, date, 0.0, width, HEADER_HEIGHT, height);
+       print_month_summary (context, model, cal_view, print_view_type, date, 0.0, width, HEADER_HEIGHT, 
height);
 
        /* Print the border around the header. */
        print_border (context, 0.0, width, 0.0, HEADER_HEIGHT + 10, 1.0, 0.9);
@@ -3158,13 +3141,13 @@ print_month_view (GtkPrintContext *context,
 
        /* Print the 2 mini calendar-months. */
        print_month_small (
-               context, gcal,
+               context, model,
                time_add_month_with_zone (date, 1, zone),
                l, 4, l + small_month_width + week_numbers_inc, HEADER_HEIGHT + 4,
                DATE_MONTH | DATE_YEAR, 0, 0, FALSE);
 
        print_month_small (
-               context, gcal,
+               context, model,
                time_add_month_with_zone (date, -1, zone),
                SMALL_MONTH_PAD, 4, SMALL_MONTH_PAD + small_month_width + week_numbers_inc, HEADER_HEIGHT + 4,
                DATE_MONTH | DATE_YEAR, 0, 0, FALSE);
@@ -3367,18 +3350,18 @@ print_calendar_draw_page (GtkPrintOperation *operation,
                           gint page_nr,
                           PrintCalItem *pcali)
 {
-       switch (gnome_calendar_get_view (pcali->gcal)) {
-               case GNOME_CAL_DAY_VIEW:
-                       print_day_view (context, pcali->gcal, pcali->start);
+       switch (pcali->print_view_type) {
+               case E_PRINT_VIEW_DAY:
+                       print_day_view (context, pcali->cal_view, pcali->tasks_table, pcali->start);
                        break;
-               case GNOME_CAL_WORK_WEEK_VIEW:
-                       print_work_week_view (context, pcali->gcal, pcali->start);
+               case E_PRINT_VIEW_WORKWEEK:
+                       print_work_week_view (context, pcali->cal_view, pcali->start);
                        break;
-               case GNOME_CAL_WEEK_VIEW:
-                       print_week_view (context, pcali->gcal, pcali->start);
+               case E_PRINT_VIEW_WEEK:
+                       print_week_view (context, pcali->cal_view, pcali->start);
                        break;
-               case GNOME_CAL_MONTH_VIEW:
-                       print_month_view (context, pcali->gcal, pcali->start);
+               case E_PRINT_VIEW_MONTH:
+                       print_month_view (context, pcali->cal_view, pcali->print_view_type, pcali->start);
                        break;
                default:
                        g_return_if_reached ();
@@ -3386,27 +3369,25 @@ print_calendar_draw_page (GtkPrintOperation *operation,
 }
 
 void
-print_calendar (GnomeCalendar *gcal,
+print_calendar (ECalendarView *cal_view,
+               ETable *tasks_table,
+               EPrintView print_view_type,
                 GtkPrintOperationAction action,
                 time_t start)
 {
        GtkPrintOperation *operation;
        PrintCalItem pcali;
 
-       g_return_if_fail (gcal != NULL);
-       g_return_if_fail (GNOME_IS_CALENDAR (gcal));
+       g_return_if_fail (cal_view != NULL);
+       g_return_if_fail (E_IS_CALENDAR_VIEW (cal_view));
 
-       if (gnome_calendar_get_view (gcal) == GNOME_CAL_MONTH_VIEW) {
-               GnomeCalendarViewType view_type;
-               ECalendarView *calendar_view;
+       if (print_view_type == E_PRINT_VIEW_MONTH) {
                EWeekView *week_view;
                GDate date;
                gboolean multi_week_view;
                gint weeks_shown;
 
-               view_type = gnome_calendar_get_view (gcal);
-               calendar_view = gnome_calendar_get_calendar_view (gcal, view_type);
-               week_view = E_WEEK_VIEW (calendar_view);
+               week_view = E_WEEK_VIEW (cal_view);
                weeks_shown = e_week_view_get_weeks_shown (week_view);
                multi_week_view = e_week_view_get_multi_week_view (week_view);
                e_week_view_get_first_day_shown (week_view, &date);
@@ -3431,7 +3412,9 @@ print_calendar (GnomeCalendar *gcal,
                }
        }
 
-       pcali.gcal = (GnomeCalendar *) gcal;
+       pcali.cal_view = cal_view;
+       pcali.tasks_table = tasks_table;
+       pcali.print_view_type = print_view_type;
        pcali.start = start;
 
        operation = e_print_operation_new ();
diff --git a/calendar/gui/print.h b/calendar/gui/print.h
index f949b56..75b835b 100644
--- a/calendar/gui/print.h
+++ b/calendar/gui/print.h
@@ -26,17 +26,19 @@
 
 #include <e-util/e-util.h>
 
-#include "calendar/gui/gnome-cal.h"
+#include "calendar/gui/e-calendar-view.h"
 
 typedef enum {
-       PRINT_VIEW_DAY,
-       PRINT_VIEW_WEEK,
-       PRINT_VIEW_MONTH,
-       PRINT_VIEW_YEAR,
-       PRINT_VIEW_LIST
-} PrintView;
+       E_PRINT_VIEW_DAY,
+       E_PRINT_VIEW_WORKWEEK,
+       E_PRINT_VIEW_WEEK,
+       E_PRINT_VIEW_MONTH,
+       E_PRINT_VIEW_LIST
+} EPrintView;
 
-void           print_calendar                  (GnomeCalendar *gcal,
+void           print_calendar                  (ECalendarView *cal_view,
+                                                ETable *tasks_table,
+                                                EPrintView print_view_type,
                                                 GtkPrintOperationAction action,
                                                 time_t start);
 void           print_comp                      (ECalComponent *comp,
diff --git a/calendar/gui/tag-calendar.c b/calendar/gui/tag-calendar.c
index 8b3a16c..6759338 100644
--- a/calendar/gui/tag-calendar.c
+++ b/calendar/gui/tag-calendar.c
@@ -29,8 +29,842 @@
 
 #include "shell/e-shell.h"
 #include "calendar-config.h"
+#include "comp-util.h"
+#include "e-cal-data-model-subscriber.h"
 #include "tag-calendar.h"
 
+struct _ETagCalendarPrivate
+{
+       ECalendar *calendar;    /* weak-referenced */
+       ECalendarItem *calitem; /* weak-referenced */
+       ECalDataModel *data_model; /* not referenced, due to circular dependency */
+       gboolean recur_events_italic;
+
+       GHashTable *objects;    /* ObjectInfo ~> 1 (unused) */
+       GHashTable *dates;      /* julian date ~> DateInfo */
+
+       guint32 range_start_julian;
+       guint32 range_end_julian;
+};
+
+enum {
+       PROP_0,
+       PROP_CALENDAR,
+       PROP_RECUR_EVENTS_ITALIC
+};
+
+static void e_tag_calendar_cal_data_model_subscriber_init (ECalDataModelSubscriberInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (ETagCalendar, e_tag_calendar, G_TYPE_OBJECT,
+       G_IMPLEMENT_INTERFACE (E_TYPE_CAL_DATA_MODEL_SUBSCRIBER, 
e_tag_calendar_cal_data_model_subscriber_init))
+
+typedef struct {
+       gconstpointer client;
+       ECalComponentId *id;
+       gboolean is_transparent; /* neither of the two means is_single */
+       gboolean is_recurring;
+       guint32 start_julian;
+       guint32 end_julian;
+} ObjectInfo;
+
+typedef struct {
+       guint n_transparent;
+       guint n_recurring;
+       guint n_single;
+} DateInfo;
+
+static guint
+object_info_hash (gconstpointer v)
+{
+       const ObjectInfo *oinfo = v;
+
+       if (!v)
+               return 0;
+
+       return g_direct_hash (oinfo->client) ^ e_cal_component_id_hash (oinfo->id);
+}
+
+/* component-related equality, for hash tables */
+static gboolean
+object_info_equal (gconstpointer v1,
+                  gconstpointer v2)
+{
+       const ObjectInfo *oinfo1 = v1;
+       const ObjectInfo *oinfo2 = v2;
+
+       if (oinfo1 == oinfo2)
+               return TRUE;
+
+       if (!oinfo1 || !oinfo2)
+               return FALSE;
+
+       return oinfo1->client == oinfo2->client &&
+              e_cal_component_id_equal (oinfo1->id, oinfo2->id);
+}
+
+/* date-related equality, for drawing changes */
+static gboolean
+object_info_data_equal (ObjectInfo *o1,
+                       ObjectInfo *o2)
+{
+       if (o1 == o2)
+               return TRUE;
+
+       if (!o1 || !o2)
+               return FALSE;
+
+       return (o1->is_transparent ? 1: 0) == (o2->is_transparent ? 1 : 0) &&
+              (o1->start_julian ? 1: 0) == (o2->is_recurring ? 1 : 0) &&
+              (o1->start_julian == o2->start_julian) &&
+              (o1->end_julian == o2->end_julian);
+}
+
+static ObjectInfo *
+object_info_new (ECalClient *client,
+                ECalComponentId *id, /* will be consumed */
+                gboolean is_transparent,
+                gboolean is_recurring,
+                guint32 start_julian,
+                guint32 end_julian)
+{
+       ObjectInfo *oinfo;
+
+       g_return_val_if_fail (client != NULL, NULL);
+       g_return_val_if_fail (id != NULL, NULL);
+
+       oinfo = g_new0 (ObjectInfo, 1);
+       oinfo->client = client;
+       oinfo->id = id;
+       oinfo->is_transparent = is_transparent;
+       oinfo->is_recurring = is_recurring;
+       oinfo->start_julian = start_julian;
+       oinfo->end_julian = end_julian;
+
+       return oinfo;
+}
+
+static void
+object_info_free (gpointer ptr)
+{
+       ObjectInfo *oinfo = ptr;
+
+       if (oinfo) {
+               e_cal_component_free_id (oinfo->id);
+               g_free (oinfo);
+       }
+}
+
+static DateInfo *
+date_info_new (void)
+{
+       return g_new0 (DateInfo, 1);
+}
+
+static void
+date_info_free (gpointer ptr)
+{
+       DateInfo *dinfo = ptr;
+
+       if (dinfo)
+               g_free (dinfo);
+}
+
+static gboolean
+date_info_update (DateInfo *dinfo,
+                 ObjectInfo *oinfo,
+                 gboolean inc)
+{
+       gint nn = inc ? +1 : -1;
+       gboolean ui_changed = FALSE;
+
+       g_return_val_if_fail (dinfo != NULL, FALSE);
+       g_return_val_if_fail (oinfo != NULL, FALSE);
+
+       if (oinfo->is_transparent) {
+               dinfo->n_transparent += nn;
+               ui_changed = ui_changed || (inc && dinfo->n_transparent == 1) || (!inc && 
dinfo->n_transparent == 0);
+       } else if (oinfo->is_recurring) {
+               dinfo->n_recurring += nn;
+               ui_changed = ui_changed || (inc && dinfo->n_recurring == 1) || (!inc && dinfo->n_recurring == 
0);
+       } else {
+               dinfo->n_single += nn;
+               ui_changed = ui_changed || (inc && dinfo->n_single == 1) || (!inc && dinfo->n_single == 0);
+       }
+
+       return ui_changed;
+}
+
+static guint8
+date_info_get_style (DateInfo *dinfo,
+                    gboolean recur_events_italic)
+{
+       guint8 style = 0;
+
+       g_return_val_if_fail (dinfo != NULL, 0);
+
+       if (dinfo->n_transparent > 0 ||
+           (recur_events_italic && dinfo->n_recurring > 0))
+               style |= E_CALENDAR_ITEM_MARK_ITALIC;
+
+       if (dinfo->n_single > 0 ||
+           (!recur_events_italic && dinfo->n_recurring > 0))
+               style |= E_CALENDAR_ITEM_MARK_BOLD;
+
+       return style;
+}
+
+static gint32
+encode_ymd_to_julian (gint year,
+                     gint month,
+                     gint day)
+{
+       GDate dt;
+
+       g_date_clear (&dt, 1);
+       g_date_set_dmy (&dt, day, month, year);
+
+       return g_date_get_julian (&dt);
+}
+
+static guint32
+encode_timet_to_julian (time_t t,
+                       gboolean is_date,
+                       const icaltimezone *zone)
+{
+       struct icaltimetype tt;
+
+       if (!t)
+               return 0;
+
+       if (zone)
+               tt = icaltime_from_timet_with_zone (t, is_date, zone);
+       else
+               tt = icaltime_from_timet (t, is_date);
+
+       if (!icaltime_is_valid_time (tt) || icaltime_is_null_time (tt))
+               return 0;
+
+       return encode_ymd_to_julian (tt.year, tt.month, tt.day);
+}
+
+static void
+decode_julian (guint32 julian,
+              gint *year,
+              gint *month,
+              gint *day)
+{
+       GDate dt;
+
+       g_date_clear (&dt, 1);
+       g_date_set_julian (&dt, julian);
+
+       *year = g_date_get_year (&dt);
+       *month = g_date_get_month (&dt);
+       *day = g_date_get_day (&dt);
+}
+
+static void
+tag_calendar_date_cb (gpointer key,
+                     gpointer value,
+                     gpointer user_data)
+{
+       ETagCalendar *tag_calendar = user_data;
+       DateInfo *dinfo = value;
+       gint year, month, day;
+
+       decode_julian (GPOINTER_TO_UINT (key), &year, &month, &day);
+
+       e_calendar_item_mark_day (tag_calendar->priv->calitem, year, month - 1, day,
+               date_info_get_style (dinfo, tag_calendar->priv->recur_events_italic), FALSE);
+}
+
+static void
+e_tag_calendar_remark_days (ETagCalendar *tag_calendar)
+{
+       g_return_if_fail (E_IS_TAG_CALENDAR (tag_calendar));
+       g_return_if_fail (tag_calendar->priv->calitem != NULL);
+
+       e_calendar_item_clear_marks (tag_calendar->priv->calitem);
+
+       g_hash_table_foreach (tag_calendar->priv->dates, tag_calendar_date_cb, tag_calendar);
+}
+
+static time_t
+e_tag_calendar_date_to_timet (gint year,
+                             gint month,
+                             gint day,
+                             const icaltimezone *with_zone)
+{
+       GDate *date;
+       time_t tt;
+
+       date = g_date_new_dmy (day, month, year);
+       g_return_val_if_fail (date != NULL, (time_t) -1);
+
+       tt = cal_comp_gdate_to_timet (date, with_zone);
+
+       g_date_free (date);
+
+       return tt;
+}
+
+static void
+e_tag_calendar_date_range_changed_cb (ETagCalendar *tag_calendar)
+{
+       gint start_year, start_month, start_day, end_year, end_month, end_day;
+       time_t range_start, range_end;
+
+       g_return_if_fail (E_IS_TAG_CALENDAR (tag_calendar));
+
+       if (!tag_calendar->priv->data_model ||
+           !tag_calendar->priv->calitem)
+               return;
+
+       g_return_if_fail (E_IS_CALENDAR_ITEM (tag_calendar->priv->calitem));
+
+       /* This can fail on start, when the ECalendarItem wasn't updated (drawn) yet */
+       if (!e_calendar_item_get_date_range (tag_calendar->priv->calitem,
+               &start_year, &start_month, &start_day, &end_year, &end_month, &end_day))
+               return;
+
+       start_month++;
+       end_month++;
+
+       range_start = e_tag_calendar_date_to_timet (start_year, start_month, start_day, NULL);
+       range_end = e_tag_calendar_date_to_timet (end_year, end_month, end_day, NULL);
+
+       tag_calendar->priv->range_start_julian = encode_ymd_to_julian (start_year, start_month, start_day);
+       tag_calendar->priv->range_end_julian = encode_ymd_to_julian (end_year, end_month, end_day);
+
+       /* Range change causes removal of marks in the calendar */
+       e_tag_calendar_remark_days (tag_calendar);
+
+       e_cal_data_model_subscribe (tag_calendar->priv->data_model,
+               E_CAL_DATA_MODEL_SUBSCRIBER (tag_calendar),
+               range_start, range_end);
+}
+
+static gboolean
+e_tag_calendar_query_tooltip_cb (ECalendar *calendar,
+                                gint x,
+                                gint y,
+                                gboolean keayboard_mode,
+                                GtkTooltip *tooltip,
+                                ETagCalendar *tag_calendar)
+{
+       GDate date;
+       gint32 julian, events;
+       DateInfo *date_info;
+       gchar *msg;
+
+       g_return_val_if_fail (E_IS_CALENDAR (calendar), FALSE);
+       g_return_val_if_fail (E_IS_TAG_CALENDAR (tag_calendar), FALSE);
+       g_return_val_if_fail (GTK_IS_TOOLTIP (tooltip), FALSE);
+
+       if (!e_calendar_item_convert_position_to_date (calendar->calitem, x, y, &date))
+               return FALSE;
+
+       julian = encode_ymd_to_julian (g_date_get_year (&date), g_date_get_month (&date), g_date_get_day 
(&date));
+       date_info = g_hash_table_lookup (tag_calendar->priv->dates, GINT_TO_POINTER (julian));
+
+       if (!date_info)
+               return FALSE;
+
+       events = date_info->n_transparent + date_info->n_recurring + date_info->n_single;
+
+       if (events <= 0)
+               return FALSE;
+
+       msg = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE, "%d event", "%d events", events), events);
+
+       gtk_tooltip_set_text (tooltip, msg);
+
+       g_free (msg);
+
+       return TRUE;
+}
+
+static void
+get_component_julian_range (ECalClient *client,
+                           ECalComponent *comp,
+                           guint32 *start_julian,
+                           guint32 *end_julian)
+{
+       time_t instance_start = 0, instance_end = 0;
+       gboolean start_is_date = FALSE, end_is_date = FALSE;
+       const icaltimezone *zone;
+
+       g_return_if_fail (client != NULL);
+       g_return_if_fail (comp != NULL);
+
+       zone = calendar_config_get_icaltimezone ();
+
+       cal_comp_get_instance_times (client, e_cal_component_get_icalcomponent (comp),
+               zone, &instance_start, &start_is_date, &instance_end, &end_is_date, NULL);
+
+       *start_julian = encode_timet_to_julian (instance_start, start_is_date, zone);
+       *end_julian = encode_timet_to_julian (instance_end - 1, end_is_date, zone);
+}
+
+static void
+e_tag_calendar_update_by_oinfo (ETagCalendar *tag_calendar,
+                               ObjectInfo *oinfo,
+                               gboolean inc)
+{
+       ECalendarItem *calitem;
+       guint32 dt, start_julian, end_julian;
+       DateInfo *dinfo;
+
+       g_return_if_fail (tag_calendar->priv->calitem != NULL);
+
+       calitem = tag_calendar->priv->calitem;
+       g_return_if_fail (calitem != NULL);
+
+       if (!oinfo)
+               return;
+
+       start_julian = oinfo->start_julian;
+       end_julian = oinfo->end_julian;
+
+       if (inc) {
+               if (start_julian < tag_calendar->priv->range_start_julian)
+                       start_julian = tag_calendar->priv->range_start_julian;
+
+               if (end_julian > tag_calendar->priv->range_end_julian)
+                       end_julian = tag_calendar->priv->range_end_julian;
+       }
+
+       for (dt = start_julian; dt <= end_julian; dt++) {
+               dinfo = g_hash_table_lookup (tag_calendar->priv->dates, GUINT_TO_POINTER (dt));
+
+               if (!dinfo) {
+                       if (!inc)
+                               continue;
+
+                       dinfo = date_info_new ();
+                       g_hash_table_insert (tag_calendar->priv->dates, GUINT_TO_POINTER (dt), dinfo);
+               }
+
+               if (date_info_update (dinfo, oinfo, inc)) {
+                       gint year, month, day;
+                       guint8 style;
+
+                       decode_julian (dt, &year, &month, &day);
+                       style = date_info_get_style (dinfo, tag_calendar->priv->recur_events_italic);
+
+                       e_calendar_item_mark_day (calitem, year, month - 1, day, style, FALSE);
+
+                       if (!style && !inc)
+                               g_hash_table_remove (tag_calendar->priv->dates, GUINT_TO_POINTER (dt));
+               }
+       }
+}
+
+static void
+e_tag_calendar_update_component_dates (ETagCalendar *tag_calendar,
+                                      ObjectInfo *old_oinfo,
+                                      ObjectInfo *new_oinfo)
+{
+       g_return_if_fail (tag_calendar->priv->calitem != NULL);
+
+       e_tag_calendar_update_by_oinfo (tag_calendar, old_oinfo, FALSE);
+       e_tag_calendar_update_by_oinfo (tag_calendar, new_oinfo, TRUE);
+}
+
+static void
+e_tag_calendar_data_subscriber_component_added (ECalDataModelSubscriber *subscriber,
+                                               ECalClient *client,
+                                               ECalComponent *comp)
+{
+       ETagCalendar *tag_calendar;
+       ECalComponentTransparency transparency;
+       guint32 start_julian = 0, end_julian = 0;
+       ObjectInfo *oinfo;
+
+       g_return_if_fail (E_IS_TAG_CALENDAR (subscriber));
+
+       tag_calendar = E_TAG_CALENDAR (subscriber);
+
+       get_component_julian_range (client, comp, &start_julian, &end_julian);
+       if (start_julian == 0 || end_julian == 0)
+               return;
+
+       e_cal_component_get_transparency (comp, &transparency);
+
+       oinfo = object_info_new (client, e_cal_component_get_id (comp),
+               transparency == E_CAL_COMPONENT_TRANSP_TRANSPARENT,
+               e_cal_component_is_instance (comp),
+               start_julian, end_julian);
+
+       e_tag_calendar_update_component_dates (tag_calendar, NULL, oinfo);
+
+       g_hash_table_insert (tag_calendar->priv->objects, oinfo, GINT_TO_POINTER (0));
+}
+
+static void
+e_tag_calendar_data_subscriber_component_modified (ECalDataModelSubscriber *subscriber,
+                                                  ECalClient *client,
+                                                  ECalComponent *comp)
+{
+       ETagCalendar *tag_calendar;
+       ECalComponentTransparency transparency;
+       guint32 start_julian = 0, end_julian = 0;
+       gpointer orig_key, orig_value;
+       ObjectInfo *old_oinfo = NULL, *new_oinfo;
+
+       g_return_if_fail (E_IS_TAG_CALENDAR (subscriber));
+
+       tag_calendar = E_TAG_CALENDAR (subscriber);
+
+       get_component_julian_range (client, comp, &start_julian, &end_julian);
+       if (start_julian == 0 || end_julian == 0)
+               return;
+
+       e_cal_component_get_transparency (comp, &transparency);
+
+       new_oinfo = object_info_new (client, e_cal_component_get_id (comp),
+               transparency == E_CAL_COMPONENT_TRANSP_TRANSPARENT,
+               e_cal_component_is_instance (comp),
+               start_julian, end_julian);
+
+       if (!g_hash_table_lookup_extended (tag_calendar->priv->objects, new_oinfo, &orig_key, &orig_value)) {
+               object_info_free (new_oinfo);
+               return;
+       }
+
+       old_oinfo = orig_key;
+
+       if (object_info_data_equal (old_oinfo, new_oinfo)) {
+               object_info_free (new_oinfo);
+               return;
+       }
+
+       e_tag_calendar_update_component_dates (tag_calendar, old_oinfo, new_oinfo);
+
+       /* it also frees old_oinfo */
+       g_hash_table_insert (tag_calendar->priv->objects, new_oinfo, GINT_TO_POINTER (0));
+}
+
+static void
+e_tag_calendar_data_subscriber_component_removed (ECalDataModelSubscriber *subscriber,
+                                                 ECalClient *client,
+                                                 const gchar *uid,
+                                                 const gchar *rid)
+{
+       ETagCalendar *tag_calendar;
+       ECalComponentId id;
+       gpointer orig_key, orig_value;
+       ObjectInfo fake_oinfo, *old_oinfo;
+
+       g_return_if_fail (E_IS_TAG_CALENDAR (subscriber));
+
+       tag_calendar = E_TAG_CALENDAR (subscriber);
+
+       id.uid = (gchar *) uid;
+       id.rid = (gchar *) rid;
+
+       /* only these two values are used for GHashTable compare */
+       fake_oinfo.client = client;
+       fake_oinfo.id = &id;
+
+       if (!g_hash_table_lookup_extended (tag_calendar->priv->objects, &fake_oinfo, &orig_key, &orig_value))
+               return;
+
+       old_oinfo = orig_key;
+
+       e_tag_calendar_update_component_dates (tag_calendar, old_oinfo, NULL);
+
+       g_hash_table_remove (tag_calendar->priv->objects, old_oinfo);
+}
+
+static void
+e_tag_calendar_data_subscriber_freeze (ECalDataModelSubscriber *subscriber)
+{
+       /* Ignore freezes here */
+}
+
+static void
+e_tag_calendar_data_subscriber_thaw (ECalDataModelSubscriber *subscriber)
+{
+       /* Ignore freezes here */
+}
+
+static void
+e_tag_calendar_set_calendar (ETagCalendar *tag_calendar,
+                            ECalendar *calendar)
+{
+       g_return_if_fail (E_IS_TAG_CALENDAR (tag_calendar));
+       g_return_if_fail (E_IS_CALENDAR (calendar));
+       g_return_if_fail (calendar->calitem != NULL);
+       g_return_if_fail (tag_calendar->priv->calendar == NULL);
+
+       tag_calendar->priv->calendar = calendar;
+       tag_calendar->priv->calitem = calendar->calitem;
+
+       g_object_weak_ref (G_OBJECT (tag_calendar->priv->calendar),
+               (GWeakNotify) g_nullify_pointer, &tag_calendar->priv->calendar);
+       g_object_weak_ref (G_OBJECT (tag_calendar->priv->calitem),
+               (GWeakNotify) g_nullify_pointer, &tag_calendar->priv->calitem);
+}
+
+static void
+e_tag_calendar_set_property (GObject *object,
+                            guint property_id,
+                            const GValue *value,
+                            GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_CALENDAR:
+                       e_tag_calendar_set_calendar (
+                               E_TAG_CALENDAR (object),
+                               g_value_get_object (value));
+                       return;
+
+               case PROP_RECUR_EVENTS_ITALIC:
+                       e_tag_calendar_set_recur_events_italic (
+                               E_TAG_CALENDAR (object),
+                               g_value_get_boolean (value));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_tag_calendar_get_property (GObject *object,
+                            guint property_id,
+                            GValue *value,
+                            GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_CALENDAR:
+                       g_value_set_object (value,
+                               e_tag_calendar_get_calendar (E_TAG_CALENDAR (object)));
+                       return;
+
+               case PROP_RECUR_EVENTS_ITALIC:
+                       g_value_set_boolean (value,
+                               e_tag_calendar_get_recur_events_italic (E_TAG_CALENDAR (object)));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_tag_calendar_constructed (GObject *object)
+{
+       ETagCalendar *tag_calendar = E_TAG_CALENDAR (object);
+       GSettings *settings;
+
+       /* Chain up to parent's constructed() method. */
+       G_OBJECT_CLASS (e_tag_calendar_parent_class)->constructed (object);
+
+       g_return_if_fail (tag_calendar->priv->calendar != NULL);
+       g_return_if_fail (tag_calendar->priv->calitem != NULL);
+
+       g_signal_connect_swapped (tag_calendar->priv->calitem, "date-range-changed",
+               G_CALLBACK (e_tag_calendar_date_range_changed_cb), tag_calendar);
+
+       g_signal_connect (tag_calendar->priv->calendar, "query-tooltip",
+               G_CALLBACK (e_tag_calendar_query_tooltip_cb), tag_calendar);
+
+       gtk_widget_set_has_tooltip (GTK_WIDGET (tag_calendar->priv->calendar), TRUE);
+
+       settings = g_settings_new ("org.gnome.evolution.calendar");
+
+       g_settings_bind (
+               settings, "recur-events-italic",
+               tag_calendar, "recur-events-italic",
+               G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_NO_SENSITIVITY);
+
+       g_object_unref (settings);
+}
+
+static void
+e_tag_calendar_dispose (GObject *object)
+{
+       ETagCalendar *tag_calendar = E_TAG_CALENDAR (object);
+
+       if (tag_calendar->priv->calendar != NULL) {
+               g_signal_handlers_disconnect_by_func (tag_calendar->priv->calendar->calitem,
+                       G_CALLBACK (e_tag_calendar_date_range_changed_cb), tag_calendar);
+               g_signal_handlers_disconnect_by_func (tag_calendar->priv->calendar,
+                       G_CALLBACK (e_tag_calendar_query_tooltip_cb), tag_calendar);
+               g_object_weak_unref (G_OBJECT (tag_calendar->priv->calendar),
+                       (GWeakNotify) g_nullify_pointer, &tag_calendar->priv->calendar);
+               tag_calendar->priv->calendar = NULL;
+       }
+
+       if (tag_calendar->priv->calitem != NULL) {
+               g_object_weak_unref (G_OBJECT (tag_calendar->priv->calitem),
+                       (GWeakNotify) g_nullify_pointer, &tag_calendar->priv->calitem);
+               tag_calendar->priv->calitem = NULL;
+       }
+
+       if (tag_calendar->priv->data_model)
+               e_tag_calendar_unsubscribe (tag_calendar, tag_calendar->priv->data_model);
+
+       /* Chain up to parent's dispose() method. */
+       G_OBJECT_CLASS (e_tag_calendar_parent_class)->dispose (object);
+}
+
+static void
+e_tag_calendar_finalize (GObject *object)
+{
+       ETagCalendar *tag_calendar = E_TAG_CALENDAR (object);
+
+       g_warn_if_fail (tag_calendar->priv->data_model == NULL);
+
+       g_hash_table_destroy (tag_calendar->priv->objects);
+       g_hash_table_destroy (tag_calendar->priv->dates);
+
+       /* Chain up to parent's finalize() method. */
+       G_OBJECT_CLASS (e_tag_calendar_parent_class)->finalize (object);
+}
+
+static void
+e_tag_calendar_class_init (ETagCalendarClass *class)
+{
+       GObjectClass *object_class;
+
+       g_type_class_add_private (class, sizeof (ETagCalendarPrivate));
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->set_property = e_tag_calendar_set_property;
+       object_class->get_property = e_tag_calendar_get_property;
+       object_class->constructed = e_tag_calendar_constructed;
+       object_class->dispose = e_tag_calendar_dispose;
+       object_class->finalize = e_tag_calendar_finalize;
+
+       g_object_class_install_property (
+               object_class,
+               PROP_CALENDAR,
+               g_param_spec_object (
+                       "calendar",
+                       "Calendar",
+                       NULL,
+                       E_TYPE_CALENDAR,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT_ONLY));
+
+       g_object_class_install_property (
+               object_class,
+               PROP_RECUR_EVENTS_ITALIC,
+               g_param_spec_boolean (
+                       "recur-events-italic",
+                       "Recur Events Italic",
+                       NULL,
+                       FALSE,
+                       G_PARAM_READWRITE));
+}
+
+static void
+e_tag_calendar_cal_data_model_subscriber_init (ECalDataModelSubscriberInterface *iface)
+{
+       iface->component_added = e_tag_calendar_data_subscriber_component_added;
+       iface->component_modified = e_tag_calendar_data_subscriber_component_modified;
+       iface->component_removed = e_tag_calendar_data_subscriber_component_removed;
+       iface->freeze = e_tag_calendar_data_subscriber_freeze;
+       iface->thaw = e_tag_calendar_data_subscriber_thaw;
+}
+
+static void
+e_tag_calendar_init (ETagCalendar *tag_calendar)
+{
+       tag_calendar->priv = G_TYPE_INSTANCE_GET_PRIVATE (tag_calendar, E_TYPE_TAG_CALENDAR, 
ETagCalendarPrivate);
+
+       tag_calendar->priv->objects = g_hash_table_new_full (
+               object_info_hash,
+               object_info_equal,
+               object_info_free,
+               g_free);
+
+       tag_calendar->priv->dates = g_hash_table_new_full (
+               g_direct_hash,
+               g_direct_equal,
+               NULL,
+               date_info_free);
+}
+
+ETagCalendar *
+e_tag_calendar_new (ECalendar *calendar)
+{
+       return g_object_new (E_TYPE_TAG_CALENDAR, "calendar", calendar, NULL);
+}
+
+ECalendar *
+e_tag_calendar_get_calendar (ETagCalendar *tag_calendar)
+{
+       g_return_val_if_fail (E_IS_TAG_CALENDAR (tag_calendar), NULL);
+
+       return tag_calendar->priv->calendar;
+}
+
+gboolean
+e_tag_calendar_get_recur_events_italic (ETagCalendar *tag_calendar)
+{
+       g_return_val_if_fail (E_IS_TAG_CALENDAR (tag_calendar), FALSE);
+
+       return tag_calendar->priv->recur_events_italic;
+}
+
+void
+e_tag_calendar_set_recur_events_italic (ETagCalendar *tag_calendar,
+                                       gboolean recur_events_italic)
+{
+       g_return_if_fail (E_IS_TAG_CALENDAR (tag_calendar));
+
+       if ((tag_calendar->priv->recur_events_italic ? 1 : 0) == (recur_events_italic ? 1 : 0))
+               return;
+
+       tag_calendar->priv->recur_events_italic = recur_events_italic;
+
+       g_object_notify (G_OBJECT (tag_calendar), "recur-events-italic");
+
+       e_tag_calendar_remark_days (tag_calendar);
+}
+
+void
+e_tag_calendar_subscribe (ETagCalendar *tag_calendar,
+                         ECalDataModel *data_model)
+{
+       g_return_if_fail (E_IS_TAG_CALENDAR (tag_calendar));
+       g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model));
+       g_return_if_fail (tag_calendar->priv->data_model != data_model);
+
+       /* if the reference is held by the priv->data_model, then
+          an unsubscribe may cause free of the tag_calendar */
+       g_object_ref (tag_calendar);
+
+       if (tag_calendar->priv->data_model)
+               e_tag_calendar_unsubscribe (tag_calendar, tag_calendar->priv->data_model);
+
+       tag_calendar->priv->data_model = data_model;
+       e_tag_calendar_date_range_changed_cb (tag_calendar);
+
+       g_object_unref (tag_calendar);
+}
+
+void
+e_tag_calendar_unsubscribe (ETagCalendar *tag_calendar,
+                           ECalDataModel *data_model)
+{
+       g_return_if_fail (E_IS_TAG_CALENDAR (tag_calendar));
+       g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model));
+       g_return_if_fail (tag_calendar->priv->data_model == data_model);
+
+       e_cal_data_model_unsubscribe (data_model, E_CAL_DATA_MODEL_SUBSCRIBER (tag_calendar));
+       tag_calendar->priv->data_model = NULL;
+
+       /* calitem can be NULL during dispose of an ECalBaseShellContents */
+       if (tag_calendar->priv->calitem)
+               e_calendar_item_clear_marks (tag_calendar->priv->calitem);
+
+       g_hash_table_remove_all (tag_calendar->priv->objects);
+       g_hash_table_remove_all (tag_calendar->priv->dates);
+}
+
 struct calendar_tag_closure {
        ECalendarItem *calitem;
        icaltimezone *zone;
@@ -127,51 +961,6 @@ tag_calendar_cb (ECalComponent *comp,
        return TRUE;
 }
 
-/**
- * tag_calendar_by_client:
- * @ecal: Calendar widget to tag.
- * @client: A calendar client object.
- * @cancellable: A #GCancellable; can be %NULL
- *
- * Tags an #ECalendar widget with the events that occur in its current time
- * range.  The occurrences are extracted from the specified calendar @client.
- **/
-void
-tag_calendar_by_client (ECalendar *ecal,
-                        ECalClient *client,
-                        GCancellable *cancellable)
-{
-       GSettings *settings;
-       struct calendar_tag_closure *closure;
-
-       g_return_if_fail (E_IS_CALENDAR (ecal));
-       g_return_if_fail (E_IS_CAL_CLIENT (client));
-
-       /* If the ECalendar isn't visible, we just return. */
-       if (!gtk_widget_get_visible (GTK_WIDGET (ecal)))
-               return;
-
-       closure = g_new0 (struct calendar_tag_closure, 1);
-
-       if (!prepare_tag (ecal, closure, NULL, TRUE)) {
-               g_free (closure);
-               return;
-       }
-
-       settings = g_settings_new ("org.gnome.evolution.calendar");
-
-       closure->skip_transparent_events = TRUE;
-       closure->recur_events_italic =
-               g_settings_get_boolean (settings, "recur-events-italic");
-
-       g_object_unref (settings);
-
-       e_cal_client_generate_instances (
-               client, closure->start_time, closure->end_time, cancellable,
-               (ECalRecurInstanceFn) tag_calendar_cb,
-               closure, (GDestroyNotify) g_free);
-}
-
 /* Resolves TZIDs for the recurrence generator, for when the comp is not on
  * the server. We need to try to use builtin timezones first, as they may not
  * be added to the server yet. */
diff --git a/calendar/gui/tag-calendar.h b/calendar/gui/tag-calendar.h
index d1fd4f9..8b8a889 100644
--- a/calendar/gui/tag-calendar.h
+++ b/calendar/gui/tag-calendar.h
@@ -28,11 +28,66 @@
 
 #include <libecal/libecal.h>
 #include <e-util/e-util.h>
+#include <calendar/gui/e-cal-data-model.h>
 
-void tag_calendar_by_client (ECalendar *ecal, ECalClient *client, GCancellable *cancellable);
-void tag_calendar_by_comp (ECalendar *ecal, ECalComponent *comp,
-                          ECalClient *client, icaltimezone *display_zone,
-                          gboolean clear_first, gboolean comp_is_on_server,
-                          gboolean can_recur_events_italic, GCancellable *cancellable);
+/* Standard GObject macros */
+#define E_TYPE_TAG_CALENDAR \
+       (e_tag_calendar_get_type ())
+#define E_TAG_CALENDAR(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_TAG_CALENDAR, ETagCalendar))
+#define E_TAG_CALENDAR_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_TAG_CALENDAR, ETagCalendarClass))
+#define E_IS_TAG_CALENDAR(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_TAG_CALENDAR))
+#define E_IS_TAG_CALENDAR_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_TAG_CALENDAR))
+#define E_TAG_CALENDAR_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_TAG_CALENDAR, ETagCalendarClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ETagCalendar ETagCalendar;
+typedef struct _ETagCalendarClass ETagCalendarClass;
+typedef struct _ETagCalendarPrivate ETagCalendarPrivate;
+
+struct _ETagCalendar {
+       GObject parent;
+       ETagCalendarPrivate *priv;
+};
+
+struct _ETagCalendarClass {
+       GObjectClass parent_class;
+};
+
+GType          e_tag_calendar_get_type         (void);
+
+ETagCalendar * e_tag_calendar_new              (ECalendar *calendar);
+ECalendar *    e_tag_calendar_get_calendar     (ETagCalendar *tag_calendar);
+gboolean       e_tag_calendar_get_recur_events_italic
+                                               (ETagCalendar *tag_calendar);
+void           e_tag_calendar_set_recur_events_italic
+                                               (ETagCalendar *tag_calendar,
+                                                gboolean recur_events_italic);
+void           e_tag_calendar_subscribe        (ETagCalendar *tag_calendar,
+                                                ECalDataModel *data_model);
+void           e_tag_calendar_unsubscribe      (ETagCalendar *tag_calendar,
+                                                ECalDataModel *data_model);
+
+
+void           tag_calendar_by_comp            (ECalendar *ecal,
+                                                ECalComponent *comp,
+                                                ECalClient *client,
+                                                icaltimezone *display_zone,
+                                                gboolean clear_first,
+                                                gboolean comp_is_on_server,
+                                                gboolean can_recur_events_italic,
+                                                GCancellable *cancellable);
+
+G_END_DECLS
 
 #endif
diff --git a/e-util/e-alarm-selector.c b/e-util/e-alarm-selector.c
index 4003c58..30eb82f 100644
--- a/e-util/e-alarm-selector.c
+++ b/e-util/e-alarm-selector.c
@@ -41,7 +41,7 @@ alarm_selector_get_source_selected (ESourceSelector *selector,
        return e_source_alarms_get_include_me (extension);
 }
 
-static void
+static gboolean
 alarm_selector_set_source_selected (ESourceSelector *selector,
                                     ESource *source,
                                     gboolean selected)
@@ -52,16 +52,20 @@ alarm_selector_set_source_selected (ESourceSelector *selector,
        /* Make sure this source is a calendar. */
        extension_name = e_source_selector_get_extension_name (selector);
        if (!e_source_has_extension (source, extension_name))
-               return;
+               return FALSE;
 
        extension_name = E_SOURCE_EXTENSION_ALARMS;
        extension = e_source_get_extension (source, extension_name);
-       g_return_if_fail (E_IS_SOURCE_ALARMS (extension));
+       g_return_val_if_fail (E_IS_SOURCE_ALARMS (extension), FALSE);
 
        if (selected != e_source_alarms_get_include_me (extension)) {
                e_source_alarms_set_include_me (extension, selected);
                e_source_selector_queue_write (selector, source);
+
+               return TRUE;
        }
+
+       return FALSE;
 }
 
 static void
diff --git a/e-util/e-alert-sink.c b/e-util/e-alert-sink.c
index e545a7c..708984b 100644
--- a/e-util/e-alert-sink.c
+++ b/e-util/e-alert-sink.c
@@ -28,7 +28,11 @@
 #include <config.h>
 #endif
 
+#include <glib/gi18n-lib.h>
+#include <camel/camel.h>
+
 #include "e-alert-sink.h"
+#include "e-activity.h"
 
 #include "e-alert-dialog.h"
 
@@ -90,3 +94,212 @@ e_alert_sink_submit_alert (EAlertSink *alert_sink,
 
        iface->submit_alert (alert_sink, alert);
 }
+
+struct _EAlertSinkThreadJobData {
+       EActivity *activity;
+       gchar *alert_ident;
+       gchar *alert_arg_0;
+       GError *error;
+
+       EAlertSinkThreadJobFunc func;
+       gpointer user_data;
+       GDestroyNotify free_user_data;
+};
+
+static gboolean
+e_alert_sink_thread_job_done_cb (gpointer user_data)
+{
+       EAlertSinkThreadJobData *job_data = user_data;
+       EAlertSink *alert_sink;
+       GCancellable *cancellable;
+
+       g_return_val_if_fail (job_data != NULL, FALSE);
+       g_return_val_if_fail (job_data->func != NULL, FALSE);
+
+       alert_sink = e_activity_get_alert_sink (job_data->activity);
+       cancellable = e_activity_get_cancellable (job_data->activity);
+
+       camel_operation_pop_message (cancellable);
+
+       if (e_activity_handle_cancellation (job_data->activity, job_data->error)) {
+               /* do nothing */
+       } else if (job_data->error != NULL) {
+               if (job_data->alert_arg_0) {
+                       e_alert_submit (
+                               alert_sink,
+                               job_data->alert_ident,
+                               job_data->alert_arg_0, job_data->error->message, NULL);
+               } else {
+                       e_alert_submit (
+                               alert_sink,
+                               job_data->alert_ident,
+                               job_data->error->message, NULL);
+               }
+       } else {
+               e_activity_set_state (job_data->activity, E_ACTIVITY_COMPLETED);
+       }
+
+       /* clean-up */
+       g_clear_object (&job_data->activity);
+       g_clear_error (&job_data->error);
+       g_free (job_data->alert_ident);
+       g_free (job_data->alert_arg_0);
+
+       if (job_data->free_user_data)
+               job_data->free_user_data (job_data->user_data);
+
+       g_free (job_data);
+
+       return FALSE;
+}
+
+static gpointer
+e_alert_sink_thread_job (gpointer user_data)
+{
+       EAlertSinkThreadJobData *job_data = user_data;
+       GCancellable *cancellable;
+
+       g_return_val_if_fail (job_data != NULL, NULL);
+       g_return_val_if_fail (job_data->func != NULL, NULL);
+       g_return_val_if_fail (job_data->error == NULL, NULL);
+
+       cancellable = e_activity_get_cancellable (job_data->activity);
+
+       job_data->func (job_data, job_data->user_data, cancellable, &job_data->error);
+
+       g_timeout_add (1, e_alert_sink_thread_job_done_cb, job_data);
+
+       return NULL;
+}
+
+/**
+ * e_alert_sink_submit_thread_job:
+ * @alert_sink: an #EAlertSink instance
+ * @description: user-friendly description of the job, to be shown in UI
+ * @alert_ident: in case of an error, this alert identificator is used
+ *    for EAlert construction
+ * @alert_arg_0: (allow-none): in case of an error, use this string as
+ *    the first argument to the EAlert construction; the second argument
+ *    is the actual error message; can be #NULL, in which case only
+ *    the error message is passed to the EAlert construction
+ * @func: function to be run in a dedicated thread
+ * @user_data: (allow-none): custom data passed into @func; can be #NULL
+ * @free_user_data: (allow-none): function to be called on @user_data,
+ *   when the job is over; can be #NULL
+ *
+ * Runs the @func in a dedicated thread. Any error is propagated to UI.
+ * The cancellable passed into the @func is a #CamelOperation, thus
+ * the caller can overwrite progress and description message on it.
+ *
+ * Returns: (transfer full): Newly created #EActivity on success.
+ *   The caller is responsible to g_object_unref() it when done with it.
+ *
+ * Note: The @free_user_data, if set, is called in the main thread.
+ *
+ * Note: This function should be called only from the main thread.
+ *
+ * Since: 3.14
+ **/
+EActivity *
+e_alert_sink_submit_thread_job (EAlertSink *alert_sink,
+                               const gchar *description,
+                               const gchar *alert_ident,
+                               const gchar *alert_arg_0,
+                               EAlertSinkThreadJobFunc func,
+                               gpointer user_data,
+                               GDestroyNotify free_user_data)
+{
+       EActivity *activity;
+       GCancellable *cancellable;
+       EAlertSinkThreadJobData *job_data;
+       GThread *thread;
+
+       g_return_val_if_fail (E_IS_ALERT_SINK (alert_sink), NULL);
+       g_return_val_if_fail (description != NULL, NULL);
+       g_return_val_if_fail (func != NULL, NULL);
+
+       activity = e_activity_new ();
+       cancellable = camel_operation_new ();
+
+       e_activity_set_alert_sink (activity, alert_sink);
+       e_activity_set_cancellable (activity, cancellable);
+       e_activity_set_text (activity, description);
+
+       camel_operation_push_message (cancellable, "%s", description);
+
+       job_data = g_new0 (EAlertSinkThreadJobData, 1);
+       job_data->activity = g_object_ref (activity);
+       job_data->alert_ident = g_strdup (alert_ident);
+       job_data->alert_arg_0 = g_strdup (alert_arg_0);
+       job_data->error = NULL;
+       job_data->func = func;
+       job_data->user_data = user_data;
+       job_data->free_user_data = free_user_data;
+
+       thread = g_thread_try_new (G_STRFUNC, e_alert_sink_thread_job, job_data, &job_data->error);
+
+       g_object_unref (cancellable);
+
+       if (thread) {
+               g_thread_unref (thread);
+       } else {
+               g_prefix_error (&job_data->error, _("Failed to create a thread: "));
+               g_timeout_add (1, e_alert_sink_thread_job_done_cb, job_data);
+       }
+
+       return activity;
+}
+
+/**
+ * e_alert_sink_thread_job_set_alert_ident:
+ * @job_data: Thread job data, as passed to a thread
+ *    function specified at e_alert_sink_submit_thread_job()
+ * @alert_ident: A new alert identificator to use; cannot be #NULL
+ *
+ * Change an alert identificator to be used for error reporting.
+ * This can be used within a thread function at e_alert_sink_submit_thread_job(),
+ * to overwrite the default error message, in case of a need to more fine-tuned
+ * infomation to a user being available.
+ *
+ * See: e_alert_sink_thread_job_set_alert_arg_0
+ *
+ * Since: 3.14
+ **/
+void
+e_alert_sink_thread_job_set_alert_ident (EAlertSinkThreadJobData *job_data,
+                                        const gchar *alert_ident)
+{
+       g_return_if_fail (job_data != NULL);
+       g_return_if_fail (alert_ident != NULL);
+
+       if (job_data->alert_ident != alert_ident) {
+               g_free (job_data->alert_ident);
+               job_data->alert_ident = g_strdup (alert_ident);
+       }
+}
+
+/**
+ * e_alert_sink_thread_job_set_alert_arg_0:
+ * @job_data: Thread job data, as passed to a thread
+ *    function specified at e_alert_sink_submit_thread_job()
+ * @alert_arg_0: (allow-none): A new argument 0 of the alert;
+ *    can be #NULL, to unset the previously set value
+ *
+ * Change an argument 0 for an alert to be used for error reporting.
+ * This can be used within a thread function at e_alert_sink_submit_thread_job(),
+ * to overwrite the default argument 0 of the erorr message. It might be
+ * usually used with combination of e_alert_sink_thread_job_set_alert_ident().
+ *
+ * Since: 3.14
+ **/
+void
+e_alert_sink_thread_job_set_alert_arg_0 (EAlertSinkThreadJobData *job_data,
+                                        const gchar *alert_arg_0)
+{
+       g_return_if_fail (job_data != NULL);
+
+       if (job_data->alert_arg_0 != alert_arg_0) {
+               g_free (job_data->alert_arg_0);
+               job_data->alert_arg_0 = g_strdup (alert_arg_0);
+       }
+}
diff --git a/e-util/e-alert-sink.h b/e-util/e-alert-sink.h
index a85897f..4ccf29e 100644
--- a/e-util/e-alert-sink.h
+++ b/e-util/e-alert-sink.h
@@ -61,6 +61,31 @@ GType                e_alert_sink_get_type           (void) G_GNUC_CONST;
 void           e_alert_sink_submit_alert       (EAlertSink *alert_sink,
                                                 EAlert *alert);
 
+struct _EActivity;
+
+struct _EAlertSinkThreadJobData;
+typedef struct _EAlertSinkThreadJobData EAlertSinkThreadJobData;
+
+typedef void   (* EAlertSinkThreadJobFunc)     (EAlertSinkThreadJobData *job_data,
+                                                gpointer user_data,
+                                                GCancellable *cancellable,
+                                                GError **error);
+
+struct _EActivity *
+               e_alert_sink_submit_thread_job  (EAlertSink *alert_sink,
+                                                const gchar *description,
+                                                const gchar *alert_ident,
+                                                const gchar *alert_arg_0,
+                                                EAlertSinkThreadJobFunc func,
+                                                gpointer user_data,
+                                                GDestroyNotify free_user_data);
+void           e_alert_sink_thread_job_set_alert_ident
+                                               (EAlertSinkThreadJobData *job_data,
+                                                const gchar *alert_ident);
+void           e_alert_sink_thread_job_set_alert_arg_0
+                                               (EAlertSinkThreadJobData *job_data,
+                                                const gchar *alert_arg_0);
+
 G_END_DECLS
 
 #endif /* E_ALERT_SINK_H */
diff --git a/e-util/e-autocomplete-selector.c b/e-util/e-autocomplete-selector.c
index f37a1e4..df22c81 100644
--- a/e-util/e-autocomplete-selector.c
+++ b/e-util/e-autocomplete-selector.c
@@ -41,7 +41,7 @@ autocomplete_selector_get_source_selected (ESourceSelector *selector,
        return e_source_autocomplete_get_include_me (extension);
 }
 
-static void
+static gboolean
 autocomplete_selector_set_source_selected (ESourceSelector *selector,
                                            ESource *source,
                                            gboolean selected)
@@ -52,16 +52,20 @@ autocomplete_selector_set_source_selected (ESourceSelector *selector,
        /* Make sure this source is an address book. */
        extension_name = e_source_selector_get_extension_name (selector);
        if (!e_source_has_extension (source, extension_name))
-               return;
+               return FALSE;
 
        extension_name = E_SOURCE_EXTENSION_AUTOCOMPLETE;
        extension = e_source_get_extension (source, extension_name);
-       g_return_if_fail (E_IS_SOURCE_AUTOCOMPLETE (extension));
+       g_return_val_if_fail (E_IS_SOURCE_AUTOCOMPLETE (extension), FALSE);
 
        if (selected != e_source_autocomplete_get_include_me (extension)) {
                e_source_autocomplete_set_include_me (extension, selected);
                e_source_selector_queue_write (selector, source);
+
+               return TRUE;
        }
+
+       return FALSE;
 }
 
 static void
diff --git a/e-util/e-calendar-item.c b/e-util/e-calendar-item.c
index 0527dc2..3258ac9 100644
--- a/e-util/e-calendar-item.c
+++ b/e-util/e-calendar-item.c
@@ -212,6 +212,11 @@ static void        e_calendar_item_set_selection_if_emission
                                                 const GDate *start_date,
                                                 const GDate *end_date,
                                                 gboolean emission);
+static void    e_calendar_item_set_first_month_with_emit
+                                               (ECalendarItem *calitem,
+                                                gint year,
+                                                gint month,
+                                                gboolean emit_date_range_moved);
 
 /* Our arguments. */
 enum {
@@ -242,10 +247,11 @@ enum {
 };
 
 enum {
-  DATE_RANGE_CHANGED,
-  SELECTION_CHANGED,
-  SELECTION_PREVIEW_CHANGED,
-  LAST_SIGNAL
+       DATE_RANGE_CHANGED,
+       DATE_RANGE_MOVED,
+       SELECTION_CHANGED,
+       SELECTION_PREVIEW_CHANGED,
+       LAST_SIGNAL
 };
 
 static guint e_calendar_item_signals[LAST_SIGNAL] = { 0 };
@@ -540,6 +546,16 @@ e_calendar_item_class_init (ECalendarItemClass *class)
                g_cclosure_marshal_VOID__VOID,
                G_TYPE_NONE, 0);
 
+       /* Invoked when a user changes date range, by pressing month/year
+          arrows or any similar way, but not when selecting a day in the calendar. */
+       e_calendar_item_signals[DATE_RANGE_MOVED] = g_signal_new (
+               "date-range-moved",
+               G_TYPE_FROM_CLASS (object_class),
+               G_SIGNAL_RUN_FIRST,
+               0, NULL, NULL,
+               g_cclosure_marshal_VOID__VOID,
+               G_TYPE_NONE, 0);
+
        e_calendar_item_signals[SELECTION_CHANGED] = g_signal_new (
                "selection_changed",
                G_TYPE_FROM_CLASS (object_class),
@@ -1923,13 +1939,13 @@ e_calendar_item_stop_selecting (ECalendarItem *calitem,
         * after the last month, we move backwards or forwards one month.
         * The set_month () call should take care of updating the selection. */
        if (calitem->selection_end_month_offset == -1)
-               e_calendar_item_set_first_month (
+               e_calendar_item_set_first_month_with_emit (
                        calitem, calitem->year,
-                       calitem->month - 1);
+                       calitem->month - 1, FALSE);
        else if (calitem->selection_start_month_offset == calitem->rows * calitem->cols)
-               e_calendar_item_set_first_month (
+               e_calendar_item_set_first_month_with_emit (
                        calitem, calitem->year,
-                       calitem->month + 1);
+                       calitem->month + 1, FALSE);
 
        calitem->selection_changed = TRUE;
        if (calitem->selecting_axis) {
@@ -2301,13 +2317,13 @@ e_calendar_item_button_press (ECalendarItem *calitem,
        event_time = gdk_event_get_time (button_event);
 
        if (event_button == 4)
-               e_calendar_item_set_first_month (
+               e_calendar_item_set_first_month_with_emit (
                        calitem, calitem->year,
-                       calitem->month - 1);
+                       calitem->month - 1, TRUE);
        else if (event_button == 5)
-               e_calendar_item_set_first_month (
+               e_calendar_item_set_first_month_with_emit (
                        calitem, calitem->year,
-                       calitem->month + 1);
+                       calitem->month + 1, TRUE);
 
        if (!e_calendar_item_convert_position_to_day (calitem,
                                                      event_x_win,
@@ -2808,6 +2824,36 @@ e_calendar_item_get_first_month (ECalendarItem *calitem,
        *month = calitem->month;
 }
 
+gboolean
+e_calendar_item_convert_position_to_date (ECalendarItem *calitem,
+                                         gint event_x,
+                                         gint event_y,
+                                         GDate *date)
+{
+       gint month_offset = -1;
+       gint day = -1, dday, dmonth, dyear;
+       gboolean entire_week = FALSE;
+
+       g_return_val_if_fail (E_IS_CALENDAR_ITEM (calitem), FALSE);
+       g_return_val_if_fail (date != NULL, FALSE);
+
+       if (calitem->rows == 0 || calitem->cols == 0)
+               return FALSE;
+
+       if (!e_calendar_item_convert_position_to_day (calitem, event_x, event_y, FALSE, &month_offset, &day, 
&entire_week) ||
+           day < 0 || entire_week)
+               return FALSE;
+
+       dyear = calitem->year;
+       dmonth = calitem->month + month_offset;
+       e_calendar_item_normalize_date (calitem, &dyear, &dmonth);
+       dday = day;
+
+       g_date_set_dmy (date, dday, dmonth + 1, dyear);
+
+       return g_date_valid (date);
+}
+
 static void
 e_calendar_item_preserve_day_selection (ECalendarItem *calitem,
                                         gint selected_day,
@@ -2847,10 +2893,11 @@ e_calendar_item_preserve_day_selection (ECalendarItem *calitem,
 }
 
 /* This also handles values of month < 0 or > 11 by updating the year. */
-void
-e_calendar_item_set_first_month (ECalendarItem *calitem,
-                                 gint year,
-                                 gint month)
+static void
+e_calendar_item_set_first_month_with_emit (ECalendarItem *calitem,
+                                          gint year,
+                                          gint month,
+                                          gboolean emit_date_range_moved)
 {
        gint new_year, new_month, months_diff, num_months;
        gint old_days_in_selection, new_days_in_selection;
@@ -2949,6 +2996,18 @@ e_calendar_item_set_first_month (ECalendarItem *calitem,
 
        e_calendar_item_date_range_changed (calitem);
        gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (calitem));
+
+       if (emit_date_range_moved)
+               g_signal_emit (calitem, e_calendar_item_signals[DATE_RANGE_MOVED], 0);
+}
+
+/* This also handles values of month < 0 or > 11 by updating the year. */
+void
+e_calendar_item_set_first_month (ECalendarItem *calitem,
+                                gint year,
+                                gint month)
+{
+       e_calendar_item_set_first_month_with_emit (calitem, year, month, TRUE);
 }
 
 /* Get the maximum number of days selectable */
@@ -3454,6 +3513,8 @@ e_calendar_item_set_selection (ECalendarItem *calitem,
                                const GDate *start_date,
                                const GDate *end_date)
 {
+       GDate current_start_date, current_end_date;
+
        /* If the user is in the middle of a selection, we must abort it. */
        if (calitem->selecting) {
                gnome_canvas_item_ungrab (
@@ -3462,6 +3523,14 @@ e_calendar_item_set_selection (ECalendarItem *calitem,
                calitem->selecting = FALSE;
        }
 
+       if (e_calendar_item_get_selection (calitem, &current_start_date, &current_end_date)) {
+               /* No change, no need to recalculate anything */
+               if (g_date_valid (start_date) && g_date_valid (end_date) &&
+                   g_date_compare (start_date, &current_start_date) == 0 &&
+                   g_date_compare (end_date, &current_end_date) == 0)
+                       return;
+       }
+
        e_calendar_item_set_selection_if_emission (calitem,
                                                   start_date, end_date,
                                                   TRUE);
@@ -3676,7 +3745,7 @@ e_calendar_item_on_menu_item_activate (GtkWidget *menuitem,
 
        month -= month_offset;
        e_calendar_item_normalize_date (calitem, &year, &month);
-       e_calendar_item_set_first_month (calitem, year, month);
+       e_calendar_item_set_first_month_with_emit (calitem, year, month, TRUE);
 }
 
 static void
diff --git a/e-util/e-calendar-item.h b/e-util/e-calendar-item.h
index 29a6741..6d2dcc4 100644
--- a/e-util/e-calendar-item.h
+++ b/e-util/e-calendar-item.h
@@ -385,6 +385,12 @@ gint       e_calendar_item_get_week_number         (ECalendarItem *calitem,
                                                 gint year);
 void   e_calendar_item_style_updated           (GtkWidget *widget,
                                                 ECalendarItem *calitem);
+gboolean
+       e_calendar_item_convert_position_to_date
+                                               (ECalendarItem *calitem,
+                                                gint event_x,
+                                                gint event_y,
+                                                GDate *date);
 
 G_END_DECLS
 
diff --git a/e-util/e-misc-utils.c b/e-util/e-misc-utils.c
index 58978e8..046568b 100644
--- a/e-util/e-misc-utils.c
+++ b/e-util/e-misc-utils.c
@@ -49,6 +49,8 @@
 #include <camel/camel.h>
 #include <libedataserver/libedataserver.h>
 
+#include "e-alert-sink.h"
+#include "e-client-cache.h"
 #include "e-filter-option.h"
 #include "e-util-private.h"
 
@@ -2348,6 +2350,146 @@ e_util_allow_auth_prompt_and_refresh_client_finish (EClient *client,
 }
 
 /**
+ * e_util_get_open_source_job_info:
+ * @extension_name: an extension name of the source
+ * @source_display_name: an ESource's display name
+ * @description: (out) (transfer-full): a description to use
+ * @alert_ident: (out) (transfer-full): an alert ident to use on failure
+ * @alert_arg_0: (out) (transfer-full): an alert argument 0 to use on failure
+ *
+ * Populates @desription, @alert_ident and @alert_arg_0 to be used
+ * to open an #ESource with extension @extension_name. The values
+ * can be used for functions like e_alert_sink_submit_thread_job().
+ *
+ * If #TRUE is returned, then the caller is responsible to free
+ * all @desription, @alert_ident and @alert_arg_0 with g_free(),
+ * when no longer needed.
+ *
+ * Returns: #TRUE, if the values for @desription, @alert_ident and @alert_arg_0
+ *     were set for the given @extension_name; when #FALSE is returned, then
+ *     none of these out variables are changed.
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_util_get_open_source_job_info (const gchar *extension_name,
+                                const gchar *source_display_name,
+                                gchar **description,
+                                gchar **alert_ident,
+                                gchar **alert_arg_0)
+{
+       g_return_val_if_fail (extension_name != NULL, FALSE);
+       g_return_val_if_fail (source_display_name != NULL, FALSE);
+       g_return_val_if_fail (description != NULL, FALSE);
+       g_return_val_if_fail (alert_ident != NULL, FALSE);
+       g_return_val_if_fail (alert_arg_0 != NULL, FALSE);
+
+       if (g_ascii_strcasecmp (extension_name, E_SOURCE_EXTENSION_CALENDAR) == 0) {
+               *alert_ident = g_strdup ("calendar:failed-open-calendar");
+               *description = g_strdup_printf (_("Opening calendar '%s'"), source_display_name);
+       } else if (g_ascii_strcasecmp (extension_name, E_SOURCE_EXTENSION_MEMO_LIST) == 0) {
+               *alert_ident = g_strdup ("calendar:failed-open-memos");
+               *description = g_strdup_printf (_("Opening memo list '%s'"), source_display_name);
+       } else if (g_ascii_strcasecmp (extension_name, E_SOURCE_EXTENSION_TASK_LIST) == 0) {
+               *alert_ident = g_strdup ("calendar:failed-open-tasks");
+               *description = g_strdup_printf (_("Opening task list '%s'"), source_display_name);
+       } else if (g_ascii_strcasecmp (extension_name, E_SOURCE_EXTENSION_ADDRESS_BOOK) == 0) {
+               *alert_ident = g_strdup ("addressbook:load-error");
+               *description = g_strdup_printf (_("Opening address book '%s'"), source_display_name);
+       } else {
+               return FALSE;
+       }
+
+       *alert_arg_0 = g_strdup (source_display_name);
+
+       return TRUE;
+}
+
+/**
+ * e_util_propagate_open_source_job_error:
+ * @job_data: an #EAlertSinkThreadJobData instance
+ * @extension_name: what extension name had beeing opened
+ * @local_error: (allow none): a #GError as obtained in a thread job; can be NULL for success
+ * @error: (allow none): an output #GError, to which propagate the @local_error
+ *
+ * Propagates (and cosumes) the @local_error into the @error, eventually
+ * changes alert_ident for the @job_data for well-known error codes,
+ * where is available better error description.
+ *
+ * Since: 3.14
+ **/
+void
+e_util_propagate_open_source_job_error (EAlertSinkThreadJobData *job_data,
+                                       const gchar *extension_name,
+                                       GError *local_error,
+                                       GError **error)
+{
+       const gchar *alert_ident = NULL;
+
+       g_return_if_fail (job_data != NULL);
+       g_return_if_fail (extension_name != NULL);
+
+       if (!local_error)
+               return;
+
+       if (!error) {
+               g_error_free (local_error);
+               return;
+       }
+
+       if (g_error_matches (local_error, E_CLIENT_ERROR, E_CLIENT_ERROR_REPOSITORY_OFFLINE)) {
+               if (g_ascii_strcasecmp (extension_name, E_SOURCE_EXTENSION_CALENDAR) == 0) {
+                       alert_ident = "calendar:prompt-no-contents-offline-calendar";
+               } else if (g_ascii_strcasecmp (extension_name, E_SOURCE_EXTENSION_MEMO_LIST) == 0) {
+                       alert_ident = "calendar:prompt-no-contents-offline-memos";
+               } else if (g_ascii_strcasecmp (extension_name, E_SOURCE_EXTENSION_TASK_LIST) == 0) {
+                       alert_ident = "calendar:prompt-no-contents-offline-tasks";
+               } else if (g_ascii_strcasecmp (extension_name, E_SOURCE_EXTENSION_ADDRESS_BOOK) == 0) {
+               }
+       }
+
+       if (alert_ident)
+               e_alert_sink_thread_job_set_alert_ident (job_data, alert_ident);
+
+       g_propagate_error (error, local_error);
+}
+
+EClient *
+e_util_open_client_sync (EAlertSinkThreadJobData *job_data,
+                        EClientCache *client_cache,
+                        const gchar *extension_name,
+                        ESource *source,
+                        GCancellable *cancellable,
+                        GError **error)
+{
+       gchar *description = NULL, *alert_ident = NULL, *alert_arg_0 = NULL;
+       EClient *client = NULL;
+       GError *local_error = NULL;
+
+       g_warn_if_fail (e_util_get_open_source_job_info (extension_name,
+               e_source_get_display_name (source), &description, &alert_ident, &alert_arg_0));
+
+       camel_operation_push_message (cancellable, "%s", description);
+
+       client = e_client_cache_get_client_sync (client_cache, source, extension_name, cancellable, 
&local_error);
+
+       camel_operation_pop_message (cancellable);
+
+       if (!client) {
+               e_alert_sink_thread_job_set_alert_ident (job_data, alert_ident);
+               e_alert_sink_thread_job_set_alert_arg_0 (job_data, alert_arg_0);
+
+               e_util_propagate_open_source_job_error (job_data, extension_name, local_error, error);
+       }
+
+       g_free (description);
+       g_free (alert_ident);
+       g_free (alert_arg_0);
+
+       return client;
+}
+
+/**
  * e_binding_transform_color_to_string:
  * @binding: a #GBinding
  * @source_value: a #GValue of type #GDK_TYPE_COLOR
diff --git a/e-util/e-misc-utils.h b/e-util/e-misc-utils.h
index 903f26c..b480aa6 100644
--- a/e-util/e-misc-utils.h
+++ b/e-util/e-misc-utils.h
@@ -207,6 +207,25 @@ gboolean   e_util_allow_auth_prompt_and_refresh_client_finish
                                                 GAsyncResult *result,
                                                 GError **error);
 
+gboolean       e_util_get_open_source_job_info (const gchar *extension_name,
+                                                const gchar *source_display_name,
+                                                gchar **description,
+                                                gchar **alert_ident,
+                                                gchar **alert_arg_0);
+struct _EAlertSinkThreadJobData;
+void           e_util_propagate_open_source_job_error
+                                               (struct _EAlertSinkThreadJobData *job_data,
+                                                const gchar *extension_name,
+                                                GError *local_error,
+                                                GError **error);
+struct _EClientCache;
+EClient *      e_util_open_client_sync         (struct _EAlertSinkThreadJobData *job_data,
+                                                struct _EClientCache *client_cache,
+                                                const gchar *extension_name,
+                                                ESource *source,
+                                                GCancellable *cancellable,
+                                                GError **error);
+
 /* Useful GBinding transform functions */
 gboolean       e_binding_transform_color_to_string
                                                (GBinding *binding,
diff --git a/e-util/e-proxy-link-selector.c b/e-util/e-proxy-link-selector.c
index 4e1a62d..e4e025e 100644
--- a/e-util/e-proxy-link-selector.c
+++ b/e-util/e-proxy-link-selector.c
@@ -184,7 +184,7 @@ proxy_link_selector_get_source_selected (ESourceSelector *selector,
        return selected;
 }
 
-static void
+static gboolean
 proxy_link_selector_set_source_selected (ESourceSelector *selector,
                                          ESource *source,
                                          gboolean selected)
@@ -201,10 +201,10 @@ proxy_link_selector_set_source_selected (ESourceSelector *selector,
        /* Make sure this source has an Authentication extension. */
        extension_name = e_source_selector_get_extension_name (selector);
        if (!e_source_has_extension (source, extension_name))
-               return;
+               return FALSE;
 
        extension = e_source_get_extension (source, extension_name);
-       g_return_if_fail (E_IS_SOURCE_AUTHENTICATION (extension));
+       g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (extension), FALSE);
 
        if (selected)
                target_source = link_selector->priv->target_source;
@@ -218,7 +218,11 @@ proxy_link_selector_set_source_selected (ESourceSelector *selector,
                e_source_authentication_set_proxy_uid (
                        extension, new_target_uid);
                e_source_selector_queue_write (selector, source);
+
+               return TRUE;
        }
+
+       return FALSE;
 }
 
 static void
diff --git a/e-util/e-source-selector.c b/e-util/e-source-selector.c
index 2952e4b..527b576 100644
--- a/e-util/e-source-selector.c
+++ b/e-util/e-source-selector.c
@@ -76,6 +76,8 @@ enum {
        PRIMARY_SELECTION_CHANGED,
        POPUP_EVENT,
        DATA_DROPPED,
+       SOURCE_SELECTED,
+       SOURCE_UNSELECTED,
        NUM_SIGNALS
 };
 
@@ -476,6 +478,9 @@ source_selector_source_added_cb (ESourceRegistry *registry,
        source_selector_build_model (selector);
 
        source_selector_expand_to_source (selector, source);
+
+       if (e_source_selector_source_is_selected (selector, source))
+               g_signal_emit (selector, signals[SOURCE_SELECTED], 0, source);
 }
 
 static void
@@ -513,6 +518,9 @@ source_selector_source_removed_cb (ESourceRegistry *registry,
        if (!e_source_has_extension (source, extension_name))
                return;
 
+       if (e_source_selector_source_is_selected (selector, source))
+               g_signal_emit (selector, signals[SOURCE_UNSELECTED], 0, source);
+
        source_selector_build_model (selector);
 }
 
@@ -534,6 +542,9 @@ source_selector_source_enabled_cb (ESourceRegistry *registry,
        source_selector_build_model (selector);
 
        source_selector_expand_to_source (selector, source);
+
+       if (e_source_selector_source_is_selected (selector, source))
+               g_signal_emit (selector, signals[SOURCE_SELECTED], 0, source);
 }
 
 static void
@@ -551,6 +562,9 @@ source_selector_source_disabled_cb (ESourceRegistry *registry,
        if (!e_source_has_extension (source, extension_name))
                return;
 
+       if (e_source_selector_source_is_selected (selector, source))
+               g_signal_emit (selector, signals[SOURCE_UNSELECTED], 0, source);
+
        source_selector_build_model (selector);
 }
 
@@ -1254,7 +1268,7 @@ source_selector_get_source_selected (ESourceSelector *selector,
        return selected;
 }
 
-static void
+static gboolean
 source_selector_set_source_selected (ESourceSelector *selector,
                                      ESource *source,
                                      gboolean selected)
@@ -1265,17 +1279,21 @@ source_selector_set_source_selected (ESourceSelector *selector,
        extension_name = e_source_selector_get_extension_name (selector);
 
        if (!e_source_has_extension (source, extension_name))
-               return;
+               return FALSE;
 
        extension = e_source_get_extension (source, extension_name);
 
        if (!E_IS_SOURCE_SELECTABLE (extension))
-               return;
+               return FALSE;
 
        if (selected != e_source_selectable_get_selected (extension)) {
                e_source_selectable_set_selected (extension, selected);
                e_source_selector_queue_write (selector, source);
+
+               return TRUE;
        }
+
+       return FALSE;
 }
 
 static gboolean
@@ -1431,6 +1449,22 @@ e_source_selector_class_init (ESourceSelectorClass *class)
                E_TYPE_SOURCE,
                GDK_TYPE_DRAG_ACTION,
                G_TYPE_UINT);
+
+       signals[SOURCE_SELECTED] = g_signal_new (
+               "source-selected",
+               G_OBJECT_CLASS_TYPE (object_class),
+               G_SIGNAL_RUN_LAST,
+               G_STRUCT_OFFSET (ESourceSelectorClass, source_selected),
+               NULL, NULL, NULL,
+               G_TYPE_NONE, 1, E_TYPE_SOURCE);
+
+       signals[SOURCE_UNSELECTED] = g_signal_new (
+               "source-unselected",
+               G_OBJECT_CLASS_TYPE (object_class),
+               G_SIGNAL_RUN_LAST,
+               G_STRUCT_OFFSET (ESourceSelectorClass, source_unselected),
+               NULL, NULL, NULL,
+               G_TYPE_NONE, 1, E_TYPE_SOURCE);
 }
 
 static void
@@ -1833,9 +1867,10 @@ e_source_selector_select_source (ESourceSelector *selector,
        class = E_SOURCE_SELECTOR_GET_CLASS (selector);
        g_return_if_fail (class->set_source_selected != NULL);
 
-       class->set_source_selected (selector, source, TRUE);
-
-       g_signal_emit (selector, signals[SELECTION_CHANGED], 0);
+       if (class->set_source_selected (selector, source, TRUE)) {
+               g_signal_emit (selector, signals[SOURCE_SELECTED], 0, source);
+               g_signal_emit (selector, signals[SELECTION_CHANGED], 0);
+       }
 }
 
 /**
@@ -1869,9 +1904,10 @@ e_source_selector_unselect_source (ESourceSelector *selector,
        class = E_SOURCE_SELECTOR_GET_CLASS (selector);
        g_return_if_fail (class->set_source_selected != NULL);
 
-       class->set_source_selected (selector, source, FALSE);
-
-       g_signal_emit (selector, signals[SELECTION_CHANGED], 0);
+       if (class->set_source_selected (selector, source, FALSE)) {
+               g_signal_emit (selector, signals[SOURCE_UNSELECTED], 0, source);
+               g_signal_emit (selector, signals[SELECTION_CHANGED], 0);
+       }
 }
 
 /**
@@ -1891,6 +1927,7 @@ e_source_selector_select_exclusive (ESourceSelector *selector,
        GHashTable *source_index;
        GHashTableIter iter;
        gpointer key;
+       gboolean any_changed = FALSE;
 
        g_return_if_fail (E_IS_SOURCE_SELECTOR (selector));
        g_return_if_fail (E_IS_SOURCE (source));
@@ -1903,10 +1940,17 @@ e_source_selector_select_exclusive (ESourceSelector *selector,
 
        while (g_hash_table_iter_next (&iter, &key, NULL)) {
                gboolean selected = e_source_equal (key, source);
-               class->set_source_selected (selector, key, selected);
+               if (class->set_source_selected (selector, key, selected)) {
+                       any_changed = TRUE;
+                       if (selected)
+                               g_signal_emit (selector, signals[SOURCE_SELECTED], 0, key);
+                       else
+                               g_signal_emit (selector, signals[SOURCE_UNSELECTED], 0, key);
+               }
        }
 
-       g_signal_emit (selector, signals[SELECTION_CHANGED], 0);
+       if (any_changed)
+               g_signal_emit (selector, signals[SELECTION_CHANGED], 0);
 }
 
 /**
diff --git a/e-util/e-source-selector.h b/e-util/e-source-selector.h
index 61ca895..f3e9e56 100644
--- a/e-util/e-source-selector.h
+++ b/e-util/e-source-selector.h
@@ -64,7 +64,7 @@ struct _ESourceSelectorClass {
        /* Methods */
        gboolean        (*get_source_selected)  (ESourceSelector *selector,
                                                 ESource *source);
-       void            (*set_source_selected)  (ESourceSelector *selector,
+       gboolean        (*set_source_selected)  (ESourceSelector *selector,
                                                 ESource *source,
                                                 gboolean selected);
 
@@ -80,6 +80,10 @@ struct _ESourceSelectorClass {
                                                 ESource *destination,
                                                 GdkDragAction action,
                                                 guint target_info);
+       void            (*source_selected)      (ESourceSelector *selector,
+                                                ESource *source);
+       void            (*source_unselected)    (ESourceSelector *selector,
+                                                ESource *source);
 
        gpointer padding1;
        gpointer padding2;
diff --git a/e-util/e-table-one.c b/e-util/e-table-one.c
index 96082df..e2b02ea 100644
--- a/e-util/e-table-one.c
+++ b/e-util/e-table-one.c
@@ -142,8 +142,14 @@ table_one_free_value (ETableModel *etm,
 {
        ETableOne *one = E_TABLE_ONE (etm);
 
-       if (one->source)
+       if (one->source) {
                e_table_model_free_value (one->source, col, value);
+               if (one->data && one->data[col] != value && one->data[col]) {
+                       e_table_model_free_value (one->source, col, one->data[col]);
+                       one->data[col] = NULL;
+               }
+       }
+
        if (one->data)
                one->data[col] = one->source ? e_table_model_initialize_value (one->source, col) : NULL;
 }
diff --git a/e-util/e-table-sorter.c b/e-util/e-table-sorter.c
index 6087b3c..bd3cb55 100644
--- a/e-util/e-table-sorter.c
+++ b/e-util/e-table-sorter.c
@@ -169,6 +169,34 @@ table_sorter_sort (ETableSorter *table_sorter)
 
        g_qsort_with_data (table_sorter->sorted, rows, sizeof (gint), qsort_callback, &qd);
 
+       for (j = 0; j < cols; j++) {
+               ETableColumnSpecification *spec;
+               ETableCol *col;
+               GtkSortType sort_type;
+
+               if (j < group_cols)
+                       spec = e_table_sort_info_grouping_get_nth (
+                               table_sorter->sort_info,
+                               j, &sort_type);
+               else
+                       spec = e_table_sort_info_sorting_get_nth (
+                               table_sorter->sort_info,
+                               j - group_cols, &sort_type);
+
+               col = e_table_header_get_column_by_spec (
+                       table_sorter->full_header, spec);
+               if (col == NULL) {
+                       gint last = e_table_header_count (
+                               table_sorter->full_header) - 1;
+                       col = e_table_header_get_column (
+                               table_sorter->full_header, last);
+               }
+
+               for (i = 0; i < rows; i++) {
+                       e_table_model_free_value (table_sorter->source, col->spec->model_col, qd.vals[i * 
cols + j]);
+               }
+       }
+
        g_free (qd.vals);
        g_free (qd.ascending);
        g_free (qd.compare);
diff --git a/e-util/e-table-sorting-utils.c b/e-util/e-table-sorting-utils.c
index 972a3fc..d0b8f4a 100644
--- a/e-util/e-table-sorting-utils.c
+++ b/e-util/e-table-sorting-utils.c
@@ -182,6 +182,24 @@ e_table_sorting_utils_sort (ETableModel *source,
        g_qsort_with_data (
                map_table, rows, sizeof (gint), e_sort_callback, &closure);
 
+       for (j = 0; j < cols; j++) {
+               ETableColumnSpecification *spec;
+               ETableCol *col;
+
+               spec = e_table_sort_info_sorting_get_nth (
+                       sort_info, j, &closure.sort_type[j]);
+
+               col = e_table_header_get_column_by_spec (full_header, spec);
+               if (col == NULL) {
+                       gint last = e_table_header_count (full_header) - 1;
+                       col = e_table_header_get_column (full_header, last);
+               }
+
+               for (i = 0; i < rows; i++) {
+                       e_table_model_free_value (source, col->spec->compare_col, closure.vals[map_table[i] * 
cols + j]);
+               }
+       }
+
        g_free (closure.vals);
        g_free (closure.sort_type);
        g_free (closure.compare);
diff --git a/modules/cal-config-contacts/e-contacts-selector.c 
b/modules/cal-config-contacts/e-contacts-selector.c
index 7cc2421..95468b5 100644
--- a/modules/cal-config-contacts/e-contacts-selector.c
+++ b/modules/cal-config-contacts/e-contacts-selector.c
@@ -44,7 +44,7 @@ contacts_selector_get_source_selected (ESourceSelector *selector,
        return e_source_contacts_get_include_me (extension);
 }
 
-static void
+static gboolean
 contacts_selector_set_source_selected (ESourceSelector *selector,
                                        ESource *source,
                                        gboolean selected)
@@ -55,16 +55,20 @@ contacts_selector_set_source_selected (ESourceSelector *selector,
        /* Make sure this source is an address book. */
        extension_name = e_source_selector_get_extension_name (selector);
        if (!e_source_has_extension (source, extension_name))
-               return;
+               return FALSE;
 
        extension_name = E_SOURCE_EXTENSION_CONTACTS_BACKEND;
        extension = e_source_get_extension (source, extension_name);
-       g_return_if_fail (E_IS_SOURCE_CONTACTS (extension));
+       g_return_val_if_fail (E_IS_SOURCE_CONTACTS (extension), FALSE);
 
        if (selected != e_source_contacts_get_include_me (extension)) {
                e_source_contacts_set_include_me (extension, selected);
                e_source_selector_queue_write (selector, source);
+
+               return TRUE;
        }
+
+       return FALSE;
 }
 
 static void
diff --git a/modules/calendar/Makefile.am b/modules/calendar/Makefile.am
index ce02506..73ae356 100644
--- a/modules/calendar/Makefile.am
+++ b/modules/calendar/Makefile.am
@@ -13,58 +13,54 @@ module_calendar_la_CPPFLAGS = \
        $(NULL)
 
 module_calendar_la_SOURCES = \
-       evolution-module-calendar.c                     \
-       e-calendar-preferences.c                        \
-       e-calendar-preferences.h                        \
-       e-cal-attachment-handler.c                      \
-       e-cal-attachment-handler.h                      \
-       e-cal-config-hook.c                             \
-       e-cal-config-hook.h                             \
-       e-cal-event-hook.c                              \
-       e-cal-event-hook.h                              \
-       e-cal-shell-backend.c                           \
-       e-cal-shell-backend.h                           \
-       e-cal-shell-content.c                           \
-       e-cal-shell-content.h                           \
-       e-cal-shell-migrate.c                           \
-       e-cal-shell-migrate.h                           \
-       e-cal-shell-sidebar.c                           \
-       e-cal-shell-sidebar.h                           \
-       e-cal-shell-view.c                              \
-       e-cal-shell-view.h                              \
-       e-cal-shell-view-actions.c                      \
-       e-cal-shell-view-actions.h                      \
-       e-cal-shell-view-memopad.c                      \
-       e-cal-shell-view-private.c                      \
-       e-cal-shell-view-private.h                      \
-       e-cal-shell-view-taskpad.c                      \
-       e-memo-shell-backend.c                          \
-       e-memo-shell-backend.h                          \
-       e-memo-shell-content.c                          \
-       e-memo-shell-content.h                          \
-       e-memo-shell-migrate.c                          \
-       e-memo-shell-migrate.h                          \
-       e-memo-shell-sidebar.c                          \
-       e-memo-shell-sidebar.h                          \
-       e-memo-shell-view.c                             \
-       e-memo-shell-view.h                             \
-       e-memo-shell-view-actions.c                     \
-       e-memo-shell-view-actions.h                     \
-       e-memo-shell-view-private.c                     \
-       e-memo-shell-view-private.h                     \
-       e-task-shell-backend.c                          \
-       e-task-shell-backend.h                          \
-       e-task-shell-content.c                          \
-       e-task-shell-content.h                          \
-       e-task-shell-migrate.c                          \
-       e-task-shell-migrate.h                          \
-       e-task-shell-sidebar.c                          \
-       e-task-shell-sidebar.h                          \
-       e-task-shell-view.c                             \
-       e-task-shell-view.h                             \
-       e-task-shell-view-actions.c                     \
-       e-task-shell-view-actions.h                     \
-       e-task-shell-view-private.c                     \
+       evolution-module-calendar.c     \
+       e-cal-attachment-handler.c      \
+       e-cal-attachment-handler.h      \
+       e-cal-base-shell-backend.c      \
+       e-cal-base-shell-backend.h      \
+       e-cal-base-shell-content.c      \
+       e-cal-base-shell-content.h      \
+       e-cal-base-shell-sidebar.c      \
+       e-cal-base-shell-sidebar.h      \
+       e-cal-base-shell-view.c         \
+       e-cal-base-shell-view.h         \
+       e-cal-config-hook.c             \
+       e-cal-config-hook.h             \
+       e-cal-event-hook.c              \
+       e-cal-event-hook.h              \
+       e-cal-shell-backend.c           \
+       e-cal-shell-backend.h           \
+       e-cal-shell-content.c           \
+       e-cal-shell-content.h           \
+       e-cal-shell-view.c              \
+       e-cal-shell-view.h              \
+       e-cal-shell-view-actions.c      \
+       e-cal-shell-view-actions.h      \
+       e-cal-shell-view-private.c      \
+       e-cal-shell-view-private.h      \
+       e-cal-shell-view-memopad.c      \
+       e-cal-shell-view-taskpad.c      \
+       e-calendar-preferences.c        \
+       e-calendar-preferences.h        \
+       e-memo-shell-backend.c          \
+       e-memo-shell-backend.h          \
+       e-memo-shell-content.c          \
+       e-memo-shell-content.h          \
+       e-memo-shell-view.c             \
+       e-memo-shell-view.h             \
+       e-memo-shell-view-actions.c     \
+       e-memo-shell-view-actions.h     \
+       e-memo-shell-view-private.c     \
+       e-memo-shell-view-private.h     \
+       e-task-shell-backend.c          \
+       e-task-shell-backend.h          \
+       e-task-shell-content.c          \
+       e-task-shell-content.h          \
+       e-task-shell-view.c             \
+       e-task-shell-view.h             \
+       e-task-shell-view-actions.c     \
+       e-task-shell-view-actions.h     \
+       e-task-shell-view-private.c     \
        e-task-shell-view-private.h
 
 module_calendar_la_LIBADD = \
@@ -84,7 +80,6 @@ module_calendar_la_LDFLAGS = \
 
 ui_DATA = e-calendar-preferences.ui
 
-EXTRA_DIST =                   \
-       $(ui_DATA)
+EXTRA_DIST = $(ui_DATA)
 
 -include $(top_srcdir)/git.mk
diff --git a/modules/calendar/e-cal-attachment-handler.c b/modules/calendar/e-cal-attachment-handler.c
index 2aed148..81e396b 100644
--- a/modules/calendar/e-cal-attachment-handler.c
+++ b/modules/calendar/e-cal-attachment-handler.c
@@ -30,6 +30,8 @@
 #include <libecal/libecal.h>
 
 #include <shell/e-shell.h>
+#include <shell/e-shell-view.h>
+#include <shell/e-shell-window.h>
 
 #define E_CAL_ATTACHMENT_HANDLER_GET_PRIVATE(obj) \
        (G_TYPE_INSTANCE_GET_PRIVATE \
@@ -117,160 +119,106 @@ attachment_handler_get_component (EAttachment *attachment)
        return component;
 }
 
-static gboolean
-attachment_handler_update_objects (ECalClient *client,
-                                   icalcomponent *component)
-{
-       icalcomponent_kind kind;
-       icalcomponent *vcalendar;
-       gboolean success;
-       GError *error = NULL;
-
-       kind = icalcomponent_isa (component);
-
-       switch (kind) {
-               case ICAL_VTODO_COMPONENT:
-               case ICAL_VEVENT_COMPONENT:
-                       vcalendar = e_cal_util_new_top_level ();
-                       if (icalcomponent_get_method (component) == ICAL_METHOD_CANCEL)
-                               icalcomponent_set_method (vcalendar, ICAL_METHOD_CANCEL);
-                       else
-                               icalcomponent_set_method (vcalendar, ICAL_METHOD_PUBLISH);
-                       icalcomponent_add_component (
-                               vcalendar, icalcomponent_new_clone (component));
-                       break;
-
-               case ICAL_VCALENDAR_COMPONENT:
-                       vcalendar = icalcomponent_new_clone (component);
-                       if (!icalcomponent_get_first_property (vcalendar, ICAL_METHOD_PROPERTY))
-                               icalcomponent_set_method (vcalendar, ICAL_METHOD_PUBLISH);
-                       break;
-
-               default:
-                       return FALSE;
-       }
-
-       success = e_cal_client_receive_objects_sync (
-               client, vcalendar, NULL, &error);
+typedef struct {
+       EShell *shell;
+       ESource *source;
+       icalcomponent *icalcomp;
+       const gchar *extension_name;
+} ImportComponentData;
 
-       if (error != NULL) {
-               g_warning (
-                       "%s: Failed to receive objects: %s",
-                       G_STRFUNC, error->message);
-               g_error_free (error);
+static void
+import_component_data_free (gpointer ptr)
+{
+       ImportComponentData *icd = ptr;
+
+       if (icd) {
+               g_clear_object (&icd->shell);
+               g_clear_object (&icd->source);
+               if (icd->icalcomp)
+                       icalcomponent_free (icd->icalcomp);
+               g_free (icd);
        }
-
-       icalcomponent_free (vcalendar);
-
-       return success;
 }
 
 static void
-attachment_handler_import_event (GObject *source_object,
-                                 GAsyncResult *result,
-                                 gpointer user_data)
+import_component_thread (EAlertSinkThreadJobData *job_data,
+                        gpointer user_data,
+                        GCancellable *cancellable,
+                        GError **error)
 {
-       EAttachment *attachment = user_data;
-       EClient *client;
-       icalcomponent *component;
-       icalcomponent *subcomponent;
+       ImportComponentData *icd = user_data;
+       icalcomponent_kind need_kind = ICAL_ANY_COMPONENT;
+       icalcomponent *subcomp, *vcalendar;
        icalcompiter iter;
-       GError *error = NULL;
+       EClient *e_client;
+       ECalClient *client = NULL;
 
-       client = e_cal_client_connect_finish (result, &error);
+       g_return_if_fail (icd != NULL);
 
-       /* Sanity check. */
-       g_return_if_fail (
-               ((client != NULL) && (error == NULL)) ||
-               ((client == NULL) && (error != NULL)));
+       e_client = e_util_open_client_sync (job_data, e_shell_get_client_cache (icd->shell), 
icd->extension_name, icd->source, cancellable, error);
+       if (e_client)
+               client = E_CAL_CLIENT (e_client);
 
-       if (error != NULL) {
-               g_warning ("%s: %s", G_STRFUNC, error->message);
-               g_object_unref (attachment);
-               g_error_free (error);
+       if (!client)
                return;
-       }
 
-       component = attachment_handler_get_component (attachment);
-       g_return_if_fail (component != NULL);
+       if (g_str_equal (icd->extension_name, E_SOURCE_EXTENSION_CALENDAR))
+               need_kind = ICAL_VEVENT_COMPONENT;
+       else if (g_str_equal (icd->extension_name, E_SOURCE_EXTENSION_MEMO_LIST))
+               need_kind = ICAL_VJOURNAL_COMPONENT;
+       else if (g_str_equal (icd->extension_name, E_SOURCE_EXTENSION_TASK_LIST))
+               need_kind = ICAL_VTODO_COMPONENT;
+
+       if (need_kind == ICAL_ANY_COMPONENT) {
+               g_warn_if_reached ();
+               goto out;
+       }
 
-       iter = icalcomponent_begin_component (component, ICAL_ANY_COMPONENT);
+       iter = icalcomponent_begin_component (icd->icalcomp, ICAL_ANY_COMPONENT);
 
-       while ((subcomponent = icalcompiter_deref (&iter)) != NULL) {
+       while ((subcomp = icalcompiter_deref (&iter)) != NULL) {
                icalcomponent_kind kind;
 
-               kind = icalcomponent_isa (subcomponent);
+               kind = icalcomponent_isa (subcomp);
                icalcompiter_next (&iter);
 
-               if (kind == ICAL_VEVENT_COMPONENT)
+               if (kind == need_kind)
                        continue;
 
                if (kind == ICAL_VTIMEZONE_COMPONENT)
                        continue;
 
-               icalcomponent_remove_component (component, subcomponent);
-               icalcomponent_free (subcomponent);
+               icalcomponent_remove_component (icd->icalcomp, subcomp);
+               icalcomponent_free (subcomp);
        }
 
-       /* XXX Do something with the return value. */
-       attachment_handler_update_objects (E_CAL_CLIENT (client), component);
-
-       g_object_unref (attachment);
-       g_object_unref (client);
-}
-
-static void
-attachment_handler_import_todo (GObject *source_object,
-                                GAsyncResult *result,
-                                gpointer user_data)
-{
-       EAttachment *attachment = user_data;
-       EClient *client;
-       icalcomponent *component;
-       icalcomponent *subcomponent;
-       icalcompiter iter;
-       GError *error = NULL;
-
-       client = e_cal_client_connect_finish (result, &error);
-
-       /* Sanity check. */
-       g_return_if_fail (
-               ((client != NULL) && (error == NULL)) ||
-               ((client == NULL) && (error != NULL)));
-
-       if (error != NULL) {
-               g_warning ("%s: %s", G_STRFUNC, error->message);
-               g_object_unref (attachment);
-               g_error_free (error);
-               return;
-       }
-
-       component = attachment_handler_get_component (attachment);
-       g_return_if_fail (component != NULL);
-
-       iter = icalcomponent_begin_component (component, ICAL_ANY_COMPONENT);
-
-       while ((subcomponent = icalcompiter_deref (&iter)) != NULL) {
-               icalcomponent_kind kind;
-
-               kind = icalcomponent_isa (subcomponent);
-               icalcompiter_next (&iter);
-
-               if (kind == ICAL_VTODO_COMPONENT)
-                       continue;
+       switch (icalcomponent_isa (icd->icalcomp)) {
+               case ICAL_VEVENT_COMPONENT:
+               case ICAL_VJOURNAL_COMPONENT:
+               case ICAL_VTODO_COMPONENT:
+                       vcalendar = e_cal_util_new_top_level ();
+                       if (icalcomponent_get_method (icd->icalcomp) == ICAL_METHOD_CANCEL)
+                               icalcomponent_set_method (vcalendar, ICAL_METHOD_CANCEL);
+                       else
+                               icalcomponent_set_method (vcalendar, ICAL_METHOD_PUBLISH);
+                       icalcomponent_add_component (vcalendar, icalcomponent_new_clone (icd->icalcomp));
+                       break;
 
-               if (kind == ICAL_VTIMEZONE_COMPONENT)
-                       continue;
+               case ICAL_VCALENDAR_COMPONENT:
+                       vcalendar = icalcomponent_new_clone (icd->icalcomp);
+                       if (!icalcomponent_get_first_property (vcalendar, ICAL_METHOD_PROPERTY))
+                               icalcomponent_set_method (vcalendar, ICAL_METHOD_PUBLISH);
+                       break;
 
-               icalcomponent_remove_component (component, subcomponent);
-               icalcomponent_free (subcomponent);
+               default:
+                       goto out;
        }
 
-       /* XXX Do something with the return value. */
-       attachment_handler_update_objects (E_CAL_CLIENT (client), component);
+       e_cal_client_receive_objects_sync (client, vcalendar, cancellable, error);
 
-       g_object_unref (attachment);
-       g_object_unref (client);
+       icalcomponent_free (vcalendar);
+ out:
+       g_clear_object (&client);
 }
 
 static void
@@ -286,6 +234,7 @@ attachment_handler_run_dialog (GtkWindow *parent,
                                const gchar *title)
 {
        EShell *shell;
+       EShellWindow *shell_window = NULL;
        GtkWidget *dialog;
        GtkWidget *container;
        GtkWidget *widget;
@@ -309,6 +258,25 @@ attachment_handler_run_dialog (GtkWindow *parent,
                        g_return_if_reached ();
        }
 
+       if (E_IS_SHELL_WINDOW (parent)) {
+               shell_window = E_SHELL_WINDOW (parent);
+               shell = e_shell_window_get_shell (shell_window);
+       } else {
+               GList *windows, *wlink;
+
+               shell = e_shell_get_default ();
+
+               windows = gtk_application_get_windows (GTK_APPLICATION (shell));
+               for (wlink = windows; wlink; wlink = g_list_next (wlink)) {
+                       if (E_IS_SHELL_WINDOW (wlink->data)) {
+                               shell_window = E_SHELL_WINDOW (wlink->data);
+                               break;
+                       }
+               }
+       }
+
+       g_return_if_fail (shell_window != NULL);
+
        component = attachment_handler_get_component (attachment);
        g_return_if_fail (component != NULL);
 
@@ -339,7 +307,6 @@ attachment_handler_run_dialog (GtkWindow *parent,
 
        container = widget;
 
-       shell = e_shell_get_default ();
        registry = e_shell_get_registry (shell);
        widget = e_source_selector_new (registry, extension_name);
        selector = E_SOURCE_SELECTOR (widget);
@@ -355,35 +322,59 @@ attachment_handler_run_dialog (GtkWindow *parent,
                goto exit;
 
        source = e_source_selector_ref_primary_selection (selector);
-       if (source == NULL)
-               goto exit;
-
-       switch (source_type) {
-       case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
-               e_cal_client_connect (
-                       source, source_type, NULL,
-                       attachment_handler_import_event,
-                       g_object_ref (attachment));
-               break;
-       case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
-               e_cal_client_connect (
-                       source, source_type, NULL,
-                       attachment_handler_import_todo,
-                       g_object_ref (attachment));
-               break;
-       default:
-               break;
+       if (source != NULL) {
+               EShellView *shell_view;
+               EActivity *activity;
+               icalcomponent *icalcomp;
+               ImportComponentData *icd;
+               const gchar *description;
+               const gchar *alert_ident;
+
+               icalcomp = attachment_handler_get_component (attachment);
+
+               switch (source_type) {
+                       case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+                               description = _("Importing an event");
+                               alert_ident = "calendar:failed-create-event";
+                               break;
+                       case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+                               description = _("Importing a memo");
+                               alert_ident = "calendar:failed-create-memo";
+                               break;
+                       case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+                               description = _("Importing a task");
+                               alert_ident = "calendar:failed-create-task";
+                               break;
+                       default:
+                               g_warn_if_reached ();
+                               return;
+               }
+
+               shell_view = e_shell_window_get_shell_view (shell_window,
+                       e_shell_window_get_active_view (shell_window));
+
+               icd = g_new0 (ImportComponentData, 1);
+               icd->shell = g_object_ref (shell);
+               icd->source = g_object_ref (source);
+               icd->icalcomp = icalcomponent_new_clone (icalcomp);
+               icd->extension_name = extension_name;
+
+               activity = e_shell_view_submit_thread_job (shell_view, description, alert_ident,
+                       e_source_get_display_name (source), import_component_thread, icd,
+                       import_component_data_free);
+
+               g_clear_object (&activity);
+               g_object_unref (source);
        }
 
-       g_object_unref (source);
-
  exit:
        gtk_widget_destroy (dialog);
 }
 
 static void
-attachment_handler_import_to_calendar (GtkAction *action,
-                                       EAttachmentHandler *handler)
+attachment_handler_import_ical (EAttachmentHandler *handler,
+                               ECalClientSourceType source_type,
+                               const gchar *title)
 {
        EAttachment *attachment;
        EAttachmentView *view;
@@ -399,40 +390,31 @@ attachment_handler_import_to_calendar (GtkAction *action,
        g_return_if_fail (g_list_length (selected) == 1);
        attachment = E_ATTACHMENT (selected->data);
 
-       attachment_handler_run_dialog (
-               parent, attachment,
-               E_CAL_CLIENT_SOURCE_TYPE_EVENTS,
-               _("Select a Calendar"));
+       attachment_handler_run_dialog (parent, attachment, source_type, title);
 
        g_object_unref (attachment);
        g_list_free (selected);
 }
 
 static void
-attachment_handler_import_to_tasks (GtkAction *action,
-                                    EAttachmentHandler *handler)
+attachment_handler_import_to_calendar (GtkAction *action,
+                                       EAttachmentHandler *handler)
 {
-       EAttachment *attachment;
-       EAttachmentView *view;
-       GList *selected;
-       gpointer parent;
-
-       view = e_attachment_handler_get_view (handler);
-
-       parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
-       parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
-
-       selected = e_attachment_view_get_selected_attachments (view);
-       g_return_if_fail (g_list_length (selected) == 1);
-       attachment = E_ATTACHMENT (selected->data);
+       attachment_handler_import_ical (handler, E_CAL_CLIENT_SOURCE_TYPE_EVENTS, _("Select a Calendar"));
+}
 
-       attachment_handler_run_dialog (
-               parent, attachment,
-               E_CAL_CLIENT_SOURCE_TYPE_TASKS,
-               _("Select a Task List"));
+static void
+attachment_handler_import_to_memos (GtkAction *action,
+                                    EAttachmentHandler *handler)
+{
+       attachment_handler_import_ical (handler, E_CAL_CLIENT_SOURCE_TYPE_MEMOS, _("Select a Memo List"));
+}
 
-       g_object_unref (attachment);
-       g_list_free (selected);
+static void
+attachment_handler_import_to_tasks (GtkAction *action,
+                                    EAttachmentHandler *handler)
+{
+       attachment_handler_import_ical (handler, E_CAL_CLIENT_SOURCE_TYPE_TASKS, _("Select a Task List"));
 }
 
 static GtkActionEntry standard_entries[] = {
@@ -444,9 +426,16 @@ static GtkActionEntry standard_entries[] = {
          NULL,  /* XXX Add a tooltip! */
          G_CALLBACK (attachment_handler_import_to_calendar) },
 
+       { "import-to-memos",
+         "stock_mail-import",
+         N_("I_mport to Memo List"),
+         NULL,
+         NULL,  /* XXX Add a tooltip! */
+         G_CALLBACK (attachment_handler_import_to_memos) },
+
        { "import-to-tasks",
          "stock_mail-import",
-         N_("I_mport to Tasks"),
+         N_("I_mport to Task List"),
          NULL,
          NULL,  /* XXX Add a tooltip! */
          G_CALLBACK (attachment_handler_import_to_tasks) }
@@ -462,6 +451,7 @@ cal_attachment_handler_update_actions (EAttachmentView *view)
        icalcomponent *subcomponent;
        icalcomponent_kind kind;
        gboolean is_vevent = FALSE;
+       gboolean is_vjournal = FALSE;
        gboolean is_vtodo = FALSE;
 
        selected = e_attachment_view_get_selected_attachments (view);
@@ -482,12 +472,16 @@ cal_attachment_handler_update_actions (EAttachmentView *view)
 
        kind = icalcomponent_isa (subcomponent);
        is_vevent = (kind == ICAL_VEVENT_COMPONENT);
+       is_vjournal = (kind == ICAL_VJOURNAL_COMPONENT);
        is_vtodo = (kind == ICAL_VTODO_COMPONENT);
 
 exit:
        action = e_attachment_view_get_action (view, "import-to-calendar");
        gtk_action_set_visible (action, is_vevent);
 
+       action = e_attachment_view_get_action (view, "import-to-memos");
+       gtk_action_set_visible (action, is_vjournal);
+
        action = e_attachment_view_get_action (view, "import-to-tasks");
        gtk_action_set_visible (action, is_vtodo);
 
diff --git a/modules/calendar/e-cal-base-shell-backend.c b/modules/calendar/e-cal-base-shell-backend.c
new file mode 100644
index 0000000..43f48d0
--- /dev/null
+++ b/modules/calendar/e-cal-base-shell-backend.c
@@ -0,0 +1,598 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Milan Crha <mcrha redhat com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+
+#include <libedataserver/libedataserver.h>
+
+#include <calendar/gui/dialogs/comp-editor.h>
+#include <calendar/gui/dialogs/event-editor.h>
+#include <calendar/gui/dialogs/memo-editor.h>
+#include <calendar/gui/dialogs/task-editor.h>
+#include <calendar/gui/comp-util.h>
+
+#include "shell/e-shell-backend.h"
+#include "shell/e-shell-view.h"
+#include "shell/e-shell-window.h"
+
+#include "e-cal-base-shell-backend.h"
+
+#define E_CAL_BASE_SHELL_BACKEND_GET_PRIVATE(obj) \
+       (G_TYPE_INSTANCE_GET_PRIVATE \
+       ((obj), E_TYPE_CAL_BASE_SHELL_BACKEND, ECalBaseShellBackendPrivate))
+
+struct _ECalBaseShellBackendPrivate {
+       gint placeholder;
+};
+
+G_DEFINE_ABSTRACT_TYPE (ECalBaseShellBackend, e_cal_base_shell_backend, E_TYPE_SHELL_BACKEND)
+
+static gboolean
+cal_base_shell_backend_handle_uri_cb (EShellBackend *shell_backend,
+                                     const gchar *uri)
+{
+       ECalBaseShellBackendClass *klass;
+
+       g_return_val_if_fail (E_IS_CAL_BASE_SHELL_BACKEND (shell_backend), FALSE);
+       g_return_val_if_fail (uri != NULL, FALSE);
+
+       klass = E_CAL_BASE_SHELL_BACKEND_GET_CLASS (shell_backend);
+       g_return_val_if_fail (klass != NULL, FALSE);
+
+       return klass->handle_uri && klass->handle_uri (shell_backend, uri);
+}
+
+static void
+cal_base_shell_backend_window_added_cb (ECalBaseShellBackend *cal_base_shell_backend,
+                                       GtkWindow *window)
+{
+       ECalBaseShellBackendClass *cal_base_shell_backend_class;
+       const gchar *backend_name;
+
+       if (!E_IS_SHELL_WINDOW (window))
+               return;
+
+       cal_base_shell_backend_class = E_CAL_BASE_SHELL_BACKEND_GET_CLASS (cal_base_shell_backend);
+       g_return_if_fail (cal_base_shell_backend_class != NULL);
+
+       backend_name = E_SHELL_BACKEND_GET_CLASS (cal_base_shell_backend)->name;
+
+       if (cal_base_shell_backend_class->new_item_entries &&
+           cal_base_shell_backend_class->new_item_n_entries > 0)
+               e_shell_window_register_new_item_actions (
+                       E_SHELL_WINDOW (window), backend_name,
+                       cal_base_shell_backend_class->new_item_entries,
+                       cal_base_shell_backend_class->new_item_n_entries);
+
+       if (cal_base_shell_backend_class->source_entries &&
+           cal_base_shell_backend_class->source_n_entries > 0)
+               e_shell_window_register_new_source_actions (
+                       E_SHELL_WINDOW (window), backend_name,
+                       cal_base_shell_backend_class->source_entries,
+                       cal_base_shell_backend_class->source_n_entries);
+}
+
+static void
+cal_base_shell_backend_constructed (GObject *object)
+{
+       EShell *shell;
+       EShellBackend *shell_backend;
+
+       /* Chain up to parent's constructed() method. */
+       G_OBJECT_CLASS (e_cal_base_shell_backend_parent_class)->constructed (object);
+
+       shell_backend = E_SHELL_BACKEND (object);
+       shell = e_shell_backend_get_shell (shell_backend);
+
+       g_signal_connect_swapped (
+               shell, "handle-uri",
+               G_CALLBACK (cal_base_shell_backend_handle_uri_cb),
+               shell_backend);
+
+       g_signal_connect_swapped (
+               shell, "window-added",
+               G_CALLBACK (cal_base_shell_backend_window_added_cb),
+               shell_backend);
+}
+
+static void
+e_cal_base_shell_backend_class_init (ECalBaseShellBackendClass *class)
+{
+       GObjectClass *object_class;
+
+       g_type_class_add_private (class, sizeof (ECalBaseShellBackendPrivate));
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->constructed = cal_base_shell_backend_constructed;
+
+       class->new_item_entries = NULL;
+       class->new_item_n_entries = 0;
+       class->source_entries = NULL;
+       class->source_n_entries = 0;
+       class->handle_uri = NULL;
+
+       /* Register relevant ESource extensions. */
+       g_type_ensure (E_TYPE_SOURCE_CALENDAR);
+}
+
+static void
+e_cal_base_shell_backend_init (ECalBaseShellBackend *cal_base_shell_backend)
+{
+       icalarray *builtin_timezones;
+       gint ii;
+
+       cal_base_shell_backend->priv = E_CAL_BASE_SHELL_BACKEND_GET_PRIVATE (cal_base_shell_backend);
+
+       /* XXX Pre-load all built-in timezones in libical.
+        *
+        *     Built-in time zones in libical 0.43 are loaded on demand,
+        *     but not in a thread-safe manner, resulting in a race when
+        *     multiple threads call icaltimezone_load_builtin_timezone()
+        *     on the same time zone.  Until built-in time zone loading
+        *     in libical is made thread-safe, work around the issue by
+        *     loading all built-in time zones now, so libical's internal
+        *     time zone array will be fully populated before any threads
+        *     are spawned.
+        */
+       builtin_timezones = icaltimezone_get_builtin_timezones ();
+       for (ii = 0; ii < builtin_timezones->num_elements; ii++) {
+               icaltimezone *zone;
+
+               zone = icalarray_element_at (builtin_timezones, ii);
+
+               /* We don't care about the component right now,
+                * we just need some function that will trigger
+                * icaltimezone_load_builtin_timezone(). */
+               icaltimezone_get_component (zone);
+       }
+}
+
+void
+e_cal_base_shell_backend_util_new_source (EShellWindow *shell_window,
+                                         ECalClientSourceType source_type)
+{
+       EShell *shell;
+       ESourceRegistry *registry;
+       GtkWidget *config;
+       GtkWidget *dialog;
+       GtkWindow *window;
+       const gchar *icon_name;
+       const gchar *title;
+
+       g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
+
+       switch (source_type) {
+               case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+                       title = _("New Calendar");
+                       icon_name = "x-office-calendar";
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+                       title = _("New Memo List");
+                       icon_name = "stock_notes";
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+                       title = _("New Task List");
+                       icon_name = "stock_todo";
+                       break;
+               default:
+                       g_warn_if_reached ();
+                       return;
+       }
+
+       shell = e_shell_window_get_shell (shell_window);
+
+       registry = e_shell_get_registry (shell);
+       config = e_cal_source_config_new (registry, NULL, source_type);
+
+       dialog = e_source_config_dialog_new (E_SOURCE_CONFIG (config));
+       window = GTK_WINDOW (dialog);
+
+       gtk_window_set_transient_for (window, GTK_WINDOW (shell_window));
+       gtk_window_set_icon_name (window, icon_name);
+       gtk_window_set_title (window, title);
+
+       gtk_widget_show (dialog);
+}
+
+typedef struct {
+       EShellBackend *shell_backend;
+       ECalClientSourceType source_type;
+       gchar *source_uid;
+       gchar *comp_uid;
+       gchar *comp_rid;
+
+       ECalClient *cal_client;
+       icalcomponent *existing_icalcomp;
+} HandleUriData;
+
+static void
+handle_uri_data_free (gpointer ptr)
+{
+       HandleUriData *hud = ptr;
+
+       if (!hud)
+               return;
+
+       if (hud->cal_client) {
+               CompEditor *editor;
+
+               editor = comp_editor_find_instance (hud->comp_uid);
+
+               if (!editor) {
+                       EShell *shell;
+                       ESourceRegistry *registry;
+                       ECalComponent *comp;
+                       CompEditorFlags flags = 0;
+                       icalcomponent *icalcomp = hud->existing_icalcomp;
+                       icalproperty *icalprop;
+
+                       shell = e_shell_backend_get_shell (hud->shell_backend);
+                       registry = e_shell_get_registry (shell);
+
+                       comp = e_cal_component_new ();
+                       if (!e_cal_component_set_icalcomponent (comp, hud->existing_icalcomp)) {
+                               g_warning ("%s: Failed to set icalcomp to comp", G_STRFUNC);
+                       } else {
+                               /* The 'comp' consumed the icalcomp */
+                               hud->existing_icalcomp = NULL;
+                       }
+
+                       switch (hud->source_type) {
+                               case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+                                       icalprop = icalcomp ? icalcomponent_get_first_property (
+                                               icalcomp, ICAL_ATTENDEE_PROPERTY) : NULL;
+                                       if (icalprop != NULL)
+                                               flags |= COMP_EDITOR_MEETING;
+
+                                       if (itip_organizer_is_user (registry, comp, hud->cal_client))
+                                               flags |= COMP_EDITOR_USER_ORG;
+
+                                       if (itip_sentby_is_user (registry, comp, hud->cal_client))
+                                               flags |= COMP_EDITOR_USER_ORG;
+
+                                       if (!e_cal_component_has_attendees (comp))
+                                               flags |= COMP_EDITOR_USER_ORG;
+
+                                       editor = event_editor_new (hud->cal_client, shell, flags);
+                                       break;
+                               case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+                                       if (e_cal_component_has_organizer (comp))
+                                               flags |= COMP_EDITOR_IS_SHARED;
+
+                                       if (itip_organizer_is_user (registry, comp, hud->cal_client))
+                                               flags |= COMP_EDITOR_USER_ORG;
+
+                                       editor = memo_editor_new (hud->cal_client, shell, flags);
+                                       break;
+                               case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+                                       icalprop = icalcomp ? icalcomponent_get_first_property (icalcomp, 
ICAL_ATTENDEE_PROPERTY) : NULL;
+                                       if (icalprop != NULL)
+                                               flags |= COMP_EDITOR_IS_ASSIGNED;
+
+                                       if (itip_organizer_is_user (registry, comp, hud->cal_client))
+                                               flags |= COMP_EDITOR_USER_ORG;
+
+                                       if (!e_cal_component_has_attendees (comp))
+                                               flags |= COMP_EDITOR_USER_ORG;
+
+                                       editor = task_editor_new (hud->cal_client, shell, flags);
+                                       break;
+                               default:
+                                       g_warn_if_reached ();
+                                       break;
+                       }
+
+                       if (editor)
+                               comp_editor_edit_comp (editor, comp);
+
+                       g_object_unref (comp);
+               }
+
+               if (editor)
+                       gtk_window_present (GTK_WINDOW (editor));
+       }
+
+       if (hud->existing_icalcomp)
+               icalcomponent_free (hud->existing_icalcomp);
+
+       g_clear_object (&hud->cal_client);
+       g_clear_object (&hud->shell_backend);
+       g_free (hud->source_uid);
+       g_free (hud->comp_uid);
+       g_free (hud->comp_rid);
+       g_free (hud);
+}
+
+static void
+cal_base_shell_backend_handle_uri_thread (EAlertSinkThreadJobData *job_data,
+                                         gpointer user_data,
+                                         GCancellable *cancellable,
+                                         GError **error)
+{
+       HandleUriData *hud = user_data;
+       EShell *shell;
+       ESourceRegistry *registry;
+       ESource *source;
+       const gchar *extension_name;
+       GError *local_error = NULL;
+
+       g_return_if_fail (hud != NULL);
+
+       switch (hud->source_type) {
+               case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+                       extension_name = E_SOURCE_EXTENSION_CALENDAR;
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+                       extension_name = E_SOURCE_EXTENSION_MEMO_LIST;
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+                       extension_name = E_SOURCE_EXTENSION_TASK_LIST;
+                       break;
+               default:
+                       g_warn_if_reached ();
+                       return;
+       }
+
+       shell = e_shell_backend_get_shell (hud->shell_backend);
+       registry = e_shell_get_registry (shell);
+       source = e_source_registry_ref_source (registry, hud->source_uid);
+       if (!source) {
+               g_set_error (&local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+                       _("Source with UID '%s' not found"), hud->source_uid);
+       } else {
+               EClientCache *client_cache;
+               EClient *client;
+
+               client_cache = e_shell_get_client_cache (shell);
+
+               client = e_client_cache_get_client_sync (client_cache, source, extension_name, cancellable, 
&local_error);
+               if (client) {
+                       hud->cal_client = E_CAL_CLIENT (client);
+
+                       if (!e_cal_client_get_object_sync (hud->cal_client, hud->comp_uid,
+                               hud->comp_rid, &hud->existing_icalcomp, cancellable, &local_error))
+                               g_clear_object (&hud->cal_client);
+               }
+       }
+
+       e_util_propagate_open_source_job_error (job_data, extension_name, local_error, error);
+
+       g_clear_object (&source);
+}
+
+static void
+populate_g_date (GDate *date,
+                 time_t utc_time,
+                 icaltimezone *zone)
+{
+       struct icaltimetype icaltm;
+
+       g_return_if_fail (date != NULL);
+
+       if ((gint) utc_time == -1)
+               return;
+
+       if (zone)
+               icaltm = icaltime_from_timet_with_zone (utc_time, FALSE, zone);
+       else
+               icaltm = icaltime_from_timet (utc_time, FALSE);
+
+       if (icaltime_is_null_time (icaltm) ||
+           !icaltime_is_valid_time (icaltm))
+               return;
+
+       g_date_set_dmy (date, icaltm.day, icaltm.month, icaltm.year);
+}
+
+gboolean
+e_cal_base_shell_backend_util_handle_uri (EShellBackend *shell_backend,
+                                         ECalClientSourceType source_type,
+                                         const gchar *uri,
+                                         ECalBaseShellBackendHandleStartEndDatesFunc handle_start_end_dates)
+{
+       EShell *shell;
+       EShellWindow *shell_window;
+       SoupURI *soup_uri;
+       const gchar *cp;
+       gchar *source_uid = NULL;
+       gchar *comp_uid = NULL;
+       gchar *comp_rid = NULL;
+       gboolean handled = FALSE;
+       GSettings *settings;
+       GList *windows, *link;
+       GDate start_date;
+       GDate end_date;
+       icaltimezone *zone = NULL;
+       const gchar *extension_name;
+
+       g_return_val_if_fail (E_IS_CAL_BASE_SHELL_BACKEND (shell_backend), FALSE);
+       g_return_val_if_fail (uri != NULL, FALSE);
+
+       switch (source_type) {
+               case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+                       extension_name = E_SOURCE_EXTENSION_CALENDAR;
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+                       extension_name = E_SOURCE_EXTENSION_MEMO_LIST;
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+                       extension_name = E_SOURCE_EXTENSION_TASK_LIST;
+                       break;
+               default:
+                       g_warn_if_reached ();
+                       return FALSE;
+       }
+
+       shell = e_shell_backend_get_shell (shell_backend);
+
+       soup_uri = soup_uri_new (uri);
+
+       if (soup_uri == NULL)
+               return FALSE;
+
+       g_date_clear (&start_date, 1);
+       g_date_clear (&end_date, 1);
+
+       settings = g_settings_new ("org.gnome.evolution.calendar");
+
+       if (g_settings_get_boolean (settings, "use-system-timezone"))
+               zone = e_cal_util_get_system_timezone ();
+       else {
+               gchar *location;
+
+               location = g_settings_get_string (settings, "timezone");
+
+               if (location != NULL) {
+                       zone = icaltimezone_get_builtin_timezone (location);
+                       g_free (location);
+               }
+       }
+
+       if (zone == NULL)
+               zone = icaltimezone_get_utc_timezone ();
+
+       g_object_unref (settings);
+
+       cp = soup_uri_get_query (soup_uri);
+       if (cp == NULL)
+               goto exit;
+
+       while (*cp != '\0') {
+               gchar *header;
+               gchar *content;
+               gsize header_len;
+               gsize content_len;
+
+               header_len = strcspn (cp, "=&");
+
+               /* If it's malformed, give up. */
+               if (cp[header_len] != '=')
+                       break;
+
+               header = (gchar *) cp;
+               header[header_len] = '\0';
+               cp += header_len + 1;
+
+               content_len = strcspn (cp, "&");
+
+               content = g_strndup (cp, content_len);
+               if (g_ascii_strcasecmp (header, "startdate") == 0)
+                       populate_g_date (&start_date, time_from_isodate (content), zone);
+               else if (g_ascii_strcasecmp (header, "enddate") == 0)
+                       populate_g_date (&end_date, time_from_isodate (content) - 1, zone);
+               else if (g_ascii_strcasecmp (header, "source-uid") == 0)
+                       source_uid = g_strdup (content);
+               else if (g_ascii_strcasecmp (header, "comp-uid") == 0)
+                       comp_uid = g_strdup (content);
+               else if (g_ascii_strcasecmp (header, "comp-rid") == 0)
+                       comp_rid = g_strdup (content);
+               g_free (content);
+
+               cp += content_len;
+               if (*cp == '&') {
+                       cp++;
+                       if (strcmp (cp, "amp;") == 0)
+                               cp += 4;
+               }
+       }
+
+       /* This is primarily for launching Evolution
+        * from the calendar in the clock applet. */
+       if (g_date_valid (&start_date) && handle_start_end_dates) {
+               if (g_date_valid (&end_date) && g_date_compare (&start_date, &end_date) > 0)
+                       end_date = start_date;
+
+               handle_start_end_dates (shell_backend, &start_date, &end_date);
+               handled = TRUE;
+               goto exit;
+       }
+
+       if (source_uid == NULL || comp_uid == NULL)
+               goto exit;
+
+       /* URI is valid, so consider it handled.  Whether
+        * we successfully open it is another matter... */
+       handled = TRUE;
+
+       shell_window = NULL;
+       windows = gtk_application_get_windows (GTK_APPLICATION (shell));
+       for (link = windows; link; link = g_list_next (link)) {
+               GtkWindow *window = link->data;
+
+               if (E_IS_SHELL_WINDOW (window)) {
+                       shell_window = E_SHELL_WINDOW (window);
+                       break;
+               }
+       }
+
+       if (shell_window) {
+               HandleUriData *hud;
+               ESourceRegistry *registry;
+               ESource *source;
+               EShellView *shell_view;
+               EActivity *activity;
+               gchar *description = NULL, *alert_ident = NULL, *alert_arg_0 = NULL;
+               const gchar *source_display_name = ""; /* not NULL intentionally */
+
+               hud = g_new0 (HandleUriData, 1);
+               hud->shell_backend = g_object_ref (shell_backend);
+               hud->source_type = source_type;
+               hud->source_uid = g_strdup (source_uid);
+               hud->comp_uid = g_strdup (comp_uid);
+               hud->comp_rid = g_strdup (comp_rid);
+               hud->cal_client = NULL;
+               hud->existing_icalcomp = NULL;
+
+               registry = e_shell_get_registry (shell);
+               source = e_source_registry_ref_source (registry, source_uid);
+               if (source)
+                       source_display_name = e_source_get_display_name (source);
+
+               shell_view = e_shell_window_get_shell_view (shell_window,
+                       e_shell_window_get_active_view (shell_window));
+
+               g_warn_if_fail (e_util_get_open_source_job_info (extension_name,
+                       source_display_name, &description, &alert_ident, &alert_arg_0));
+
+               activity = e_shell_view_submit_thread_job (
+                       shell_view, description, alert_ident, alert_arg_0,
+                       cal_base_shell_backend_handle_uri_thread, hud, handle_uri_data_free);
+
+               g_clear_object (&activity);
+               g_clear_object (&source);
+               g_free (description);
+               g_free (alert_ident);
+               g_free (alert_arg_0);
+       } else {
+               g_warn_if_reached ();
+       }
+
+ exit:
+       g_free (source_uid);
+       g_free (comp_uid);
+       g_free (comp_rid);
+
+       soup_uri_free (soup_uri);
+
+       return handled;
+}
diff --git a/modules/calendar/e-cal-base-shell-backend.h b/modules/calendar/e-cal-base-shell-backend.h
new file mode 100644
index 0000000..51bc09c
--- /dev/null
+++ b/modules/calendar/e-cal-base-shell-backend.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Milan Crha <mcrha redhat com>
+ */
+
+#ifndef E_CAL_BASE_SHELL_BACKEND_H
+#define E_CAL_BASE_SHELL_BACKEND_H
+
+#include <shell/e-shell-backend.h>
+#include <shell/e-shell-window.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CAL_BASE_SHELL_BACKEND \
+       (e_cal_base_shell_backend_get_type ())
+#define E_CAL_BASE_SHELL_BACKEND(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_CAL_BASE_SHELL_BACKEND, ECalBaseShellBackend))
+#define E_CAL_BASE_SHELL_BACKEND_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_CAL_BASE_SHELL_BACKEND, ECalBaseShellBackendClass))
+#define E_IS_CAL_BASE_SHELL_BACKEND(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_CAL_BASE_SHELL_BACKEND))
+#define E_IS_CAL_BASE_SHELL_BACKEND_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_CAL_BASE_SHELL_BACKEND))
+#define E_CAL_BASE_SHELL_BACKEND_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_CAL_BASE_SHELL_BACKEND, ECalBaseShellBackendClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ECalBaseShellBackend ECalBaseShellBackend;
+typedef struct _ECalBaseShellBackendClass ECalBaseShellBackendClass;
+typedef struct _ECalBaseShellBackendPrivate ECalBaseShellBackendPrivate;
+
+struct _ECalBaseShellBackend {
+       EShellBackend parent;
+       ECalBaseShellBackendPrivate *priv;
+};
+
+struct _ECalBaseShellBackendClass {
+       EShellBackendClass parent_class;
+
+       GtkActionEntry *new_item_entries;
+       guint new_item_n_entries;
+
+       GtkActionEntry *source_entries;
+       guint source_n_entries;
+
+       gboolean (* handle_uri) (EShellBackend *shell_backend,
+                                const gchar *uri);
+};
+
+GType          e_cal_base_shell_backend_get_type       (void);
+
+void           e_cal_base_shell_backend_util_new_source
+                                                       (EShellWindow *shell_window,
+                                                        ECalClientSourceType source_type);
+
+typedef void (* ECalBaseShellBackendHandleStartEndDatesFunc)
+                                                       (EShellBackend *shell_backend,
+                                                        const GDate *start_date,
+                                                        const GDate *end_date);
+gboolean       e_cal_base_shell_backend_util_handle_uri
+                                                       (EShellBackend *shell_backend,
+                                                        ECalClientSourceType source_type,
+                                                        const gchar *uri,
+                                                        ECalBaseShellBackendHandleStartEndDatesFunc 
handle_start_end_dates);
+
+G_END_DECLS
+
+#endif /* E_CAL_BASE_SHELL_BACKEND_H */
diff --git a/modules/calendar/e-cal-base-shell-content.c b/modules/calendar/e-cal-base-shell-content.c
new file mode 100644
index 0000000..e1d0129
--- /dev/null
+++ b/modules/calendar/e-cal-base-shell-content.c
@@ -0,0 +1,378 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Milan Crha <mcrha redhat com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <glib/gi18n.h>
+
+#include "e-cal-base-shell-sidebar.h"
+#include "e-cal-base-shell-view.h"
+#include "e-cal-base-shell-content.h"
+
+struct _ECalBaseShellContentPrivate {
+       ECalDataModel *data_model;
+       ECalModel *model;
+       gulong object_created_id;
+};
+
+enum {
+       PROP_0,
+       PROP_DATA_MODEL,
+       PROP_MODEL
+};
+
+G_DEFINE_ABSTRACT_TYPE (ECalBaseShellContent, e_cal_base_shell_content, E_TYPE_SHELL_CONTENT)
+
+static void
+cal_base_shell_content_client_opened_cb (ECalBaseShellSidebar *cal_base_shell_sidebar,
+                                        ECalClient *client,
+                                        ECalBaseShellContent *shell_content)
+{
+       g_return_if_fail (E_IS_CAL_CLIENT (client));
+       g_return_if_fail (E_IS_CAL_BASE_SHELL_CONTENT (shell_content));
+
+       e_cal_data_model_add_client (shell_content->priv->data_model, client);
+}
+
+static void
+cal_base_shell_content_client_closed_cb (ECalBaseShellSidebar *cal_base_shell_sidebar,
+                                        ESource *source,
+                                        ECalBaseShellContent *shell_content)
+{
+       g_return_if_fail (E_IS_SOURCE (source));
+       g_return_if_fail (E_IS_CAL_BASE_SHELL_CONTENT (shell_content));
+
+       e_cal_data_model_remove_client (shell_content->priv->data_model, e_source_get_uid (source));
+}
+
+static void
+cal_base_shell_content_primary_selection_changed_cb (ESourceSelector *selector,
+                                                    GParamSpec *param,
+                                                    ECalBaseShellContent *shell_content)
+{
+       ESource *source;
+
+       g_return_if_fail (E_IS_SOURCE_SELECTOR (selector));
+       g_return_if_fail (E_IS_CAL_BASE_SHELL_CONTENT (shell_content));
+
+       source = e_source_selector_ref_primary_selection (selector);
+       if (source)
+               e_cal_model_set_default_source_uid (shell_content->priv->model, e_source_get_uid (source));
+
+       g_clear_object (&source);
+}
+
+static void
+cal_base_shell_content_object_created_cb (ECalBaseShellContent *cal_base_shell_content,
+                                         ECalClient *client,
+                                         ECalModel *model)
+{
+       EShellView *shell_view;
+       EShellSidebar *shell_sidebar;
+       ESourceSelector *selector;
+
+       g_return_if_fail (E_IS_CAL_BASE_SHELL_CONTENT (cal_base_shell_content));
+       g_return_if_fail (E_IS_CAL_CLIENT (client));
+
+       shell_view = e_shell_content_get_shell_view (E_SHELL_CONTENT (cal_base_shell_content));
+       g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
+
+       shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+       g_return_if_fail (E_IS_SHELL_SIDEBAR (shell_sidebar));
+
+       selector = e_cal_base_shell_sidebar_get_selector (E_CAL_BASE_SHELL_SIDEBAR (shell_sidebar));
+       e_source_selector_select_source (selector, e_client_get_source (E_CLIENT (client)));
+}
+
+static void
+cal_base_shell_content_view_created_cb (EShellWindow *shell_window,
+                                       EShellView *shell_view,
+                                       ECalBaseShellContent *cal_base_shell_content)
+{
+       EShellSidebar *shell_sidebar;
+       ECalBaseShellContentClass *klass;
+       ESourceSelector *selector;
+
+       g_signal_handlers_disconnect_by_func (
+               shell_window,
+               cal_base_shell_content_view_created_cb, cal_base_shell_content);
+
+       g_return_if_fail (E_IS_CAL_BASE_SHELL_CONTENT (cal_base_shell_content));
+
+       shell_view = e_shell_content_get_shell_view (E_SHELL_CONTENT (cal_base_shell_content));
+       g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
+
+       shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+       g_return_if_fail (E_IS_SHELL_SIDEBAR (shell_sidebar));
+
+       g_signal_connect (shell_sidebar, "client-opened",
+               G_CALLBACK (cal_base_shell_content_client_opened_cb), cal_base_shell_content);
+       g_signal_connect (shell_sidebar, "client-closed",
+               G_CALLBACK (cal_base_shell_content_client_closed_cb), cal_base_shell_content);
+
+       cal_base_shell_content->priv->object_created_id = g_signal_connect_swapped (
+               cal_base_shell_content->priv->model, "object-created",
+               G_CALLBACK (cal_base_shell_content_object_created_cb), cal_base_shell_content);
+
+       selector = e_cal_base_shell_sidebar_get_selector (E_CAL_BASE_SHELL_SIDEBAR (shell_sidebar));
+       g_signal_connect (selector, "notify::primary-selection",
+               G_CALLBACK (cal_base_shell_content_primary_selection_changed_cb), cal_base_shell_content);
+
+       klass = E_CAL_BASE_SHELL_CONTENT_GET_CLASS (cal_base_shell_content);
+       g_return_if_fail (klass != NULL);
+
+       if (klass->view_created)
+               klass->view_created (cal_base_shell_content);
+}
+
+static GCancellable *
+cal_base_shell_content_submit_data_model_thread_job (GObject *responder,
+                                                    const gchar *description,
+                                                    const gchar *alert_ident,
+                                                    const gchar *alert_arg_0,
+                                                    EAlertSinkThreadJobFunc func,
+                                                    gpointer user_data,
+                                                    GDestroyNotify free_user_data)
+{
+       EShellView *shell_view;
+       EActivity *activity;
+       GCancellable *cancellable = NULL;
+
+       g_return_val_if_fail (E_IS_CAL_BASE_SHELL_CONTENT (responder), NULL);
+
+       shell_view = e_shell_content_get_shell_view (E_SHELL_CONTENT (responder));
+       activity = e_shell_view_submit_thread_job (shell_view, description,
+               alert_ident, alert_arg_0, func, user_data, free_user_data);
+
+       if (activity) {
+               cancellable = e_activity_get_cancellable (activity);
+               if (cancellable)
+                       g_object_ref (cancellable);
+               g_object_unref (activity);
+       }
+
+       return cancellable;
+}
+
+static void
+cal_base_shell_content_get_property (GObject *object,
+                                    guint property_id,
+                                    GValue *value,
+                                    GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_DATA_MODEL:
+                       g_value_set_object (
+                               value, e_cal_base_shell_content_get_data_model (
+                               E_CAL_BASE_SHELL_CONTENT (object)));
+                       return;
+
+               case PROP_MODEL:
+                       g_value_set_object (
+                               value, e_cal_base_shell_content_get_model (
+                               E_CAL_BASE_SHELL_CONTENT (object)));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+cal_base_shell_content_dispose (GObject *object)
+{
+       ECalBaseShellContent *cal_base_shell_content;
+
+       cal_base_shell_content = E_CAL_BASE_SHELL_CONTENT (object);
+
+       e_cal_data_model_set_disposing (cal_base_shell_content->priv->data_model, TRUE);
+
+       if (cal_base_shell_content->priv->object_created_id != 0) {
+               g_signal_handler_disconnect (cal_base_shell_content->priv->model,
+                       cal_base_shell_content->priv->object_created_id);
+               cal_base_shell_content->priv->object_created_id = 0;
+       }
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_cal_base_shell_content_parent_class)->dispose (object);
+}
+
+static void
+cal_base_shell_content_finalize (GObject *object)
+{
+       ECalBaseShellContent *cal_base_shell_content;
+
+       cal_base_shell_content = E_CAL_BASE_SHELL_CONTENT (object);
+
+       if (cal_base_shell_content->priv->model &&
+           cal_base_shell_content->priv->data_model)
+               e_cal_data_model_unsubscribe (cal_base_shell_content->priv->data_model,
+                       E_CAL_DATA_MODEL_SUBSCRIBER (cal_base_shell_content->priv->model));
+
+       g_clear_object (&cal_base_shell_content->priv->model);
+       g_clear_object (&cal_base_shell_content->priv->data_model);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_cal_base_shell_content_parent_class)->finalize (object);
+}
+
+static void
+cal_base_shell_content_constructed (GObject *object)
+{
+       EShell *shell;
+       EShellView *shell_view;
+       EShellWindow *shell_window;
+       ECalBaseShellContent *cal_base_shell_content;
+       ECalBaseShellContentClass *klass;
+       ESourceRegistry *registry;
+       ESource *default_source = NULL;
+       const gchar *created_signal_name;
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_cal_base_shell_content_parent_class)->constructed (object);
+
+       cal_base_shell_content = E_CAL_BASE_SHELL_CONTENT (object);
+       cal_base_shell_content->priv->data_model = e_cal_base_shell_content_create_new_data_model 
(cal_base_shell_content);
+
+       klass = E_CAL_BASE_SHELL_CONTENT_GET_CLASS (cal_base_shell_content);
+       g_return_if_fail (klass != NULL);
+       g_return_if_fail (klass->new_cal_model != NULL);
+
+       shell_view = e_shell_content_get_shell_view (E_SHELL_CONTENT (cal_base_shell_content));
+       shell_window = e_shell_view_get_shell_window (shell_view);
+       shell = e_shell_window_get_shell (shell_window);
+       registry = e_shell_get_registry (shell);
+
+       cal_base_shell_content->priv->model = klass->new_cal_model (
+               cal_base_shell_content->priv->data_model, registry, shell);
+
+       g_object_bind_property (
+               cal_base_shell_content->priv->model, "timezone",
+               cal_base_shell_content->priv->data_model, "timezone",
+               G_BINDING_SYNC_CREATE);
+
+       switch (e_cal_base_shell_view_get_source_type (shell_view)) {
+               case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+                       e_cal_data_model_set_expand_recurrences (cal_base_shell_content->priv->data_model, 
TRUE);
+                       default_source = e_source_registry_ref_default_calendar (registry);
+                       created_signal_name = "shell-view-created::calendar";
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+                       default_source = e_source_registry_ref_default_memo_list (registry);
+                       created_signal_name = "shell-view-created::memos";
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+                       default_source = e_source_registry_ref_default_task_list (registry);
+                       created_signal_name = "shell-view-created::tasks";
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_LAST:
+                       g_warn_if_reached ();
+                       return;
+       }
+
+       e_cal_model_set_default_source_uid (cal_base_shell_content->priv->model, e_source_get_uid 
(default_source));
+
+       g_clear_object (&default_source);
+
+       g_signal_connect (
+               shell_window, created_signal_name,
+               G_CALLBACK (cal_base_shell_content_view_created_cb),
+               cal_base_shell_content);
+}
+
+static void
+e_cal_base_shell_content_class_init (ECalBaseShellContentClass *class)
+{
+       GObjectClass *object_class;
+
+       g_type_class_add_private (class, sizeof (ECalBaseShellContentPrivate));
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->get_property = cal_base_shell_content_get_property;
+       object_class->dispose = cal_base_shell_content_dispose;
+       object_class->finalize = cal_base_shell_content_finalize;
+       object_class->constructed = cal_base_shell_content_constructed;
+
+       g_object_class_install_property (
+               object_class,
+               PROP_DATA_MODEL,
+               g_param_spec_object (
+                       "data-model",
+                       NULL,
+                       NULL,
+                       E_TYPE_CAL_DATA_MODEL,
+                       G_PARAM_READABLE));
+
+       g_object_class_install_property (
+               object_class,
+               PROP_MODEL,
+               g_param_spec_object (
+                       "model",
+                       NULL,
+                       NULL,
+                       E_TYPE_CAL_MODEL,
+                       G_PARAM_READABLE));
+}
+
+static void
+e_cal_base_shell_content_init (ECalBaseShellContent *cal_base_shell_content)
+{
+       cal_base_shell_content->priv = G_TYPE_INSTANCE_GET_PRIVATE (
+               cal_base_shell_content, E_TYPE_CAL_BASE_SHELL_CONTENT, ECalBaseShellContentPrivate);
+}
+
+ECalDataModel *
+e_cal_base_shell_content_get_data_model (ECalBaseShellContent *cal_base_shell_content)
+{
+       g_return_val_if_fail (E_IS_CAL_BASE_SHELL_CONTENT (cal_base_shell_content), NULL);
+
+       return cal_base_shell_content->priv->data_model;
+}
+
+ECalModel *
+e_cal_base_shell_content_get_model (ECalBaseShellContent *cal_base_shell_content)
+{
+       g_return_val_if_fail (E_IS_CAL_BASE_SHELL_CONTENT (cal_base_shell_content), NULL);
+
+       return cal_base_shell_content->priv->model;
+}
+
+void
+e_cal_base_shell_content_prepare_for_quit (ECalBaseShellContent *cal_base_shell_content,
+                                          EActivity *activity)
+{
+       ECalBaseShellContentClass *klass;
+
+       g_return_if_fail (E_IS_CAL_BASE_SHELL_CONTENT (cal_base_shell_content));
+
+       klass = E_CAL_BASE_SHELL_CONTENT_GET_CLASS (cal_base_shell_content);
+       g_return_if_fail (klass != NULL);
+
+       if (klass->prepare_for_quit)
+               klass->prepare_for_quit (cal_base_shell_content, activity);
+}
+
+ECalDataModel *
+e_cal_base_shell_content_create_new_data_model (ECalBaseShellContent *cal_base_shell_content)
+{
+       g_return_val_if_fail (E_IS_CAL_BASE_SHELL_CONTENT (cal_base_shell_content), NULL);
+
+       return e_cal_data_model_new (cal_base_shell_content_submit_data_model_thread_job, G_OBJECT 
(cal_base_shell_content));
+}
diff --git a/modules/calendar/e-cal-base-shell-content.h b/modules/calendar/e-cal-base-shell-content.h
new file mode 100644
index 0000000..b362c40
--- /dev/null
+++ b/modules/calendar/e-cal-base-shell-content.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Milan Crha <mcrha redhat com>
+ */
+
+#ifndef E_CAL_BASE_SHELL_CONTENT_H
+#define E_CAL_BASE_SHELL_CONTENT_H
+
+#include <shell/e-shell-content.h>
+#include <shell/e-shell-searchbar.h>
+#include <shell/e-shell-view.h>
+
+#include <calendar/gui/e-cal-data-model.h>
+#include <calendar/gui/e-cal-model.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CAL_BASE_SHELL_CONTENT \
+       (e_cal_base_shell_content_get_type ())
+#define E_CAL_BASE_SHELL_CONTENT(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_CAL_BASE_SHELL_CONTENT, ECalBaseShellContent))
+#define E_CAL_BASE_SHELL_CONTENT_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_CAL_BASE_SHELL_CONTENT, ECalBaseShellContentClass))
+#define E_IS_CAL_BASE_SHELL_CONTENT(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_CAL_BASE_SHELL_CONTENT))
+#define E_IS_CAL_BASE_SHELL_CONTENT_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_CAL_BASE_SHELL_CONTENT))
+#define E_CAL_BASE_SHELL_CONTENT_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_CAL_BASE_SHELL_CONTENT, ECalBaseShellContentClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ECalBaseShellContent ECalBaseShellContent;
+typedef struct _ECalBaseShellContentClass ECalBaseShellContentClass;
+typedef struct _ECalBaseShellContentPrivate ECalBaseShellContentPrivate;
+
+enum {
+       E_CAL_BASE_SHELL_CONTENT_SELECTION_SINGLE         = 1 << 0,
+       E_CAL_BASE_SHELL_CONTENT_SELECTION_MULTIPLE       = 1 << 1,
+       E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_EDITABLE    = 1 << 2,
+       E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_INSTANCE    = 1 << 3,
+       E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_MEETING     = 1 << 4,
+       E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_ORGANIZER   = 1 << 5,
+       E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_RECURRING   = 1 << 6,
+       E_CAL_BASE_SHELL_CONTENT_SELECTION_CAN_DELEGATE   = 1 << 7,
+       E_CAL_BASE_SHELL_CONTENT_SELECTION_CAN_ASSIGN     = 1 << 8,
+       E_CAL_BASE_SHELL_CONTENT_SELECTION_HAS_COMPLETE   = 1 << 9,
+       E_CAL_BASE_SHELL_CONTENT_SELECTION_HAS_INCOMPLETE = 1 << 10,
+       E_CAL_BASE_SHELL_CONTENT_SELECTION_HAS_URL        = 1 << 11
+};
+
+struct _ECalBaseShellContent {
+       EShellContent parent;
+       ECalBaseShellContentPrivate *priv;
+};
+
+struct _ECalBaseShellContentClass {
+       EShellContentClass parent_class;
+
+       /* Virtual methods */
+
+       /* To create correct ECalModel instance for the content */
+       ECalModel *     (*new_cal_model)        (ECalDataModel *cal_data_model,
+                                                ESourceRegistry *registry,
+                                                EShell *shell);
+
+       /* This is called when the shell view is fully created;
+          it can be used for further initialization of the object, when it needs other
+          sub-parts of the shell view. */
+       void            (* view_created)        (ECalBaseShellContent *cal_base_shell_content);
+
+       /* This is called when a user initiated a quit; implementors
+          should stop everything or pile on top of the activity */
+       void            (* prepare_for_quit)    (ECalBaseShellContent *cal_base_shell_content,
+                                                EActivity *activity);
+};
+
+GType          e_cal_base_shell_content_get_type       (void);
+
+ECalDataModel *        e_cal_base_shell_content_get_data_model (ECalBaseShellContent 
*cal_base_shell_content);
+ECalModel *    e_cal_base_shell_content_get_model      (ECalBaseShellContent *cal_base_shell_content);
+void           e_cal_base_shell_content_prepare_for_quit
+                                                       (ECalBaseShellContent *cal_base_shell_content,
+                                                        EActivity *activity);
+
+ECalDataModel *        e_cal_base_shell_content_create_new_data_model
+                                                       (ECalBaseShellContent *cal_base_shell_content);
+
+G_END_DECLS
+
+#endif /* E_CAL_BASE_SHELL_CONTENT_H */
diff --git a/modules/calendar/e-cal-base-shell-sidebar.c b/modules/calendar/e-cal-base-shell-sidebar.c
new file mode 100644
index 0000000..b5bf20d
--- /dev/null
+++ b/modules/calendar/e-cal-base-shell-sidebar.c
@@ -0,0 +1,916 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Milan Crha <mcrha redhat com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <glib/gi18n.h>
+
+#include "e-util/e-util.h"
+#include "calendar/gui/comp-util.h"
+
+#include "e-cal-base-shell-view.h"
+#include "e-cal-base-shell-sidebar.h"
+
+#define E_CAL_BASE_SHELL_SIDEBAR_GET_PRIVATE(obj) \
+       (G_TYPE_INSTANCE_GET_PRIVATE \
+       ((obj), E_TYPE_CAL_BASE_SHELL_SIDEBAR, ECalBaseShellSidebarPrivate))
+
+struct _ECalBaseShellSidebarPrivate {
+       ECalendar *date_navigator; /* not referenced, is inside itself */
+       GtkWidget *paned; /* not referenced, is inside itself */
+       ESourceSelector *selector; /* not referenced, is inside itself */
+
+       gulong date_navigator_scroll_event_handler_id;
+
+       GHashTable *selected_uids; /* source UID -> cancellable */
+};
+
+enum {
+       PROP_0,
+       PROP_DATE_NAVIGATOR,
+       PROP_SELECTOR
+};
+
+enum {
+       CLIENT_OPENED,
+       CLIENT_CLOSED,
+       LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+G_DEFINE_DYNAMIC_TYPE (ECalBaseShellSidebar, e_cal_base_shell_sidebar, E_TYPE_SHELL_SIDEBAR)
+
+static gboolean
+cal_base_shell_sidebar_map_uid_to_source (GValue *value,
+                                         GVariant *variant,
+                                         gpointer user_data)
+{
+       ESourceRegistry *registry;
+       ESource *source;
+       const gchar *uid;
+
+       registry = E_SOURCE_REGISTRY (user_data);
+       uid = g_variant_get_string (variant, NULL);
+       if (uid != NULL && *uid != '\0')
+               source = e_source_registry_ref_source (registry, uid);
+       else
+               source = e_source_registry_ref_default_calendar (registry);
+       g_value_take_object (value, source);
+
+       return (source != NULL);
+}
+
+static GVariant *
+cal_base_shell_sidebar_map_source_to_uid (const GValue *value,
+                                         const GVariantType *expected_type,
+                                         gpointer user_data)
+{
+       GVariant *variant = NULL;
+       ESource *source;
+
+       source = g_value_get_object (value);
+
+       if (source != NULL) {
+               const gchar *uid;
+
+               uid = e_source_get_uid (source);
+               variant = g_variant_new_string (uid);
+       }
+
+       return variant;
+}
+
+static void
+cal_base_shell_sidebar_restore_state_cb (EShellWindow *shell_window,
+                                        EShellView *shell_view,
+                                        EShellSidebar *shell_sidebar)
+{
+       ECalBaseShellSidebarPrivate *priv;
+       ESourceRegistry *registry;
+       ESourceSelector *selector;
+       GSettings *settings;
+       const gchar *primary_source_key;
+
+       priv = E_CAL_BASE_SHELL_SIDEBAR (shell_sidebar)->priv;
+
+       g_signal_handlers_disconnect_by_func (
+               shell_window,
+               cal_base_shell_sidebar_restore_state_cb, shell_sidebar);
+
+       switch (e_cal_base_shell_view_get_source_type (shell_view)) {
+               case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+                       primary_source_key = "primary-calendar";
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+                       primary_source_key = "primary-memos";
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+                       primary_source_key = "primary-tasks";
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_LAST:
+                       g_warn_if_reached ();
+                       return;
+       }
+
+       selector = E_SOURCE_SELECTOR (priv->selector);
+       registry = e_source_selector_get_registry (selector);
+
+       /* Bind GObject properties to settings keys. */
+
+       settings = g_settings_new ("org.gnome.evolution.calendar");
+
+       g_settings_bind_with_mapping (
+               settings, primary_source_key,
+               selector, "primary-selection",
+               G_SETTINGS_BIND_DEFAULT,
+               cal_base_shell_sidebar_map_uid_to_source,
+               cal_base_shell_sidebar_map_source_to_uid,
+               g_object_ref (registry),
+               (GDestroyNotify) g_object_unref);
+
+       if (priv->date_navigator) {
+               g_settings_bind (
+                       settings, "date-navigator-pane-position",
+                       priv->paned, "vposition",
+                       G_SETTINGS_BIND_DEFAULT);
+       }
+
+       g_object_unref (settings);
+}
+
+static guint32
+cal_base_shell_sidebar_check_state (EShellSidebar *shell_sidebar)
+{
+       ECalBaseShellSidebar *cal_base_shell_sidebar;
+       ESourceSelector *selector;
+       ESourceRegistry *registry;
+       ESource *source;
+       gboolean is_writable = FALSE;
+       gboolean is_removable = FALSE;
+       gboolean is_remote_creatable = FALSE;
+       gboolean is_remote_deletable = FALSE;
+       gboolean in_collection = FALSE;
+       gboolean refresh_supported = FALSE;
+       gboolean has_primary_source = FALSE;
+       guint32 state = 0;
+
+       cal_base_shell_sidebar = E_CAL_BASE_SHELL_SIDEBAR (shell_sidebar);
+       selector = e_cal_base_shell_sidebar_get_selector (cal_base_shell_sidebar);
+       source = e_source_selector_ref_primary_selection (selector);
+       registry = e_source_selector_get_registry (selector);
+
+       if (source != NULL) {
+               EClient *client;
+               ESource *collection;
+
+               has_primary_source = TRUE;
+               is_writable = e_source_get_writable (source);
+               is_removable = e_source_get_removable (source);
+               is_remote_creatable = e_source_get_remote_creatable (source);
+               is_remote_deletable = e_source_get_remote_deletable (source);
+
+               collection = e_source_registry_find_extension (
+                       registry, source, E_SOURCE_EXTENSION_COLLECTION);
+               if (collection != NULL) {
+                       in_collection = TRUE;
+                       g_object_unref (collection);
+               }
+
+               client = e_client_selector_ref_cached_client (
+                       E_CLIENT_SELECTOR (selector), source);
+
+               if (client != NULL) {
+                       refresh_supported =
+                               e_client_check_refresh_supported (client);
+                       g_object_unref (client);
+               }
+
+               g_object_unref (source);
+       }
+
+       if (has_primary_source)
+               state |= E_CAL_BASE_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE;
+       if (is_writable)
+               state |= E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_WRITABLE;
+       if (is_removable)
+               state |= E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOVABLE;
+       if (is_remote_creatable)
+               state |= E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_CREATABLE;
+       if (is_remote_deletable)
+               state |= E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_DELETABLE;
+       if (in_collection)
+               state |= E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IN_COLLECTION;
+       if (refresh_supported)
+               state |= E_CAL_BASE_SHELL_SIDEBAR_SOURCE_SUPPORTS_REFRESH;
+
+       return state;
+}
+
+static gboolean
+cal_base_shell_sidebar_date_navigator_scroll_event_cb (ECalBaseShellSidebar *cal_base_shell_sidebar,
+                                                      GdkEventScroll *event,
+                                                      ECalendar *date_navigator)
+{
+       ECalendarItem *calitem;
+       gint year = -1, month = -1;
+       GdkScrollDirection direction;
+
+       calitem = date_navigator->calitem;
+       e_calendar_item_get_first_month (calitem, &year, &month);
+       if (year == -1 || month == -1)
+               return FALSE;
+
+       direction = event->direction;
+
+       if (direction == GDK_SCROLL_SMOOTH) {
+               static gdouble total_delta_y = 0.0;
+
+               total_delta_y += event->delta_y;
+
+               if (total_delta_y >= 1.0) {
+                       total_delta_y = 0.0;
+                       direction = GDK_SCROLL_DOWN;
+               } else if (total_delta_y <= -1.0) {
+                       total_delta_y = 0.0;
+                       direction = GDK_SCROLL_UP;
+               } else {
+                       return FALSE;
+               }
+       }
+
+       switch (direction) {
+               case GDK_SCROLL_UP:
+                       month--;
+                       if (month < 0) {
+                               year--;
+                               month += 12;
+                       }
+                       break;
+
+               case GDK_SCROLL_DOWN:
+                       month++;
+                       if (month >= 12) {
+                               year++;
+                               month -= 12;
+                       }
+                       break;
+
+               default:
+                       g_return_val_if_reached (FALSE);
+       }
+
+       e_calendar_item_set_first_month (calitem, year, month);
+
+       return TRUE;
+}
+
+typedef struct _OpenClientData {
+       const gchar *extension_name;
+       ECalBaseShellSidebar *sidebar;
+       ESource *source;
+       EClient *client;
+} OpenClientData;
+
+static void
+open_client_data_free (gpointer pdata)
+{
+       OpenClientData *data = pdata;
+
+       if (data) {
+               if (data->client) {
+                       g_signal_emit (data->sidebar, signals[CLIENT_OPENED], 0, data->client);
+               } else {
+                       ESourceSelector *selector = e_cal_base_shell_sidebar_get_selector (data->sidebar);
+                       e_source_selector_unselect_source (selector, data->source);
+               }
+
+               g_clear_object (&data->sidebar);
+               g_clear_object (&data->source);
+               g_clear_object (&data->client);
+               g_free (data);
+       }
+}
+
+static void
+e_cal_base_shell_sidebar_open_client_thread (EAlertSinkThreadJobData *job_data,
+                                            gpointer user_data,
+                                            GCancellable *cancellable,
+                                            GError **error)
+{
+       EClientSelector *selector;
+       OpenClientData *data = user_data;
+       GError *local_error = NULL;
+
+       g_return_if_fail (data != NULL);
+
+       selector = E_CLIENT_SELECTOR (e_cal_base_shell_sidebar_get_selector (data->sidebar));
+       data->client = e_client_selector_get_client_sync (
+               selector, data->source, TRUE, cancellable, &local_error);
+
+       e_util_propagate_open_source_job_error (job_data, data->extension_name, local_error, error);
+}
+
+static void
+e_cal_base_shell_sidebar_ensure_source_opened (ECalBaseShellSidebar *sidebar,
+                                              ESource *source)
+{
+       OpenClientData *data;
+       EShellView *shell_view;
+       EActivity *activity;
+       gchar *description = NULL, *alert_ident = NULL, *alert_arg_0 = NULL;
+       const gchar *extension_name;
+
+       g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (sidebar));
+       g_return_if_fail (E_IS_SOURCE (source));
+
+       shell_view = e_shell_sidebar_get_shell_view (E_SHELL_SIDEBAR (sidebar));
+
+       switch (e_cal_base_shell_view_get_source_type (shell_view)) {
+               case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+                       extension_name = E_SOURCE_EXTENSION_CALENDAR;
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+                       extension_name = E_SOURCE_EXTENSION_MEMO_LIST;
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+                       extension_name = E_SOURCE_EXTENSION_TASK_LIST;
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_LAST:
+                       g_warn_if_reached ();
+                       return;
+       }
+
+       if (!e_util_get_open_source_job_info (extension_name, e_source_get_display_name (source),
+               &description, &alert_ident, &alert_arg_0)) {
+               g_warn_if_reached ();
+               return;
+       }
+
+       data = g_new0 (OpenClientData, 1);
+       data->extension_name = extension_name; /* no need to copy, it's a static string */
+       data->sidebar = g_object_ref (sidebar);
+       data->source = g_object_ref (source);
+
+       activity = e_shell_view_submit_thread_job (
+               shell_view, description, alert_ident, alert_arg_0,
+               e_cal_base_shell_sidebar_open_client_thread, data,
+               open_client_data_free);
+
+       if (activity) {
+               GCancellable *cancellable;
+
+               cancellable = e_activity_get_cancellable (activity);
+
+               g_hash_table_insert (sidebar->priv->selected_uids,
+                       g_strdup (e_source_get_uid (source)),
+                       g_object_ref (cancellable));
+
+               g_object_unref (activity);
+       }
+
+       g_free (description);
+       g_free (alert_ident);
+       g_free (alert_arg_0);
+}
+
+static void
+e_cal_base_shell_sidebar_source_selected (ESourceSelector *selector,
+                                         ESource *source,
+                                         ECalBaseShellSidebar *sidebar)
+{
+       g_return_if_fail (E_IS_SOURCE_SELECTOR (selector));
+       g_return_if_fail (E_IS_SOURCE (source));
+       g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (sidebar));
+
+       if (!g_hash_table_contains (sidebar->priv->selected_uids, e_source_get_uid (source))) {
+               e_cal_base_shell_sidebar_ensure_source_opened (sidebar, source);
+       }
+}
+
+static void
+e_cal_base_shell_sidebar_source_unselected (ESourceSelector *selector,
+                                           ESource *source,
+                                           ECalBaseShellSidebar *sidebar)
+{
+       g_return_if_fail (E_IS_SOURCE_SELECTOR (selector));
+       g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (sidebar));
+
+       if (g_hash_table_remove (sidebar->priv->selected_uids, e_source_get_uid (source)))
+               g_signal_emit (sidebar, signals[CLIENT_CLOSED], 0, source);
+}
+
+static void
+e_cal_base_shell_sidebar_selector_realize_cb (ESourceSelector *selector,
+                                             ECalBaseShellSidebar *sidebar)
+{
+       g_return_if_fail (E_IS_SOURCE_SELECTOR (selector));
+       g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (sidebar));
+
+       e_cal_base_shell_sidebar_ensure_sources_open (sidebar);
+}
+
+typedef struct {
+       ESource *source;
+       ESource *destination;
+       gboolean do_copy;
+       icalcomponent *icalcomp;
+       EClientSelector *selector;
+} TransferItemToData;
+
+static void
+transfer_item_to_data_free (gpointer ptr)
+{
+       TransferItemToData *titd = ptr;
+
+       if (titd) {
+               g_clear_object (&titd->source);
+               g_clear_object (&titd->destination);
+               g_clear_object (&titd->selector);
+
+               if (titd->icalcomp)
+                       icalcomponent_free (titd->icalcomp);
+
+               g_free (titd);
+       }
+}
+
+static void
+cal_base_shell_sidebar_transfer_thread (EAlertSinkThreadJobData *job_data,
+                                       gpointer user_data,
+                                       GCancellable *cancellable,
+                                       GError **error)
+{
+       TransferItemToData *titd = user_data;
+       EClient *source_client, *destination_client;
+
+       g_return_if_fail (titd != NULL);
+       g_return_if_fail (E_IS_SOURCE (titd->source));
+       g_return_if_fail (E_IS_SOURCE (titd->destination));
+       g_return_if_fail (E_IS_CLIENT_SELECTOR (titd->selector));
+       g_return_if_fail (titd->icalcomp != NULL);
+
+       source_client = e_client_selector_get_client_sync (
+               titd->selector, titd->source, FALSE, cancellable, error);
+       if (!source_client)
+               return;
+
+       destination_client = e_client_selector_get_client_sync (
+               titd->selector, titd->destination, FALSE, cancellable, error);
+       if (!destination_client) {
+               g_object_unref (source_client);
+               return;
+       }
+
+       cal_comp_transfer_item_to_sync (E_CAL_CLIENT (source_client), E_CAL_CLIENT (destination_client),
+               titd->icalcomp, titd->do_copy, cancellable, error);
+
+       g_clear_object (&source_client);
+       g_clear_object (&destination_client);
+}
+
+static gboolean
+e_cal_base_shell_sidebar_selector_data_dropped (ESourceSelector *selector,
+                                               GtkSelectionData *selection_data,
+                                               ESource *destination,
+                                               GdkDragAction action,
+                                               guint info,
+                                               ECalBaseShellSidebar *sidebar)
+{
+       icalcomponent *icalcomp = NULL;
+       EActivity *activity;
+       EShellView *shell_view;
+       ESource *source = NULL;
+       ESourceRegistry *registry;
+       gchar **segments;
+       gchar *source_uid = NULL;
+       gchar *message = NULL;
+       const gchar *display_name, *alert_ident;
+       const guchar *data;
+       gboolean do_copy;
+       TransferItemToData *titd;
+
+       g_return_val_if_fail (E_IS_SOURCE_SELECTOR (selector), FALSE);
+       g_return_val_if_fail (E_IS_SOURCE (destination), FALSE);
+       g_return_val_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (sidebar), FALSE);
+
+       data = gtk_selection_data_get_data (selection_data);
+       g_return_val_if_fail (data != NULL, FALSE);
+
+       segments = g_strsplit ((const gchar *) data, "\n", 2);
+       if (g_strv_length (segments) != 2)
+               goto exit;
+
+       source_uid = g_strdup (segments[0]);
+       icalcomp = icalparser_parse_string (segments[1]);
+
+       if (!icalcomp)
+               goto exit;
+
+       registry = e_source_selector_get_registry (selector);
+       source = e_source_registry_ref_source (registry, source_uid);
+       if (!source)
+               goto exit;
+
+       display_name = e_source_get_display_name (destination);
+       do_copy = action == GDK_ACTION_COPY ? TRUE : FALSE;
+       shell_view = e_shell_sidebar_get_shell_view (E_SHELL_SIDEBAR (sidebar));
+
+       switch (e_cal_base_shell_view_get_source_type (shell_view)) {
+               case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+                       message = do_copy ?
+                               g_strdup_printf (_("Copying an event into the calendar '%s'"), display_name) :
+                               g_strdup_printf (_("Moving an event into the calendar '%s'"), display_name);
+                       alert_ident = do_copy ? "calendar:failed-copy-event" : "calendar:failed-move-event";
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+                       message = do_copy ?
+                               g_strdup_printf (_("Copying a memo into the memo list '%s'"), display_name) :
+                               g_strdup_printf (_("Moving a memo into the memo list '%s'"), display_name);
+                       alert_ident = do_copy ? "calendar:failed-copy-memo" : "calendar:failed-move-memo";
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+                       message = do_copy ?
+                               g_strdup_printf (_("Copying a task into the task list '%s'"), display_name) :
+                               g_strdup_printf (_("Moving a task into the task list '%s'"), display_name);
+                       alert_ident = do_copy ? "calendar:failed-copy-task" : "calendar:failed-move-task";
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_LAST:
+                       g_warn_if_reached ();
+                       goto exit;
+       }
+
+       titd = g_new0 (TransferItemToData, 1);
+       titd->source = g_object_ref (source);
+       titd->destination = g_object_ref (destination);
+       titd->do_copy = do_copy;
+       titd->icalcomp = icalcomp;
+       titd->selector = g_object_ref (selector);
+
+       icalcomp = NULL;
+
+       activity = e_shell_view_submit_thread_job (shell_view, message,
+               alert_ident, display_name, cal_base_shell_sidebar_transfer_thread,
+               titd, transfer_item_to_data_free);
+
+       g_clear_object (&activity);
+
+ exit:
+       if (icalcomp)
+               icalcomponent_free (icalcomp);
+
+       g_clear_object (&source);
+       g_free (message);
+       g_free (source_uid);
+       g_strfreev (segments);
+
+       return TRUE;
+}
+
+static void
+cancel_and_unref (gpointer data)
+{
+       GCancellable *cancellable = data;
+
+       if (cancellable) {
+               g_cancellable_cancel (cancellable);
+               g_object_unref (cancellable);
+       }
+}
+
+static void
+cal_base_shell_sidebar_get_property (GObject *object,
+                                    guint property_id,
+                                    GValue *value,
+                                    GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_DATE_NAVIGATOR:
+                       g_value_set_object (
+                               value,
+                               e_cal_base_shell_sidebar_get_date_navigator (
+                               E_CAL_BASE_SHELL_SIDEBAR (object)));
+                       return;
+
+               case PROP_SELECTOR:
+                       g_value_set_object (
+                               value,
+                               e_cal_base_shell_sidebar_get_selector (
+                               E_CAL_BASE_SHELL_SIDEBAR (object)));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+cal_base_shell_sidebar_constructed (GObject *object)
+{
+       EShellWindow *shell_window;
+       EShellView *shell_view;
+       EShellBackend *shell_backend;
+       EShell *shell;
+       EClientCache *client_cache;
+       const gchar *source_extension, *selector_name, *restore_state_signal;
+       ECalBaseShellSidebar *cal_base_shell_sidebar;
+       GtkWidget *container, *widget;
+       AtkObject *a11y;
+       gboolean add_navigator = FALSE;
+
+       /* Chain up to parent's constructed() method. */
+       G_OBJECT_CLASS (e_cal_base_shell_sidebar_parent_class)->constructed (object);
+
+       cal_base_shell_sidebar = E_CAL_BASE_SHELL_SIDEBAR (object);
+       shell_view = e_shell_sidebar_get_shell_view (E_SHELL_SIDEBAR (object));
+       shell_backend = e_shell_view_get_shell_backend (shell_view);
+       shell_window = e_shell_view_get_shell_window (shell_view);
+       shell = e_shell_backend_get_shell (shell_backend);
+
+       switch (e_cal_base_shell_view_get_source_type (shell_view)) {
+               case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+                       source_extension = E_SOURCE_EXTENSION_CALENDAR;
+                       selector_name = _("Calendar Selector");
+                       restore_state_signal = "shell-view-created::calendar";
+                       add_navigator = TRUE;
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+                       source_extension = E_SOURCE_EXTENSION_MEMO_LIST;
+                       selector_name = _("Memo List Selector");
+                       restore_state_signal = "shell-view-created::memos";
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+                       source_extension = E_SOURCE_EXTENSION_TASK_LIST;
+                       selector_name = _("Task List Selector");
+                       restore_state_signal = "shell-view-created::tasks";
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_LAST:
+                       g_warn_if_reached ();
+                       return;
+       }
+
+       client_cache = e_shell_get_client_cache (shell);
+
+       container = GTK_WIDGET (object);
+
+       widget = e_paned_new (GTK_ORIENTATION_VERTICAL);
+       gtk_container_add (GTK_CONTAINER (container), widget);
+       cal_base_shell_sidebar->priv->paned = widget;
+
+       container = widget;
+
+       widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+       gtk_paned_pack1 (GTK_PANED (container), widget, TRUE, TRUE);
+
+       container = widget;
+
+       widget = gtk_scrolled_window_new (NULL, NULL);
+       gtk_scrolled_window_set_policy (
+               GTK_SCROLLED_WINDOW (widget),
+               GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+       gtk_scrolled_window_set_shadow_type (
+               GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+       gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+
+       container = widget;
+
+       widget = e_client_selector_new (client_cache, source_extension);
+       a11y = gtk_widget_get_accessible (widget);
+       atk_object_set_name (a11y, selector_name);
+       cal_base_shell_sidebar->priv->selector = E_SOURCE_SELECTOR (widget);
+       gtk_container_add (GTK_CONTAINER (container), widget);
+
+       if (add_navigator) {
+               ECalendarItem *calitem;
+
+               container = cal_base_shell_sidebar->priv->paned;
+
+               widget = e_calendar_new ();
+               calitem = E_CALENDAR (widget)->calitem;
+               e_calendar_item_set_days_start_week_sel (calitem, 9);
+               e_calendar_item_set_max_days_sel (calitem, 42);
+               gtk_paned_pack2 (GTK_PANED (container), widget, FALSE, FALSE);
+               cal_base_shell_sidebar->priv->date_navigator = E_CALENDAR (widget);
+               gtk_widget_show (widget);
+
+               gnome_canvas_item_set (
+                       GNOME_CANVAS_ITEM (cal_base_shell_sidebar->priv->date_navigator->calitem),
+                       "move-selection-when-moving", FALSE,
+                       NULL);
+
+               cal_base_shell_sidebar->priv->date_navigator_scroll_event_handler_id = 
g_signal_connect_swapped (
+                       cal_base_shell_sidebar->priv->date_navigator, "scroll-event",
+                       G_CALLBACK (cal_base_shell_sidebar_date_navigator_scroll_event_cb), 
cal_base_shell_sidebar);
+       }
+
+       gtk_widget_show_all (GTK_WIDGET (object));
+
+       gtk_drag_dest_set (
+               GTK_WIDGET (cal_base_shell_sidebar->priv->selector), GTK_DEST_DEFAULT_ALL,
+               NULL, 0, GDK_ACTION_COPY | GDK_ACTION_MOVE);
+
+       e_drag_dest_add_calendar_targets (GTK_WIDGET (cal_base_shell_sidebar->priv->selector));
+
+       g_signal_connect (cal_base_shell_sidebar->priv->selector,
+               "realize", G_CALLBACK (e_cal_base_shell_sidebar_selector_realize_cb),
+               cal_base_shell_sidebar);
+
+       g_signal_connect (cal_base_shell_sidebar->priv->selector,
+               "data-dropped", G_CALLBACK (e_cal_base_shell_sidebar_selector_data_dropped),
+               cal_base_shell_sidebar);
+
+       g_signal_connect (cal_base_shell_sidebar->priv->selector,
+               "source-selected", G_CALLBACK (e_cal_base_shell_sidebar_source_selected),
+               cal_base_shell_sidebar);
+
+       g_signal_connect (cal_base_shell_sidebar->priv->selector,
+               "source-unselected", G_CALLBACK (e_cal_base_shell_sidebar_source_unselected),
+               cal_base_shell_sidebar);
+
+       /* Restore widget state from the last session once
+        * the shell view is fully initialized and visible. */
+       g_signal_connect (
+               shell_window, restore_state_signal,
+               G_CALLBACK (cal_base_shell_sidebar_restore_state_cb),
+               cal_base_shell_sidebar);
+}
+
+static void
+cal_base_shell_sidebar_dispose (GObject *object)
+{
+       ECalBaseShellSidebar *cal_base_shell_sidebar;
+
+       cal_base_shell_sidebar = E_CAL_BASE_SHELL_SIDEBAR (object);
+
+       if (cal_base_shell_sidebar->priv->date_navigator_scroll_event_handler_id > 0 &&
+           cal_base_shell_sidebar->priv->date_navigator) {
+               g_signal_handler_disconnect (cal_base_shell_sidebar->priv->date_navigator,
+                       cal_base_shell_sidebar->priv->date_navigator_scroll_event_handler_id);
+               cal_base_shell_sidebar->priv->date_navigator_scroll_event_handler_id = 0;
+       }
+
+       cal_base_shell_sidebar->priv->date_navigator = NULL;
+       cal_base_shell_sidebar->priv->selector = NULL;
+       cal_base_shell_sidebar->priv->paned = NULL;
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_cal_base_shell_sidebar_parent_class)->dispose (object);
+}
+
+static void
+cal_base_shell_sidebar_finalize (GObject *object)
+{
+       ECalBaseShellSidebar *cal_base_shell_sidebar;
+
+       cal_base_shell_sidebar = E_CAL_BASE_SHELL_SIDEBAR (object);
+
+       g_hash_table_destroy (cal_base_shell_sidebar->priv->selected_uids);
+       cal_base_shell_sidebar->priv->selected_uids = NULL;
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_cal_base_shell_sidebar_parent_class)->finalize (object);
+}
+
+static void
+e_cal_base_shell_sidebar_class_init (ECalBaseShellSidebarClass *class)
+{
+       GObjectClass *object_class;
+       EShellSidebarClass *shell_sidebar_class;
+
+       g_type_class_add_private (class, sizeof (ECalBaseShellSidebarPrivate));
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->get_property = cal_base_shell_sidebar_get_property;
+       object_class->constructed = cal_base_shell_sidebar_constructed;
+       object_class->dispose = cal_base_shell_sidebar_dispose;
+       object_class->finalize = cal_base_shell_sidebar_finalize;
+
+       shell_sidebar_class = E_SHELL_SIDEBAR_CLASS (class);
+       shell_sidebar_class->check_state = cal_base_shell_sidebar_check_state;
+
+       g_object_class_install_property (
+               object_class,
+               PROP_SELECTOR,
+               g_param_spec_object (
+                       "selector",
+                       "Source Selector Widget",
+                       "This widget displays groups of calendars",
+                       E_TYPE_SOURCE_SELECTOR,
+                       G_PARAM_READABLE));
+
+       g_object_class_install_property (
+               object_class,
+               PROP_DATE_NAVIGATOR,
+               g_param_spec_object (
+                       "date-navigator",
+                       "Date Navigator Widget",
+                       "This widget displays a miniature calendar",
+                       E_TYPE_CALENDAR,
+                       G_PARAM_READABLE));
+
+       signals[CLIENT_OPENED] = g_signal_new (
+               "client-opened",
+               G_OBJECT_CLASS_TYPE (object_class),
+               G_SIGNAL_RUN_LAST,
+               G_STRUCT_OFFSET (ECalBaseShellSidebarClass, client_opened),
+               NULL, NULL,
+               g_cclosure_marshal_VOID__OBJECT,
+               G_TYPE_NONE, 1,
+               E_TYPE_CAL_CLIENT);
+
+       signals[CLIENT_CLOSED] = g_signal_new (
+               "client-closed",
+               G_OBJECT_CLASS_TYPE (object_class),
+               G_SIGNAL_RUN_LAST,
+               G_STRUCT_OFFSET (ECalBaseShellSidebarClass, client_closed),
+               NULL, NULL,
+               g_cclosure_marshal_VOID__OBJECT,
+               G_TYPE_NONE, 1,
+               E_TYPE_SOURCE);
+}
+
+static void
+e_cal_base_shell_sidebar_class_finalize (ECalBaseShellSidebarClass *class)
+{
+}
+
+static void
+e_cal_base_shell_sidebar_init (ECalBaseShellSidebar *cal_base_shell_sidebar)
+{
+       cal_base_shell_sidebar->priv = E_CAL_BASE_SHELL_SIDEBAR_GET_PRIVATE (cal_base_shell_sidebar);
+       cal_base_shell_sidebar->priv->selected_uids =
+               g_hash_table_new_full (g_str_hash, g_str_equal, g_free, cancel_and_unref);
+}
+
+void
+e_cal_base_shell_sidebar_type_register (GTypeModule *type_module)
+{
+       /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
+        *     function, so we have to wrap it with a public function in
+        *     order to register types from a separate compilation unit. */
+       e_cal_base_shell_sidebar_register_type (type_module);
+}
+
+GtkWidget *
+e_cal_base_shell_sidebar_new (EShellView *shell_view)
+{
+       g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
+
+       return g_object_new (
+               E_TYPE_CAL_BASE_SHELL_SIDEBAR,
+               "shell-view", shell_view, NULL);
+}
+
+ECalendar *
+e_cal_base_shell_sidebar_get_date_navigator (ECalBaseShellSidebar *cal_base_shell_sidebar)
+{
+       g_return_val_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (cal_base_shell_sidebar), NULL);
+
+       return cal_base_shell_sidebar->priv->date_navigator;
+}
+
+ESourceSelector *
+e_cal_base_shell_sidebar_get_selector (ECalBaseShellSidebar *cal_base_shell_sidebar)
+{
+       g_return_val_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (cal_base_shell_sidebar), NULL);
+
+       return cal_base_shell_sidebar->priv->selector;
+}
+
+void
+e_cal_base_shell_sidebar_ensure_sources_open (ECalBaseShellSidebar *cal_base_shell_sidebar)
+{
+       GList *selected, *link;
+       ESourceSelector *selector;
+
+       g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (cal_base_shell_sidebar));
+
+       selector = cal_base_shell_sidebar->priv->selector;
+       g_return_if_fail (E_IS_SOURCE_SELECTOR (selector));
+
+       selected = e_source_selector_get_selection (selector);
+       for (link = selected; link; link = g_list_next (link)) {
+               ESource *source = link->data;
+
+               e_cal_base_shell_sidebar_ensure_source_opened (cal_base_shell_sidebar, source);
+       }
+
+       g_list_free_full (selected, g_object_unref);
+}
diff --git a/modules/calendar/e-cal-base-shell-sidebar.h b/modules/calendar/e-cal-base-shell-sidebar.h
new file mode 100644
index 0000000..6ef73fc
--- /dev/null
+++ b/modules/calendar/e-cal-base-shell-sidebar.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Milan Crha <mcrha redhat com>
+ */
+
+#ifndef E_CAL_BASE_SHELL_SIDEBAR_H
+#define E_CAL_BASE_SHELL_SIDEBAR_H
+
+#include <libecal/libecal.h>
+
+#include <shell/e-shell-sidebar.h>
+#include <shell/e-shell-view.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CAL_BASE_SHELL_SIDEBAR \
+       (e_cal_base_shell_sidebar_get_type ())
+#define E_CAL_BASE_SHELL_SIDEBAR(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_CAL_BASE_SHELL_SIDEBAR, ECalBaseShellSidebar))
+#define E_CAL_BASE_SHELL_SIDEBAR_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_CAL_BASE_SHELL_SIDEBAR, ECalBaseShellSidebarClass))
+#define E_IS_CAL_BASE_SHELL_SIDEBAR(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_CAL_BASE_SHELL_SIDEBAR))
+#define E_IS_CAL_BASE_SHELL_SIDEBAR_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_CAL_BASE_SHELL_SIDEBAR))
+#define E_CAL_BASE_SHELL_SIDEBAR_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_CAL_BASE_SHELL_SIDEBAR, ECalBaseShellSidebarClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ECalBaseShellSidebar ECalBaseShellSidebar;
+typedef struct _ECalBaseShellSidebarClass ECalBaseShellSidebarClass;
+typedef struct _ECalBaseShellSidebarPrivate ECalBaseShellSidebarPrivate;
+
+enum {
+       E_CAL_BASE_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE = 1 << 0,
+       E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_WRITABLE = 1 << 1,
+       E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOVABLE = 1 << 2,
+       E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_CREATABLE = 1 << 3,
+       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
+};
+
+struct _ECalBaseShellSidebar {
+       EShellSidebar parent;
+       ECalBaseShellSidebarPrivate *priv;
+};
+
+struct _ECalBaseShellSidebarClass {
+       EShellSidebarClass parent_class;
+
+       /* Signals */
+       void    (*client_opened)        (ECalBaseShellSidebar *cal_shell_sidebar,
+                                        ECalClient *client);
+       void    (*client_closed)        (ECalBaseShellSidebar *cal_shell_sidebar,
+                                        ESource *source);
+};
+
+GType          e_cal_base_shell_sidebar_get_type       (void);
+void           e_cal_base_shell_sidebar_type_register  (GTypeModule *type_module);
+GtkWidget *    e_cal_base_shell_sidebar_new            (EShellView *shell_view);
+
+ECalendar *    e_cal_base_shell_sidebar_get_date_navigator
+                                                       (ECalBaseShellSidebar *cal_base_shell_sidebar);
+ESourceSelector *
+               e_cal_base_shell_sidebar_get_selector   (ECalBaseShellSidebar *cal_base_shell_sidebar);
+void           e_cal_base_shell_sidebar_ensure_sources_open
+                                                       (ECalBaseShellSidebar *cal_base_shell_sidebar);
+
+G_END_DECLS
+
+#endif /* E_CAL_BASE_SHELL_SIDEBAR_H */
diff --git a/modules/calendar/e-cal-base-shell-view.c b/modules/calendar/e-cal-base-shell-view.c
new file mode 100644
index 0000000..dd6957d
--- /dev/null
+++ b/modules/calendar/e-cal-base-shell-view.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Milan Crha <mcrha redhat com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gtk/gtk.h>
+#include <glib/gi18n-lib.h>
+
+#include <camel/camel.h>
+
+#include <calendar/gui/dialogs/copy-source-dialog.h>
+
+#include "e-cal-base-shell-content.h"
+#include "e-cal-base-shell-sidebar.h"
+
+#include "e-cal-base-shell-view.h"
+
+#define E_CAL_BASE_SHELL_VIEW_GET_PRIVATE(obj) \
+       (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;
+};
+
+static void
+cal_base_shell_view_prepare_for_quit_cb (EShell *shell,
+                                        EActivity *activity,
+                                        ECalBaseShellView *cal_base_shell_view)
+{
+       EShellContent *shell_content;
+
+       g_return_if_fail (E_IS_CAL_BASE_SHELL_VIEW (cal_base_shell_view));
+
+       /* Stop running searches, if any; the activity tight
+        * on the search prevents application from quitting. */
+       /*e_cal_base_shell_view_search_stop (cal_base_shell_view);*/
+
+       shell_content = e_shell_view_get_shell_content (E_SHELL_VIEW (cal_base_shell_view));
+       e_cal_base_shell_content_prepare_for_quit (E_CAL_BASE_SHELL_CONTENT (shell_content), activity);
+}
+
+static void
+cal_base_shell_view_dispose (GObject *object)
+{
+       ECalBaseShellView *cal_base_shell_view = E_CAL_BASE_SHELL_VIEW (object);
+
+       if (cal_base_shell_view->priv->shell && cal_base_shell_view->priv->prepare_for_quit_handler_id) {
+               g_signal_handler_disconnect (cal_base_shell_view->priv->shell,
+                       cal_base_shell_view->priv->prepare_for_quit_handler_id);
+               cal_base_shell_view->priv->prepare_for_quit_handler_id = 0;
+       }
+
+       g_clear_object (&cal_base_shell_view->priv->shell);
+
+       /* Chain up to parent's dispose() method. */
+       G_OBJECT_CLASS (e_cal_base_shell_view_parent_class)->dispose (object);
+}
+
+static void
+cal_base_shell_view_constructed (GObject *object)
+{
+       EShellWindow *shell_window;
+       EShellView *shell_view;
+       EShell *shell;
+       ECalBaseShellView *cal_base_shell_view = E_CAL_BASE_SHELL_VIEW (object);
+
+       /* Chain up to parent's constructed() method. */
+       G_OBJECT_CLASS (e_cal_base_shell_view_parent_class)->constructed (object);
+
+       shell_view = E_SHELL_VIEW (cal_base_shell_view);
+       shell_window = e_shell_view_get_shell_window (shell_view);
+       shell = e_shell_window_get_shell (shell_window);
+
+       cal_base_shell_view->priv->shell = g_object_ref (shell);
+       cal_base_shell_view->priv->prepare_for_quit_handler_id = g_signal_connect (
+               shell, "prepare-for-quit",
+               G_CALLBACK (cal_base_shell_view_prepare_for_quit_cb),
+               cal_base_shell_view);
+}
+
+static void
+e_cal_base_shell_view_class_init (ECalBaseShellViewClass *class)
+{
+       GObjectClass *object_class;
+
+       g_type_class_add_private (class, sizeof (ECalBaseShellViewPrivate));
+
+       object_class = G_OBJECT_CLASS (class);
+       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;
+}
+
+static void
+e_cal_base_shell_view_init (ECalBaseShellView *cal_base_shell_view)
+{
+       cal_base_shell_view->priv = E_CAL_BASE_SHELL_VIEW_GET_PRIVATE (cal_base_shell_view);
+}
+
+ECalClientSourceType
+e_cal_base_shell_view_get_source_type (EShellView *shell_view)
+{
+       ECalBaseShellViewClass *base_class;
+
+       g_return_val_if_fail (E_IS_CAL_BASE_SHELL_VIEW (shell_view), E_CAL_CLIENT_SOURCE_TYPE_LAST);
+
+       base_class = E_CAL_BASE_SHELL_VIEW_GET_CLASS (shell_view);
+       g_return_val_if_fail (base_class != NULL, E_CAL_CLIENT_SOURCE_TYPE_LAST);
+
+       return base_class->source_type;
+}
+
+static void
+cal_base_shell_view_allow_auth_prompt_and_refresh_done_cb (GObject *source_object,
+                                                          GAsyncResult *result,
+                                                          gpointer user_data)
+{
+       EClient *client;
+       EActivity *activity;
+       EAlertSink *alert_sink;
+       ESource *source;
+       const gchar *display_name;
+       GError *local_error = NULL;
+
+       g_return_if_fail (E_IS_CAL_CLIENT (source_object));
+
+       client = E_CLIENT (source_object);
+       source = e_client_get_source (client);
+       activity = user_data;
+       alert_sink = e_activity_get_alert_sink (activity);
+       display_name = e_source_get_display_name (source);
+
+       e_util_allow_auth_prompt_and_refresh_client_finish (client, result, &local_error);
+
+       if (e_activity_handle_cancellation (activity, local_error)) {
+               g_error_free (local_error);
+
+       } else if (local_error != NULL) {
+               const gchar *error_message;
+
+               switch (e_cal_client_get_source_type (E_CAL_CLIENT (client))) {
+               default:
+               case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+                       error_message = "calendar:refresh-error-events";
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+                       error_message = "calendar:refresh-error-tasks";
+                       break;
+               case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+                       error_message = "calendar:refresh-error-memos";
+                       break;
+               }
+               e_alert_submit (
+                       alert_sink,
+                       error_message,
+                       display_name, 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_allow_auth_prompt_and_refresh (EShellView *shell_view,
+                                                    EClient *client)
+{
+       EShellBackend *shell_backend;
+       EShellContent *shell_content;
+       EActivity *activity;
+       EAlertSink *alert_sink;
+       GCancellable *cancellable;
+
+       g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
+       g_return_if_fail (E_IS_CLIENT (client));
+
+       shell_backend = e_shell_view_get_shell_backend (shell_view);
+       shell_content = e_shell_view_get_shell_content (shell_view);
+
+       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);
+
+       e_util_allow_auth_prompt_and_refresh_client (client, cancellable,
+               cal_base_shell_view_allow_auth_prompt_and_refresh_done_cb, activity);
+
+       e_shell_backend_add_activity (shell_backend, activity);
+
+       g_object_unref (cancellable);
+}
+
+void
+e_cal_base_shell_view_model_row_appended (EShellView *shell_view,
+                                         ECalModel *model)
+{
+       EShellSidebar *shell_sidebar;
+       ESourceSelector *selector;
+       ESourceRegistry *registry;
+       ESource *source;
+       const gchar *source_uid;
+
+       g_return_if_fail (E_IS_CAL_BASE_SHELL_VIEW (shell_view));
+       g_return_if_fail (E_IS_CAL_MODEL (model));
+
+       /* This is the "Click to Add" handler. */
+
+       source_uid = e_cal_model_get_default_source_uid (model);
+       g_return_if_fail (source_uid != NULL);
+
+       registry = e_cal_model_get_registry (model);
+       shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+       selector = e_cal_base_shell_sidebar_get_selector (E_CAL_BASE_SHELL_SIDEBAR (shell_sidebar));
+
+       source = e_source_registry_ref_source (registry, source_uid);
+       g_return_if_fail (source != NULL);
+
+       /* Make sure the source where the component was added is selected,
+          thus the added component is visible in the view */
+       e_source_selector_select_source (selector, source);
+
+       g_clear_object (&source);
+}
+
+void
+e_cal_base_shell_view_copy_calendar (EShellView *shell_view)
+{
+       EShellContent *shell_content;
+       EShellSidebar *shell_sidebar;
+       EShellWindow *shell_window;
+       ESourceSelector *selector;
+       ESource *from_source;
+       ECalModel *model;
+
+       g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
+
+       shell_content = e_shell_view_get_shell_content (shell_view);
+       shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+       shell_window = e_shell_view_get_shell_window (shell_view);
+
+       g_return_if_fail (E_IS_CAL_BASE_SHELL_CONTENT (shell_content));
+       g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (shell_sidebar));
+
+       model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (shell_content));
+       selector = e_cal_base_shell_sidebar_get_selector (E_CAL_BASE_SHELL_SIDEBAR (shell_sidebar));
+
+       from_source = e_source_selector_ref_primary_selection (selector);
+       g_return_if_fail (from_source != NULL);
+
+       copy_source_dialog (GTK_WINDOW (shell_window), model, from_source);
+
+       g_clear_object (&from_source);
+}
diff --git a/modules/calendar/e-cal-base-shell-view.h b/modules/calendar/e-cal-base-shell-view.h
new file mode 100644
index 0000000..8cdcf5d
--- /dev/null
+++ b/modules/calendar/e-cal-base-shell-view.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Milan Crha <mcrha redhat com>
+ */
+
+#ifndef E_CAL_BASE_SHELL_VIEW_H
+#define E_CAL_BASE_SHELL_VIEW_H
+
+#include <e-util/e-util.h>
+#include <shell/e-shell-view.h>
+#include <calendar/gui/e-cal-model.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CAL_BASE_SHELL_VIEW \
+       (e_cal_base_shell_view_get_type ())
+#define E_CAL_BASE_SHELL_VIEW(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_CAL_BASE_SHELL_VIEW, ECalBaseShellView))
+#define E_CAL_BASE_SHELL_VIEW_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_CAL_BASE_SHELL_VIEW, ECalBaseShellViewClass))
+#define E_IS_CAL_BASE_SHELL_VIEW(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_CAL_BASE_SHELL_VIEW))
+#define E_IS_CAL_BASE_SHELL_VIEW_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_CAL_BASE_SHELL_VIEW))
+#define E_CAL_BASE_SHELL_VIEW_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_CAL_BASE_SHELL_VIEW, ECalBaseShellViewClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ECalBaseShellView ECalBaseShellView;
+typedef struct _ECalBaseShellViewClass ECalBaseShellViewClass;
+typedef struct _ECalBaseShellViewPrivate ECalBaseShellViewPrivate;
+
+struct _ECalBaseShellView {
+       EShellView parent;
+       ECalBaseShellViewPrivate *priv;
+};
+
+struct _ECalBaseShellViewClass {
+       EShellViewClass parent_class;
+
+       ECalClientSourceType source_type;
+};
+
+GType          e_cal_base_shell_view_get_type          (void);
+
+ECalClientSourceType
+               e_cal_base_shell_view_get_source_type   (EShellView *shell_view);
+
+void           e_cal_base_shell_view_allow_auth_prompt_and_refresh
+                                                       (EShellView *shell_view,
+                                                        EClient *client);
+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);
+
+G_END_DECLS
+
+#endif /* E_CAL_BASE_SHELL_VIEW_H */
diff --git a/modules/calendar/e-cal-shell-backend.c b/modules/calendar/e-cal-shell-backend.c
index 65f8802..a7b402c 100644
--- a/modules/calendar/e-cal-shell-backend.c
+++ b/modules/calendar/e-cal-shell-backend.c
@@ -1,5 +1,6 @@
 /*
- * e-cal-shell-backend.c
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
@@ -7,43 +8,30 @@
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
  * for more details.
  *
  * You should have received a copy of the GNU Lesser General Public License
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
  */
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
 
-#include "e-cal-shell-backend.h"
-
 #include <string.h>
 #include <glib/gi18n.h>
-#include <libecal/libecal.h>
 
-#include "shell/e-shell.h"
-#include "shell/e-shell-backend.h"
-#include "shell/e-shell-window.h"
+#include <calendar/gui/e-calendar-view.h>
+#include <calendar/gui/e-cal-ops.h>
+#include <calendar/importers/evolution-calendar-importer.h>
 
-#include "calendar/gui/comp-util.h"
-#include "calendar/gui/dialogs/event-editor.h"
-#include "calendar/gui/e-calendar-view.h"
-#include "calendar/gui/gnome-cal.h"
-#include "calendar/importers/evolution-calendar-importer.h"
+#include "e-calendar-preferences.h"
 
+#include "e-cal-base-shell-sidebar.h"
 #include "e-cal-shell-content.h"
-#include "e-cal-shell-migrate.h"
-#include "e-cal-shell-sidebar.h"
 #include "e-cal-shell-view.h"
-
-#include "e-calendar-preferences.h"
+#include "e-cal-shell-backend.h"
 
 #define E_CAL_SHELL_BACKEND_GET_PRIVATE(obj) \
        (G_TYPE_INSTANCE_GET_PRIVATE \
@@ -53,144 +41,7 @@ struct _ECalShellBackendPrivate {
        gint placeholder;
 };
 
-G_DEFINE_DYNAMIC_TYPE (
-       ECalShellBackend,
-       e_cal_shell_backend,
-       E_TYPE_SHELL_BACKEND)
-
-static void
-cal_shell_backend_new_event (ECalClient *cal_client,
-                             EShell *shell,
-                             CompEditorFlags flags,
-                             gboolean all_day)
-{
-       ECalComponent *comp;
-       GSettings *settings;
-       CompEditor *editor;
-
-       settings = g_settings_new ("org.gnome.evolution.calendar");
-
-       editor = event_editor_new (cal_client, shell, flags);
-       comp = cal_comp_event_new_with_current_time (
-               cal_client, all_day,
-               g_settings_get_boolean (settings, "use-default-reminder"),
-               g_settings_get_int (settings, "default-reminder-interval"),
-               g_settings_get_enum (settings, "default-reminder-units"));
-       e_cal_component_commit_sequence (comp);
-       comp_editor_edit_comp (editor, comp);
-
-       gtk_window_present (GTK_WINDOW (editor));
-
-       g_object_unref (comp);
-
-       g_object_unref (settings);
-}
-
-static void
-cal_shell_backend_event_new_cb (GObject *source_object,
-                                GAsyncResult *result,
-                                gpointer user_data)
-{
-       EShell *shell = E_SHELL (user_data);
-       EClient *client;
-       CompEditorFlags flags = 0;
-       gboolean all_day = FALSE;
-       GError *error = NULL;
-
-       flags |= COMP_EDITOR_NEW_ITEM;
-       flags |= COMP_EDITOR_USER_ORG;
-
-       client = e_client_cache_get_client_finish (
-               E_CLIENT_CACHE (source_object), result, &error);
-
-       /* Sanity check. */
-       g_return_if_fail (
-               ((client != NULL) && (error == NULL)) ||
-               ((client == NULL) && (error != NULL)));
-
-       if (client != NULL) {
-               cal_shell_backend_new_event (
-                       E_CAL_CLIENT (client), shell, flags, all_day);
-               g_object_unref (client);
-       } else {
-               /* XXX Handle errors better. */
-               g_warning ("%s: %s", G_STRFUNC, error->message);
-               g_error_free (error);
-       }
-
-       g_object_unref (shell);
-}
-
-static void
-cal_shell_backend_event_all_day_new_cb (GObject *source_object,
-                                        GAsyncResult *result,
-                                        gpointer user_data)
-{
-       EShell *shell = E_SHELL (user_data);
-       EClient *client;
-       CompEditorFlags flags = 0;
-       gboolean all_day = TRUE;
-       GError *error = NULL;
-
-       flags |= COMP_EDITOR_NEW_ITEM;
-       flags |= COMP_EDITOR_USER_ORG;
-
-       client = e_client_cache_get_client_finish (
-               E_CLIENT_CACHE (source_object), result, &error);
-
-       /* Sanity check. */
-       g_return_if_fail (
-               ((client != NULL) && (error == NULL)) ||
-               ((client == NULL) && (error != NULL)));
-
-       if (client != NULL) {
-               cal_shell_backend_new_event (
-                       E_CAL_CLIENT (client), shell, flags, all_day);
-               g_object_unref (client);
-       } else {
-               /* XXX Handle errors better. */
-               g_warning ("%s: %s", G_STRFUNC, error->message);
-               g_error_free (error);
-       }
-
-       g_object_unref (shell);
-}
-
-static void
-cal_shell_backend_event_meeting_new_cb (GObject *source_object,
-                                        GAsyncResult *result,
-                                        gpointer user_data)
-{
-       EShell *shell = E_SHELL (user_data);
-       EClient *client;
-       CompEditorFlags flags = 0;
-       gboolean all_day = FALSE;
-       GError *error = NULL;
-
-       flags |= COMP_EDITOR_NEW_ITEM;
-       flags |= COMP_EDITOR_USER_ORG;
-       flags |= COMP_EDITOR_MEETING;
-
-       client = e_client_cache_get_client_finish (
-               E_CLIENT_CACHE (source_object), result, &error);
-
-       /* Sanity check. */
-       g_return_if_fail (
-               ((client != NULL) && (error == NULL)) ||
-               ((client == NULL) && (error != NULL)));
-
-       if (client != NULL) {
-               cal_shell_backend_new_event (
-                       E_CAL_CLIENT (client), shell, flags, all_day);
-               g_object_unref (client);
-       } else {
-               /* XXX Handle errors better. */
-               g_warning ("%s: %s", G_STRFUNC, error->message);
-               g_error_free (error);
-       }
-
-       g_object_unref (shell);
-}
+G_DEFINE_DYNAMIC_TYPE (ECalShellBackend, e_cal_shell_backend, E_TYPE_CAL_BASE_SHELL_BACKEND)
 
 static void
 action_event_new_cb (GtkAction *action,
@@ -199,33 +50,29 @@ action_event_new_cb (GtkAction *action,
        EShell *shell;
        EShellView *shell_view;
        EShellBackend *shell_backend;
-       ESource *source;
-       ESourceRegistry *registry;
-       EClientCache *client_cache;
+       GSettings *settings;
        const gchar *action_name;
+       gboolean is_all_day;
+       gboolean is_meeting;
 
        shell = e_shell_window_get_shell (shell_window);
-       client_cache = e_shell_get_client_cache (shell);
 
        action_name = gtk_action_get_name (action);
+       is_all_day = g_strcmp0 (action_name, "event-all-day-new") == 0;
+       is_meeting = g_strcmp0 (action_name, "event-meeting-new") == 0;
 
        /* With a 'calendar' active shell view pass the new appointment
         * request to it, thus the event will inherit selected time from
         * the view. */
        shell_view = e_shell_window_peek_shell_view (shell_window, "calendar");
        if (shell_view != NULL) {
-               EShellWindow *shell_window;
                EShellContent *shell_content;
-               GnomeCalendar *gcal;
-               GnomeCalendarViewType view_type;
                ECalendarView *view;
 
                shell_backend = e_shell_view_get_shell_backend (shell_view);
                shell_content = e_shell_view_get_shell_content (shell_view);
-               shell_window = e_shell_view_get_shell_window (shell_view);
 
-               e_shell_backend_set_prefer_new_item (
-                       shell_backend, action_name);
+               e_shell_backend_set_prefer_new_item (shell_backend, action_name);
 
                /* This forces the shell window to update the "New" toolbar
                 * button menu, and the toolbar button will then update its
@@ -233,85 +80,31 @@ action_event_new_cb (GtkAction *action,
                 * set on the shell backend. */
                g_object_notify (G_OBJECT (shell_window), "active-view");
 
-               gcal = e_cal_shell_content_get_calendar (
-                       E_CAL_SHELL_CONTENT (shell_content));
-
-               view_type = gnome_calendar_get_view (gcal);
-               view = gnome_calendar_get_calendar_view (gcal, view_type);
-
+               view = e_cal_shell_content_get_current_calendar_view (E_CAL_SHELL_CONTENT (shell_content));
                if (view != NULL) {
-                       e_calendar_view_new_appointment_full (
-                               view,
-                               g_str_equal (action_name, "event-all-day-new"),
-                               g_str_equal (action_name, "event-meeting-new"),
-                               TRUE);
-
+                       e_calendar_view_new_appointment_full (view, is_all_day, is_meeting, TRUE);
                        return;
                }
        }
 
-       /* This callback is used for both appointments and meetings. */
-
-       registry = e_shell_get_registry (shell);
-       source = e_source_registry_ref_default_calendar (registry);
-
        shell_backend = e_shell_get_backend_by_name (shell, "calendar");
        e_shell_backend_set_prefer_new_item (shell_backend, action_name);
 
-       /* Use a callback function appropriate for the action. */
-       if (strcmp (action_name, "event-all-day-new") == 0)
-               e_client_cache_get_client (
-                       client_cache, source,
-                       E_SOURCE_EXTENSION_CALENDAR,
-                       NULL,
-                       cal_shell_backend_event_all_day_new_cb,
-                       g_object_ref (shell));
-       else if (strcmp (action_name, "event-meeting-new") == 0)
-               e_client_cache_get_client (
-                       client_cache, source,
-                       E_SOURCE_EXTENSION_CALENDAR,
-                       NULL,
-                       cal_shell_backend_event_meeting_new_cb,
-                       g_object_ref (shell));
-       else
-               e_client_cache_get_client (
-                       client_cache, source,
-                       E_SOURCE_EXTENSION_CALENDAR,
-                       NULL,
-                       cal_shell_backend_event_new_cb,
-                       g_object_ref (shell));
-
-       g_object_unref (source);
+       settings = g_settings_new ("org.gnome.evolution.calendar");
+
+       e_cal_ops_new_event_editor (shell_window, NULL, is_meeting, is_all_day,
+               g_settings_get_boolean (settings, "use-default-reminder"),
+               g_settings_get_int (settings, "default-reminder-interval"),
+               g_settings_get_enum (settings, "default-reminder-units"));
+
+       g_clear_object (&settings);
 }
 
 static void
 action_calendar_new_cb (GtkAction *action,
                         EShellWindow *shell_window)
 {
-       EShell *shell;
-       ESourceRegistry *registry;
-       ECalClientSourceType source_type;
-       GtkWidget *config;
-       GtkWidget *dialog;
-       const gchar *icon_name;
-
-       shell = e_shell_window_get_shell (shell_window);
-
-       registry = e_shell_get_registry (shell);
-       source_type = E_CAL_CLIENT_SOURCE_TYPE_EVENTS;
-       config = e_cal_source_config_new (registry, NULL, source_type);
-
-       dialog = e_source_config_dialog_new (E_SOURCE_CONFIG (config));
-
-       gtk_window_set_transient_for (
-               GTK_WINDOW (dialog), GTK_WINDOW (shell_window));
-
-       icon_name = gtk_action_get_icon_name (action);
-       gtk_window_set_icon_name (GTK_WINDOW (dialog), icon_name);
-
-       gtk_window_set_title (GTK_WINDOW (dialog), _("New Calendar"));
-
-       gtk_widget_show (dialog);
+       e_cal_base_shell_backend_util_new_source (shell_window, E_CAL_CLIENT_SOURCE_TYPE_EVENTS);
 }
 
 static GtkActionEntry item_entries[] = {
@@ -349,282 +142,46 @@ static GtkActionEntry source_entries[] = {
 };
 
 static void
-cal_shell_backend_init_importers (void)
+cal_shell_backend_handle_uri_start_end_dates (EShellBackend *shell_backend,
+                                             const GDate *start_date,
+                                             const GDate *end_date)
 {
-       EImportClass *import_class;
-       EImportImporter *importer;
-
-       import_class = g_type_class_ref (e_import_get_type ());
-
-       importer = gnome_calendar_importer_peek ();
-       e_import_class_add_importer (import_class, importer, NULL, NULL);
-
-       importer = ical_importer_peek ();
-       e_import_class_add_importer (import_class, importer, NULL, NULL);
-
-       importer = vcal_importer_peek ();
-       e_import_class_add_importer (import_class, importer, NULL, NULL);
-}
+       g_return_if_fail (E_IS_CAL_SHELL_BACKEND (shell_backend));
+       g_return_if_fail (g_date_valid (start_date));
 
-static void
-populate_g_date (GDate *date,
-                 time_t utc_time,
-                 icaltimezone *zone)
-{
-       struct icaltimetype icaltm;
-
-       g_return_if_fail (date != NULL);
-
-       if ((gint) utc_time == -1)
-               return;
-
-       if (zone)
-               icaltm = icaltime_from_timet_with_zone (utc_time, FALSE, zone);
+       if (g_date_valid (end_date))
+               e_cal_shell_backend_open_date_range (E_CAL_SHELL_BACKEND (shell_backend), start_date, 
end_date);
        else
-               icaltm = icaltime_from_timet (utc_time, FALSE);
-
-       if (icaltime_is_null_time (icaltm) ||
-           !icaltime_is_valid_time (icaltm))
-               return;
-
-       g_date_set_dmy (date, icaltm.day, icaltm.month, icaltm.year);
+               e_cal_shell_backend_open_date_range (E_CAL_SHELL_BACKEND (shell_backend), start_date, NULL);
 }
 
 static gboolean
-cal_shell_backend_handle_uri_cb (EShellBackend *shell_backend,
-                                 const gchar *uri)
+e_cal_shell_backend_handle_uri (EShellBackend *shell_backend,
+                               const gchar *uri)
 {
-       EShell *shell;
-       CompEditor *editor;
-       CompEditorFlags flags = 0;
-       EClient *client;
-       EClientCache *client_cache;
-       ECalComponent *comp;
-       ESource *source;
-       ESourceRegistry *registry;
-       GSettings *settings;
-       SoupURI *soup_uri;
-       icalcomponent *icalcomp;
-       icalproperty *icalprop;
-       const gchar *cp;
-       gchar *source_uid = NULL;
-       gchar *comp_uid = NULL;
-       gchar *comp_rid = NULL;
-       GDate start_date;
-       GDate end_date;
-       icaltimezone *zone = NULL;
-       gboolean handled = FALSE;
-       GError *error = NULL;
-
-       shell = e_shell_backend_get_shell (shell_backend);
-       client_cache = e_shell_get_client_cache (shell);
-
        if (strncmp (uri, "calendar:", 9) != 0)
                return FALSE;
 
-       soup_uri = soup_uri_new (uri);
-
-       if (soup_uri == NULL)
-               return FALSE;
-
-       cp = soup_uri_get_query (soup_uri);
-       if (cp == NULL)
-               goto exit;
-
-       g_date_clear (&start_date, 1);
-       g_date_clear (&end_date, 1);
-
-       settings = g_settings_new ("org.gnome.evolution.calendar");
-
-       if (g_settings_get_boolean (settings, "use-system-timezone"))
-               zone = e_cal_util_get_system_timezone ();
-       else {
-               gchar *location;
-
-               location = g_settings_get_string (settings, "timezone");
-
-               if (location != NULL) {
-                       zone = icaltimezone_get_builtin_timezone (location);
-                       g_free (location);
-               }
-       }
-
-       if (zone == NULL)
-               zone = icaltimezone_get_utc_timezone ();
-
-       g_object_unref (settings);
-
-       while (*cp != '\0') {
-               gchar *header;
-               gchar *content;
-               gsize header_len;
-               gsize content_len;
-
-               header_len = strcspn (cp, "=&");
-
-               /* It it's malformed, give up. */
-               if (cp[header_len] != '=')
-                       break;
-
-               header = (gchar *) cp;
-               header[header_len] = '\0';
-               cp += header_len + 1;
-
-               content_len = strcspn (cp, "&");
-
-               content = g_strndup (cp, content_len);
-               if (g_ascii_strcasecmp (header, "startdate") == 0)
-                       populate_g_date (&start_date, time_from_isodate (content), zone);
-               else if (g_ascii_strcasecmp (header, "enddate") == 0)
-                       populate_g_date (&end_date, time_from_isodate (content), zone);
-               else if (g_ascii_strcasecmp (header, "source-uid") == 0)
-                       source_uid = g_strdup (content);
-               else if (g_ascii_strcasecmp (header, "comp-uid") == 0)
-                       comp_uid = g_strdup (content);
-               else if (g_ascii_strcasecmp (header, "comp-rid") == 0)
-                       comp_rid = g_strdup (content);
-               g_free (content);
-
-               cp += content_len;
-               if (*cp == '&') {
-                       cp++;
-                       if (strncmp (cp, "amp;", 4) == 0)
-                               cp += 4;
-               }
-       }
-
-       /* This is primarily for launching Evolution
-        * from the calendar in the clock applet. */
-       if (g_date_valid (&start_date)) {
-               if (g_date_valid (&end_date))
-                       e_cal_shell_backend_open_date_range (
-                               E_CAL_SHELL_BACKEND (shell_backend),
-                               &start_date, &end_date);
-               else
-                       e_cal_shell_backend_open_date_range (
-                               E_CAL_SHELL_BACKEND (shell_backend),
-                               &start_date, NULL);
-               handled = TRUE;
-               goto exit;
-       }
-
-       if (source_uid == NULL || comp_uid == NULL)
-               goto exit;
-
-       /* URI is valid, so consider it handled.  Whether
-        * we successfully open it is another matter... */
-       handled = TRUE;
-
-       registry = e_shell_get_registry (shell);
-       source = e_source_registry_ref_source (registry, source_uid);
-       if (source == NULL) {
-               g_printerr ("No source for UID '%s'\n", source_uid);
-               goto exit;
-       }
-
-       client = e_client_cache_get_client_sync (
-               client_cache, source,
-               E_SOURCE_EXTENSION_CALENDAR,
-               NULL, &error);
-
-       /* Sanity check. */
-       g_return_val_if_fail (
-               ((client != NULL) && (error == NULL)) ||
-               ((client == NULL) && (error != NULL)), FALSE);
-
-       if (error != NULL) {
-               g_warning (
-                       "%s: Failed to create/open client '%s': %s",
-                       G_STRFUNC, e_source_get_display_name (source),
-                       error->message);
-               g_object_unref (source);
-               g_error_free (error);
-               goto exit;
-       }
-
-       g_object_unref (source);
-       source = NULL;
-
-       /* XXX Copied from e_cal_shell_view_open_event().
-        *     Clearly a new utility function is needed. */
-
-       editor = comp_editor_find_instance (comp_uid);
-
-       if (editor != NULL)
-               goto present;
-
-       e_cal_client_get_object_sync (
-               E_CAL_CLIENT (client),comp_uid,
-               comp_rid, &icalcomp, NULL, &error);
-
-       if (error != NULL) {
-               g_warning (
-                       "%s: Failed to get object from client: %s",
-                       G_STRFUNC, error->message);
-               g_object_unref (client);
-               g_error_free (error);
-               goto exit;
-       }
-
-       comp = e_cal_component_new ();
-       if (!e_cal_component_set_icalcomponent (comp, icalcomp)) {
-               g_warning ("%s: Failed to set icalcomp to comp\n", G_STRFUNC);
-               icalcomponent_free (icalcomp);
-               icalcomp = NULL;
-       }
-
-       icalprop = icalcomp ? icalcomponent_get_first_property (
-               icalcomp, ICAL_ATTENDEE_PROPERTY) : NULL;
-       if (icalprop != NULL)
-               flags |= COMP_EDITOR_MEETING;
-
-       if (itip_organizer_is_user (registry, comp, E_CAL_CLIENT (client)))
-               flags |= COMP_EDITOR_USER_ORG;
-
-       if (itip_sentby_is_user (registry, comp, E_CAL_CLIENT (client)))
-               flags |= COMP_EDITOR_USER_ORG;
-
-       if (!e_cal_component_has_attendees (comp))
-               flags |= COMP_EDITOR_USER_ORG;
-
-       editor = event_editor_new (E_CAL_CLIENT (client), shell, flags);
-       comp_editor_edit_comp (editor, comp);
-
-       g_object_unref (comp);
-
-present:
-       gtk_window_present (GTK_WINDOW (editor));
-
-       g_object_unref (client);
-
-exit:
-       g_free (source_uid);
-       g_free (comp_uid);
-       g_free (comp_rid);
-
-       soup_uri_free (soup_uri);
-
-       return handled;
+       return e_cal_base_shell_backend_util_handle_uri (shell_backend,
+               E_CAL_CLIENT_SOURCE_TYPE_TASKS, uri, cal_shell_backend_handle_uri_start_end_dates);
 }
 
 static void
-cal_shell_backend_window_added_cb (EShellBackend *shell_backend,
-                                   GtkWindow *window)
+cal_shell_backend_init_importers (void)
 {
-       const gchar *backend_name;
+       EImportClass *import_class;
+       EImportImporter *importer;
 
-       if (!E_IS_SHELL_WINDOW (window))
-               return;
+       import_class = g_type_class_ref (e_import_get_type ());
 
-       backend_name = E_SHELL_BACKEND_GET_CLASS (shell_backend)->name;
+       importer = gnome_calendar_importer_peek ();
+       e_import_class_add_importer (import_class, importer, NULL, NULL);
 
-       e_shell_window_register_new_item_actions (
-               E_SHELL_WINDOW (window), backend_name,
-               item_entries, G_N_ELEMENTS (item_entries));
+       importer = ical_importer_peek ();
+       e_import_class_add_importer (import_class, importer, NULL, NULL);
 
-       e_shell_window_register_new_source_actions (
-               E_SHELL_WINDOW (window), backend_name,
-               source_entries, G_N_ELEMENTS (source_entries));
+       importer = vcal_importer_peek ();
+       e_import_class_add_importer (import_class, importer, NULL, NULL);
 }
 
 static void
@@ -682,28 +239,14 @@ cal_shell_backend_use_system_timezone_changed_cb (GSettings *settings,
 static void
 cal_shell_backend_constructed (GObject *object)
 {
-       EShell *shell;
        EShellBackend *shell_backend;
        GtkWidget *preferences_window;
        GSettings *settings;
 
        shell_backend = E_SHELL_BACKEND (object);
-       shell = e_shell_backend_get_shell (shell_backend);
-
-       g_signal_connect_swapped (
-               shell, "handle-uri",
-               G_CALLBACK (cal_shell_backend_handle_uri_cb),
-               shell_backend);
-
-       g_signal_connect_swapped (
-               shell, "window-added",
-               G_CALLBACK (cal_shell_backend_window_added_cb),
-               shell_backend);
-
-       cal_shell_backend_init_importers ();
 
        /* Setup preference widget factories */
-       preferences_window = e_shell_get_preferences_window (shell);
+       preferences_window = e_shell_get_preferences_window (e_shell_backend_get_shell (shell_backend));
 
        e_preferences_window_add_page (
                E_PREFERENCES_WINDOW (preferences_window),
@@ -734,6 +277,8 @@ cal_shell_backend_constructed (GObject *object)
        /* Chain up to parent's constructed() method. */
        G_OBJECT_CLASS (e_cal_shell_backend_parent_class)->constructed (object);
 
+       cal_shell_backend_init_importers ();
+
        ensure_alarm_notify_is_running ();
 }
 
@@ -742,6 +287,7 @@ e_cal_shell_backend_class_init (ECalShellBackendClass *class)
 {
        GObjectClass *object_class;
        EShellBackendClass *shell_backend_class;
+       ECalBaseShellBackendClass *cal_base_shell_backend_class;
 
        g_type_class_add_private (class, sizeof (ECalShellBackendPrivate));
 
@@ -756,48 +302,24 @@ e_cal_shell_backend_class_init (ECalShellBackendClass *class)
        shell_backend_class->sort_order = 400;
        shell_backend_class->preferences_page = "calendar-and-tasks";
        shell_backend_class->start = NULL;
-       shell_backend_class->migrate = e_cal_shell_backend_migrate;
 
-       /* Register relevant ESource extensions. */
-       E_TYPE_SOURCE_CALENDAR;
+       cal_base_shell_backend_class = E_CAL_BASE_SHELL_BACKEND_CLASS (class);
+       cal_base_shell_backend_class->new_item_entries = item_entries;
+       cal_base_shell_backend_class->new_item_n_entries = G_N_ELEMENTS (item_entries);
+       cal_base_shell_backend_class->source_entries = source_entries;
+       cal_base_shell_backend_class->source_n_entries = G_N_ELEMENTS (source_entries);
+       cal_base_shell_backend_class->handle_uri = e_cal_shell_backend_handle_uri;
 }
 
 static void
-e_cal_shell_backend_class_finalize (ECalShellBackendClass *class)
+e_cal_shell_backend_init (ECalShellBackend *cal_shell_backend)
 {
+       cal_shell_backend->priv = E_CAL_SHELL_BACKEND_GET_PRIVATE (cal_shell_backend);
 }
 
 static void
-e_cal_shell_backend_init (ECalShellBackend *cal_shell_backend)
+e_cal_shell_backend_class_finalize (ECalShellBackendClass *class)
 {
-       icalarray *builtin_timezones;
-       gint ii;
-
-       cal_shell_backend->priv =
-               E_CAL_SHELL_BACKEND_GET_PRIVATE (cal_shell_backend);
-
-       /* XXX Pre-load all built-in timezones in libical.
-        *
-        *     Built-in time zones in libical 0.43 are loaded on demand,
-        *     but not in a thread-safe manner, resulting in a race when
-        *     multiple threads call icaltimezone_load_builtin_timezone()
-        *     on the same time zone.  Until built-in time zone loading
-        *     in libical is made thread-safe, work around the issue by
-        *     loading all built-in time zones now, so libical's internal
-        *     time zone array will be fully populated before any threads
-        *     are spawned.
-        */
-       builtin_timezones = icaltimezone_get_builtin_timezones ();
-       for (ii = 0; ii < builtin_timezones->num_elements; ii++) {
-               icaltimezone *zone;
-
-               zone = icalarray_element_at (builtin_timezones, ii);
-
-               /* We don't care about the component right now,
-                * we just need some function that will trigger
-                * icaltimezone_load_builtin_timezone(). */
-               icaltimezone_get_component (zone);
-       }
 }
 
 void
@@ -820,7 +342,7 @@ e_cal_shell_backend_open_date_range (ECalShellBackend *cal_shell_backend,
        EShellSidebar *shell_sidebar;
        GtkWidget *shell_window = NULL;
        GtkApplication *application;
-       ECalendar *navigator;
+       ECalendar *calendar;
        GList *list;
 
        g_return_if_fail (E_IS_CAL_SHELL_BACKEND (cal_shell_backend));
@@ -838,8 +360,7 @@ e_cal_shell_backend_open_date_range (ECalShellBackend *cal_shell_backend,
                if (E_IS_SHELL_WINDOW (window)) {
                        const gchar *active_view;
 
-                       active_view = e_shell_window_get_active_view (
-                               E_SHELL_WINDOW (window));
+                       active_view = e_shell_window_get_active_view (E_SHELL_WINDOW (window));
                        if (g_strcmp0 (active_view, "calendar") == 0) {
                                gtk_window_present (GTK_WINDOW (window));
                                shell_window = window;
@@ -856,12 +377,9 @@ e_cal_shell_backend_open_date_range (ECalShellBackend *cal_shell_backend,
 
        /* Now dig up the date navigator and select the date range. */
 
-       shell_view = e_shell_window_get_shell_view (
-               E_SHELL_WINDOW (shell_window), "calendar");
+       shell_view = e_shell_window_get_shell_view (E_SHELL_WINDOW (shell_window), "calendar");
        shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
-       navigator = e_cal_shell_sidebar_get_date_navigator (
-               E_CAL_SHELL_SIDEBAR (shell_sidebar));
+       calendar = e_cal_base_shell_sidebar_get_date_navigator (E_CAL_BASE_SHELL_SIDEBAR (shell_sidebar));
 
-       e_calendar_item_set_selection (
-               navigator->calitem, start_date, end_date);
+       e_calendar_item_set_selection (calendar->calitem, start_date, end_date);
 }
diff --git a/modules/calendar/e-cal-shell-backend.h b/modules/calendar/e-cal-shell-backend.h
index 7938fde..84c2a76 100644
--- a/modules/calendar/e-cal-shell-backend.h
+++ b/modules/calendar/e-cal-shell-backend.h
@@ -1,5 +1,6 @@
 /*
- * e-cal-shell-backend.h
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
@@ -7,21 +8,17 @@
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
  * for more details.
  *
  * You should have received a copy of the GNU Lesser General Public License
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
  */
 
 #ifndef E_CAL_SHELL_BACKEND_H
 #define E_CAL_SHELL_BACKEND_H
 
-#include <shell/e-shell-backend.h>
+#include "e-cal-base-shell-backend.h"
 
 /* Standard GObject macros */
 #define E_TYPE_CAL_SHELL_BACKEND \
@@ -49,21 +46,19 @@ typedef struct _ECalShellBackendClass ECalShellBackendClass;
 typedef struct _ECalShellBackendPrivate ECalShellBackendPrivate;
 
 struct _ECalShellBackend {
-       EShellBackend parent;
+       ECalBaseShellBackend parent;
        ECalShellBackendPrivate *priv;
 };
 
 struct _ECalShellBackendClass {
-       EShellBackendClass parent_class;
+       ECalBaseShellBackendClass parent_class;
 };
 
-GType          e_cal_shell_backend_get_type    (void);
-void           e_cal_shell_backend_type_register
-                                       (GTypeModule *type_module);
-void           e_cal_shell_backend_open_date_range
-                                       (ECalShellBackend *cal_shell_backend,
-                                        const GDate *start_date,
-                                        const GDate *end_date);
+GType          e_cal_shell_backend_get_type            (void);
+void           e_cal_shell_backend_type_register       (GTypeModule *type_module);
+void           e_cal_shell_backend_open_date_range     (ECalShellBackend *cal_shell_backend,
+                                                        const GDate *start_date,
+                                                        const GDate *end_date);
 
 G_END_DECLS
 
diff --git a/modules/calendar/e-cal-shell-content.c b/modules/calendar/e-cal-shell-content.c
index 5d1066e..b128f7b 100644
--- a/modules/calendar/e-cal-shell-content.c
+++ b/modules/calendar/e-cal-shell-content.c
@@ -1,5 +1,6 @@
 /*
- * e-cal-shell-content.c
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
@@ -7,35 +8,37 @@
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
  * for more details.
  *
  * You should have received a copy of the GNU Lesser General Public License
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
  */
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
 
-#include "e-cal-shell-content.h"
-
 #include <string.h>
-#include <glib/gi18n.h>
+#include <math.h>
+#include <glib/gi18n-lib.h>
 
 #include "calendar/gui/calendar-config.h"
 #include "calendar/gui/calendar-view.h"
+#include "calendar/gui/comp-util.h"
 #include "calendar/gui/e-cal-list-view.h"
 #include "calendar/gui/e-cal-model-calendar.h"
+#include "calendar/gui/e-cal-model-memos.h"
+#include "calendar/gui/e-cal-model-tasks.h"
 #include "calendar/gui/e-calendar-view.h"
 #include "calendar/gui/e-day-view.h"
+#include "calendar/gui/e-month-view.h"
 #include "calendar/gui/e-week-view.h"
+#include "calendar/gui/tag-calendar.h"
 
+#include "e-cal-base-shell-sidebar.h"
 #include "e-cal-shell-view-private.h"
+#include "e-cal-shell-content.h"
 
 #define E_CAL_SHELL_CONTENT_GET_PRIVATE(obj) \
        (G_TYPE_INSTANCE_GET_PRIVATE \
@@ -43,534 +46,680 @@
 
 struct _ECalShellContentPrivate {
        GtkWidget *hpaned;
-       GtkWidget *notebook;
        GtkWidget *vpaned;
 
-       GtkWidget *calendar;
+       GtkWidget *calendar_notebook;
        GtkWidget *task_table;
+       ECalModel *task_model;
+       ECalDataModel *task_data_model;
+
        GtkWidget *memo_table;
+       ECalModel *memo_model;
+       ECalDataModel *memo_data_model;
+
+       ETagCalendar *tag_calendar;
+       gulong datepicker_selection_changed_id;
+       gulong datepicker_range_moved_id;
+
+       ECalViewKind current_view;
+       ECalendarView *views[E_CAL_VIEW_KIND_LAST];
+       GDate view_start, view_end;
+       guint32 view_start_range_day_offset;
+       GDate last_range_start; /* because "date-range-changed" can be emit with no real change */
+
+       gulong current_view_id_changed_id;
 };
 
 enum {
        PROP_0,
-       PROP_CALENDAR,
+       PROP_CALENDAR_NOTEBOOK,
        PROP_MEMO_TABLE,
-       PROP_TASK_TABLE
+       PROP_TASK_TABLE,
+       PROP_CURRENT_VIEW_ID,
+       PROP_CURRENT_VIEW
 };
 
 /* Used to indicate who has the focus within the calendar view. */
 typedef enum {
-       FOCUS_CALENDAR,
+       FOCUS_CALENDAR_NOTEBOOK,
        FOCUS_MEMO_TABLE,
        FOCUS_TASK_TABLE,
        FOCUS_OTHER
 } FocusLocation;
 
-G_DEFINE_DYNAMIC_TYPE (
-       ECalShellContent,
-       e_cal_shell_content,
-       E_TYPE_SHELL_CONTENT)
+G_DEFINE_DYNAMIC_TYPE (ECalShellContent, e_cal_shell_content, E_TYPE_CAL_BASE_SHELL_CONTENT)
 
-static void
-cal_shell_content_display_view_cb (ECalShellContent *cal_shell_content,
-                                   GalView *gal_view)
+static time_t
+convert_to_local_zone (time_t tm,
+                      icaltimezone *from_zone)
 {
-       GnomeCalendar *calendar;
-       GnomeCalendarViewType view_type;
-       GType gal_view_type;
-
-       gal_view_type = G_OBJECT_TYPE (gal_view);
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-
-       if (gal_view_type == GAL_TYPE_VIEW_ETABLE) {
-               ECalendarView *calendar_view;
-
-               view_type = GNOME_CAL_LIST_VIEW;
-               calendar_view = gnome_calendar_get_calendar_view (
-                       calendar, view_type);
-               gal_view_etable_attach_table (
-                       GAL_VIEW_ETABLE (gal_view),
-                       E_CAL_LIST_VIEW (calendar_view)->table);
-
-       } else if (gal_view_type == GAL_TYPE_VIEW_CALENDAR_DAY) {
-               view_type = GNOME_CAL_DAY_VIEW;
-
-       } else if (gal_view_type == GAL_TYPE_VIEW_CALENDAR_WORK_WEEK) {
-               view_type = GNOME_CAL_WORK_WEEK_VIEW;
-
-       } else if (gal_view_type == GAL_TYPE_VIEW_CALENDAR_WEEK) {
-               view_type = GNOME_CAL_WEEK_VIEW;
-
-       } else if (gal_view_type == GAL_TYPE_VIEW_CALENDAR_MONTH) {
-               view_type = GNOME_CAL_MONTH_VIEW;
+       struct icaltimetype tt;
 
-       } else {
-               g_return_if_reached ();
-       }
-
-       gnome_calendar_display_view (calendar, view_type);
+       tt = icaltime_from_timet_with_zone (tm, FALSE, from_zone);
+       return icaltime_as_timet (tt);
 }
 
 static void
-cal_shell_content_notify_view_id_cb (ECalShellContent *cal_shell_content)
+cal_shell_content_update_model_and_current_view_times (ECalShellContent *cal_shell_content,
+                                                      ECalModel *model,
+                                                      ECalendarItem *calitem,
+                                                      time_t view_start_tt,
+                                                      time_t view_end_tt,
+                                                      const GDate *view_start,
+                                                      const GDate *view_end)
 {
-       EShellContent *shell_content;
-       EShellView *shell_view;
-       GSettings *settings;
-       GtkWidget *paned;
-       const gchar *key;
-       const gchar *view_id;
+       ECalendarView *current_view;
+       gint syy, smm, sdd, eyy, emm, edd;
+       time_t visible_range_start, visible_range_end;
+       gboolean filters_updated = FALSE;
+       icaltimezone *zone;
+       gchar *cal_filter;
 
-       settings = g_settings_new ("org.gnome.evolution.calendar");
-       paned = cal_shell_content->priv->hpaned;
+       g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
+       g_return_if_fail (E_IS_CAL_MODEL (model));
+       g_return_if_fail (E_IS_CALENDAR_ITEM (calitem));
 
-       shell_content = E_SHELL_CONTENT (cal_shell_content);
-       shell_view = e_shell_content_get_shell_view (shell_content);
-       view_id = e_shell_view_get_view_id (shell_view);
+       current_view = e_cal_shell_content_get_current_calendar_view (cal_shell_content);
+       g_return_if_fail (current_view != NULL);
 
-       if (view_id != NULL && strcmp (view_id, "Month_View") == 0)
-               key = "month-hpane-position";
-       else
-               key = "hpane-position";
+       zone = e_cal_model_get_timezone (model);
+       cal_filter = e_cal_data_model_dup_filter (e_cal_model_get_data_model (model));
 
-       g_settings_unbind (paned, "hposition");
+       g_signal_handler_block (calitem, cal_shell_content->priv->datepicker_range_moved_id);
+       g_signal_handler_block (calitem, cal_shell_content->priv->datepicker_selection_changed_id);
 
-       g_settings_bind (
-               settings, key,
-               paned, "hposition",
-               G_SETTINGS_BIND_DEFAULT);
+       visible_range_start = view_start_tt;
+       visible_range_end = view_end_tt;
 
-       g_object_unref (settings);
-}
+       e_calendar_view_precalc_visible_time_range (current_view, view_start_tt, view_end_tt, 
&visible_range_start, &visible_range_end);
+       if (view_start_tt != visible_range_start || view_end_tt != visible_range_end) {
+               time_t cmp_range_start = convert_to_local_zone (visible_range_start, zone);
+               time_t cmp_range_end = convert_to_local_zone (visible_range_end, zone);
 
-static gchar *
-cal_shell_content_get_pad_state_filename (EShellContent *shell_content,
-                                          ETable *table)
-{
-       EShellBackend *shell_backend;
-       EShellView *shell_view;
-       const gchar *config_dir, *nick = NULL;
+               if (view_start_tt != cmp_range_start ||
+                   view_end_tt != cmp_range_end - 1) {
+                       /* Calendar views update their inner time range during e_cal_model_set_time_range() 
call,
+                          while they can change it if needed (like a clamp of a week view with a week start 
day
+                          not being Monday */
+                       GDate new_view_start, new_view_end;
 
-       g_return_val_if_fail (shell_content != NULL, NULL);
-       g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
-       g_return_val_if_fail (table != NULL, NULL);
-       g_return_val_if_fail (E_IS_TABLE (table), NULL);
+                       /* Midnight means the next day, which is not desired here */
+                       cmp_range_end--;
+                       visible_range_end--;
 
-       if (E_IS_TASK_TABLE (table))
-               nick = "TaskPad";
-       else if (E_IS_MEMO_TABLE (table))
-               nick = "MemoPad";
+                       /* These times are in the correct zone already */
+                       time_to_gdate_with_zone (&new_view_start, cmp_range_start, NULL);
+                       time_to_gdate_with_zone (&new_view_end, cmp_range_end, NULL);
 
-       g_return_val_if_fail (nick != NULL, NULL);
+                       e_calendar_item_set_selection (calitem, &new_view_start, &new_view_end);
+                       e_cal_shell_content_update_filters (cal_shell_content, cal_filter, 
visible_range_start, visible_range_end);
+                       e_calendar_view_set_selected_time_range (current_view, cmp_range_start, 
cmp_range_start);
+                       filters_updated = TRUE;
 
-       shell_view = e_shell_content_get_shell_view (shell_content);
-       shell_backend = e_shell_view_get_shell_backend (shell_view);
-       config_dir = e_shell_backend_get_config_dir (shell_backend);
+                       view_start_tt = cmp_range_start;
+                       view_end_tt = cmp_range_end;
+               }
+       }
 
-       return g_build_filename (config_dir, nick, NULL);
-}
+       if (!filters_updated) {
+               e_calendar_item_set_selection (calitem, view_start, view_end);
+               e_cal_shell_content_update_filters (cal_shell_content, cal_filter, view_start_tt, 
view_end_tt);
+               e_calendar_view_set_selected_time_range (current_view, view_start_tt, view_start_tt);
+       }
 
-static void
-cal_shell_content_save_table_state (EShellContent *shell_content,
-                                    ETable *table)
-{
-       gchar *filename;
+       gtk_widget_queue_draw (GTK_WIDGET (current_view));
 
-       filename = cal_shell_content_get_pad_state_filename (
-               shell_content, table);
-       g_return_if_fail (filename != NULL);
+       g_free (cal_filter);
 
-       e_table_save_state (table, filename);
-       g_free (filename);
-}
+       g_signal_handler_unblock (calitem, cal_shell_content->priv->datepicker_range_moved_id);
+       g_signal_handler_unblock (calitem, cal_shell_content->priv->datepicker_selection_changed_id);
 
-static void
-cal_shell_content_load_table_state (EShellContent *shell_content,
-                                    ETable *table)
-{
-       gchar *filename;
+       if (e_calendar_item_get_date_range (calitem, &syy, &smm, &sdd, &eyy, &emm, &edd)) {
+               GDate range_start;
 
-       filename = cal_shell_content_get_pad_state_filename (
-               shell_content, table);
-       g_return_if_fail (filename != NULL);
+               g_date_set_dmy (&range_start, sdd, smm + 1, syy);
 
-       e_table_load_state (table, filename);
-       g_free (filename);
+               cal_shell_content->priv->view_start_range_day_offset =
+                       g_date_get_julian (&cal_shell_content->priv->view_start) - g_date_get_julian 
(&range_start);
+       }
 }
 
-void
-e_cal_shell_content_save_state (ECalShellContent *cal_shell_content)
+static void
+e_cal_shell_content_change_view (ECalShellContent *cal_shell_content,
+                                ECalViewKind to_view,
+                                const GDate *view_start,
+                                const GDate *view_end,
+                                gboolean force_change)
 {
-       ECalShellContentPrivate *priv;
+       EShellSidebar *shell_sidebar;
+       EShellView *shell_view;
+       ECalendar *calendar;
+       ECalModel *model;
+       icaltimezone *zone;
+       time_t view_start_tt, view_end_tt;
+       gboolean view_changed = FALSE;
+       gint selected_days;
 
-       g_return_if_fail (cal_shell_content != NULL);
        g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
+       g_return_if_fail (to_view >= E_CAL_VIEW_KIND_DAY && to_view < E_CAL_VIEW_KIND_LAST);
+       g_return_if_fail (view_start != NULL);
+       g_return_if_fail (g_date_valid (view_start));
+       g_return_if_fail (view_end != NULL);
+       g_return_if_fail (g_date_valid (view_end));
+
+       shell_view = e_shell_content_get_shell_view (E_SHELL_CONTENT (cal_shell_content));
+       shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+       g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (shell_sidebar));
+
+       calendar = e_cal_base_shell_sidebar_get_date_navigator (E_CAL_BASE_SHELL_SIDEBAR (shell_sidebar));
+       g_return_if_fail (E_IS_CALENDAR (calendar));
+
+       model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
+       zone = e_cal_model_get_timezone (model);
+       view_start_tt = cal_comp_gdate_to_timet (view_start, zone);
+       view_end_tt = cal_comp_gdate_to_timet (view_end, zone);
+
+       if (to_view != cal_shell_content->priv->current_view) {
+               g_signal_handler_block (cal_shell_content, 
cal_shell_content->priv->current_view_id_changed_id);
+               e_cal_shell_content_set_current_view_id (cal_shell_content, to_view);
+               g_signal_handler_unblock (cal_shell_content, 
cal_shell_content->priv->current_view_id_changed_id);
+               view_changed = TRUE;
+       }
 
-       priv = cal_shell_content->priv;
+       selected_days = g_date_get_julian (view_end) - g_date_get_julian (view_start) + 1;
 
-       if (priv->task_table != NULL)
-               cal_shell_content_save_table_state (
-                       E_SHELL_CONTENT (cal_shell_content),
-                       E_TABLE (priv->task_table));
+       if (cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_DAY) {
+               EDayView *day_view;
 
-       if (priv->memo_table != NULL)
-               cal_shell_content_save_table_state (
-                       E_SHELL_CONTENT (cal_shell_content),
-                       E_TABLE (priv->memo_table));
-}
+               day_view = E_DAY_VIEW (cal_shell_content->priv->views[E_CAL_VIEW_KIND_DAY]);
+               e_day_view_set_days_shown (day_view, selected_days);
+       } else if (cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_MONTH) {
+               EWeekView *month_view;
 
-static void
-cal_shell_content_set_property (GObject *object,
-                                guint property_id,
-                                const GValue *value,
-                                GParamSpec *pspec)
-{
-       switch (property_id) {
+               month_view = E_WEEK_VIEW (cal_shell_content->priv->views[E_CAL_VIEW_KIND_MONTH]);
+               e_week_view_set_weeks_shown (month_view, selected_days / 7);
        }
 
-       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
-}
+       if (!force_change &&
+           g_date_valid (&cal_shell_content->priv->view_start) &&
+           g_date_valid (&cal_shell_content->priv->view_end) &&
+           g_date_compare (&cal_shell_content->priv->view_start, view_start) == 0 &&
+           g_date_compare (&cal_shell_content->priv->view_end, view_end) == 0) {
+               ECalendarItem *calitem = calendar->calitem;
 
-static void
-cal_shell_content_get_property (GObject *object,
-                                guint property_id,
-                                GValue *value,
-                                GParamSpec *pspec)
-{
-       switch (property_id) {
-               case PROP_CALENDAR:
-                       g_value_set_object (
-                               value, e_cal_shell_content_get_calendar (
-                               E_CAL_SHELL_CONTENT (object)));
-                       return;
+               if (view_changed)
+                       cal_shell_content_update_model_and_current_view_times (
+                               cal_shell_content, model, calendar->calitem, view_start_tt, view_end_tt, 
view_start, view_end);
 
-               case PROP_MEMO_TABLE:
-                       g_value_set_object (
-                               value, e_cal_shell_content_get_memo_table (
-                               E_CAL_SHELL_CONTENT (object)));
-                       return;
+               g_signal_handler_block (calitem, cal_shell_content->priv->datepicker_range_moved_id);
+               g_signal_handler_block (calitem, cal_shell_content->priv->datepicker_selection_changed_id);
 
-               case PROP_TASK_TABLE:
-                       g_value_set_object (
-                               value, e_cal_shell_content_get_task_table (
-                               E_CAL_SHELL_CONTENT (object)));
-                       return;
+               e_calendar_item_set_selection (calitem, view_start, view_end);
+
+               g_signal_handler_unblock (calitem, cal_shell_content->priv->datepicker_range_moved_id);
+               g_signal_handler_unblock (calitem, cal_shell_content->priv->datepicker_selection_changed_id);
+
+               return;
        }
 
-       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+       cal_shell_content->priv->view_start = *view_start;
+       cal_shell_content->priv->view_end = *view_end;
+
+       cal_shell_content_update_model_and_current_view_times (
+               cal_shell_content, model, calendar->calitem, view_start_tt, view_end_tt, view_start, 
view_end);
 }
 
 static void
-cal_shell_content_dispose (GObject *object)
+cal_shell_content_clamp_for_whole_weeks (GDateWeekday week_start_day,
+                                        GDate *sel_start,
+                                        GDate *sel_end)
 {
-       ECalShellContentPrivate *priv;
+       GDateWeekday wday;
+       guint32 julian_start, julian_end;
 
-       priv = E_CAL_SHELL_CONTENT_GET_PRIVATE (object);
+       g_return_if_fail (sel_start != NULL);
+       g_return_if_fail (sel_end != NULL);
 
-       if (priv->hpaned != NULL) {
-               g_object_unref (priv->hpaned);
-               priv->hpaned = NULL;
+       wday = g_date_get_weekday (sel_start);
+       if (week_start_day > wday) {
+               g_date_subtract_days (sel_start, wday);
+               wday = g_date_get_weekday (sel_start);
        }
 
-       if (priv->notebook != NULL) {
-               g_object_unref (priv->notebook);
-               priv->notebook = NULL;
-       }
+       if (week_start_day < wday)
+               g_date_subtract_days (sel_start, wday - week_start_day);
 
-       if (priv->vpaned != NULL) {
-               g_object_unref (priv->vpaned);
-               priv->vpaned = NULL;
-       }
+       julian_start = g_date_get_julian (sel_start);
+       julian_end = g_date_get_julian (sel_end);
 
-       if (priv->calendar != NULL) {
-               g_object_unref (priv->calendar);
-               priv->calendar = NULL;
-       }
+       if (((julian_end - julian_start + 1) % 7) != 0)
+               g_date_add_days (sel_end, 7 - ((julian_end - julian_start + 1) % 7));
 
-       if (priv->task_table != NULL) {
-               g_object_unref (priv->task_table);
-               priv->task_table = NULL;
-       }
+       julian_end = g_date_get_julian (sel_end);
 
-       if (priv->memo_table != NULL) {
-               g_object_unref (priv->memo_table);
-               priv->memo_table = NULL;
+       /* Can show only up to 6 weeks */
+       if ((julian_end - julian_start + 1) / 7 > 6) {
+               *sel_end = *sel_start;
+               g_date_add_days (sel_end, (7 * 6) - 1);
        }
 
-       /* Chain up to parent's dispose() method. */
-       G_OBJECT_CLASS (e_cal_shell_content_parent_class)->dispose (object);
+       if (g_date_compare (sel_start, sel_end) == 0)
+               g_date_add_days (sel_end, 6);
 }
 
-static time_t
-gc_get_default_time (ECalModel *model,
-                     gpointer user_data)
+static gboolean
+cal_shell_content_weekday_within (GDateWeekday start_wday,
+                                 GDateWeekday end_wday,
+                                 GDateWeekday test_wday)
 {
-       GnomeCalendar *gcal = user_data;
-       time_t res = 0, end;
+       gint ii;
 
-       g_return_val_if_fail (model != NULL, 0);
-       g_return_val_if_fail (GNOME_IS_CALENDAR (user_data), 0);
+       if (start_wday <= end_wday)
+               return start_wday <= test_wday && test_wday <= end_wday;
 
-       gnome_calendar_get_current_time_range (gcal, &res, &end);
+       for (ii = 0; ii < 7; ii++) {
+               if (start_wday == test_wday)
+                       return TRUE;
 
-       return res;
-}
+               if (start_wday == end_wday)
+                       break;
 
-static void
-cal_shell_content_is_editing_changed_cb (gpointer cal_view_tasks_memos_table,
-                                         GParamSpec *param,
-                                         EShellView *shell_view)
-{
-       g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
+               start_wday = e_weekday_get_next (start_wday);
+       }
 
-       e_shell_view_update_actions (shell_view);
+       return FALSE;
 }
 
 static void
-cal_shell_content_constructed (GObject *object)
+cal_shell_content_datepicker_selection_changed_cb (ECalendarItem *calitem,
+                                                  ECalShellContent *cal_shell_content)
 {
-       ECalShellContentPrivate *priv;
-       ECalendarView *calendar_view;
-       ECalModel *memo_model = NULL;
-       ECalModel *task_model = NULL;
-       EShell *shell;
-       EShellContent *shell_content;
-       EShellView *shell_view;
-       EShellWindow *shell_window;
-       EShellContent *foreign_content;
-       EShellView *foreign_view;
-       GnomeCalendar *calendar;
-       ESourceRegistry *registry;
-       GalViewInstance *view_instance;
-       GSettings *settings;
-       GtkWidget *container;
-       GtkWidget *widget;
-       gchar *markup;
-       gint ii;
+       GDate sel_start, sel_end;
+       guint32 selected_days, start_julian, end_julian;
 
-       priv = E_CAL_SHELL_CONTENT_GET_PRIVATE (object);
+       g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
+       g_return_if_fail (E_IS_CALENDAR_ITEM (calitem));
 
-       /* Chain up to parent's constructed() method. */
-       G_OBJECT_CLASS (e_cal_shell_content_parent_class)->constructed (object);
+       g_date_clear (&sel_start, 1);
+       g_date_clear (&sel_end, 1);
 
-       shell_content = E_SHELL_CONTENT (object);
-       shell_view = e_shell_content_get_shell_view (shell_content);
-       shell_window = e_shell_view_get_shell_window (shell_view);
+       e_calendar_item_get_selection (calitem, &sel_start, &sel_end);
 
-       shell = e_shell_window_get_shell (shell_window);
+       start_julian = g_date_get_julian (&sel_start);
+       end_julian = g_date_get_julian (&sel_end);
 
-       /* We borrow the memopad and taskpad models from the memo
-        * and task views, loading the views if necessary. */
-       foreign_view = e_shell_window_get_shell_view (shell_window, "memos");
-       foreign_content = e_shell_view_get_shell_content (foreign_view);
-       g_object_get (foreign_content, "model", &memo_model, NULL);
+       g_return_if_fail (start_julian <= end_julian);
 
-       foreign_view = e_shell_window_get_shell_view (shell_window, "tasks");
-       foreign_content = e_shell_view_get_shell_content (foreign_view);
-       g_object_get (foreign_content, "model", &task_model, NULL);
+       if (g_date_compare (&cal_shell_content->priv->view_start, &sel_start) == 0 &&
+           g_date_compare (&cal_shell_content->priv->view_end, &sel_end) == 0) {
+               /* No change in the selection range */
+               return;
+       }
 
-       /* Build content widgets. */
+       selected_days = end_julian - start_julian + 1;
+       if (selected_days == 1) {
+               GDateWeekday sel_start_wday, sel_end_wday, cur_start_wday, cur_end_wday;
 
-       container = GTK_WIDGET (object);
+               /* Clicked inside currently selected view range; do not do anything,
+                  just make sure the days are selected again */
+               if (g_date_compare (&cal_shell_content->priv->view_start, &sel_start) <= 0 &&
+                   g_date_compare (&sel_start, &cal_shell_content->priv->view_end) <= 0) {
+                       sel_start = cal_shell_content->priv->view_start;
+                       sel_end = cal_shell_content->priv->view_end;
 
-       widget = e_paned_new (GTK_ORIENTATION_HORIZONTAL);
-       gtk_container_add (GTK_CONTAINER (container), widget);
-       priv->hpaned = g_object_ref (widget);
-       gtk_widget_show (widget);
+                       e_calendar_item_set_selection (calitem, &sel_start, &sel_end);
+                       return;
+               }
 
-       container = priv->hpaned;
+               sel_start_wday = g_date_get_weekday (&sel_start);
+               sel_end_wday = g_date_get_weekday (&sel_end);
+               cur_start_wday = g_date_get_weekday (&cal_shell_content->priv->view_start);
+               cur_end_wday = g_date_get_weekday (&cal_shell_content->priv->view_end);
+
+               if ((cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_WORKWEEK ||
+                   (cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_DAY &&
+                   e_day_view_get_days_shown (E_DAY_VIEW 
(cal_shell_content->priv->views[E_CAL_VIEW_KIND_DAY])) != 1)) &&
+                   cal_shell_content_weekday_within (cur_start_wday, cur_end_wday, sel_start_wday)) {
+                       if (cur_start_wday < sel_start_wday) {
+                               g_date_subtract_days (&sel_start, sel_start_wday - cur_start_wday);
+                       } else if (cur_start_wday > sel_start_wday) {
+                               g_date_subtract_days (&sel_start, 7 - (cur_start_wday - sel_start_wday));
+                       }
+                       sel_end = sel_start;
+                       if (cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_DAY)
+                               g_date_add_days (&sel_end, e_day_view_get_days_shown (E_DAY_VIEW 
(cal_shell_content->priv->views[E_CAL_VIEW_KIND_DAY])) - 1);
+                       else
+                               g_date_add_days (&sel_end, e_day_view_get_days_shown (E_DAY_VIEW 
(cal_shell_content->priv->views[E_CAL_VIEW_KIND_WORKWEEK])) - 1);
+
+                       e_cal_shell_content_change_view (cal_shell_content, 
cal_shell_content->priv->current_view, &sel_start, &sel_end, FALSE);
+               } else if (cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_WEEK &&
+                   cal_shell_content_weekday_within (cur_start_wday, cur_end_wday, sel_start_wday) &&
+                   cal_shell_content_weekday_within (cur_start_wday, cur_end_wday, sel_end_wday)) {
+                       if (cur_start_wday < sel_start_wday)
+                               g_date_subtract_days (&sel_start, sel_start_wday - cur_start_wday);
+                       sel_end = sel_start;
+                       cal_shell_content_clamp_for_whole_weeks (calitem->week_start_day, &sel_start, 
&sel_end);
+
+                       e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_WEEK, &sel_start, 
&sel_end, FALSE);
+               } else if (cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_MONTH ||
+                          cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_LIST) {
+                       /* whole month */
+                       g_date_set_day (&sel_start, 1);
+                       sel_end = sel_start;
+                       g_date_set_day (&sel_end, g_date_get_days_in_month (g_date_get_month (&sel_start), 
g_date_get_year (&sel_start)) - 1);
+                       cal_shell_content_clamp_for_whole_weeks (calitem->week_start_day, &sel_start, 
&sel_end);
+
+                       e_cal_shell_content_change_view (cal_shell_content, 
cal_shell_content->priv->current_view, &sel_start, &sel_end, FALSE);
+               } else {
+                       e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_DAY, &sel_start, 
&sel_end, FALSE);
+               }
+       } else if (selected_days < 7) {
+               GDateWeekday first_work_wday;
+
+               first_work_wday = e_cal_model_get_work_day_first (e_cal_base_shell_content_get_model 
(E_CAL_BASE_SHELL_CONTENT (cal_shell_content)));
+
+               if (cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_WORKWEEK &&
+                   first_work_wday == g_date_get_weekday (&sel_start) &&
+                   selected_days == e_day_view_get_days_shown (E_DAY_VIEW 
(cal_shell_content->priv->views[E_CAL_VIEW_KIND_WORKWEEK])))
+                       e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_WORKWEEK, 
&sel_start, &sel_end, FALSE);
+               else
+                       e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_DAY, &sel_start, 
&sel_end, FALSE);
+       } else if (selected_days == 7) {
+               GDateWeekday sel_start_wday;
+
+               sel_start_wday = g_date_get_weekday (&sel_start);
+
+               if (sel_start_wday == calitem->week_start_day &&
+                   cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_DAY &&
+                   e_day_view_get_days_shown (E_DAY_VIEW 
(cal_shell_content->priv->views[E_CAL_VIEW_KIND_DAY])) == 7) {
+                       e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_DAY, &sel_start, 
&sel_end, FALSE);
+               } else {
+                       e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_WEEK, &sel_start, 
&sel_end, FALSE);
+               }
+       } else {
+               if (cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_LIST) {
+                       /* whole month */
+                       g_date_set_day (&sel_start, 1);
+                       sel_end = sel_start;
+                       g_date_set_day (&sel_end, g_date_get_days_in_month (g_date_get_month (&sel_start), 
g_date_get_year (&sel_start)));
+                       cal_shell_content_clamp_for_whole_weeks (calitem->week_start_day, &sel_start, 
&sel_end);
+
+                       e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_LIST, &sel_start, 
&sel_end, FALSE);
+               } else {
+                       cal_shell_content_clamp_for_whole_weeks (calitem->week_start_day, &sel_start, 
&sel_end);
+                       e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_MONTH, 
&sel_start, &sel_end, FALSE);
+               }
+       }
+}
 
-       widget = gtk_notebook_new ();
-       gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE);
-       gtk_notebook_set_show_border (GTK_NOTEBOOK (widget), FALSE);
-       gtk_paned_pack1 (GTK_PANED (container), widget, TRUE, FALSE);
-       priv->notebook = g_object_ref (widget);
-       gtk_widget_show (widget);
+static void
+cal_shell_content_datepicker_range_moved_cb (ECalendarItem *calitem,
+                                            ECalShellContent *cal_shell_content)
+{
+       gint start_year, start_month, start_day, end_year, end_month, end_day;
+       GDate sel_start_date, sel_end_date, range_start_date;
 
-       /* FIXME Need to deal with saving and restoring the position.
-        *       Month view has its own position. */
-       widget = e_paned_new (GTK_ORIENTATION_VERTICAL);
-       e_paned_set_fixed_resize (E_PANED (widget), FALSE);
-       gtk_paned_pack2 (GTK_PANED (container), widget, FALSE, TRUE);
-       priv->vpaned = g_object_ref (widget);
-       gtk_widget_show (widget);
+       g_return_if_fail (E_IS_CALENDAR_ITEM (calitem));
+       g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
 
-       container = priv->notebook;
+       if (!e_calendar_item_get_date_range (calitem, &start_year, &start_month, &start_day, &end_year, 
&end_month, &end_day))
+               return;
 
-       /* Add views in the order defined by GnomeCalendarViewType, such
-        * that the notebook page number corresponds to the view type. */
+       g_date_set_dmy (&range_start_date, start_day, start_month + 1, start_year);
 
-       registry = e_shell_get_registry (shell);
-       priv->calendar = gnome_calendar_new (registry);
-       calendar = GNOME_CALENDAR (priv->calendar);
+       if (g_date_valid (&cal_shell_content->priv->last_range_start) &&
+           g_date_compare (&cal_shell_content->priv->last_range_start, &range_start_date) == 0) {
+               return;
+       }
 
-       for (ii = 0; ii < GNOME_CAL_LAST_VIEW; ii++) {
-               calendar_view = gnome_calendar_get_calendar_view (calendar, ii);
+       cal_shell_content->priv->last_range_start = range_start_date;
 
-               e_signal_connect_notify (
-                       calendar_view, "notify::is-editing",
-                       G_CALLBACK (cal_shell_content_is_editing_changed_cb), shell_view);
+       g_date_clear (&sel_start_date, 1);
+       g_date_clear (&sel_end_date, 1);
 
-               gtk_notebook_append_page (
-                       GTK_NOTEBOOK (container),
-                       GTK_WIDGET (calendar_view), NULL);
-               gtk_widget_show (GTK_WIDGET (calendar_view));
-       }
+       if (cal_shell_content->priv->view_start_range_day_offset == (guint32) -1) {
+               sel_start_date = cal_shell_content->priv->view_start;
+               sel_end_date = cal_shell_content->priv->view_end;
+               cal_shell_content->priv->view_start_range_day_offset =
+                       g_date_get_julian (&cal_shell_content->priv->view_start) - g_date_get_julian 
(&range_start_date);
+       } else {
+               gint view_days;
 
-       g_object_bind_property (
-               priv->calendar, "view",
-               priv->notebook, "page",
-               G_BINDING_SYNC_CREATE);
+               view_days = g_date_get_julian (&cal_shell_content->priv->view_end) - g_date_get_julian 
(&cal_shell_content->priv->view_start);
 
-       container = priv->vpaned;
+               sel_start_date = range_start_date;
+               g_date_add_days (&sel_start_date, cal_shell_content->priv->view_start_range_day_offset);
 
-       widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
-       gtk_paned_pack1 (GTK_PANED (container), widget, TRUE, TRUE);
-       gtk_widget_show (widget);
+               sel_end_date = sel_start_date;
+               g_date_add_days (&sel_end_date, view_days);
+       }
 
-       container = widget;
+       g_signal_handler_block (calitem, cal_shell_content->priv->datepicker_range_moved_id);
 
-       widget = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
-       gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0);
-       gtk_widget_show (widget);
+       e_calendar_item_set_selection (calitem, &sel_start_date, &sel_end_date);
 
-       widget = gtk_label_new (NULL);
-       markup = g_strdup_printf ("<b>%s</b>", _("Tasks"));
-       gtk_label_set_markup (GTK_LABEL (widget), markup);
-       gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0);
-       gtk_widget_show (widget);
-       g_free (markup);
+       g_signal_handler_unblock (calitem, cal_shell_content->priv->datepicker_range_moved_id);
+}
 
-       widget = gtk_scrolled_window_new (NULL, NULL);
-       gtk_scrolled_window_set_policy (
-               GTK_SCROLLED_WINDOW (widget),
-               GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-       gtk_scrolled_window_set_shadow_type (
-               GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
-       gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
-       gtk_widget_show (widget);
+static gboolean
+cal_shell_content_datepicker_button_press_cb (ECalendar *calendar,
+                                             GdkEvent *event,
+                                             ECalShellContent *cal_shell_content)
+{
+       g_return_val_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content), FALSE);
 
-       container = widget;
+       if (!event)
+               return FALSE;
 
-       widget = e_task_table_new (shell_view, task_model);
-       gtk_container_add (GTK_CONTAINER (container), widget);
-       priv->task_table = g_object_ref (widget);
-       gtk_widget_show (widget);
+       if (event->type == GDK_2BUTTON_PRESS) {
+               ECalendarItem *calitem = calendar->calitem;
+               GDate sel_start, sel_end;
 
-       cal_shell_content_load_table_state (
-               shell_content, E_TABLE (widget));
+               g_date_clear (&sel_start, 1);
+               g_date_clear (&sel_end, 1);
 
-       g_signal_connect_swapped (
-               widget, "open-component",
-               G_CALLBACK (e_cal_shell_view_taskpad_open_task),
-               shell_view);
+               e_calendar_item_get_selection (calitem, &sel_start, &sel_end);
 
-       e_signal_connect_notify (
-               widget, "notify::is-editing",
-               G_CALLBACK (cal_shell_content_is_editing_changed_cb), shell_view);
+               /* Switch to a day view on a double-click */
+               e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_DAY, &sel_start, 
&sel_start, FALSE);
+       }
 
-       container = priv->vpaned;
+       return FALSE;
+}
 
-       widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
-       gtk_paned_pack2 (GTK_PANED (container), widget, TRUE, TRUE);
-       gtk_widget_show (widget);
+static void
+cal_shell_content_current_view_id_changed_cb (ECalShellContent *cal_shell_content)
+{
+       GDate sel_start, sel_end;
+       GDateWeekday work_day_first, week_start_day;
+       ECalModel *model;
+       gint ii;
 
-       container = widget;
+       g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
 
-       widget = gtk_label_new (NULL);
-       markup = g_strdup_printf ("<b>%s</b>", _("Memos"));
-       gtk_label_set_markup (GTK_LABEL (widget), markup);
-       gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0);
-       gtk_widget_show (widget);
-       g_free (markup);
+       model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
+       work_day_first = e_cal_model_get_work_day_first (model);
+       week_start_day = e_cal_model_get_week_start_day (model);
+       sel_start = cal_shell_content->priv->view_start;
+       sel_end = cal_shell_content->priv->view_end;
+
+       switch (cal_shell_content->priv->current_view) {
+               case E_CAL_VIEW_KIND_DAY:
+                       /* Left the start & end being the current view start */
+                       sel_end = sel_start;
+                       break;
+               case E_CAL_VIEW_KIND_WORKWEEK:
+                       cal_shell_content_clamp_for_whole_weeks (week_start_day, &sel_start, &sel_end);
+                       ii = 0;
+                       while (g_date_get_weekday (&sel_start) != work_day_first && ii < 7) {
+                               g_date_add_days (&sel_start, 1);
+                               ii++;
+                       }
+
+                       sel_end = sel_start;
+                       g_date_add_days (&sel_end, e_day_view_get_days_shown (E_DAY_VIEW 
(cal_shell_content->priv->views[E_CAL_VIEW_KIND_WORKWEEK])) - 1);
+                       break;
+               case E_CAL_VIEW_KIND_WEEK:
+                       sel_end = sel_start;
+                       cal_shell_content_clamp_for_whole_weeks (week_start_day, &sel_start, &sel_end);
+                       break;
+               case E_CAL_VIEW_KIND_MONTH:
+               case E_CAL_VIEW_KIND_LIST:
+                       if (g_date_get_day (&sel_start) != 1 &&
+                           (g_date_get_julian (&sel_end) - g_date_get_julian (&sel_start) + 1) / 7 >= 3 &&
+                           g_date_get_month (&sel_start) != g_date_get_month (&sel_end)) {
+                               g_date_set_day (&sel_start, 1);
+                               g_date_add_months (&sel_start, 1);
+                       } else {
+                               g_date_set_day (&sel_start, 1);
+                       }
+                       sel_end = sel_start;
+                       g_date_add_months (&sel_end, 1);
+                       g_date_subtract_days (&sel_end, 1);
+                       cal_shell_content_clamp_for_whole_weeks (week_start_day, &sel_start, &sel_end);
+                       break;
+               default:
+                       g_warn_if_reached ();
+                       return;
+       }
 
-       widget = gtk_scrolled_window_new (NULL, NULL);
-       gtk_scrolled_window_set_policy (
-               GTK_SCROLLED_WINDOW (widget),
-               GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-       gtk_scrolled_window_set_shadow_type (
-               GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
-       gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
-       gtk_widget_show (widget);
+       /* Ensure a change */
+       e_cal_shell_content_change_view (cal_shell_content, cal_shell_content->priv->current_view, 
&sel_start, &sel_end, TRUE);
+}
 
-       container = widget;
+static void
+cal_shell_content_display_view_cb (ECalShellContent *cal_shell_content,
+                                   GalView *gal_view)
+{
+       ECalViewKind view_kind;
+       GType gal_view_type;
 
-       widget = e_memo_table_new (shell_view, memo_model);
-       gtk_container_add (GTK_CONTAINER (container), widget);
-       priv->memo_table = g_object_ref (widget);
-       gtk_widget_show (widget);
+       gal_view_type = G_OBJECT_TYPE (gal_view);
 
-       cal_shell_content_load_table_state (
-               shell_content, E_TABLE (widget));
+       if (gal_view_type == GAL_TYPE_VIEW_ETABLE) {
+               ECalendarView *calendar_view;
 
-       e_cal_model_set_default_time_func (
-               memo_model, gc_get_default_time, calendar);
+               view_kind = E_CAL_VIEW_KIND_LIST;
+               calendar_view = cal_shell_content->priv->views[view_kind];
+               gal_view_etable_attach_table (
+                       GAL_VIEW_ETABLE (gal_view),
+                       E_CAL_LIST_VIEW (calendar_view)->table);
 
-       g_signal_connect_swapped (
-               widget, "open-component",
-               G_CALLBACK (e_cal_shell_view_memopad_open_memo),
-               shell_view);
+       } else if (gal_view_type == GAL_TYPE_VIEW_CALENDAR_DAY) {
+               view_kind = E_CAL_VIEW_KIND_DAY;
 
-       e_signal_connect_notify (
-               widget, "notify::is-editing",
-               G_CALLBACK (cal_shell_content_is_editing_changed_cb), shell_view);
+       } else if (gal_view_type == GAL_TYPE_VIEW_CALENDAR_WORK_WEEK) {
+               view_kind = E_CAL_VIEW_KIND_WORKWEEK;
 
-       /* Load the view instance. */
+       } else if (gal_view_type == GAL_TYPE_VIEW_CALENDAR_WEEK) {
+               view_kind = E_CAL_VIEW_KIND_WEEK;
 
-       view_instance = e_shell_view_new_view_instance (shell_view, NULL);
-       g_signal_connect_swapped (
-               view_instance, "display-view",
-               G_CALLBACK (cal_shell_content_display_view_cb),
-               object);
-       /* XXX Actually, don't load the view instance just yet.
-        *     The GtkWidget::map() callback below explains why. */
-       e_shell_view_set_view_instance (shell_view, view_instance);
-       g_object_unref (view_instance);
+       } else if (gal_view_type == GAL_TYPE_VIEW_CALENDAR_MONTH) {
+               view_kind = E_CAL_VIEW_KIND_MONTH;
 
-       e_signal_connect_notify_swapped (
-               shell_view, "notify::view-id",
-               G_CALLBACK (cal_shell_content_notify_view_id_cb),
-               object);
+       } else {
+               g_return_if_reached ();
+       }
+
+       e_cal_shell_content_set_current_view_id (cal_shell_content, view_kind);
+}
+
+static void
+cal_shell_content_notify_view_id_cb (ECalShellContent *cal_shell_content)
+{
+       EShellContent *shell_content;
+       EShellView *shell_view;
+       GSettings *settings;
+       GtkWidget *paned;
+       const gchar *key;
+       const gchar *view_id;
 
        settings = g_settings_new ("org.gnome.evolution.calendar");
+       paned = cal_shell_content->priv->hpaned;
+
+       shell_content = E_SHELL_CONTENT (cal_shell_content);
+       shell_view = e_shell_content_get_shell_view (shell_content);
+       view_id = e_shell_view_get_view_id (shell_view);
+
+       if (view_id != NULL && strcmp (view_id, "Month_View") == 0)
+               key = "month-hpane-position";
+       else
+               key = "hpane-position";
+
+       g_settings_unbind (paned, "hposition");
 
        g_settings_bind (
-               settings, "tag-vpane-position",
-               priv->vpaned, "proportion",
+               settings, key,
+               paned, "hposition",
                G_SETTINGS_BIND_DEFAULT);
 
        g_object_unref (settings);
-
-       if (memo_model)
-               g_object_unref (memo_model);
-       if (task_model)
-               g_object_unref (task_model);
 }
 
 static void
-cal_shell_content_map (GtkWidget *widget)
+cal_shell_content_is_editing_changed_cb (gpointer cal_view_tasks_memos_table,
+                                         GParamSpec *param,
+                                         EShellView *shell_view)
+{
+       g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
+
+       e_shell_view_update_actions (shell_view);
+}
+
+static gchar *
+cal_shell_content_get_pad_state_filename (EShellContent *shell_content,
+                                          ETable *table)
 {
+       EShellBackend *shell_backend;
        EShellView *shell_view;
-       EShellContent *shell_content;
-       GalViewInstance *view_instance;
+       const gchar *config_dir, *nick = NULL;
+
+       g_return_val_if_fail (shell_content != NULL, NULL);
+       g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
+       g_return_val_if_fail (table != NULL, NULL);
+       g_return_val_if_fail (E_IS_TABLE (table), NULL);
+
+       if (E_IS_TASK_TABLE (table))
+               nick = "TaskPad";
+       else if (E_IS_MEMO_TABLE (table))
+               nick = "MemoPad";
+
+       g_return_val_if_fail (nick != NULL, NULL);
 
-       shell_content = E_SHELL_CONTENT (widget);
        shell_view = e_shell_content_get_shell_view (shell_content);
-       view_instance = e_shell_view_get_view_instance (shell_view);
+       shell_backend = e_shell_view_get_shell_backend (shell_view);
+       config_dir = e_shell_backend_get_config_dir (shell_backend);
 
-       /* XXX Delay loading the GalViewInstance until after ECalShellView
-        *     has a chance to install the sidebar's date navigator into
-        *     GnomeCalendar, since loading the GalViewInstance triggers a
-        *     callback in GnomeCalendar that requires the date navigator.
-        *     Ordinarily we would do this at the end of constructed(), but
-        *     that's too soon in this case.  (This feels kind of kludgy.) */
-       gal_view_instance_load (view_instance);
+       return g_build_filename (config_dir, nick, NULL);
+}
 
-       /* Chain up to parent's map() method. */
-       GTK_WIDGET_CLASS (e_cal_shell_content_parent_class)->map (widget);
+static void
+cal_shell_content_save_table_state (EShellContent *shell_content,
+                                    ETable *table)
+{
+       gchar *filename;
+
+       filename = cal_shell_content_get_pad_state_filename (
+               shell_content, table);
+       g_return_if_fail (filename != NULL);
+
+       e_table_save_state (table, filename);
+       g_free (filename);
+}
+
+static void
+cal_shell_content_load_table_state (EShellContent *shell_content,
+                                    ETable *table)
+{
+       gchar *filename;
+
+       filename = cal_shell_content_get_pad_state_filename (shell_content, table);
+       g_return_if_fail (filename != NULL);
+
+       e_table_load_state (table, filename);
+       g_free (filename);
 }
 
-/* Helper for cal_shell_content_check_state() */
 static icalproperty *
 cal_shell_content_get_attendee_prop (icalcomponent *icalcomp,
                                      const gchar *address)
@@ -598,7 +747,6 @@ cal_shell_content_get_attendee_prop (icalcomponent *icalcomp,
        return NULL;
 }
 
-/* Helper for cal_shell_content_check_state() */
 static gboolean
 cal_shell_content_icalcomp_is_delegated (icalcomponent *icalcomp,
                                          const gchar *user_email)
@@ -652,9 +800,7 @@ cal_shell_content_check_state (EShellContent *shell_content)
        EShellBackend *shell_backend;
        ESourceRegistry *registry;
        ECalShellContent *cal_shell_content;
-       GnomeCalendar *calendar;
        ECalendarView *calendar_view;
-       GnomeCalendarViewType view_type;
        gboolean selection_is_editable = FALSE;
        gboolean selection_is_instance = FALSE;
        gboolean selection_is_meeting = FALSE;
@@ -673,9 +819,7 @@ cal_shell_content_check_state (EShellContent *shell_content)
        shell = e_shell_backend_get_shell (shell_backend);
        registry = e_shell_get_registry (shell);
 
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-       view_type = gnome_calendar_get_view (calendar);
-       calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+       calendar_view = e_cal_shell_content_get_current_calendar_view (cal_shell_content);
 
        selected = e_calendar_view_get_selected_events (calendar_view);
        n_selected = g_list_length (selected);
@@ -764,21 +908,21 @@ cal_shell_content_check_state (EShellContent *shell_content)
        g_list_free (selected);
 
        if (n_selected == 1)
-               state |= E_CAL_SHELL_CONTENT_SELECTION_SINGLE;
+               state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_SINGLE;
        if (n_selected > 1)
-               state |= E_CAL_SHELL_CONTENT_SELECTION_MULTIPLE;
+               state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_MULTIPLE;
        if (selection_is_editable)
-               state |= E_CAL_SHELL_CONTENT_SELECTION_IS_EDITABLE;
+               state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_EDITABLE;
        if (selection_is_instance)
-               state |= E_CAL_SHELL_CONTENT_SELECTION_IS_INSTANCE;
+               state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_INSTANCE;
        if (selection_is_meeting)
-               state |= E_CAL_SHELL_CONTENT_SELECTION_IS_MEETING;
+               state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_MEETING;
        if (selection_is_organizer)
-               state |= E_CAL_SHELL_CONTENT_SELECTION_IS_ORGANIZER;
+               state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_ORGANIZER;
        if (selection_is_recurring)
-               state |= E_CAL_SHELL_CONTENT_SELECTION_IS_RECURRING;
+               state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_RECURRING;
        if (selection_can_delegate)
-               state |= E_CAL_SHELL_CONTENT_SELECTION_CAN_DELEGATE;
+               state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_CAN_DELEGATE;
 
        return state;
 }
@@ -786,25 +930,716 @@ cal_shell_content_check_state (EShellContent *shell_content)
 static void
 cal_shell_content_focus_search_results (EShellContent *shell_content)
 {
-       ECalShellContent *cal_shell_content;
-       GnomeCalendar *calendar;
-       GnomeCalendarViewType view_type;
        ECalendarView *calendar_view;
 
-       cal_shell_content = E_CAL_SHELL_CONTENT (shell_content);
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-       view_type = gnome_calendar_get_view (calendar);
-       calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+       calendar_view = e_cal_shell_content_get_current_calendar_view (E_CAL_SHELL_CONTENT (shell_content));
 
        gtk_widget_grab_focus (GTK_WIDGET (calendar_view));
 }
 
+static time_t
+cal_shell_content_get_default_time (ECalModel *model,
+                                   gpointer user_data)
+{
+       ECalShellContent *cal_shell_content = user_data;
+
+       g_return_val_if_fail (model != NULL, 0);
+       g_return_val_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content), 0);
+
+       return cal_comp_gdate_to_timet (&cal_shell_content->priv->view_start,
+               e_cal_model_get_timezone (model));
+}
+
+static void
+update_adjustment (ECalShellContent *cal_shell_content,
+                   GtkAdjustment *adjustment,
+                   EWeekView *week_view,
+                  gboolean move_by_week)
+{
+       GDate start_date, end_date;
+       GDate first_day_shown;
+       ECalModel *model;
+       gint week_offset;
+       struct icaltimetype start_tt = icaltime_null_time ();
+       time_t lower;
+       guint32 old_first_day_julian, new_first_day_julian;
+       icaltimezone *timezone;
+       gdouble value;
+
+       e_week_view_get_first_day_shown (week_view, &first_day_shown);
+
+       /* If we don't have a valid date set yet, just return. */
+       if (!g_date_valid (&first_day_shown))
+               return;
+
+       value = gtk_adjustment_get_value (adjustment);
+
+       /* Determine the first date shown. */
+       start_date = week_view->base_date;
+       week_offset = floor (value + 0.5);
+       g_date_add_days (&start_date, week_offset * 7);
+
+       /* Convert the old & new first days shown to julian values. */
+       old_first_day_julian = g_date_get_julian (&first_day_shown);
+       new_first_day_julian = g_date_get_julian (&start_date);
+
+       /* If we are already showing the date, just return. */
+       if (old_first_day_julian == new_first_day_julian)
+               return;
+
+       /* Convert it to a time_t. */
+       start_tt.year = g_date_get_year (&start_date);
+       start_tt.month = g_date_get_month (&start_date);
+       start_tt.day = g_date_get_day (&start_date);
+
+       model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
+       timezone = e_cal_model_get_timezone (model);
+       lower = icaltime_as_timet_with_zone (start_tt, timezone);
+
+       end_date = start_date;
+       if (move_by_week) {
+               g_date_add_days (&end_date, 7 - 1);
+       } else {
+               g_date_add_days (&end_date, 7 * e_week_view_get_weeks_shown (week_view) - 1);
+       }
+
+       e_week_view_set_update_base_date (week_view, FALSE);
+       e_cal_shell_content_change_view (cal_shell_content, cal_shell_content->priv->current_view, 
&start_date, &end_date, FALSE);
+       e_calendar_view_set_selected_time_range (E_CALENDAR_VIEW (week_view), lower, lower);
+       e_week_view_set_update_base_date (week_view, TRUE);
+}
+
+static void
+week_view_adjustment_changed_cb (GtkAdjustment *adjustment,
+                                ECalShellContent *cal_shell_content)
+{
+       ECalendarView *view;
+
+       g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
+
+       view = cal_shell_content->priv->views[E_CAL_VIEW_KIND_WEEK];
+       update_adjustment (cal_shell_content, adjustment, E_WEEK_VIEW (view), TRUE);
+}
+
+static void
+month_view_adjustment_changed_cb (GtkAdjustment *adjustment,
+                                 ECalShellContent *cal_shell_content)
+{
+       ECalendarView *view;
+
+       g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
+
+       view = cal_shell_content->priv->views[E_CAL_VIEW_KIND_MONTH];
+       update_adjustment (cal_shell_content, adjustment, E_WEEK_VIEW (view), FALSE);
+}
+
+static void
+cal_shell_content_notify_work_day_cb (ECalModel *model,
+                                     GParamSpec *param,
+                                     ECalShellContent *cal_shell_content)
+{
+       GDateWeekday work_day_first, work_day_last;
+
+       g_return_if_fail (E_IS_CAL_MODEL (model));
+       g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
+
+       if (cal_shell_content->priv->current_view != E_CAL_VIEW_KIND_WORKWEEK)
+               return;
+
+       work_day_first = e_cal_model_get_work_day_first (model);
+       work_day_last = e_cal_model_get_work_day_last (model);
+
+       if (work_day_first == g_date_get_weekday (&cal_shell_content->priv->view_start) &&
+           work_day_last == g_date_get_weekday (&cal_shell_content->priv->view_end))
+               return;
+
+       /* This makes sure that the selection in the datepicker corresponds
+          to the time range used in the Work Week view */
+       cal_shell_content_current_view_id_changed_cb (cal_shell_content);
+}
+
+static void
+cal_shell_content_notify_week_start_day_cb (ECalModel *model,
+                                           GParamSpec *param,
+                                           ECalShellContent *cal_shell_content)
+{
+       g_return_if_fail (E_IS_CAL_MODEL (model));
+       g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
+
+       /* This makes sure that the selection in the datepicker corresponds
+          to the time range used in the current view */
+       cal_shell_content_current_view_id_changed_cb (cal_shell_content);
+}
+
+static void
+cal_shell_content_move_view_range_cb (ECalendarView *cal_view,
+                                     ECalendarViewMoveType move_type,
+                                     gint64 exact_date,
+                                     ECalShellContent *cal_shell_content)
+{
+       g_return_if_fail (E_IS_CALENDAR_VIEW (cal_view));
+       g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
+
+       if (!cal_view->in_focus)
+               return;
+
+       e_cal_shell_content_move_view_range (cal_shell_content, move_type, (time_t) exact_date);
+}
+
+static void
+cal_shell_content_foreign_client_opened_cb (ECalBaseShellSidebar *cal_base_shell_sidebar,
+                                           ECalClient *client,
+                                           ECalModel *model)
+{
+       g_return_if_fail (E_IS_CAL_CLIENT (client));
+       g_return_if_fail (E_IS_CAL_MODEL (model));
+
+       e_cal_data_model_add_client (e_cal_model_get_data_model (model), client);
+}
+
+static void
+cal_shell_content_foreign_client_closed_cb (ECalBaseShellSidebar *cal_base_shell_sidebar,
+                                           ESource *source,
+                                           ECalModel *model)
+{
+       g_return_if_fail (E_IS_SOURCE (source));
+       g_return_if_fail (E_IS_CAL_MODEL (model));
+
+       e_cal_data_model_remove_client (e_cal_model_get_data_model (model), e_source_get_uid (source));
+}
+
+static void
+cal_shell_content_setup_foreign_sources (EShellView *foreign_view,
+                                        ECalModel *model)
+{
+       EShellSidebar *foreign_sidebar;
+       EShellContent *foreign_content;
+       ECalModel *foreign_model;
+
+       g_return_if_fail (E_IS_SHELL_VIEW (foreign_view));
+       g_return_if_fail (E_IS_CAL_MODEL (model));
+
+       foreign_sidebar = e_shell_view_get_shell_sidebar (foreign_view);
+       g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (foreign_sidebar));
+
+       g_signal_connect_object (foreign_sidebar, "client-opened",
+               G_CALLBACK (cal_shell_content_foreign_client_opened_cb), model, 0);
+       g_signal_connect_object (foreign_sidebar, "client-closed",
+               G_CALLBACK (cal_shell_content_foreign_client_closed_cb), model, 0);
+
+       foreign_content = e_shell_view_get_shell_content (foreign_view);
+       foreign_model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (foreign_content));
+
+       g_object_bind_property (
+               foreign_model, "default-source-uid",
+               model, "default-source-uid",
+               G_BINDING_SYNC_CREATE);
+
+       g_signal_connect_object (model, "row-appended",
+               G_CALLBACK (e_cal_base_shell_view_model_row_appended), foreign_view, G_CONNECT_SWAPPED);
+
+       /* This makes sure that the local models for memos and tasks
+          in the calendar view get populated with the same sources
+          as those in the respective views. */
+
+       e_cal_base_shell_sidebar_ensure_sources_open (E_CAL_BASE_SHELL_SIDEBAR (foreign_sidebar));
+}
+
+static void
+cal_shell_content_view_created (ECalBaseShellContent *cal_base_shell_content)
+{
+       ECalShellContent *cal_shell_content;
+       EShellView *shell_view;
+       EShellView *foreign_view;
+       EShellWindow *shell_window;
+       EShellSidebar *shell_sidebar;
+       GalViewInstance *view_instance;
+       ECalendar *calendar;
+       ECalModel *model;
+       ECalDataModel *data_model;
+       GDate date;
+       time_t today;
+
+       cal_shell_content = E_CAL_SHELL_CONTENT (cal_base_shell_content);
+       cal_shell_content->priv->current_view = E_CAL_VIEW_KIND_DAY;
+
+       today = time (NULL);
+       g_date_clear (&date, 1);
+       g_date_set_time_t (&date, today);
+
+       shell_view = e_shell_content_get_shell_view (E_SHELL_CONTENT (cal_shell_content));
+       shell_window = e_shell_view_get_shell_window (shell_view);
+       shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+       g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (shell_sidebar));
+
+       calendar = e_cal_base_shell_sidebar_get_date_navigator (E_CAL_BASE_SHELL_SIDEBAR (shell_sidebar));
+       g_return_if_fail (E_IS_CALENDAR (calendar));
+
+       model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
+       e_calendar_item_set_selection (calendar->calitem, &date, &date);
+       e_cal_model_set_time_range (model, today, today);
+
+       /* Show everything known by default in the task and memo pads */
+       e_cal_model_set_time_range (cal_shell_content->priv->memo_model, 0, 0);
+       e_cal_model_set_time_range (cal_shell_content->priv->task_model, 0, 0);
+
+       cal_shell_content->priv->datepicker_selection_changed_id =
+               g_signal_connect (calendar->calitem, "selection-changed",
+               G_CALLBACK (cal_shell_content_datepicker_selection_changed_cb), cal_shell_content);
+       cal_shell_content->priv->datepicker_range_moved_id =
+               g_signal_connect (calendar->calitem, "date-range-moved",
+               G_CALLBACK (cal_shell_content_datepicker_range_moved_cb), cal_shell_content);
+
+       g_signal_connect_after (calendar, "button-press-event",
+               G_CALLBACK (cal_shell_content_datepicker_button_press_cb), cal_shell_content);
+
+       data_model = e_cal_base_shell_content_get_data_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
+       cal_shell_content->priv->tag_calendar = e_tag_calendar_new (calendar);
+       e_tag_calendar_subscribe (cal_shell_content->priv->tag_calendar, data_model);
+
+       /* Intentionally not using e_signal_connect_notify() here, no need to filter
+          out "false" notifications, it's dealt with them in another way */
+       cal_shell_content->priv->current_view_id_changed_id = g_signal_connect (
+               cal_shell_content, "notify::current-view-id",
+               G_CALLBACK (cal_shell_content_current_view_id_changed_cb), NULL);
+
+       /* List of selected Task/Memo sources is taken from respective views,
+          which are loaded if necessary. */
+       foreign_view = e_shell_window_get_shell_view (shell_window, "memos");
+       cal_shell_content_setup_foreign_sources (foreign_view,
+               cal_shell_content->priv->memo_model);
+
+       foreign_view = e_shell_window_get_shell_view (shell_window, "tasks");
+       cal_shell_content_setup_foreign_sources (foreign_view,
+               cal_shell_content->priv->task_model);
+
+       /* Finally load the view instance */
+       view_instance = e_shell_view_get_view_instance (shell_view);
+       gal_view_instance_load (view_instance);
+
+       /* Keep the toolbar view buttons in sync with the calendar. */
+       g_object_bind_property (
+               cal_shell_content, "current-view-id",
+               ACTION (CALENDAR_VIEW_DAY), "current-value",
+               G_BINDING_BIDIRECTIONAL |
+               G_BINDING_SYNC_CREATE);
+
+       e_signal_connect_notify (
+               model, "notify::work-day-monday",
+               G_CALLBACK (cal_shell_content_notify_work_day_cb), cal_shell_content);
+
+       e_signal_connect_notify (
+               model, "notify::work-day-tuesday",
+               G_CALLBACK (cal_shell_content_notify_work_day_cb), cal_shell_content);
+
+       e_signal_connect_notify (
+               model, "notify::work-day-wednesday",
+               G_CALLBACK (cal_shell_content_notify_work_day_cb), cal_shell_content);
+
+       e_signal_connect_notify (
+               model, "notify::work-day-thursday",
+               G_CALLBACK (cal_shell_content_notify_work_day_cb), cal_shell_content);
+
+       e_signal_connect_notify (
+               model, "notify::work-day-friday",
+               G_CALLBACK (cal_shell_content_notify_work_day_cb), cal_shell_content);
+
+       e_signal_connect_notify (
+               model, "notify::work-day-saturday",
+               G_CALLBACK (cal_shell_content_notify_work_day_cb), cal_shell_content);
+
+       e_signal_connect_notify (
+               model, "notify::work-day-sunday",
+               G_CALLBACK (cal_shell_content_notify_work_day_cb), cal_shell_content);
+
+       e_signal_connect_notify (
+               model, "notify::week-start-day",
+               G_CALLBACK (cal_shell_content_notify_week_start_day_cb), cal_shell_content);
+}
+
+static void
+e_cal_shell_content_create_calendar_views (ECalShellContent *cal_shell_content)
+{
+       EShellView *shell_view;
+       ECalModel *model;
+       ECalendarView *calendar_view;
+       GtkAdjustment *adjustment;
+       time_t today;
+       gint ii;
+
+       g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
+       g_return_if_fail (cal_shell_content->priv->calendar_notebook != NULL);
+       g_return_if_fail (cal_shell_content->priv->views[0] == NULL);
+
+       model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
+
+       /* Day View */
+       calendar_view = e_day_view_new (model);
+       cal_shell_content->priv->views[E_CAL_VIEW_KIND_DAY] = calendar_view;
+       g_object_ref_sink (calendar_view);
+
+       /* Work Week View */
+       calendar_view = e_day_view_new (model);
+       e_day_view_set_work_week_view (E_DAY_VIEW (calendar_view), TRUE);
+       e_day_view_set_days_shown (E_DAY_VIEW (calendar_view), 5);
+       cal_shell_content->priv->views[E_CAL_VIEW_KIND_WORKWEEK] = calendar_view;
+       g_object_ref_sink (calendar_view);
+
+       /* Week View */
+       calendar_view = e_week_view_new (model);
+       cal_shell_content->priv->views[E_CAL_VIEW_KIND_WEEK] = calendar_view;
+       g_object_ref_sink (calendar_view);
+
+       adjustment = gtk_range_get_adjustment (
+               GTK_RANGE (E_WEEK_VIEW (calendar_view)->vscrollbar));
+       g_signal_connect (
+               adjustment, "value-changed",
+               G_CALLBACK (week_view_adjustment_changed_cb), cal_shell_content);
+
+       /* Month View */
+       calendar_view = e_month_view_new (model);
+       e_week_view_set_multi_week_view (E_WEEK_VIEW (calendar_view), TRUE);
+       e_week_view_set_weeks_shown (E_WEEK_VIEW (calendar_view), 6);
+       cal_shell_content->priv->views[E_CAL_VIEW_KIND_MONTH] = calendar_view;
+       g_object_ref_sink (calendar_view);
+
+       adjustment = gtk_range_get_adjustment (
+               GTK_RANGE (E_WEEK_VIEW (calendar_view)->vscrollbar));
+       g_signal_connect (
+               adjustment, "value-changed",
+               G_CALLBACK (month_view_adjustment_changed_cb), cal_shell_content);
+
+       /* List View */
+       calendar_view = e_cal_list_view_new (model);
+       cal_shell_content->priv->views[E_CAL_VIEW_KIND_LIST] = calendar_view;
+       g_object_ref_sink (calendar_view);
+
+       shell_view = e_shell_content_get_shell_view (E_SHELL_CONTENT (cal_shell_content));
+       today = time (NULL);
+
+       for (ii = 0; ii < E_CAL_VIEW_KIND_LAST; ii++) {
+               calendar_view = cal_shell_content->priv->views[ii];
+
+               calendar_view->in_focus = ii == cal_shell_content->priv->current_view;
+
+               e_calendar_view_set_selected_time_range (calendar_view, today, today);
+
+               e_signal_connect_notify (
+                       calendar_view, "notify::is-editing",
+                       G_CALLBACK (cal_shell_content_is_editing_changed_cb), shell_view);
+
+               g_signal_connect (
+                       calendar_view, "move-view-range",
+                       G_CALLBACK (cal_shell_content_move_view_range_cb), cal_shell_content);
+
+               gtk_notebook_append_page (
+                       GTK_NOTEBOOK (cal_shell_content->priv->calendar_notebook),
+                       GTK_WIDGET (calendar_view), NULL);
+               gtk_widget_show (GTK_WIDGET (calendar_view));
+       }
+}
+
+static void
+cal_shell_content_set_property (GObject *object,
+                               guint property_id,
+                               const GValue *value,
+                               GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_CURRENT_VIEW_ID:
+                       e_cal_shell_content_set_current_view_id (E_CAL_SHELL_CONTENT (object),
+                               g_value_get_int (value));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+cal_shell_content_get_property (GObject *object,
+                               guint property_id,
+                               GValue *value,
+                               GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_CALENDAR_NOTEBOOK:
+                       g_value_set_object (
+                               value, e_cal_shell_content_get_calendar_notebook (
+                               E_CAL_SHELL_CONTENT (object)));
+                       return;
+
+               case PROP_MEMO_TABLE:
+                       g_value_set_object (
+                               value, e_cal_shell_content_get_memo_table (
+                               E_CAL_SHELL_CONTENT (object)));
+                       return;
+
+               case PROP_TASK_TABLE:
+                       g_value_set_object (
+                               value, e_cal_shell_content_get_task_table (
+                               E_CAL_SHELL_CONTENT (object)));
+                       return;
+
+               case PROP_CURRENT_VIEW_ID:
+                       g_value_set_int (value,
+                               e_cal_shell_content_get_current_view_id (E_CAL_SHELL_CONTENT (object)));
+                       return;
+
+               case PROP_CURRENT_VIEW:
+                       g_value_set_object (value,
+                               e_cal_shell_content_get_current_calendar_view (E_CAL_SHELL_CONTENT (object)));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+cal_shell_content_dispose (GObject *object)
+{
+       ECalShellContent *cal_shell_content = E_CAL_SHELL_CONTENT (object);
+       gint ii;
+
+       if (cal_shell_content->priv->task_data_model) {
+               e_cal_data_model_set_disposing (cal_shell_content->priv->task_data_model, TRUE);
+               e_cal_data_model_unsubscribe (cal_shell_content->priv->task_data_model,
+                       E_CAL_DATA_MODEL_SUBSCRIBER (cal_shell_content->priv->task_model));
+       }
+
+       if (cal_shell_content->priv->memo_data_model) {
+               e_cal_data_model_set_disposing (cal_shell_content->priv->memo_data_model, TRUE);
+               e_cal_data_model_unsubscribe (cal_shell_content->priv->memo_data_model,
+                       E_CAL_DATA_MODEL_SUBSCRIBER (cal_shell_content->priv->memo_model));
+       }
+
+       if (cal_shell_content->priv->tag_calendar) {
+               ECalDataModel *data_model;
+
+               data_model = e_cal_base_shell_content_get_data_model (E_CAL_BASE_SHELL_CONTENT 
(cal_shell_content));
+               e_cal_data_model_set_disposing (data_model, TRUE);
+               e_tag_calendar_unsubscribe (cal_shell_content->priv->tag_calendar, data_model);
+               g_clear_object (&cal_shell_content->priv->tag_calendar);
+       }
+
+       for (ii = 0; ii < E_CAL_VIEW_KIND_LAST; ii++) {
+               g_clear_object (&(cal_shell_content->priv->views[ii]));
+       }
+
+       g_clear_object (&cal_shell_content->priv->hpaned);
+       g_clear_object (&cal_shell_content->priv->vpaned);
+       g_clear_object (&cal_shell_content->priv->calendar_notebook);
+       g_clear_object (&cal_shell_content->priv->task_table);
+       g_clear_object (&cal_shell_content->priv->task_model);
+       g_clear_object (&cal_shell_content->priv->task_data_model);
+       g_clear_object (&cal_shell_content->priv->memo_table);
+       g_clear_object (&cal_shell_content->priv->memo_model);
+       g_clear_object (&cal_shell_content->priv->memo_data_model);
+
+       /* Chain up to parent's dispose() method. */
+       G_OBJECT_CLASS (e_cal_shell_content_parent_class)->dispose (object);
+}
+
+static void
+cal_shell_content_constructed (GObject *object)
+{
+       ECalShellContent *cal_shell_content;
+       EShellContent *shell_content;
+       EShellView *shell_view;
+       EShellWindow *shell_window;
+       EShell *shell;
+       GalViewInstance *view_instance;
+       GSettings *settings;
+       GtkWidget *container;
+       GtkWidget *widget;
+       gchar *markup;
+
+       /* Chain up to parent's constructed() method. */
+       G_OBJECT_CLASS (e_cal_shell_content_parent_class)->constructed (object);
+
+       cal_shell_content = E_CAL_SHELL_CONTENT (object);
+       shell_content = E_SHELL_CONTENT (cal_shell_content);
+       shell_view = e_shell_content_get_shell_view (shell_content);
+       shell_window = e_shell_view_get_shell_window (shell_view);
+       shell = e_shell_window_get_shell (shell_window);
+
+       cal_shell_content->priv->memo_data_model =
+               e_cal_base_shell_content_create_new_data_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
+       cal_shell_content->priv->memo_model =
+               e_cal_model_memos_new (cal_shell_content->priv->memo_data_model, e_shell_get_registry 
(shell), shell);
+
+       cal_shell_content->priv->task_data_model =
+               e_cal_base_shell_content_create_new_data_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
+       cal_shell_content->priv->task_model =
+               e_cal_model_tasks_new (cal_shell_content->priv->task_data_model, e_shell_get_registry 
(shell), shell);
+
+       g_object_bind_property (
+               cal_shell_content->priv->memo_model, "timezone",
+               cal_shell_content->priv->memo_data_model, "timezone",
+               G_BINDING_SYNC_CREATE);
+
+       g_object_bind_property (
+               cal_shell_content->priv->task_model, "timezone",
+               cal_shell_content->priv->task_data_model, "timezone",
+               G_BINDING_SYNC_CREATE);
+
+       /* Build content widgets. */
+
+       container = GTK_WIDGET (object);
+
+       widget = e_paned_new (GTK_ORIENTATION_HORIZONTAL);
+       gtk_container_add (GTK_CONTAINER (container), widget);
+       cal_shell_content->priv->hpaned = g_object_ref (widget);
+       gtk_widget_show (widget);
+
+       container = cal_shell_content->priv->hpaned;
+
+       widget = gtk_notebook_new ();
+       gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE);
+       gtk_notebook_set_show_border (GTK_NOTEBOOK (widget), FALSE);
+       gtk_paned_pack1 (GTK_PANED (container), widget, TRUE, FALSE);
+       cal_shell_content->priv->calendar_notebook = g_object_ref (widget);
+       gtk_widget_show (widget);
+
+       widget = e_paned_new (GTK_ORIENTATION_VERTICAL);
+       e_paned_set_fixed_resize (E_PANED (widget), FALSE);
+       gtk_paned_pack2 (GTK_PANED (container), widget, FALSE, TRUE);
+       cal_shell_content->priv->vpaned = g_object_ref (widget);
+       gtk_widget_show (widget);
+
+       container = cal_shell_content->priv->calendar_notebook;
+
+       e_cal_shell_content_create_calendar_views (cal_shell_content);
+
+       g_object_bind_property (
+               cal_shell_content, "current-view-id",
+               cal_shell_content->priv->calendar_notebook, "page",
+               G_BINDING_SYNC_CREATE);
+
+       container = cal_shell_content->priv->vpaned;
+
+       widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+       gtk_paned_pack1 (GTK_PANED (container), widget, TRUE, TRUE);
+       gtk_widget_show (widget);
+
+       container = widget;
+
+       widget = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
+       gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0);
+       gtk_widget_show (widget);
+
+       widget = gtk_label_new (NULL);
+       markup = g_strdup_printf ("<b>%s</b>", _("Tasks"));
+       gtk_label_set_markup (GTK_LABEL (widget), markup);
+       gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0);
+       gtk_widget_show (widget);
+       g_free (markup);
+
+       widget = gtk_scrolled_window_new (NULL, NULL);
+       gtk_scrolled_window_set_policy (
+               GTK_SCROLLED_WINDOW (widget),
+               GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+       gtk_scrolled_window_set_shadow_type (
+               GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+       gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+       gtk_widget_show (widget);
+
+       container = widget;
+
+       widget = e_task_table_new (shell_view, cal_shell_content->priv->task_model);
+       gtk_container_add (GTK_CONTAINER (container), widget);
+       cal_shell_content->priv->task_table = g_object_ref (widget);
+       gtk_widget_show (widget);
+
+       cal_shell_content_load_table_state (shell_content, E_TABLE (widget));
+
+       g_signal_connect_swapped (
+               widget, "open-component",
+               G_CALLBACK (e_cal_shell_view_taskpad_open_task),
+               shell_view);
+
+       e_signal_connect_notify (
+               widget, "notify::is-editing",
+               G_CALLBACK (cal_shell_content_is_editing_changed_cb), shell_view);
+
+       container = cal_shell_content->priv->vpaned;
+
+       widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+       gtk_paned_pack2 (GTK_PANED (container), widget, TRUE, TRUE);
+       gtk_widget_show (widget);
+
+       container = widget;
+
+       widget = gtk_label_new (NULL);
+       markup = g_strdup_printf ("<b>%s</b>", _("Memos"));
+       gtk_label_set_markup (GTK_LABEL (widget), markup);
+       gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0);
+       gtk_widget_show (widget);
+       g_free (markup);
+
+       widget = gtk_scrolled_window_new (NULL, NULL);
+       gtk_scrolled_window_set_policy (
+               GTK_SCROLLED_WINDOW (widget),
+               GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+       gtk_scrolled_window_set_shadow_type (
+               GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+       gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+       gtk_widget_show (widget);
+
+       container = widget;
+
+       widget = e_memo_table_new (shell_view, cal_shell_content->priv->memo_model);
+       gtk_container_add (GTK_CONTAINER (container), widget);
+       cal_shell_content->priv->memo_table = g_object_ref (widget);
+       gtk_widget_show (widget);
+
+       cal_shell_content_load_table_state (shell_content, E_TABLE (widget));
+
+       e_cal_model_set_default_time_func (cal_shell_content->priv->memo_model, 
cal_shell_content_get_default_time, cal_shell_content);
+
+       g_signal_connect_swapped (
+               widget, "open-component",
+               G_CALLBACK (e_cal_shell_view_memopad_open_memo),
+               shell_view);
+
+       e_signal_connect_notify (
+               widget, "notify::is-editing",
+               G_CALLBACK (cal_shell_content_is_editing_changed_cb), shell_view);
+
+       /* Prepare the view instance. */
+
+       view_instance = e_shell_view_new_view_instance (shell_view, NULL);
+       g_signal_connect_swapped (
+               view_instance, "display-view",
+               G_CALLBACK (cal_shell_content_display_view_cb),
+               object);
+       /* Actual load happens at cal_shell_content_view_created() */
+       e_shell_view_set_view_instance (shell_view, view_instance);
+       g_object_unref (view_instance);
+
+       e_signal_connect_notify_swapped (
+               shell_view, "notify::view-id",
+               G_CALLBACK (cal_shell_content_notify_view_id_cb),
+               cal_shell_content);
+
+       settings = g_settings_new ("org.gnome.evolution.calendar");
+
+       g_settings_bind (
+               settings, "tag-vpane-position",
+               cal_shell_content->priv->vpaned, "proportion",
+               G_SETTINGS_BIND_DEFAULT);
+
+       g_object_unref (settings);
+
+       /* Cannot access shell sidebar here, thus rely on cal_shell_content_view_created()
+          with exact widget settings which require it */
+}
+
 static void
 e_cal_shell_content_class_init (ECalShellContentClass *class)
 {
        GObjectClass *object_class;
-       GtkWidgetClass *widget_class;
        EShellContentClass *shell_content_class;
+       ECalBaseShellContentClass *cal_base_shell_content_class;
 
        g_type_class_add_private (class, sizeof (ECalShellContentPrivate));
 
@@ -814,21 +1649,22 @@ e_cal_shell_content_class_init (ECalShellContentClass *class)
        object_class->dispose = cal_shell_content_dispose;
        object_class->constructed = cal_shell_content_constructed;
 
-       widget_class = GTK_WIDGET_CLASS (class);
-       widget_class->map = cal_shell_content_map;
-
        shell_content_class = E_SHELL_CONTENT_CLASS (class);
        shell_content_class->check_state = cal_shell_content_check_state;
        shell_content_class->focus_search_results = cal_shell_content_focus_search_results;
 
+       cal_base_shell_content_class = E_CAL_BASE_SHELL_CONTENT_CLASS (class);
+       cal_base_shell_content_class->new_cal_model = e_cal_model_calendar_new;
+       cal_base_shell_content_class->view_created = cal_shell_content_view_created;
+
        g_object_class_install_property (
                object_class,
-               PROP_CALENDAR,
+               PROP_CALENDAR_NOTEBOOK,
                g_param_spec_object (
-                       "calendar",
+                       "calendar-notebook",
                        NULL,
                        NULL,
-                       GNOME_TYPE_CALENDAR,
+                       GTK_TYPE_NOTEBOOK,
                        G_PARAM_READABLE));
 
        g_object_class_install_property (
@@ -850,6 +1686,28 @@ e_cal_shell_content_class_init (ECalShellContentClass *class)
                        NULL,
                        E_TYPE_TASK_TABLE,
                        G_PARAM_READABLE));
+
+       g_object_class_install_property (
+               object_class,
+               PROP_CURRENT_VIEW_ID,
+               g_param_spec_int (
+                       "current-view-id",
+                       "Current Calendar View ID",
+                       NULL,
+                       E_CAL_VIEW_KIND_DAY,
+                       E_CAL_VIEW_KIND_LAST - 1,
+                       E_CAL_VIEW_KIND_DAY,
+                       G_PARAM_READWRITE));
+
+       g_object_class_install_property (
+               object_class,
+               PROP_CURRENT_VIEW,
+               g_param_spec_object (
+                       "current-view",
+                       "Current Calendar View",
+                       NULL,
+                       E_TYPE_CALENDAR_VIEW,
+                       G_PARAM_READABLE));
 }
 
 static void
@@ -860,10 +1718,18 @@ e_cal_shell_content_class_finalize (ECalShellContentClass *class)
 static void
 e_cal_shell_content_init (ECalShellContent *cal_shell_content)
 {
-       cal_shell_content->priv =
-               E_CAL_SHELL_CONTENT_GET_PRIVATE (cal_shell_content);
+       time_t now;
+
+       cal_shell_content->priv = E_CAL_SHELL_CONTENT_GET_PRIVATE (cal_shell_content);
+       g_date_clear (&cal_shell_content->priv->view_start, 1);
+       g_date_clear (&cal_shell_content->priv->view_end, 1);
+       g_date_clear (&cal_shell_content->priv->last_range_start, 1);
 
-       /* Postpone widget construction until we have a shell view. */
+       now = time (NULL);
+       g_date_set_time_t (&cal_shell_content->priv->view_start, now);
+       g_date_set_time_t (&cal_shell_content->priv->view_end, now);
+
+       cal_shell_content->priv->view_start_range_day_offset = (guint32) -1;
 }
 
 void
@@ -885,33 +1751,18 @@ e_cal_shell_content_new (EShellView *shell_view)
                "shell-view", shell_view, NULL);
 }
 
-ECalModel *
-e_cal_shell_content_get_model (ECalShellContent *cal_shell_content)
-{
-       GnomeCalendar *calendar;
-
-       g_return_val_if_fail (
-               E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
-
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-
-       return gnome_calendar_get_model (calendar);
-}
-
-GnomeCalendar *
-e_cal_shell_content_get_calendar (ECalShellContent *cal_shell_content)
+GtkNotebook *
+e_cal_shell_content_get_calendar_notebook (ECalShellContent *cal_shell_content)
 {
-       g_return_val_if_fail (
-               E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
+       g_return_val_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
 
-       return GNOME_CALENDAR (cal_shell_content->priv->calendar);
+       return GTK_NOTEBOOK (cal_shell_content->priv->calendar_notebook);
 }
 
 EMemoTable *
 e_cal_shell_content_get_memo_table (ECalShellContent *cal_shell_content)
 {
-       g_return_val_if_fail (
-               E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
+       g_return_val_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
 
        return E_MEMO_TABLE (cal_shell_content->priv->memo_table);
 }
@@ -919,8 +1770,7 @@ e_cal_shell_content_get_memo_table (ECalShellContent *cal_shell_content)
 ETaskTable *
 e_cal_shell_content_get_task_table (ECalShellContent *cal_shell_content)
 {
-       g_return_val_if_fail (
-               E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
+       g_return_val_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
 
        return E_TASK_TABLE (cal_shell_content->priv->task_table);
 }
@@ -932,8 +1782,7 @@ e_cal_shell_content_get_searchbar (ECalShellContent *cal_shell_content)
        EShellContent *shell_content;
        GtkWidget *widget;
 
-       g_return_val_if_fail (
-               E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
+       g_return_val_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
 
        shell_content = E_SHELL_CONTENT (cal_shell_content);
        shell_view = e_shell_content_get_shell_view (shell_content);
@@ -942,3 +1791,384 @@ e_cal_shell_content_get_searchbar (ECalShellContent *cal_shell_content)
        return E_SHELL_SEARCHBAR (widget);
 }
 
+static void
+cal_shell_content_resubscribe (ECalendarView *cal_view,
+                              ECalModel *model)
+{
+       ECalDataModel *data_model;
+       ECalDataModelSubscriber *subscriber;
+       time_t range_start, range_end;
+       gboolean is_tasks_or_memos;
+
+       g_return_if_fail (E_IS_CALENDAR_VIEW (cal_view));
+       g_return_if_fail (E_IS_CAL_MODEL (model));
+
+       data_model = e_cal_model_get_data_model (model);
+       subscriber = E_CAL_DATA_MODEL_SUBSCRIBER (model);
+       is_tasks_or_memos = e_cal_model_get_component_kind (model) == ICAL_VJOURNAL_COMPONENT ||
+               e_cal_model_get_component_kind (model) == ICAL_VTODO_COMPONENT;
+
+       if ((!is_tasks_or_memos && e_calendar_view_get_visible_time_range (cal_view, &range_start, 
&range_end)) ||
+           e_cal_data_model_get_subscriber_range (data_model, subscriber, &range_start, &range_end)) {
+               e_cal_data_model_unsubscribe (data_model, subscriber);
+               e_cal_model_remove_all_objects (model);
+
+               if (is_tasks_or_memos)
+                       e_cal_data_model_subscribe (data_model, subscriber, range_start, range_end);
+       }
+}
+
+void
+e_cal_shell_content_set_current_view_id (ECalShellContent *cal_shell_content,
+                                        ECalViewKind view_kind)
+{
+       gint ii;
+
+       g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
+       g_return_if_fail (view_kind >= E_CAL_VIEW_KIND_DAY && view_kind < E_CAL_VIEW_KIND_LAST);
+
+       if (cal_shell_content->priv->current_view == view_kind)
+               return;
+
+       for (ii = 0; ii < E_CAL_VIEW_KIND_LAST; ii++) {
+               ECalendarView *cal_view = cal_shell_content->priv->views[ii];
+               gboolean in_focus = ii == view_kind;
+               gboolean focus_changed;
+
+               if (!cal_view) {
+                       g_warn_if_reached ();
+                       continue;
+               }
+
+               focus_changed = (cal_view->in_focus ? 1 : 0) != (in_focus ? 1 : 0);
+
+               cal_view->in_focus = in_focus;
+
+               if (focus_changed && in_focus) {
+                       /* Currently focused view changed. Any events within the common time
+                          range are not shown in the newly focused view, thus make sure it'll
+                          contain all what it should have. */
+                       ECalModel *model;
+
+                       model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT 
(cal_shell_content));
+
+                       /* This may not cause any queries to backends with events,
+                          because the time range should be always within the one
+                          shown in the date picker. */
+                       cal_shell_content_resubscribe (cal_view, model);
+
+                       if (cal_shell_content->priv->task_table) {
+                               ETaskTable *task_table;
+
+                               task_table = E_TASK_TABLE (cal_shell_content->priv->task_table);
+                               cal_shell_content_resubscribe (cal_view, e_task_table_get_model (task_table));
+                       }
+
+                       if (cal_shell_content->priv->memo_table) {
+                               EMemoTable *memo_table;
+
+                               memo_table = E_MEMO_TABLE (cal_shell_content->priv->memo_table);
+                               cal_shell_content_resubscribe (cal_view, e_memo_table_get_model (memo_table));
+                       }
+               }
+       }
+
+       cal_shell_content->priv->current_view = view_kind;
+
+       g_object_notify (G_OBJECT (cal_shell_content), "current-view-id");
+
+       gtk_widget_queue_draw (GTK_WIDGET 
(cal_shell_content->priv->views[cal_shell_content->priv->current_view]));
+}
+
+ECalViewKind
+e_cal_shell_content_get_current_view_id (ECalShellContent *cal_shell_content)
+{
+       g_return_val_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content), E_CAL_VIEW_KIND_LAST);
+
+       return cal_shell_content->priv->current_view;
+}
+
+ECalendarView *
+e_cal_shell_content_get_calendar_view (ECalShellContent *cal_shell_content,
+                                      ECalViewKind view_kind)
+{
+       g_return_val_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
+       g_return_val_if_fail (view_kind >= E_CAL_VIEW_KIND_DAY && view_kind < E_CAL_VIEW_KIND_LAST, NULL);
+
+       return cal_shell_content->priv->views[view_kind];
+}
+
+ECalendarView *
+e_cal_shell_content_get_current_calendar_view (ECalShellContent *cal_shell_content)
+{
+       g_return_val_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
+
+       return e_cal_shell_content_get_calendar_view (cal_shell_content,
+               e_cal_shell_content_get_current_view_id (cal_shell_content));
+}
+
+void
+e_cal_shell_content_save_state (ECalShellContent *cal_shell_content)
+{
+       ECalShellContentPrivate *priv;
+
+       g_return_if_fail (cal_shell_content != NULL);
+       g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
+
+       priv = cal_shell_content->priv;
+
+       if (priv->task_table != NULL)
+               cal_shell_content_save_table_state (
+                       E_SHELL_CONTENT (cal_shell_content),
+                       E_TABLE (priv->task_table));
+
+       if (priv->memo_table != NULL)
+               cal_shell_content_save_table_state (
+                       E_SHELL_CONTENT (cal_shell_content),
+                       E_TABLE (priv->memo_table));
+}
+
+void
+e_cal_shell_content_get_current_range (ECalShellContent *cal_shell_content,
+                                      time_t *range_start,
+                                      time_t *range_end)
+{
+       icaltimezone *zone;
+
+       g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
+       g_return_if_fail (range_start != NULL);
+       g_return_if_fail (range_end != NULL);
+
+       zone = e_cal_data_model_get_timezone (e_cal_base_shell_content_get_data_model (
+               E_CAL_BASE_SHELL_CONTENT (cal_shell_content)));
+
+       *range_start = cal_comp_gdate_to_timet (&(cal_shell_content->priv->view_start), zone);
+       *range_end = cal_comp_gdate_to_timet (&(cal_shell_content->priv->view_end), zone);
+}
+
+void
+e_cal_shell_content_get_current_range_dates (ECalShellContent *cal_shell_content,
+                                            GDate *range_start,
+                                            GDate *range_end)
+{
+       g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
+       g_return_if_fail (range_start != NULL);
+       g_return_if_fail (range_end != NULL);
+
+       *range_start = cal_shell_content->priv->view_start;
+       *range_end = cal_shell_content->priv->view_end;
+}
+
+static void
+cal_shell_content_move_view_range_relative (ECalShellContent *cal_shell_content,
+                                           gint direction)
+{
+       GDate start, end;
+
+       g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
+       g_return_if_fail (direction != 0);
+
+       start = cal_shell_content->priv->view_start;
+       end = cal_shell_content->priv->view_end;
+
+       switch (cal_shell_content->priv->current_view) {
+               case E_CAL_VIEW_KIND_DAY:
+                       if (direction > 0) {
+                               g_date_add_days (&start, direction);
+                               g_date_add_days (&end, direction);
+                       } else {
+                               g_date_subtract_days (&start, direction * -1);
+                               g_date_subtract_days (&end, direction * -1);
+                       }
+                       break;
+               case E_CAL_VIEW_KIND_WORKWEEK:
+               case E_CAL_VIEW_KIND_WEEK:
+                       if (direction > 0) {
+                               g_date_add_days (&start, direction * 7);
+                               g_date_add_days (&end, direction * 7);
+                       } else {
+                               g_date_subtract_days (&start, direction * -7);
+                               g_date_subtract_days (&end, direction * -7);
+                       }
+                       break;
+               case E_CAL_VIEW_KIND_MONTH:
+               case E_CAL_VIEW_KIND_LIST:
+                       if (direction > 0) {
+                               g_date_add_months (&start, direction);
+                               g_date_add_months (&end, direction);
+                       } else {
+                               g_date_subtract_months (&start, direction * -1);
+                               g_date_subtract_months (&end, direction * -1);
+                       }
+                       break;
+               case E_CAL_VIEW_KIND_LAST:
+                       return;
+       }
+
+       e_cal_shell_content_change_view (cal_shell_content, cal_shell_content->priv->current_view, &start, 
&end, FALSE);
+}
+
+void
+e_cal_shell_content_move_view_range (ECalShellContent *cal_shell_content,
+                                    ECalendarViewMoveType move_type,
+                                    time_t exact_date)
+{
+       ECalendar *calendar;
+       ECalDataModel *data_model;
+       EShellSidebar *shell_sidebar;
+       EShellView *shell_view;
+       struct icaltimetype tt;
+       icaltimezone *zone;
+       GDate date;
+
+       g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
+
+       shell_view = e_shell_content_get_shell_view (E_SHELL_CONTENT (cal_shell_content));
+       shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+       g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (shell_sidebar));
+
+       calendar = e_cal_base_shell_sidebar_get_date_navigator (E_CAL_BASE_SHELL_SIDEBAR (shell_sidebar));
+       g_return_if_fail (E_IS_CALENDAR (calendar));
+       g_return_if_fail (calendar->calitem != NULL);
+
+       data_model = e_cal_base_shell_content_get_data_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
+       zone = e_cal_data_model_get_timezone (data_model);
+
+       switch (move_type) {
+               case E_CALENDAR_VIEW_MOVE_PREVIOUS:
+                       cal_shell_content_move_view_range_relative (cal_shell_content, -1);
+                       break;
+               case E_CALENDAR_VIEW_MOVE_NEXT:
+                       cal_shell_content_move_view_range_relative (cal_shell_content, +1);
+                       break;
+               case E_CALENDAR_VIEW_MOVE_TO_TODAY:
+                       tt = icaltime_current_time_with_zone (zone);
+                       g_date_set_dmy (&date, tt.day, tt.month, tt.year);
+                       /* one-day selection takes care of the view range move with left view kind */
+                       e_calendar_item_set_selection (calendar->calitem, &date, &date);
+                       break;
+               case E_CALENDAR_VIEW_MOVE_TO_EXACT_DAY:
+                       time_to_gdate_with_zone (&date, exact_date, zone);
+                       e_cal_shell_content_change_view (cal_shell_content, E_CAL_VIEW_KIND_DAY, &date, 
&date, FALSE);
+                       break;
+       }
+}
+
+static void
+cal_shell_content_update_model_filter (ECalDataModel *data_model,
+                                      ECalModel *model,
+                                      const gchar *filter,
+                                      time_t range_start,
+                                      time_t range_end)
+{
+       time_t tmp_start, tmp_end;
+
+       g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model));
+       g_return_if_fail (E_IS_CAL_MODEL (model));
+
+       e_cal_data_model_freeze_views_update (data_model);
+       if (filter != NULL)
+               e_cal_data_model_set_filter (data_model, filter);
+       e_cal_model_set_time_range (model, range_start, range_end);
+
+       if (!e_cal_data_model_get_subscriber_range (data_model, E_CAL_DATA_MODEL_SUBSCRIBER (model), 
&tmp_start, &tmp_end)) {
+               e_cal_data_model_subscribe (data_model, E_CAL_DATA_MODEL_SUBSCRIBER (model), range_start, 
range_end);
+       }
+
+       e_cal_data_model_thaw_views_update (data_model);
+}
+
+void
+e_cal_shell_content_update_filters (ECalShellContent *cal_shell_content,
+                                   const gchar *cal_filter,
+                                   time_t start_range,
+                                   time_t end_range)
+{
+       ECalDataModel *data_model;
+       ECalModel *model;
+
+       g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
+
+       if (!cal_filter)
+               return;
+
+       data_model = e_cal_base_shell_content_get_data_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
+       model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
+
+       cal_shell_content_update_model_filter (data_model, model, cal_filter, start_range, end_range);
+
+       if (cal_shell_content->priv->task_table) {
+               ETaskTable *task_table;
+               gchar *hide_completed_tasks_sexp;
+
+               /* Set the query on the task pad. */
+
+               task_table = E_TASK_TABLE (cal_shell_content->priv->task_table);
+               model = e_task_table_get_model (task_table);
+               data_model = e_cal_model_get_data_model (model);
+
+               hide_completed_tasks_sexp = calendar_config_get_hide_completed_tasks_sexp (FALSE);
+
+               if (hide_completed_tasks_sexp != NULL) {
+                       if (cal_filter != NULL) {
+                               gchar *filter;
+
+                               filter = g_strdup_printf ("(and %s %s)", hide_completed_tasks_sexp, 
cal_filter);
+                               cal_shell_content_update_model_filter (data_model, model, filter, 0, 0);
+                               g_free (filter);
+                       } else {
+                               cal_shell_content_update_model_filter (data_model, model, 
hide_completed_tasks_sexp, 0, 0);
+                       }
+               } else {
+                       cal_shell_content_update_model_filter (data_model, model, cal_filter ? cal_filter : 
"#t", 0, 0);
+               }
+
+               g_free (hide_completed_tasks_sexp);
+       }
+
+       if (cal_shell_content->priv->memo_table) {
+               EMemoTable *memo_table;
+
+               /* Set the query on the memo pad. */
+
+               memo_table = E_MEMO_TABLE (cal_shell_content->priv->memo_table);
+               model = e_memo_table_get_model (memo_table);
+               data_model = e_cal_model_get_data_model (model);
+
+               if (start_range != 0 && end_range != 0) {
+                       icaltimezone *zone;
+                       const gchar *default_tzloc = NULL;
+                       time_t end = end_range;
+                       gchar *filter;
+                       gchar *iso_start;
+                       gchar *iso_end;
+
+                       zone = e_cal_data_model_get_timezone (data_model);
+                       if (zone && zone != icaltimezone_get_utc_timezone ())
+                               default_tzloc = icaltimezone_get_location (zone);
+                       if (!default_tzloc)
+                               default_tzloc = "";
+
+                       if (start_range != (time_t) 0 && end_range != (time_t) 0) {
+                               end = time_day_end_with_zone (end_range, zone);
+                       }
+
+                       iso_start = isodate_from_time_t (start_range);
+                       iso_end = isodate_from_time_t (end);
+
+                       filter = g_strdup_printf (
+                               "(and (or (not (has-start?)) "
+                               "(occur-in-time-range? (make-time \"%s\") "
+                               "(make-time \"%s\") \"%s\")) %s)",
+                               iso_start, iso_end, default_tzloc, cal_filter ? cal_filter : "");
+
+                       cal_shell_content_update_model_filter (data_model, model, filter, 0, 0);
+
+                       g_free (filter);
+                       g_free (iso_start);
+                       g_free (iso_end);
+               } else {
+                       cal_shell_content_update_model_filter (data_model, model, cal_filter ? cal_filter : 
"#t", 0, 0);
+               }
+       }
+}
diff --git a/modules/calendar/e-cal-shell-content.h b/modules/calendar/e-cal-shell-content.h
index 489d8b6..f87fac4 100644
--- a/modules/calendar/e-cal-shell-content.h
+++ b/modules/calendar/e-cal-shell-content.h
@@ -1,5 +1,6 @@
 /*
- * e-cal-shell-content.h
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
@@ -7,15 +8,11 @@
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
  * for more details.
  *
  * You should have received a copy of the GNU Lesser General Public License
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
  */
 
 #ifndef E_CAL_SHELL_CONTENT_H
@@ -27,7 +24,9 @@
 
 #include <calendar/gui/e-memo-table.h>
 #include <calendar/gui/e-task-table.h>
-#include <calendar/gui/gnome-cal.h>
+#include <calendar/gui/e-calendar-view.h>
+
+#include "e-cal-base-shell-content.h"
 
 /* Standard GObject macros */
 #define E_TYPE_CAL_SHELL_CONTENT \
@@ -50,47 +49,60 @@
 
 G_BEGIN_DECLS
 
+typedef enum {
+       E_CAL_VIEW_KIND_DAY = 0,
+       E_CAL_VIEW_KIND_WORKWEEK,
+       E_CAL_VIEW_KIND_WEEK,
+       E_CAL_VIEW_KIND_MONTH,
+       E_CAL_VIEW_KIND_LIST,
+       E_CAL_VIEW_KIND_LAST
+} ECalViewKind;
+
 typedef struct _ECalShellContent ECalShellContent;
 typedef struct _ECalShellContentClass ECalShellContentClass;
 typedef struct _ECalShellContentPrivate ECalShellContentPrivate;
 
-enum {
-       E_CAL_SHELL_CONTENT_SELECTION_SINGLE = 1 << 0,
-       E_CAL_SHELL_CONTENT_SELECTION_MULTIPLE = 1 << 1,
-       E_CAL_SHELL_CONTENT_SELECTION_IS_EDITABLE = 1 << 2,
-       E_CAL_SHELL_CONTENT_SELECTION_IS_INSTANCE = 1 << 3,
-       E_CAL_SHELL_CONTENT_SELECTION_IS_MEETING = 1 << 4,
-       E_CAL_SHELL_CONTENT_SELECTION_IS_ORGANIZER = 1 << 5,
-       E_CAL_SHELL_CONTENT_SELECTION_IS_RECURRING = 1 << 6,
-       E_CAL_SHELL_CONTENT_SELECTION_CAN_DELEGATE = 1 << 7
-};
-
 struct _ECalShellContent {
-       EShellContent parent;
+       ECalBaseShellContent parent;
        ECalShellContentPrivate *priv;
 };
 
 struct _ECalShellContentClass {
-       EShellContentClass parent_class;
+       ECalBaseShellContentClass parent_class;
 };
 
-GType          e_cal_shell_content_get_type    (void);
-void           e_cal_shell_content_type_register
-                                       (GTypeModule *type_module);
-GtkWidget *    e_cal_shell_content_new (EShellView *shell_view);
-ECalModel *    e_cal_shell_content_get_model
-                                       (ECalShellContent *cal_shell_content);
-GnomeCalendar *        e_cal_shell_content_get_calendar
-                                       (ECalShellContent *cal_shell_content);
-EMemoTable *   e_cal_shell_content_get_memo_table
-                                       (ECalShellContent *cal_shell_content);
-ETaskTable *   e_cal_shell_content_get_task_table
-                                       (ECalShellContent *cal_shell_content);
+GType          e_cal_shell_content_get_type            (void);
+void           e_cal_shell_content_type_register       (GTypeModule *type_module);
+GtkWidget *    e_cal_shell_content_new                 (EShellView *shell_view);
+
+GtkNotebook *  e_cal_shell_content_get_calendar_notebook
+                                                       (ECalShellContent *cal_shell_content);
+EMemoTable *   e_cal_shell_content_get_memo_table      (ECalShellContent *cal_shell_content);
+ETaskTable *   e_cal_shell_content_get_task_table      (ECalShellContent *cal_shell_content);
 EShellSearchbar *
-               e_cal_shell_content_get_searchbar
-                                       (ECalShellContent *cal_shell_content);
-void           e_cal_shell_content_save_state
-                                       (ECalShellContent *cal_shell_content);
+               e_cal_shell_content_get_searchbar       (ECalShellContent *cal_shell_content);
+void           e_cal_shell_content_set_current_view_id (ECalShellContent *cal_shell_content,
+                                                        ECalViewKind view_kind);
+ECalViewKind   e_cal_shell_content_get_current_view_id (ECalShellContent *cal_shell_content);
+ECalendarView *        e_cal_shell_content_get_calendar_view   (ECalShellContent *cal_shell_content,
+                                                        ECalViewKind view_kind);
+ECalendarView *        e_cal_shell_content_get_current_calendar_view
+                                                       (ECalShellContent *cal_shell_content);
+void           e_cal_shell_content_save_state          (ECalShellContent *cal_shell_content);
+void           e_cal_shell_content_get_current_range   (ECalShellContent *cal_shell_content,
+                                                        time_t *range_start,
+                                                        time_t *range_end);
+void           e_cal_shell_content_get_current_range_dates
+                                                       (ECalShellContent *cal_shell_content,
+                                                        GDate *range_start,
+                                                        GDate *range_end);
+void           e_cal_shell_content_move_view_range     (ECalShellContent *cal_shell_content,
+                                                        ECalendarViewMoveType move_type,
+                                                        time_t exact_date);
+void           e_cal_shell_content_update_filters      (ECalShellContent *cal_shell_content,
+                                                        const gchar *cal_filter,
+                                                        time_t start_range,
+                                                        time_t end_range);
 
 G_END_DECLS
 
diff --git a/modules/calendar/e-cal-shell-view-actions.c b/modules/calendar/e-cal-shell-view-actions.c
index 93e61aa..af7855f 100644
--- a/modules/calendar/e-cal-shell-view-actions.c
+++ b/modules/calendar/e-cal-shell-view-actions.c
@@ -22,6 +22,10 @@
 #include <config.h>
 #endif
 
+#include <calendar/gui/e-cal-ops.h>
+#include <calendar/gui/print.h>
+
+#include "e-cal-base-shell-view.h"
 #include "e-cal-shell-view-private.h"
 #include "e-cal-shell-view.h"
 
@@ -32,39 +36,16 @@
 
 static void
 action_calendar_copy_cb (GtkAction *action,
-                         ECalShellView *cal_shell_view)
+                        EShellView *shell_view)
 {
-       ECalShellSidebar *cal_shell_sidebar;
-       EShell *shell;
-       EShellView *shell_view;
-       EShellWindow *shell_window;
-       ESourceRegistry *registry;
-       ESourceSelector *selector;
-       ESource *source;
-
-       shell_view = E_SHELL_VIEW (cal_shell_view);
-       shell_window = e_shell_view_get_shell_window (shell_view);
-       shell = e_shell_window_get_shell (shell_window);
-
-       registry = e_shell_get_registry (shell);
-
-       cal_shell_sidebar = cal_shell_view->priv->cal_shell_sidebar;
-       selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
-       source = e_source_selector_ref_primary_selection (selector);
-       g_return_if_fail (source != NULL);
-
-       copy_source_dialog (
-               GTK_WINDOW (shell_window), registry,
-               source, E_CAL_CLIENT_SOURCE_TYPE_EVENTS);
-
-       g_object_unref (source);
+       e_cal_base_shell_view_copy_calendar (shell_view);
 }
 
 static void
 action_calendar_delete_cb (GtkAction *action,
                            ECalShellView *cal_shell_view)
 {
-       ECalShellSidebar *cal_shell_sidebar;
+       ECalBaseShellSidebar *cal_shell_sidebar;
        EShellWindow *shell_window;
        EShellView *shell_view;
        ESource *source;
@@ -75,7 +56,7 @@ action_calendar_delete_cb (GtkAction *action,
        shell_window = e_shell_view_get_shell_window (shell_view);
 
        cal_shell_sidebar = cal_shell_view->priv->cal_shell_sidebar;
-       selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+       selector = e_cal_base_shell_sidebar_get_selector (cal_shell_sidebar);
 
        source = e_source_selector_ref_primary_selection (selector);
        g_return_if_fail (source != NULL);
@@ -106,57 +87,47 @@ static void
 action_calendar_go_back_cb (GtkAction *action,
                             ECalShellView *cal_shell_view)
 {
-       ECalShellContent *cal_shell_content;
-       GnomeCalendar *calendar;
-
-       cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-
-       gnome_calendar_previous (calendar);
+       e_cal_shell_content_move_view_range (
+               cal_shell_view->priv->cal_shell_content, E_CALENDAR_VIEW_MOVE_PREVIOUS, 0);
 }
 
 static void
 action_calendar_go_forward_cb (GtkAction *action,
                                ECalShellView *cal_shell_view)
 {
-       ECalShellContent *cal_shell_content;
-       GnomeCalendar *calendar;
-
-       cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-
-       gnome_calendar_next (calendar);
+       e_cal_shell_content_move_view_range (
+               cal_shell_view->priv->cal_shell_content, E_CALENDAR_VIEW_MOVE_NEXT, 0);
 }
 
 static void
 action_calendar_go_today_cb (GtkAction *action,
                              ECalShellView *cal_shell_view)
 {
-       ECalShellContent *cal_shell_content;
-       GnomeCalendar *calendar;
-
-       cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-
-       gnome_calendar_goto_today (calendar);
+       e_cal_shell_content_move_view_range (
+               cal_shell_view->priv->cal_shell_content, E_CALENDAR_VIEW_MOVE_TO_TODAY, 0);
 }
 
 static void
 action_calendar_jump_to_cb (GtkAction *action,
                             ECalShellView *cal_shell_view)
 {
+       ECalDataModel *data_model;
        ECalShellContent *cal_shell_content;
        EShellWindow *shell_window;
        EShellView *shell_view;
-       GnomeCalendar *calendar;
+       GDate range_start, range_end;
+       ECalendarViewMoveType move_type;
+       time_t exact_date = time (NULL);
 
        shell_view = E_SHELL_VIEW (cal_shell_view);
        shell_window = e_shell_view_get_shell_window (shell_view);
 
        cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+       e_cal_shell_content_get_current_range_dates (cal_shell_content, &range_start, &range_end);
+       data_model = e_cal_base_shell_content_get_data_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
 
-       goto_dialog (GTK_WINDOW (shell_window), calendar);
+       if (goto_dialog_run (GTK_WINDOW (shell_window), data_model, &range_start, &move_type, &exact_date))
+               e_cal_shell_content_move_view_range (cal_shell_content, move_type, exact_date);
 }
 
 static void
@@ -194,61 +165,66 @@ action_calendar_new_cb (GtkAction *action,
 }
 
 static void
-action_calendar_print_cb (GtkAction *action,
-                          ECalShellView *cal_shell_view)
+cal_shell_view_actions_print_or_preview (ECalShellView *cal_shell_view,
+                                        GtkPrintOperationAction print_action)
 {
        ECalShellContent *cal_shell_content;
-       GnomeCalendarViewType view_type;
-       GnomeCalendar *calendar;
-       ECalendarView *view;
-       GtkPrintOperationAction print_action;
+       ECalendarView *cal_view;
 
        cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-       view_type = gnome_calendar_get_view (calendar);
-       view = gnome_calendar_get_calendar_view (calendar, view_type);
-       print_action = GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG;
+       cal_view = e_cal_shell_content_get_current_calendar_view (cal_shell_content);
 
-       if (E_IS_CAL_LIST_VIEW (view)) {
+       if (E_IS_CAL_LIST_VIEW (cal_view)) {
                ETable *table;
 
-               table = E_CAL_LIST_VIEW (view)->table;
+               table = E_CAL_LIST_VIEW (cal_view)->table;
                print_table (table, _("Print"), _("Calendar"), print_action);
        } else {
-               time_t start;
+               EPrintView print_view_type;
+               ETable *tasks_table;
+               time_t start = 0, end = 0;
+
+               switch (e_cal_shell_content_get_current_view_id (cal_shell_content)) {
+                       case E_CAL_VIEW_KIND_DAY:
+                               print_view_type = E_PRINT_VIEW_DAY;
+                               break;
+                       case E_CAL_VIEW_KIND_WORKWEEK:
+                               print_view_type = E_PRINT_VIEW_WORKWEEK;
+                               break;
+                       case E_CAL_VIEW_KIND_WEEK:
+                               print_view_type = E_PRINT_VIEW_WEEK;
+                               break;
+                       case E_CAL_VIEW_KIND_MONTH:
+                               print_view_type = E_PRINT_VIEW_MONTH;
+                               break;
+                       case E_CAL_VIEW_KIND_LIST:
+                               print_view_type = E_PRINT_VIEW_LIST;
+                               break;
+                       default:
+                               g_warn_if_reached ();
+                               return;
+               }
+
+               tasks_table = E_TABLE (e_cal_shell_content_get_task_table (cal_shell_content));
 
-               gnome_calendar_get_current_time_range (calendar, &start, NULL);
-               print_calendar (calendar, print_action, start);
+               g_warn_if_fail (e_calendar_view_get_selected_time_range (cal_view, &start, &end));
+
+               print_calendar (cal_view, tasks_table, print_view_type, print_action, start);
        }
 }
 
 static void
+action_calendar_print_cb (GtkAction *action,
+                          ECalShellView *cal_shell_view)
+{
+       cal_shell_view_actions_print_or_preview (cal_shell_view, GTK_PRINT_OPERATION_ACTION_PRINT);
+}
+
+static void
 action_calendar_print_preview_cb (GtkAction *action,
                                   ECalShellView *cal_shell_view)
 {
-       ECalShellContent *cal_shell_content;
-       GnomeCalendarViewType view_type;
-       GnomeCalendar *calendar;
-       ECalendarView *view;
-       GtkPrintOperationAction print_action;
-
-       cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-       view_type = gnome_calendar_get_view (calendar);
-       view = gnome_calendar_get_calendar_view (calendar, view_type);
-       print_action = GTK_PRINT_OPERATION_ACTION_PREVIEW;
-
-       if (E_IS_CAL_LIST_VIEW (view)) {
-               ETable *table;
-
-               table = E_CAL_LIST_VIEW (view)->table;
-               print_table (table, _("Print"), _("Calendar"), print_action);
-       } else {
-               time_t start;
-
-               gnome_calendar_get_current_time_range (calendar, &start, NULL);
-               print_calendar (calendar, print_action, start);
-       }
+       cal_shell_view_actions_print_or_preview (cal_shell_view, GTK_PRINT_OPERATION_ACTION_PREVIEW);
 }
 
 static void
@@ -257,7 +233,7 @@ action_calendar_properties_cb (GtkAction *action,
 {
        EShellView *shell_view;
        EShellWindow *shell_window;
-       ECalShellSidebar *cal_shell_sidebar;
+       ECalBaseShellSidebar *cal_shell_sidebar;
        ECalClientSourceType source_type;
        ESource *source;
        ESourceSelector *selector;
@@ -270,7 +246,7 @@ action_calendar_properties_cb (GtkAction *action,
        shell_window = e_shell_view_get_shell_window (shell_view);
 
        cal_shell_sidebar = cal_shell_view->priv->cal_shell_sidebar;
-       selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+       selector = e_cal_base_shell_sidebar_get_selector (cal_shell_sidebar);
        source = e_source_selector_ref_primary_selection (selector);
        g_return_if_fail (source != NULL);
 
@@ -300,7 +276,6 @@ action_calendar_purge_cb (GtkAction *action,
        EShellView *shell_view;
        EShellWindow *shell_window;
        ECalShellContent *cal_shell_content;
-       GnomeCalendar *calendar;
        GtkSpinButton *spin_button;
        GtkWidget *container;
        GtkWidget *dialog;
@@ -312,7 +287,6 @@ action_calendar_purge_cb (GtkAction *action,
        shell_window = e_shell_view_get_shell_window (shell_view);
 
        cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
 
        dialog = gtk_message_dialog_new (
                GTK_WINDOW (shell_window),
@@ -361,9 +335,9 @@ action_calendar_purge_cb (GtkAction *action,
        tt = time (NULL);
        tt -= (days * (24 * 3600));
 
-       gnome_calendar_purge (calendar, tt);
+       e_cal_ops_purge_components (e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT 
(cal_shell_content)), tt);
 
-exit:
+ exit:
        gtk_widget_destroy (dialog);
 }
 
@@ -371,13 +345,13 @@ static void
 action_calendar_refresh_cb (GtkAction *action,
                            ECalShellView *cal_shell_view)
 {
-       ECalShellSidebar *cal_shell_sidebar;
+       ECalBaseShellSidebar *cal_shell_sidebar;
        ESourceSelector *selector;
        EClient *client = NULL;
        ESource *source;
 
        cal_shell_sidebar = cal_shell_view->priv->cal_shell_sidebar;
-       selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+       selector = e_cal_base_shell_sidebar_get_selector (cal_shell_sidebar);
 
        source = e_source_selector_ref_primary_selection (selector);
 
@@ -392,7 +366,7 @@ action_calendar_refresh_cb (GtkAction *action,
 
        g_return_if_fail (e_client_check_refresh_supported (client));
 
-       e_cal_shell_view_allow_auth_prompt_and_refresh (E_SHELL_VIEW (cal_shell_view), client);
+       e_cal_base_shell_view_allow_auth_prompt_and_refresh (E_SHELL_VIEW (cal_shell_view), client);
 
        g_object_unref (client);
 }
@@ -401,11 +375,11 @@ static void
 action_calendar_rename_cb (GtkAction *action,
                            ECalShellView *cal_shell_view)
 {
-       ECalShellSidebar *cal_shell_sidebar;
+       ECalBaseShellSidebar *cal_shell_sidebar;
        ESourceSelector *selector;
 
        cal_shell_sidebar = cal_shell_view->priv->cal_shell_sidebar;
-       selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+       selector = e_cal_base_shell_sidebar_get_selector (cal_shell_sidebar);
 
        e_source_selector_edit_primary_selection (selector);
 }
@@ -435,12 +409,12 @@ static void
 action_calendar_select_one_cb (GtkAction *action,
                                ECalShellView *cal_shell_view)
 {
-       ECalShellSidebar *cal_shell_sidebar;
+       ECalBaseShellSidebar *cal_shell_sidebar;
        ESourceSelector *selector;
        ESource *primary;
 
        cal_shell_sidebar = cal_shell_view->priv->cal_shell_sidebar;
-       selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+       selector = e_cal_base_shell_sidebar_get_selector (cal_shell_sidebar);
 
        primary = e_source_selector_ref_primary_selection (selector);
        g_return_if_fail (primary != NULL);
@@ -456,30 +430,30 @@ action_calendar_view_cb (GtkRadioAction *action,
                          ECalShellView *cal_shell_view)
 {
        EShellView *shell_view;
-       GnomeCalendarViewType view_type;
+       ECalViewKind view_kind;
        const gchar *view_id;
 
        shell_view = E_SHELL_VIEW (cal_shell_view);
-       view_type = gtk_radio_action_get_current_value (action);
+       view_kind = gtk_radio_action_get_current_value (action);
 
-       switch (view_type) {
-               case GNOME_CAL_DAY_VIEW:
+       switch (view_kind) {
+               case E_CAL_VIEW_KIND_DAY:
                        view_id = "Day_View";
                        break;
 
-               case GNOME_CAL_WORK_WEEK_VIEW:
+               case E_CAL_VIEW_KIND_WORKWEEK:
                        view_id = "Work_Week_View";
                        break;
 
-               case GNOME_CAL_WEEK_VIEW:
+               case E_CAL_VIEW_KIND_WEEK:
                        view_id = "Week_View";
                        break;
 
-               case GNOME_CAL_MONTH_VIEW:
+               case E_CAL_VIEW_KIND_MONTH:
                        view_id = "Month_View";
                        break;
 
-               case GNOME_CAL_LIST_VIEW:
+               case E_CAL_VIEW_KIND_LIST:
                        view_id = "List_View";
                        break;
 
@@ -495,9 +469,7 @@ action_event_all_day_new_cb (GtkAction *action,
                              ECalShellView *cal_shell_view)
 {
        ECalShellContent *cal_shell_content;
-       GnomeCalendarViewType view_type;
        ECalendarView *calendar_view;
-       GnomeCalendar *calendar;
 
        /* These are just for readability. */
        gboolean all_day = TRUE;
@@ -505,40 +477,34 @@ action_event_all_day_new_cb (GtkAction *action,
        gboolean no_past_date = FALSE;
 
        cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-       view_type = gnome_calendar_get_view (calendar);
-       calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+       calendar_view = e_cal_shell_content_get_current_calendar_view (cal_shell_content);
 
        e_calendar_view_new_appointment_full (
                calendar_view, all_day, meeting, no_past_date);
 }
 
 static void
-action_event_copy_cb (GtkAction *action,
-                      ECalShellView *cal_shell_view)
+cal_shell_view_transfer_selected (ECalShellView *cal_shell_view,
+                                 gboolean is_move)
 {
        EShellView *shell_view;
        EShellWindow *shell_window;
        ECalShellContent *cal_shell_content;
-       GnomeCalendarViewType view_type;
-       GnomeCalendar *calendar;
        ECalendarView *calendar_view;
        ESource *source_source = NULL;
        ESource *destination_source = NULL;
        ESourceRegistry *registry;
-       EClient *destination_client = NULL;
-       GList *selected, *iter;
-       GError *error = NULL;
+       GList *selected, *link;
+       GHashTable *by_source; /* ESource ~> GSList{icalcomponent} */
+       GHashTableIter iter;
+       gpointer key, value;
 
        shell_view = E_SHELL_VIEW (cal_shell_view);
        shell_window = e_shell_view_get_shell_window (shell_view);
 
        cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-       registry = gnome_calendar_get_registry (calendar);
-
-       view_type = gnome_calendar_get_view (calendar);
-       calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+       registry = e_shell_get_registry (e_shell_window_get_shell (shell_window));
+       calendar_view = e_cal_shell_content_get_current_calendar_view (cal_shell_content);
 
        selected = e_calendar_view_get_selected_events (calendar_view);
        g_return_if_fail (selected != NULL);
@@ -555,53 +521,65 @@ action_event_copy_cb (GtkAction *action,
        destination_source = select_source_dialog (
                GTK_WINDOW (shell_window), registry,
                E_CAL_CLIENT_SOURCE_TYPE_EVENTS, source_source);
-       if (destination_source == NULL)
+       if (destination_source == NULL) {
+               g_list_free (selected);
                return;
-
-       /* Open the destination calendar. */
-       destination_client = e_cal_client_connect_sync (
-               destination_source,
-               E_CAL_CLIENT_SOURCE_TYPE_EVENTS,
-               NULL, &error);
-
-       if (error != NULL) {
-               g_warning (
-                       "%s: Failed to open destination client: %s",
-                       G_STRFUNC, error->message);
-               g_error_free (error);
-               goto exit;
        }
 
-       e_cal_shell_view_set_status_message (
-               cal_shell_view, _("Copying Items"), -1.0);
+       by_source = g_hash_table_new ((GHashFunc) e_source_hash, (GEqualFunc) e_source_equal);
+
+       for (link = selected; link != NULL; link = g_list_next (link)) {
+               ECalendarViewEvent *event = link->data;
+               ESource *source;
+               GSList *icalcomps;
+
+               if (!event || !event->comp_data)
+                       continue;
 
-       for (iter = selected; iter != NULL; iter = iter->next) {
-               ECalendarViewEvent *event = iter->data;
-               gboolean remove = FALSE;
+               source = e_client_get_source (E_CLIENT (event->comp_data->client));
+               if (!source)
+                       continue;
 
-               e_cal_shell_view_transfer_item_to (
-                       cal_shell_view, event,
-                       E_CAL_CLIENT (destination_client), remove);
+               icalcomps = g_hash_table_lookup (by_source, source);
+               icalcomps = g_slist_prepend (icalcomps, event->comp_data->icalcomp);
+               g_hash_table_insert (by_source, source, icalcomps);
        }
 
-       e_cal_shell_view_set_status_message (cal_shell_view, NULL, -1.0);
+       e_cal_ops_transfer_components (shell_view, e_calendar_view_get_model (calendar_view),
+               E_CAL_CLIENT_SOURCE_TYPE_EVENTS, by_source, destination_source, is_move);
 
-exit:
-       if (destination_client != NULL)
-               g_object_unref (destination_client);
-       if (destination_source != NULL)
-               g_object_unref (destination_source);
+       g_hash_table_iter_init (&iter, by_source);
+       while (g_hash_table_iter_next (&iter, &key, &value)) {
+               GSList *icalcomps = value;
+
+               g_slist_free (icalcomps);
+       }
+
+       g_hash_table_destroy (by_source);
+       g_clear_object (&destination_source);
        g_list_free (selected);
 }
 
 static void
+action_event_copy_cb (GtkAction *action,
+                      ECalShellView *cal_shell_view)
+{
+       cal_shell_view_transfer_selected (cal_shell_view, FALSE);
+}
+
+static void
+action_event_move_cb (GtkAction *action,
+                      ECalShellView *cal_shell_view)
+{
+       cal_shell_view_transfer_selected (cal_shell_view, TRUE);
+}
+
+static void
 action_event_delegate_cb (GtkAction *action,
                           ECalShellView *cal_shell_view)
 {
        ESourceRegistry *registry;
        ECalShellContent *cal_shell_content;
-       GnomeCalendarViewType view_type;
-       GnomeCalendar *calendar;
        ECalendarView *calendar_view;
        ECalendarViewEvent *event;
        ECalComponent *component;
@@ -614,9 +592,7 @@ action_event_delegate_cb (GtkAction *action,
        gchar *attendee;
 
        cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-       view_type = gnome_calendar_get_view (calendar);
-       calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+       calendar_view = e_cal_shell_content_get_current_calendar_view (cal_shell_content);
 
        selected = e_calendar_view_get_selected_events (calendar_view);
        g_return_if_fail (g_list_length (selected) == 1);
@@ -706,15 +682,10 @@ action_event_delete_cb (GtkAction *action,
                         ECalShellView *cal_shell_view)
 {
        ECalShellContent *cal_shell_content;
-       GnomeCalendar *calendar;
-       GnomeCalendarViewType view_type;
        ECalendarView *calendar_view;
 
        cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-
-       view_type = gnome_calendar_get_view (calendar);
-       calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+       calendar_view = e_cal_shell_content_get_current_calendar_view (cal_shell_content);
 
        e_selectable_delete_selection (E_SELECTABLE (calendar_view));
 }
@@ -724,15 +695,10 @@ action_event_delete_occurrence_cb (GtkAction *action,
                                    ECalShellView *cal_shell_view)
 {
        ECalShellContent *cal_shell_content;
-       GnomeCalendar *calendar;
-       GnomeCalendarViewType view_type;
        ECalendarView *calendar_view;
 
        cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-
-       view_type = gnome_calendar_get_view (calendar);
-       calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+       calendar_view = e_cal_shell_content_get_current_calendar_view (cal_shell_content);
 
        e_calendar_view_delete_selected_occurrence (calendar_view);
 }
@@ -742,10 +708,7 @@ action_event_forward_cb (GtkAction *action,
                          ECalShellView *cal_shell_view)
 {
        ECalShellContent *cal_shell_content;
-       GnomeCalendarViewType view_type;
        ECalendarView *calendar_view;
-       GnomeCalendar *calendar;
-       ESourceRegistry *registry;
        ECalendarViewEvent *event;
        ECalComponent *component;
        ECalClient *client;
@@ -753,11 +716,7 @@ action_event_forward_cb (GtkAction *action,
        GList *selected;
 
        cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-       registry = gnome_calendar_get_registry (calendar);
-
-       view_type = gnome_calendar_get_view (calendar);
-       calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+       calendar_view = e_cal_shell_content_get_current_calendar_view (cal_shell_content);
 
        selected = e_calendar_view_get_selected_events (calendar_view);
        g_return_if_fail (g_list_length (selected) == 1);
@@ -770,13 +729,12 @@ action_event_forward_cb (GtkAction *action,
        client = event->comp_data->client;
        icalcomp = event->comp_data->icalcomp;
 
-       component = e_cal_component_new ();
+       component = e_cal_component_new_from_icalcomponent (icalcomponent_new_clone (icalcomp));
+       g_return_if_fail (component != NULL);
 
-       e_cal_component_set_icalcomponent (
-               component, icalcomponent_new_clone (icalcomp));
-       itip_send_comp (
-               registry, E_CAL_COMPONENT_METHOD_PUBLISH,
-               component, client, NULL, NULL, NULL, TRUE, FALSE);
+       itip_send_component (e_calendar_view_get_model (calendar_view),
+               E_CAL_COMPONENT_METHOD_PUBLISH, component, client,
+               NULL, NULL, NULL, TRUE, FALSE, TRUE);
 
        g_object_unref (component);
 
@@ -788,9 +746,7 @@ action_event_meeting_new_cb (GtkAction *action,
                              ECalShellView *cal_shell_view)
 {
        ECalShellContent *cal_shell_content;
-       GnomeCalendarViewType view_type;
        ECalendarView *calendar_view;
-       GnomeCalendar *calendar;
 
        /* These are just for readability. */
        gboolean all_day = FALSE;
@@ -798,110 +754,61 @@ action_event_meeting_new_cb (GtkAction *action,
        gboolean no_past_date = FALSE;
 
        cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-       view_type = gnome_calendar_get_view (calendar);
-       calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+       calendar_view = e_cal_shell_content_get_current_calendar_view (cal_shell_content);
 
        e_calendar_view_new_appointment_full (
                calendar_view, all_day, meeting, no_past_date);
 }
 
 static void
-action_event_move_cb (GtkAction *action,
-                      ECalShellView *cal_shell_view)
+action_event_new_cb (GtkAction *action,
+                     ECalShellView *cal_shell_view)
 {
-       EShellView *shell_view;
-       EShellWindow *shell_window;
        ECalShellContent *cal_shell_content;
-       GnomeCalendarViewType view_type;
-       GnomeCalendar *calendar;
        ECalendarView *calendar_view;
-       ESource *source_source = NULL;
-       ESource *destination_source = NULL;
-       ESourceRegistry *registry;
-       EClient *destination_client = NULL;
-       GList *selected, *iter;
-       GError *error = NULL;
-
-       shell_view = E_SHELL_VIEW (cal_shell_view);
-       shell_window = e_shell_view_get_shell_window (shell_view);
 
        cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-       registry = gnome_calendar_get_registry (calendar);
-
-       view_type = gnome_calendar_get_view (calendar);
-       calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
-
-       selected = e_calendar_view_get_selected_events (calendar_view);
-       g_return_if_fail (selected != NULL);
-
-       if (selected->data) {
-               ECalendarViewEvent *event = selected->data;
-
-               if (is_comp_data_valid (event) && event->comp_data->client)
-                       source_source = e_client_get_source (
-                               E_CLIENT (event->comp_data->client));
-       }
+       calendar_view = e_cal_shell_content_get_current_calendar_view (cal_shell_content);
 
-       /* Get a destination source from the user. */
-       destination_source = select_source_dialog (
-               GTK_WINDOW (shell_window), registry,
-               E_CAL_CLIENT_SOURCE_TYPE_EVENTS, source_source);
-       if (destination_source == NULL)
-               return;
-
-       /* Open the destination calendar. */
-       destination_client = e_cal_client_connect_sync (
-               destination_source,
-               E_CAL_CLIENT_SOURCE_TYPE_EVENTS,
-               NULL, &error);
-
-       if (error != NULL) {
-               g_warning (
-                       "%s: Failed to open destination client: %s",
-                       G_STRFUNC, error->message);
-               g_clear_error (&error);
-               goto exit;
-       }
-
-       e_cal_shell_view_set_status_message (
-               cal_shell_view, _("Moving Items"), -1.0);
+       e_calendar_view_new_appointment (calendar_view);
+}
 
-       for (iter = selected; iter != NULL; iter = iter->next) {
-               ECalendarViewEvent *event = iter->data;
-               gboolean remove = TRUE;
+typedef struct
+{
+       ECalClient *client;
+       gchar *remove_uid;
+       gchar *remove_rid;
+       icalcomponent *create_icalcomp;
+} MakeMovableData;
 
-               e_cal_shell_view_transfer_item_to (
-                       cal_shell_view, event,
-                       E_CAL_CLIENT (destination_client), remove);
+static void
+make_movable_data_free (gpointer ptr)
+{
+       MakeMovableData *mmd = ptr;
+
+       if (mmd) {
+               g_clear_object (&mmd->client);
+               g_free (mmd->remove_uid);
+               g_free (mmd->remove_rid);
+               icalcomponent_free (mmd->create_icalcomp);
+               g_free (mmd);
        }
-
-       e_cal_shell_view_set_status_message (cal_shell_view, NULL, -1.0);
-
-exit:
-       if (destination_client != NULL)
-               g_object_unref (destination_client);
-       if (destination_source != NULL)
-               g_object_unref (destination_source);
-       g_list_free (selected);
 }
 
 static void
-action_event_new_cb (GtkAction *action,
-                     ECalShellView *cal_shell_view)
+make_movable_thread (EAlertSinkThreadJobData *job_data,
+                    gpointer user_data,
+                    GCancellable *cancellable,
+                    GError **error)
 {
-       ECalShellContent *cal_shell_content;
-       GnomeCalendarViewType view_type;
-       ECalendarView *calendar_view;
-       GnomeCalendar *calendar;
+       MakeMovableData *mmd = user_data;
 
-       cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-       view_type = gnome_calendar_get_view (calendar);
-       calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+       g_return_if_fail (mmd != NULL);
 
-       e_calendar_view_new_appointment (calendar_view);
+       if (!e_cal_client_remove_object_sync (mmd->client, mmd->remove_uid, mmd->remove_rid, 
E_CAL_OBJ_MOD_THIS, cancellable, error))
+               return;
+
+       e_cal_client_create_object_sync (mmd->client, mmd->create_icalcomp, NULL, cancellable, error);
 }
 
 static void
@@ -909,8 +816,6 @@ action_event_occurrence_movable_cb (GtkAction *action,
                                     ECalShellView *cal_shell_view)
 {
        ECalShellContent *cal_shell_content;
-       GnomeCalendarViewType view_type;
-       GnomeCalendar *calendar;
        ECalModel *model;
        ECalendarView *calendar_view;
        ECalendarViewEvent *event;
@@ -924,11 +829,11 @@ action_event_occurrence_movable_cb (GtkAction *action,
        icaltimezone *timezone;
        GList *selected;
        gchar *uid;
+       EActivity *activity;
+       MakeMovableData *mmd;
 
        cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-       view_type = gnome_calendar_get_view (calendar);
-       calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+       calendar_view = e_cal_shell_content_get_current_calendar_view (cal_shell_content);
 
        model = e_calendar_view_get_model (calendar_view);
        timezone = e_cal_model_get_timezone (model);
@@ -980,21 +885,20 @@ action_event_occurrence_movable_cb (GtkAction *action,
        cal_comp_set_dtend_with_oldzone (client, exception_component, &date);
        e_cal_component_commit_sequence (exception_component);
 
-       /* Now update both ECalComponents.  Note that we do this last
-       *  since at present the updates happend synchronously so our
-       *  event may disappear. */
+       mmd = g_new0 (MakeMovableData, 1);
+       mmd->client = g_object_ref (client);
+       mmd->remove_uid = g_strdup (id->uid);
+       mmd->remove_rid = g_strdup (id->rid);
+       mmd->create_icalcomp = icalcomponent_new_clone (e_cal_component_get_icalcomponent 
(exception_component));
 
-       e_cal_client_remove_object_sync (
-               client, id->uid, id->rid, CALOBJ_MOD_THIS, NULL, NULL);
+       activity = e_shell_view_submit_thread_job (E_SHELL_VIEW (cal_shell_view),
+               _("Making an occurrence movable"), "calendar:failed-make-movable",
+               NULL, make_movable_thread, mmd, make_movable_data_free);
 
+       g_clear_object (&activity);
        e_cal_component_free_id (id);
        g_object_unref (recurring_component);
-
-       icalcomp = e_cal_component_get_icalcomponent (exception_component);
-       e_cal_client_create_object_sync (client, icalcomp, NULL, NULL, NULL);
-
        g_object_unref (exception_component);
-
        g_list_free (selected);
 }
 
@@ -1003,14 +907,10 @@ action_event_open_cb (GtkAction *action,
                       ECalShellView *cal_shell_view)
 {
        ECalShellContent *cal_shell_content;
-       GnomeCalendarViewType view_type;
-       GnomeCalendar *calendar;
        ECalendarView *view;
 
        cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-       view_type = gnome_calendar_get_view (calendar);
-       view = gnome_calendar_get_calendar_view (calendar, view_type);
+       view = e_cal_shell_content_get_current_calendar_view (cal_shell_content);
 
        e_calendar_view_open_event (view);
 }
@@ -1020,8 +920,6 @@ action_event_print_cb (GtkAction *action,
                        ECalShellView *cal_shell_view)
 {
        ECalShellContent *cal_shell_content;
-       GnomeCalendarViewType view_type;
-       GnomeCalendar *calendar;
        ECalendarView *calendar_view;
        ECalendarViewEvent *event;
        ECalComponent *component;
@@ -1031,9 +929,7 @@ action_event_print_cb (GtkAction *action,
        GList *selected;
 
        cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-       view_type = gnome_calendar_get_view (calendar);
-       calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+       calendar_view = e_cal_shell_content_get_current_calendar_view (cal_shell_content);
        model = e_calendar_view_get_model (calendar_view);
 
        selected = e_calendar_view_get_selected_events (calendar_view);
@@ -1063,27 +959,21 @@ action_event_print_cb (GtkAction *action,
 }
 
 static void
-action_event_reply_cb (GtkAction *action,
-                       ECalShellView *cal_shell_view)
+cal_shell_view_actions_reply (ECalShellView *cal_shell_view,
+                             gboolean reply_all)
 {
        ECalShellContent *cal_shell_content;
-       GnomeCalendarViewType view_type;
        ECalendarView *calendar_view;
-       GnomeCalendar *calendar;
        ECalendarViewEvent *event;
        ECalComponent *component;
        ECalClient *client;
        ESourceRegistry *registry;
        icalcomponent *icalcomp;
        GList *selected;
-       gboolean reply_all = FALSE;
 
        cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-       registry = gnome_calendar_get_registry (calendar);
-
-       view_type = gnome_calendar_get_view (calendar);
-       calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+       registry = e_shell_get_registry (e_shell_window_get_shell (e_shell_view_get_shell_window 
(E_SHELL_VIEW (cal_shell_view))));
+       calendar_view = e_cal_shell_content_get_current_calendar_view (cal_shell_content);
 
        selected = e_calendar_view_get_selected_events (calendar_view);
        g_return_if_fail (g_list_length (selected) == 1);
@@ -1110,50 +1000,17 @@ action_event_reply_cb (GtkAction *action,
 }
 
 static void
+action_event_reply_cb (GtkAction *action,
+                       ECalShellView *cal_shell_view)
+{
+       cal_shell_view_actions_reply (cal_shell_view, FALSE);
+}
+
+static void
 action_event_reply_all_cb (GtkAction *action,
                            ECalShellView *cal_shell_view)
 {
-       ECalShellContent *cal_shell_content;
-       GnomeCalendarViewType view_type;
-       ECalendarView *calendar_view;
-       GnomeCalendar *calendar;
-       ECalendarViewEvent *event;
-       ECalComponent *component;
-       ECalClient *client;
-       ESourceRegistry *registry;
-       icalcomponent *icalcomp;
-       GList *selected;
-       gboolean reply_all = TRUE;
-
-       cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-       registry = gnome_calendar_get_registry (calendar);
-
-       view_type = gnome_calendar_get_view (calendar);
-       calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
-
-       selected = e_calendar_view_get_selected_events (calendar_view);
-       g_return_if_fail (g_list_length (selected) == 1);
-
-       event = selected->data;
-
-       if (!is_comp_data_valid (event))
-               return;
-
-       client = event->comp_data->client;
-       icalcomp = event->comp_data->icalcomp;
-
-       component = e_cal_component_new ();
-
-       e_cal_component_set_icalcomponent (
-               component, icalcomponent_new_clone (icalcomp));
-       reply_to_calendar_comp (
-               registry, E_CAL_COMPONENT_METHOD_REPLY,
-               component, client, reply_all, NULL, NULL);
-
-       g_object_unref (component);
-
-       g_list_free (selected);
+       cal_shell_view_actions_reply (cal_shell_view, TRUE);
 }
 
 static void
@@ -1165,8 +1022,6 @@ action_event_save_as_cb (GtkAction *action,
        EShellWindow *shell_window;
        EShellBackend *shell_backend;
        ECalShellContent *cal_shell_content;
-       GnomeCalendarViewType view_type;
-       GnomeCalendar *calendar;
        ECalendarView *calendar_view;
        ECalendarViewEvent *event;
        ECalClient *client;
@@ -1182,9 +1037,7 @@ action_event_save_as_cb (GtkAction *action,
        shell = e_shell_window_get_shell (shell_window);
 
        cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-       view_type = gnome_calendar_get_view (calendar);
-       calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+       calendar_view = e_cal_shell_content_get_current_calendar_view (cal_shell_content);
 
        selected = e_calendar_view_get_selected_events (calendar_view);
        g_return_if_fail (g_list_length (selected) == 1);
@@ -1236,8 +1089,6 @@ edit_event_as (ECalShellView *cal_shell_view,
                gboolean as_meeting)
 {
        ECalShellContent *cal_shell_content;
-       GnomeCalendarViewType view_type;
-       GnomeCalendar *calendar;
        ECalendarView *calendar_view;
        ECalendarViewEvent *event;
        ECalClient *client;
@@ -1245,9 +1096,7 @@ edit_event_as (ECalShellView *cal_shell_view,
        GList *selected;
 
        cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-       view_type = gnome_calendar_get_view (calendar);
-       calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+       calendar_view = e_cal_shell_content_get_current_calendar_view (cal_shell_content);
 
        selected = e_calendar_view_get_selected_events (calendar_view);
        g_return_if_fail (g_list_length (selected) == 1);
@@ -1679,35 +1528,35 @@ static GtkRadioActionEntry calendar_view_entries[] = {
          N_("Day"),
          NULL,
          N_("Show one day"),
-         GNOME_CAL_DAY_VIEW },
+         E_CAL_VIEW_KIND_DAY },
 
        { "calendar-view-list",
          "view-calendar-list",
          N_("List"),
          NULL,
          N_("Show as list"),
-         GNOME_CAL_LIST_VIEW },
+         E_CAL_VIEW_KIND_LIST },
 
        { "calendar-view-month",
          "view-calendar-month",
          N_("Month"),
          NULL,
          N_("Show one month"),
-         GNOME_CAL_MONTH_VIEW },
+         E_CAL_VIEW_KIND_MONTH },
 
        { "calendar-view-week",
          "view-calendar-week",
          N_("Week"),
          NULL,
          N_("Show one week"),
-         GNOME_CAL_WEEK_VIEW },
+         E_CAL_VIEW_KIND_WEEK },
 
        { "calendar-view-workweek",
          "view-calendar-workweek",
          N_("Work Week"),
          NULL,
          N_("Show one work week"),
-         GNOME_CAL_WORK_WEEK_VIEW }
+         E_CAL_VIEW_KIND_WORKWEEK }
 };
 
 static GtkRadioActionEntry calendar_filter_entries[] = {
diff --git a/modules/calendar/e-cal-shell-view-memopad.c b/modules/calendar/e-cal-shell-view-memopad.c
index 35bbec9..22285af 100644
--- a/modules/calendar/e-cal-shell-view-memopad.c
+++ b/modules/calendar/e-cal-shell-view-memopad.c
@@ -22,6 +22,8 @@
 #include <config.h>
 #endif
 
+#include <calendar/gui/e-cal-ops.h>
+
 #include "e-cal-shell-view-private.h"
 
 /* Much of this file is based on e-memo-shell-view-actions.c. */
@@ -31,22 +33,11 @@ action_calendar_memopad_forward_cb (GtkAction *action,
                                     ECalShellView *cal_shell_view)
 {
        ECalShellContent *cal_shell_content;
-       EShell *shell;
-       EShellView *shell_view;
-       EShellWindow *shell_window;
-       ESourceRegistry *registry;
        EMemoTable *memo_table;
        ECalModelComponent *comp_data;
        ECalComponent *comp;
-       icalcomponent *clone;
        GSList *list;
 
-       shell_view = E_SHELL_VIEW (cal_shell_view);
-       shell_window = e_shell_view_get_shell_window (shell_view);
-       shell = e_shell_window_get_shell (shell_window);
-
-       registry = e_shell_get_registry (shell);
-
        cal_shell_content = cal_shell_view->priv->cal_shell_content;
        memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
 
@@ -56,13 +47,12 @@ action_calendar_memopad_forward_cb (GtkAction *action,
        g_slist_free (list);
 
        /* XXX We only forward the first selected memo. */
-       comp = e_cal_component_new ();
-       clone = icalcomponent_new_clone (comp_data->icalcomp);
-       e_cal_component_set_icalcomponent (comp, clone);
+       comp = e_cal_component_new_from_icalcomponent (icalcomponent_new_clone (comp_data->icalcomp));
+       g_return_if_fail (comp != NULL);
 
-       itip_send_comp (
-               registry, E_CAL_COMPONENT_METHOD_PUBLISH, comp,
-               comp_data->client, NULL, NULL, NULL, TRUE, FALSE);
+       itip_send_component (e_memo_table_get_model (memo_table),
+               E_CAL_COMPONENT_METHOD_PUBLISH, comp, comp_data->client,
+               NULL, NULL, NULL, TRUE, FALSE, TRUE);
 
        g_object_unref (comp);
 }
@@ -71,20 +61,15 @@ static void
 action_calendar_memopad_new_cb (GtkAction *action,
                                 ECalShellView *cal_shell_view)
 {
-       EShell *shell;
        EShellView *shell_view;
        EShellWindow *shell_window;
        ECalShellContent *cal_shell_content;
        EMemoTable *memo_table;
        ECalModelComponent *comp_data;
-       ECalClient *client;
-       ECalComponent *comp;
-       CompEditor *editor;
        GSList *list;
 
        shell_view = E_SHELL_VIEW (cal_shell_view);
        shell_window = e_shell_view_get_shell_window (shell_view);
-       shell = e_shell_window_get_shell (shell_window);
 
        cal_shell_content = cal_shell_view->priv->cal_shell_content;
        memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
@@ -94,15 +79,8 @@ action_calendar_memopad_new_cb (GtkAction *action,
        comp_data = list->data;
        g_slist_free (list);
 
-       client = comp_data->client;
-       comp = cal_comp_memo_new_with_defaults (client);
-       cal_comp_update_time_by_active_window (comp, shell);
-       editor = memo_editor_new (client, shell, COMP_EDITOR_NEW_ITEM);
-       comp_editor_edit_comp (editor, comp);
-
-       gtk_window_present (GTK_WINDOW (editor));
-
-       g_object_unref (comp);
+       e_cal_ops_new_component_editor (shell_window, E_CAL_CLIENT_SOURCE_TYPE_MEMOS,
+               e_source_get_uid (e_client_get_source (E_CLIENT (comp_data->client))), FALSE);
 }
 
 static void
@@ -399,83 +377,14 @@ void
 e_cal_shell_view_memopad_open_memo (ECalShellView *cal_shell_view,
                                     ECalModelComponent *comp_data)
 {
-       EShell *shell;
-       EShellView *shell_view;
-       EShellWindow *shell_window;
-       ESourceRegistry *registry;
-       CompEditor *editor;
-       CompEditorFlags flags = 0;
-       ECalComponent *comp;
-       icalcomponent *clone;
-       const gchar *uid;
+       EShellContent *shell_content;
+       ECalModel *model;
 
        g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
        g_return_if_fail (E_IS_CAL_MODEL_COMPONENT (comp_data));
 
-       shell_view = E_SHELL_VIEW (cal_shell_view);
-       shell_window = e_shell_view_get_shell_window (shell_view);
-       shell = e_shell_window_get_shell (shell_window);
-
-       registry = e_shell_get_registry (shell);
-
-       uid = icalcomponent_get_uid (comp_data->icalcomp);
-       editor = comp_editor_find_instance (uid);
-
-       if (editor != NULL)
-               goto exit;
-
-       comp = e_cal_component_new ();
-       clone = icalcomponent_new_clone (comp_data->icalcomp);
-       e_cal_component_set_icalcomponent (comp, clone);
-
-       if (e_cal_component_has_organizer (comp))
-               flags |= COMP_EDITOR_IS_SHARED;
-
-       if (itip_organizer_is_user (registry, comp, comp_data->client))
-               flags |= COMP_EDITOR_USER_ORG;
-
-       editor = memo_editor_new (comp_data->client, shell, flags);
-       comp_editor_edit_comp (editor, comp);
-
-       g_object_unref (comp);
-
-exit:
-       gtk_window_present (GTK_WINDOW (editor));
-}
-
-void
-e_cal_shell_view_memopad_set_status_message (ECalShellView *cal_shell_view,
-                                             const gchar *status_message,
-                                             gdouble percent)
-{
-       EActivity *activity;
-       EShellView *shell_view;
-       EShellBackend *shell_backend;
-
-       g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
-
-       shell_view = E_SHELL_VIEW (cal_shell_view);
-       shell_backend = e_shell_view_get_shell_backend (shell_view);
-
-       activity = cal_shell_view->priv->memopad_activity;
-
-       if (status_message == NULL || *status_message == '\0') {
-               if (activity != NULL) {
-                       e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
-                       g_object_unref (activity);
-                       activity = NULL;
-               }
-
-       } else if (activity == NULL) {
-               activity = e_activity_new ();
-               e_activity_set_percent (activity, percent);
-               e_activity_set_text (activity, status_message);
-               e_shell_backend_add_activity (shell_backend, activity);
-
-       } else {
-               e_activity_set_percent (activity, percent);
-               e_activity_set_text (activity, status_message);
-       }
+       shell_content = e_shell_view_get_shell_content (E_SHELL_VIEW (cal_shell_view));
+       model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (shell_content));
 
-       cal_shell_view->priv->memopad_activity = activity;
+       e_cal_ops_open_component_in_editor_sync (model, comp_data->client, comp_data->icalcomp);
 }
diff --git a/modules/calendar/e-cal-shell-view-private.c b/modules/calendar/e-cal-shell-view-private.c
index 04c6c7a..afaccaa 100644
--- a/modules/calendar/e-cal-shell-view-private.c
+++ b/modules/calendar/e-cal-shell-view-private.c
@@ -23,6 +23,7 @@
 #endif
 
 #include "e-util/e-util-private.h"
+#include <calendar/gui/e-cal-ops.h>
 
 #include "e-cal-shell-view-private.h"
 
@@ -56,7 +57,7 @@ cal_shell_view_get_current_time (ECalendarItem *calitem,
        ECalModel *model;
 
        cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       model = e_cal_shell_content_get_model (cal_shell_content);
+       model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
        timezone = e_cal_model_get_timezone (model);
 
        tt = icaltime_from_timet_with_zone (time (NULL), FALSE, timezone);
@@ -65,224 +66,10 @@ cal_shell_view_get_current_time (ECalendarItem *calitem,
 }
 
 static void
-cal_shell_view_date_navigator_date_range_changed_cb (ECalShellView *cal_shell_view,
-                                                     ECalendarItem *calitem)
-{
-       ECalShellContent *cal_shell_content;
-       GnomeCalendar *calendar;
-
-       cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-
-       gnome_calendar_update_query (calendar);
-}
-
-static void
-cal_shell_view_date_navigator_selection_changed_cb (ECalShellView *cal_shell_view,
-                                                    ECalendarItem *calitem)
-{
-       ECalShellContent *cal_shell_content;
-       GnomeCalendarViewType switch_to;
-       GnomeCalendarViewType view_type;
-       GnomeCalendar *calendar;
-       ECalModel *model;
-       GDate start_date, end_date;
-       GDate new_start_date, new_end_date;
-       icaltimetype tt;
-       icaltimezone *timezone;
-       time_t start, end, new_time;
-       gboolean starts_on_week_start_day;
-       gint new_days_shown, old_days_shown;
-       GDateWeekday week_start_day;
-
-       cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-
-       model = gnome_calendar_get_model (calendar);
-       view_type = gnome_calendar_get_view (calendar);
-       switch_to = view_type;
-
-       timezone = e_cal_model_get_timezone (model);
-       week_start_day = e_cal_model_get_week_start_day (model);
-       e_cal_model_get_time_range (model, &start, &end);
-
-       time_to_gdate_with_zone (&start_date, start, timezone);
-       time_to_gdate_with_zone (&end_date, end, timezone);
-
-       if (view_type == GNOME_CAL_MONTH_VIEW) {
-               EWeekView *week_view;
-               ECalendarView *calendar_view;
-               gboolean multi_week_view;
-               gboolean compress_weekend;
-
-               calendar_view = gnome_calendar_get_calendar_view (
-                       calendar, GNOME_CAL_MONTH_VIEW);
-
-               week_view = E_WEEK_VIEW (calendar_view);
-               multi_week_view = e_week_view_get_multi_week_view (week_view);
-               compress_weekend = e_week_view_get_compress_weekend (week_view);
-
-               if (week_start_day == G_DATE_SUNDAY &&
-                               (!multi_week_view || compress_weekend))
-                       g_date_add_days (&start_date, 1);
-       }
-
-       g_date_subtract_days (&end_date, 1);
-
-       e_calendar_item_get_selection (
-               calitem, &new_start_date, &new_end_date);
-
-       /* If the selection hasn't changed, just return. */
-       if (g_date_compare (&start_date, &new_start_date) == 0 &&
-               g_date_compare (&end_date, &new_end_date) == 0)
-               return;
-
-       old_days_shown =
-               g_date_get_julian (&end_date) -
-               g_date_get_julian (&start_date) + 1;
-       new_days_shown =
-               g_date_get_julian (&new_end_date) -
-               g_date_get_julian (&new_start_date) + 1;
-
-       /* If a complete week is selected we show the week view.
-        * Note that if weekends are compressed and the week start
-        * day is set to Sunday, we don't actually show complete
-        * weeks in the week view, so this may need tweaking. */
-       starts_on_week_start_day =
-               (g_date_get_weekday (&new_start_date) == week_start_day);
-
-       /* Update selection to be in the new time range. */
-       tt = icaltime_null_time ();
-       tt.year = g_date_get_year (&new_start_date);
-       tt.month = g_date_get_month (&new_start_date);
-       tt.day = g_date_get_day (&new_start_date);
-       new_time = icaltime_as_timet_with_zone (tt, timezone);
-
-       /* Switch views as appropriate, and change the number of
-        * days or weeks shown. */
-       if (view_type == GNOME_CAL_WORK_WEEK_VIEW && old_days_shown == new_days_shown) {
-               /* keep the work week view when has same days shown */
-               switch_to = GNOME_CAL_WORK_WEEK_VIEW;
-       } else if (new_days_shown > 9) {
-               if (view_type != GNOME_CAL_LIST_VIEW) {
-                       ECalendarView *calendar_view;
-
-                       calendar_view = gnome_calendar_get_calendar_view (
-                               calendar, GNOME_CAL_MONTH_VIEW);
-                       e_week_view_set_weeks_shown (
-                               E_WEEK_VIEW (calendar_view),
-                               (new_days_shown + 6) / 7);
-                       switch_to = GNOME_CAL_MONTH_VIEW;
-               }
-       } else if (new_days_shown == 7 && starts_on_week_start_day) {
-               switch_to = GNOME_CAL_WEEK_VIEW;
-       } else if (new_days_shown == 1 && (view_type == GNOME_CAL_WORK_WEEK_VIEW || view_type == 
GNOME_CAL_WEEK_VIEW)) {
-               /* preserve week views when clicking on one day */
-               switch_to = view_type;
-       } else {
-               ECalendarView *calendar_view;
-
-               calendar_view = gnome_calendar_get_calendar_view (
-                       calendar, GNOME_CAL_DAY_VIEW);
-               e_day_view_set_days_shown (
-                       E_DAY_VIEW (calendar_view), new_days_shown);
-
-               if (new_days_shown != 5 || !starts_on_week_start_day)
-                       switch_to = GNOME_CAL_DAY_VIEW;
-
-               else if (view_type != GNOME_CAL_WORK_WEEK_VIEW)
-                       switch_to = GNOME_CAL_DAY_VIEW;
-       }
-
-       /* Make the views display things properly. */
-       gnome_calendar_update_view_times (calendar, new_time);
-       gnome_calendar_set_view (calendar, switch_to);
-       gnome_calendar_set_range_selected (calendar, TRUE);
-
-       gnome_calendar_notify_dates_shown_changed (calendar);
-
-       g_signal_handlers_block_by_func (
-               calitem,
-               cal_shell_view_date_navigator_selection_changed_cb, cal_shell_view);
-
-       /* make sure the selected days in the calendar matches shown days */
-       e_cal_model_get_time_range (model, &start, &end);
-
-       time_to_gdate_with_zone (&start_date, start, timezone);
-       time_to_gdate_with_zone (&end_date, end, timezone);
-
-       g_date_subtract_days (&end_date, 1);
-
-       e_calendar_item_set_selection (calitem, &start_date, &end_date);
-
-       g_signal_handlers_unblock_by_func (
-               calitem,
-               cal_shell_view_date_navigator_selection_changed_cb, cal_shell_view);
-}
-
-static gboolean
-cal_shell_view_date_navigator_scroll_event_cb (ECalShellView *cal_shell_view,
-                                               GdkEventScroll *event,
-                                               ECalendar *date_navigator)
-{
-       ECalendarItem *calitem;
-       GDate start_date, end_date;
-       GdkScrollDirection direction;
-
-       calitem = date_navigator->calitem;
-       if (!e_calendar_item_get_selection (calitem, &start_date, &end_date))
-               return FALSE;
-
-       direction = event->direction;
-
-       if (direction == GDK_SCROLL_SMOOTH) {
-               static gdouble total_delta_y = 0.0;
-
-               total_delta_y += event->delta_y;
-
-               if (total_delta_y >= 1.0) {
-                       total_delta_y = 0.0;
-                       direction = GDK_SCROLL_DOWN;
-               } else if (total_delta_y <= -1.0) {
-                       total_delta_y = 0.0;
-                       direction = GDK_SCROLL_UP;
-               } else {
-                       return FALSE;
-               }
-       }
-
-       switch (direction) {
-               case GDK_SCROLL_UP:
-                       g_date_subtract_months (&start_date, 1);
-                       g_date_subtract_months (&end_date, 1);
-                       break;
-
-               case GDK_SCROLL_DOWN:
-                       g_date_add_months (&start_date, 1);
-                       g_date_add_months (&end_date, 1);
-                       break;
-
-               default:
-                       g_return_val_if_reached (FALSE);
-       }
-
-       /* XXX Does ECalendarItem emit a signal for this?  If so, maybe
-        *     we could move this handler into ECalShellSidebar. */
-       e_calendar_item_set_selection (calitem, &start_date, &end_date);
-
-       cal_shell_view_date_navigator_selection_changed_cb (
-               cal_shell_view, calitem);
-
-       return TRUE;
-}
-
-static void
 cal_shell_view_popup_event_cb (EShellView *shell_view,
                                GdkEvent *button_event)
 {
        GList *list;
-       GnomeCalendar *calendar;
-       GnomeCalendarViewType view_type;
        ECalendarView *view;
        ECalShellViewPrivate *priv;
        const gchar *widget_path;
@@ -290,10 +77,7 @@ cal_shell_view_popup_event_cb (EShellView *shell_view,
 
        priv = E_CAL_SHELL_VIEW_GET_PRIVATE (shell_view);
 
-       calendar = e_cal_shell_content_get_calendar (priv->cal_shell_content);
-
-       view_type = gnome_calendar_get_view (calendar);
-       view = gnome_calendar_get_calendar_view (calendar, view_type);
+       view = e_cal_shell_content_get_current_calendar_view (priv->cal_shell_content);
 
        list = e_calendar_view_get_selected_events (view);
        n_selected = g_list_length (list);
@@ -321,38 +105,6 @@ cal_shell_view_selector_popup_event_cb (EShellView *shell_view,
 }
 
 static void
-cal_shell_view_selector_client_added_cb (ECalShellView *cal_shell_view,
-                                         ECalClient *client)
-{
-       ECalShellContent *cal_shell_content;
-       GnomeCalendar *calendar;
-       ECalModel *model;
-
-       cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-       model = gnome_calendar_get_model (calendar);
-
-       if (e_cal_model_add_client (model, client))
-               gnome_calendar_update_query (calendar);
-}
-
-static void
-cal_shell_view_selector_client_removed_cb (ECalShellView *cal_shell_view,
-                                           ECalClient *client)
-{
-       ECalShellContent *cal_shell_content;
-       GnomeCalendar *calendar;
-       ECalModel *model;
-
-       cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-       model = gnome_calendar_get_model (calendar);
-
-       if (e_cal_model_remove_client (model, client))
-               gnome_calendar_update_query (calendar);
-}
-
-static void
 cal_shell_view_memopad_popup_event_cb (EShellView *shell_view,
                                        GdkEvent *button_event)
 {
@@ -373,18 +125,6 @@ cal_shell_view_taskpad_popup_event_cb (EShellView *shell_view,
 }
 
 static void
-cal_shell_view_user_created_cb (ECalShellView *cal_shell_view,
-                                ECalClient *client,
-                                ECalendarView *calendar_view)
-{
-       ECalShellSidebar *cal_shell_sidebar;
-
-       cal_shell_sidebar = cal_shell_view->priv->cal_shell_sidebar;
-
-       e_cal_shell_sidebar_add_client (cal_shell_sidebar, E_CLIENT (client));
-}
-
-static void
 cal_shell_view_backend_error_cb (EClientCache *client_cache,
                                  EClient *client,
                                  EAlert *alert,
@@ -488,6 +228,7 @@ e_cal_shell_view_private_constructed (ECalShellView *cal_shell_view)
        EShellWindow *shell_window;
        EShellView *shell_view;
        EShell *shell;
+       ECalendar *calendar;
        gulong handler_id;
        gint ii;
 
@@ -506,17 +247,7 @@ e_cal_shell_view_private_constructed (ECalShellView *cal_shell_view)
        priv->cal_shell_content = g_object_ref (shell_content);
        priv->cal_shell_sidebar = g_object_ref (shell_sidebar);
 
-       handler_id = g_signal_connect_swapped (
-               priv->cal_shell_sidebar, "client-added",
-               G_CALLBACK (cal_shell_view_selector_client_added_cb),
-               cal_shell_view);
-       priv->client_added_handler_id = handler_id;
-
-       handler_id = g_signal_connect_swapped (
-               priv->cal_shell_sidebar, "client-removed",
-               G_CALLBACK (cal_shell_view_selector_client_removed_cb),
-               cal_shell_view);
-       priv->client_removed_handler_id = handler_id;
+       calendar = e_cal_base_shell_sidebar_get_date_navigator (priv->cal_shell_sidebar);
 
        /* Keep our own reference to this so we can
         * disconnect our signal handlers in dispose(). */
@@ -529,25 +260,16 @@ e_cal_shell_view_private_constructed (ECalShellView *cal_shell_view)
                cal_shell_view);
        priv->backend_error_handler_id = handler_id;
 
-       /* Keep our own reference to this so we can
-        * disconnect our signal handlers in dispose(). */
-       priv->calendar = e_cal_shell_content_get_calendar (
-               E_CAL_SHELL_CONTENT (shell_content));
-       g_object_ref (priv->calendar);
-
-       handler_id = g_signal_connect_swapped (
-               priv->calendar, "dates-shown-changed",
-               G_CALLBACK (e_cal_shell_view_update_sidebar),
-               cal_shell_view);
-       priv->dates_shown_changed_handler_id = handler_id;
+       g_signal_connect_swapped (
+               e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (priv->cal_shell_content)),
+               "time-range-changed", G_CALLBACK (e_cal_shell_view_update_sidebar), cal_shell_view);
 
-       for (ii = 0; ii < GNOME_CAL_LAST_VIEW; ii++) {
+       for (ii = E_CAL_VIEW_KIND_DAY; ii < E_CAL_VIEW_KIND_LAST; ii++) {
                ECalendarView *calendar_view;
 
                /* Keep our own reference to this so we can
                 * disconnect our signal handlers in dispose(). */
-               calendar_view =
-                       gnome_calendar_get_calendar_view (priv->calendar, ii);
+               calendar_view = e_cal_shell_content_get_calendar_view (priv->cal_shell_content, ii);
                priv->views[ii].calendar_view = g_object_ref (calendar_view);
 
                handler_id = g_signal_connect_swapped (
@@ -561,53 +283,18 @@ e_cal_shell_view_private_constructed (ECalShellView *cal_shell_view)
                        G_CALLBACK (e_shell_view_update_actions),
                        cal_shell_view);
                priv->views[ii].selection_changed_handler_id = handler_id;
-
-               handler_id = g_signal_connect_swapped (
-                       calendar_view, "user-created",
-                       G_CALLBACK (cal_shell_view_user_created_cb),
-                       cal_shell_view);
-               priv->views[ii].user_created_handler_id = handler_id;
        }
 
        /* Keep our own reference to this so we can
         * disconnect our signal handlers in dispose(). */
-       priv->model = e_cal_shell_content_get_model (
-               E_CAL_SHELL_CONTENT (shell_content));
+       priv->model = e_cal_base_shell_content_get_model (
+               E_CAL_BASE_SHELL_CONTENT (shell_content));
        g_object_ref (priv->model);
 
-       handler_id = g_signal_connect_swapped (
-               priv->model, "status-message",
-               G_CALLBACK (e_cal_shell_view_set_status_message),
-               cal_shell_view);
-       priv->status_message_handler_id = handler_id;
-
        /* Keep our own reference to this so we can
         * disconnect our signal handlers in dispose(). */
-       priv->date_navigator = e_cal_shell_sidebar_get_date_navigator (
-               E_CAL_SHELL_SIDEBAR (shell_sidebar));
-
-       handler_id = g_signal_connect_swapped (
-               priv->date_navigator, "scroll-event",
-               G_CALLBACK (cal_shell_view_date_navigator_scroll_event_cb),
-               cal_shell_view);
-       priv->scroll_event_handler_id = handler_id;
-
-       handler_id = g_signal_connect_swapped (
-               priv->date_navigator->calitem, "date-range-changed",
-               G_CALLBACK (cal_shell_view_date_navigator_date_range_changed_cb),
-               cal_shell_view);
-       priv->date_range_changed_handler_id = handler_id;
-
-       handler_id = g_signal_connect_swapped (
-               priv->date_navigator->calitem, "selection-changed",
-               G_CALLBACK (cal_shell_view_date_navigator_selection_changed_cb),
-               cal_shell_view);
-       priv->selection_changed_handler_id = handler_id;
-
-       /* Keep our own reference to this so we can
-        * disconnect our signal handlers in dispose(). */
-       priv->selector = e_cal_shell_sidebar_get_selector (
-               E_CAL_SHELL_SIDEBAR (shell_sidebar));
+       priv->selector = e_cal_base_shell_sidebar_get_selector (
+               E_CAL_BASE_SHELL_SIDEBAR (shell_sidebar));
        g_object_ref (priv->selector);
 
        handler_id = g_signal_connect_swapped (
@@ -634,12 +321,6 @@ e_cal_shell_view_private_constructed (ECalShellView *cal_shell_view)
                cal_shell_view);
        priv->memo_table_selection_change_handler_id = handler_id;
 
-       handler_id = g_signal_connect_swapped (
-               priv->memo_table, "status-message",
-               G_CALLBACK (e_cal_shell_view_memopad_set_status_message),
-               cal_shell_view);
-       priv->memo_table_status_message_handler_id = handler_id;
-
        /* Keep our own reference to this so we can
         * disconnect our signal handlers in dispose(). */
        priv->task_table = e_cal_shell_content_get_task_table (
@@ -658,49 +339,18 @@ e_cal_shell_view_private_constructed (ECalShellView *cal_shell_view)
                cal_shell_view);
        priv->task_table_selection_change_handler_id = handler_id;
 
-       handler_id = g_signal_connect_swapped (
-               priv->task_table, "status-message",
-               G_CALLBACK (e_cal_shell_view_taskpad_set_status_message),
-               cal_shell_view);
-       priv->task_table_status_message_handler_id = handler_id;
-
        e_categories_add_change_hook (
                (GHookFunc) e_cal_shell_view_update_search_filter,
                cal_shell_view);
 
-       /* Give GnomeCalendar a handle to the date navigator,
-        * memo and task table. */
-       gnome_calendar_set_date_navigator (
-               priv->calendar, priv->date_navigator);
-       gnome_calendar_set_memo_table (
-               priv->calendar, GTK_WIDGET (priv->memo_table));
-       gnome_calendar_set_task_table (
-               priv->calendar, GTK_WIDGET (priv->task_table));
-
        e_calendar_item_set_get_time_callback (
-               priv->date_navigator->calitem, (ECalendarItemGetTimeCallback)
+               calendar->calitem, (ECalendarItemGetTimeCallback)
                cal_shell_view_get_current_time, cal_shell_view, NULL);
 
        init_timezone_monitors (cal_shell_view);
        e_cal_shell_view_actions_init (cal_shell_view);
        e_cal_shell_view_update_sidebar (cal_shell_view);
        e_cal_shell_view_update_search_filter (cal_shell_view);
-
-       /* Keep the ECalModel in sync with the sidebar. */
-       g_object_bind_property (
-               shell_sidebar, "default-client",
-               priv->model, "default-client",
-               G_BINDING_SYNC_CREATE);
-
-       /* Keep the toolbar view buttons in sync with the calendar. */
-       g_object_bind_property (
-               priv->calendar, "view",
-               ACTION (CALENDAR_VIEW_DAY), "current-value",
-               G_BINDING_BIDIRECTIONAL |
-               G_BINDING_SYNC_CREATE);
-
-       /* Force the main calendar to update its default source. */
-       g_signal_emit_by_name (priv->selector, "primary-selection-changed");
 }
 
 void
@@ -716,20 +366,6 @@ e_cal_shell_view_private_dispose (ECalShellView *cal_shell_view)
        if (priv->cal_shell_content != NULL)
                e_cal_shell_content_save_state (priv->cal_shell_content);
 
-       if (priv->client_added_handler_id > 0) {
-               g_signal_handler_disconnect (
-                       priv->cal_shell_sidebar,
-                       priv->client_added_handler_id);
-               priv->client_added_handler_id = 0;
-       }
-
-       if (priv->client_removed_handler_id > 0) {
-               g_signal_handler_disconnect (
-                       priv->cal_shell_sidebar,
-                       priv->client_removed_handler_id);
-               priv->client_removed_handler_id = 0;
-       }
-
        if (priv->prepare_for_quit_handler_id > 0) {
                g_signal_handler_disconnect (
                        priv->shell,
@@ -744,41 +380,6 @@ e_cal_shell_view_private_dispose (ECalShellView *cal_shell_view)
                priv->backend_error_handler_id = 0;
        }
 
-       if (priv->dates_shown_changed_handler_id > 0) {
-               g_signal_handler_disconnect (
-                       priv->calendar,
-                       priv->dates_shown_changed_handler_id);
-               priv->dates_shown_changed_handler_id = 0;
-       }
-
-       if (priv->status_message_handler_id > 0) {
-               g_signal_handler_disconnect (
-                       priv->model,
-                       priv->status_message_handler_id);
-               priv->status_message_handler_id = 0;
-       }
-
-       if (priv->scroll_event_handler_id > 0) {
-               g_signal_handler_disconnect (
-                       priv->date_navigator,
-                       priv->scroll_event_handler_id);
-               priv->scroll_event_handler_id = 0;
-       }
-
-       if (priv->date_range_changed_handler_id > 0) {
-               g_signal_handler_disconnect (
-                       priv->date_navigator->calitem,
-                       priv->date_range_changed_handler_id);
-               priv->date_range_changed_handler_id = 0;
-       }
-
-       if (priv->selection_changed_handler_id > 0) {
-               g_signal_handler_disconnect (
-                       priv->date_navigator->calitem,
-                       priv->selection_changed_handler_id);
-               priv->selection_changed_handler_id = 0;
-       }
-
        if (priv->selector_popup_event_handler_id > 0) {
                g_signal_handler_disconnect (
                        priv->selector,
@@ -800,13 +401,6 @@ e_cal_shell_view_private_dispose (ECalShellView *cal_shell_view)
                priv->memo_table_selection_change_handler_id = 0;
        }
 
-       if (priv->memo_table_status_message_handler_id > 0) {
-               g_signal_handler_disconnect (
-                       priv->memo_table,
-                       priv->memo_table_status_message_handler_id);
-               priv->memo_table_status_message_handler_id = 0;
-       }
-
        if (priv->task_table_popup_event_handler_id > 0) {
                g_signal_handler_disconnect (
                        priv->task_table,
@@ -821,14 +415,7 @@ e_cal_shell_view_private_dispose (ECalShellView *cal_shell_view)
                priv->task_table_selection_change_handler_id = 0;
        }
 
-       if (priv->task_table_status_message_handler_id > 0) {
-               g_signal_handler_disconnect (
-                       priv->task_table,
-                       priv->task_table_status_message_handler_id);
-               priv->task_table_status_message_handler_id = 0;
-       }
-
-       for (ii = 0; ii < GNOME_CAL_LAST_VIEW; ii++) {
+       for (ii = 0; ii < E_CAL_VIEW_KIND_LAST; ii++) {
                if (priv->views[ii].popup_event_handler_id > 0) {
                        g_signal_handler_disconnect (
                                priv->views[ii].calendar_view,
@@ -843,13 +430,6 @@ e_cal_shell_view_private_dispose (ECalShellView *cal_shell_view)
                        priv->views[ii].selection_changed_handler_id = 0;
                }
 
-               if (priv->views[ii].user_created_handler_id > 0) {
-                       g_signal_handler_disconnect (
-                               priv->views[ii].calendar_view,
-                               priv->views[ii].user_created_handler_id);
-                       priv->views[ii].user_created_handler_id = 0;
-               }
-
                g_clear_object (&priv->views[ii].calendar_view);
        }
 
@@ -859,37 +439,11 @@ e_cal_shell_view_private_dispose (ECalShellView *cal_shell_view)
 
        g_clear_object (&priv->shell);
        g_clear_object (&priv->client_cache);
-       g_clear_object (&priv->calendar);
        g_clear_object (&priv->model);
-       g_clear_object (&priv->date_navigator);
        g_clear_object (&priv->selector);
        g_clear_object (&priv->memo_table);
        g_clear_object (&priv->task_table);
 
-       if (priv->calendar_activity != NULL) {
-               /* XXX Activity is not cancellable. */
-               e_activity_set_state (
-                       priv->calendar_activity, E_ACTIVITY_COMPLETED);
-               g_object_unref (priv->calendar_activity);
-               priv->calendar_activity = NULL;
-       }
-
-       if (priv->memopad_activity != NULL) {
-               /* XXX Activity is not cancellable. */
-               e_activity_set_state (
-                       priv->memopad_activity, E_ACTIVITY_COMPLETED);
-               g_object_unref (priv->memopad_activity);
-               priv->memopad_activity = NULL;
-       }
-
-       if (priv->taskpad_activity != NULL) {
-               /* XXX Activity is not cancellable. */
-               e_activity_set_state (
-                       priv->taskpad_activity, E_ACTIVITY_COMPLETED);
-               g_object_unref (priv->taskpad_activity);
-               priv->taskpad_activity = NULL;
-       }
-
        for (ii = 0; ii < CHECK_NB; ii++)
                g_clear_object (&priv->monitors[ii]);
 }
@@ -901,239 +455,13 @@ e_cal_shell_view_private_finalize (ECalShellView *cal_shell_view)
 }
 
 void
-e_cal_shell_view_open_event (ECalShellView *cal_shell_view,
-                             ECalModelComponent *comp_data)
-{
-       EShell *shell;
-       EShellView *shell_view;
-       EShellWindow *shell_window;
-       ESourceRegistry *registry;
-       CompEditor *editor;
-       CompEditorFlags flags = 0;
-       ECalComponent *comp;
-       icalcomponent *clone;
-       icalproperty *prop;
-       const gchar *uid;
-
-       g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
-       g_return_if_fail (E_IS_CAL_MODEL_COMPONENT (comp_data));
-
-       shell_view = E_SHELL_VIEW (cal_shell_view);
-       shell_window = e_shell_view_get_shell_window (shell_view);
-       shell = e_shell_window_get_shell (shell_window);
-
-       registry = e_shell_get_registry (shell);
-
-       uid = icalcomponent_get_uid (comp_data->icalcomp);
-       editor = comp_editor_find_instance (uid);
-
-       if (editor != NULL)
-               goto exit;
-
-       comp = e_cal_component_new ();
-       clone = icalcomponent_new_clone (comp_data->icalcomp);
-       e_cal_component_set_icalcomponent (comp, clone);
-
-       prop = icalcomponent_get_first_property (
-               comp_data->icalcomp, ICAL_ATTENDEE_PROPERTY);
-       if (prop != NULL)
-               flags |= COMP_EDITOR_MEETING;
-
-       if (itip_organizer_is_user (registry, comp, comp_data->client))
-               flags |= COMP_EDITOR_USER_ORG;
-
-       if (itip_sentby_is_user (registry, comp, comp_data->client))
-               flags |= COMP_EDITOR_USER_ORG;
-
-       if (!e_cal_component_has_attendees (comp))
-               flags |= COMP_EDITOR_USER_ORG;
-
-       editor = event_editor_new (comp_data->client, shell, flags);
-       comp_editor_edit_comp (editor, comp);
-
-       g_object_unref (comp);
-
-exit:
-       gtk_window_present (GTK_WINDOW (editor));
-}
-
-void
-e_cal_shell_view_set_status_message (ECalShellView *cal_shell_view,
-                                     const gchar *status_message,
-                                     gdouble percent)
-{
-       EActivity *activity;
-       EShellView *shell_view;
-       EShellBackend *shell_backend;
-
-       g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
-
-       shell_view = E_SHELL_VIEW (cal_shell_view);
-       shell_backend = e_shell_view_get_shell_backend (shell_view);
-
-       activity = cal_shell_view->priv->calendar_activity;
-
-       if (status_message == NULL || *status_message == '\0') {
-               if (activity != NULL) {
-                       e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
-                       g_object_unref (activity);
-                       activity = NULL;
-               }
-       } else if (activity == NULL) {
-               activity = e_activity_new ();
-               e_activity_set_percent (activity, percent);
-               e_activity_set_text (activity, status_message);
-               e_shell_backend_add_activity (shell_backend, activity);
-       } else {
-               e_activity_set_percent (activity, percent);
-               e_activity_set_text (activity, status_message);
-       }
-
-       cal_shell_view->priv->calendar_activity = activity;
-}
-
-static void
-cal_transferring_update_alert (ECalShellView *cal_shell_view,
-                               const gchar *domain,
-                               const gchar *calendar,
-                               const gchar *message)
-{
-       ECalShellViewPrivate *priv;
-       EShellContent *shell_content;
-       EAlert *alert;
-
-       g_return_if_fail (cal_shell_view != NULL);
-       g_return_if_fail (cal_shell_view->priv != NULL);
-
-       priv = cal_shell_view->priv;
-
-       if (priv->transfer_alert) {
-               e_alert_response (
-                       priv->transfer_alert,
-                       e_alert_get_default_response (priv->transfer_alert));
-               priv->transfer_alert = NULL;
-       }
-
-       if (!message)
-               return;
-
-       alert = e_alert_new (domain, calendar, message, NULL);
-       g_return_if_fail (alert != NULL);
-
-       priv->transfer_alert = alert;
-       g_object_add_weak_pointer (G_OBJECT (alert), &priv->transfer_alert);
-       e_alert_start_timer (priv->transfer_alert, 300);
-
-       shell_content = e_shell_view_get_shell_content (E_SHELL_VIEW (cal_shell_view));
-       e_alert_sink_submit_alert (E_ALERT_SINK (shell_content), priv->transfer_alert);
-       g_object_unref (priv->transfer_alert);
-}
-
-typedef struct _TransferItemToData {
-       ECalShellView *cal_shell_view;
-       EActivity *activity;
-       const gchar *display_name;
-       gboolean remove;
-} TransferItemToData;
-
-static void
-transfer_item_to_cb (GObject *src_object,
-                     GAsyncResult *result,
-                     gpointer user_data)
-{
-       TransferItemToData *titd = user_data;
-       GError *error = NULL;
-       GCancellable *cancellable;
-       gboolean success;
-
-       success = cal_comp_transfer_item_to_finish (E_CAL_CLIENT (src_object), result, &error);
-
-       cancellable = e_activity_get_cancellable (titd->activity);
-       e_activity_set_state (
-               titd->activity,
-               g_cancellable_is_cancelled (cancellable) ? E_ACTIVITY_CANCELLED : E_ACTIVITY_COMPLETED);
-
-       if (!success) {
-               cal_transferring_update_alert (
-                       titd->cal_shell_view,
-                       titd->remove ? "calendar:failed-move-event" : "calendar:failed-copy-event",
-                       titd->display_name,
-                       error->message);
-               g_clear_error (&error);
-       }
-
-       g_object_unref (titd->activity);
-       g_free (titd);
-}
-
-void
-e_cal_shell_view_transfer_item_to (ECalShellView *cal_shell_view,
-                                   ECalendarViewEvent *event,
-                                   ECalClient *destination_client,
-                                   gboolean remove)
-{
-       EActivity *activity;
-       EShellBackend *shell_backend;
-       ESource *source;
-       GCancellable *cancellable = NULL;
-       gchar *message;
-       const gchar *display_name;
-       TransferItemToData *titd;
-
-       g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
-       g_return_if_fail (event != NULL);
-       g_return_if_fail (is_comp_data_valid (event) != FALSE);
-       g_return_if_fail (E_IS_CAL_CLIENT (destination_client));
-
-       if (!is_comp_data_valid (event))
-               return;
-
-       source = e_client_get_source (E_CLIENT (destination_client));
-       display_name = e_source_get_display_name (source);
-
-       message = remove ?
-               g_strdup_printf (_("Moving an event into the calendar %s"), display_name) :
-               g_strdup_printf (_("Copying an event into the calendar %s"), display_name);
-
-       shell_backend = e_shell_view_get_shell_backend (E_SHELL_VIEW (cal_shell_view));
-
-       cancellable = g_cancellable_new ();
-       activity = e_activity_new ();
-       e_activity_set_cancellable (activity, cancellable);
-       e_activity_set_state (activity, E_ACTIVITY_RUNNING);
-       e_activity_set_text (activity, message);
-       g_free (message);
-
-       e_shell_backend_add_activity (shell_backend, activity);
-
-       titd = g_new0 (TransferItemToData, 1);
-
-       titd->cal_shell_view = cal_shell_view;
-       titd->activity = activity;
-       titd->display_name = display_name;
-       titd->remove = remove;
-
-       cal_comp_transfer_item_to (
-               event->comp_data->client, destination_client,
-               event->comp_data->icalcomp, !remove, cancellable, transfer_item_to_cb, titd);
-}
-
-void
 e_cal_shell_view_update_sidebar (ECalShellView *cal_shell_view)
 {
        EShellView *shell_view;
        EShellSidebar *shell_sidebar;
        ECalShellContent *cal_shell_content;
-       GnomeCalendar *calendar;
-       GnomeCalendarViewType view_type;
        ECalendarView *calendar_view;
-       ECalModel *model;
-       time_t start_time, end_time;
-       struct tm start_tm, end_tm;
-       struct icaltimetype start_tt, end_tt;
-       icaltimezone *timezone;
-       gchar buffer[512] = { 0 };
-       gchar end_buffer[512] = { 0 };
+       gchar *description;
 
        g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
 
@@ -1141,117 +469,13 @@ e_cal_shell_view_update_sidebar (ECalShellView *cal_shell_view)
        shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
 
        cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-
-       model = gnome_calendar_get_model (calendar);
-       timezone = e_cal_model_get_timezone (model);
-
-       view_type = gnome_calendar_get_view (calendar);
-       calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
-
-       if (!e_calendar_view_get_visible_time_range (
-               calendar_view, &start_time, &end_time)) {
-               e_shell_sidebar_set_secondary_text (shell_sidebar, "");
-               return;
-       }
 
-       start_tt = icaltime_from_timet_with_zone (start_time, FALSE, timezone);
-       start_tm.tm_year = start_tt.year - 1900;
-       start_tm.tm_mon = start_tt.month - 1;
-       start_tm.tm_mday = start_tt.day;
-       start_tm.tm_hour = start_tt.hour;
-       start_tm.tm_min = start_tt.minute;
-       start_tm.tm_sec = start_tt.second;
-       start_tm.tm_isdst = -1;
-       start_tm.tm_wday = time_day_of_week (
-               start_tt.day, start_tt.month - 1, start_tt.year);
-
-       /* Subtract one from end_time so we don't get an extra day. */
-       end_tt = icaltime_from_timet_with_zone (end_time - 1, FALSE, timezone);
-       end_tm.tm_year = end_tt.year - 1900;
-       end_tm.tm_mon = end_tt.month - 1;
-       end_tm.tm_mday = end_tt.day;
-       end_tm.tm_hour = end_tt.hour;
-       end_tm.tm_min = end_tt.minute;
-       end_tm.tm_sec = end_tt.second;
-       end_tm.tm_isdst = -1;
-       end_tm.tm_wday = time_day_of_week (
-               end_tt.day, end_tt.month - 1, end_tt.year);
-
-       switch (view_type) {
-               case GNOME_CAL_DAY_VIEW:
-               case GNOME_CAL_WORK_WEEK_VIEW:
-               case GNOME_CAL_WEEK_VIEW:
-                       if (start_tm.tm_year == end_tm.tm_year &&
-                               start_tm.tm_mon == end_tm.tm_mon &&
-                               start_tm.tm_mday == end_tm.tm_mday) {
-                               e_utf8_strftime (
-                                       buffer, sizeof (buffer),
-                                       _("%A %d %b %Y"), &start_tm);
-                       } else if (start_tm.tm_year == end_tm.tm_year) {
-                               e_utf8_strftime (
-                                       buffer, sizeof (buffer),
-                                       _("%a %d %b"), &start_tm);
-                               e_utf8_strftime (
-                                       end_buffer, sizeof (end_buffer),
-                                       _("%a %d %b %Y"), &end_tm);
-                               strcat (buffer, " - ");
-                               strcat (buffer, end_buffer);
-                       } else {
-                               e_utf8_strftime (
-                                       buffer, sizeof (buffer),
-                                       _("%a %d %b %Y"), &start_tm);
-                               e_utf8_strftime (
-                                       end_buffer, sizeof (end_buffer),
-                                       _("%a %d %b %Y"), &end_tm);
-                               strcat (buffer, " - ");
-                               strcat (buffer, end_buffer);
-                       }
-                       break;
+       calendar_view = e_cal_shell_content_get_current_calendar_view (cal_shell_content);
+       description = e_calendar_view_get_description_text (calendar_view);
 
-               case GNOME_CAL_MONTH_VIEW:
-               case GNOME_CAL_LIST_VIEW:
-                       if (start_tm.tm_year == end_tm.tm_year) {
-                               if (start_tm.tm_mon == end_tm.tm_mon) {
-                                       e_utf8_strftime (
-                                               buffer,
-                                               sizeof (buffer),
-                                               "%d", &start_tm);
-                                       e_utf8_strftime (
-                                               end_buffer,
-                                               sizeof (end_buffer),
-                                               _("%d %b %Y"), &end_tm);
-                                       strcat (buffer, " - ");
-                                       strcat (buffer, end_buffer);
-                               } else {
-                                       e_utf8_strftime (
-                                               buffer,
-                                               sizeof (buffer),
-                                               _("%d %b"), &start_tm);
-                                       e_utf8_strftime (
-                                               end_buffer,
-                                               sizeof (end_buffer),
-                                               _("%d %b %Y"), &end_tm);
-                                       strcat (buffer, " - ");
-                                       strcat (buffer, end_buffer);
-                               }
-                       } else {
-                               e_utf8_strftime (
-                                       buffer, sizeof (buffer),
-                                       _("%d %b %Y"), &start_tm);
-                               e_utf8_strftime (
-                                       end_buffer, sizeof (end_buffer),
-                                       _("%d %b %Y"), &end_tm);
-                               strcat (buffer, " - ");
-                               strcat (buffer, end_buffer);
-                       }
-                       break;
-
-               default:
-                       g_return_if_reached ();
-       }
+       e_shell_sidebar_set_secondary_text (shell_sidebar, description ? description : "");
 
-       e_shell_sidebar_set_secondary_text (shell_sidebar, buffer);
+       g_free (description);
 }
 
 static gint
@@ -1384,16 +608,13 @@ cal_search_get_object_list_cb (GObject *source,
                        cal_iterate_searching (cal_shell_view);
                }
 
-       } else {
+       } else if (cal_shell_view->priv->searching_activity) {
                GSList *iter;
                GCancellable *cancellable;
                time_t start, end;
 
-               cancellable = e_activity_get_cancellable (
-                       cal_shell_view->priv->searching_activity);
-               start = time_add_day (
-                       cal_shell_view->priv->search_time,
-                       (-1) * cal_shell_view->priv->search_direction);
+               cancellable = e_activity_get_cancellable (cal_shell_view->priv->searching_activity);
+               start = time_add_day (cal_shell_view->priv->search_time, (-1) * 
cal_shell_view->priv->search_direction);
                end = cal_shell_view->priv->search_time;
                if (start > end) {
                        time_t tmp = start;
@@ -1417,6 +638,8 @@ cal_search_get_object_list_cb (GObject *source,
                }
 
                e_cal_client_free_icalcomp_slist (icalcomps);
+       } else {
+               e_cal_client_free_icalcomp_slist (icalcomps);
        }
 }
 
@@ -1424,9 +647,8 @@ static gboolean
 cal_searching_check_candidates (ECalShellView *cal_shell_view)
 {
        ECalShellContent *cal_shell_content;
-       GnomeCalendarViewType view_type;
        ECalendarView *calendar_view;
-       GnomeCalendar *calendar;
+       ECalViewKind view_kind;
        GSList *iter;
        time_t value, candidate = -1;
 
@@ -1434,16 +656,15 @@ cal_searching_check_candidates (ECalShellView *cal_shell_view)
        g_return_val_if_fail (cal_shell_view->priv != NULL, FALSE);
 
        cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-       view_type = gnome_calendar_get_view (calendar);
-       calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+       calendar_view = e_cal_shell_content_get_current_calendar_view (cal_shell_content);
+       view_kind = e_cal_shell_content_get_current_view_id (cal_shell_content);
 
        if (!e_calendar_view_get_selected_time_range (calendar_view, &value, NULL))
                return FALSE;
 
        if (cal_shell_view->priv->search_direction > 0 &&
-           (view_type == GNOME_CAL_WEEK_VIEW ||
-            view_type == GNOME_CAL_MONTH_VIEW))
+           (view_kind == E_CAL_VIEW_KIND_WEEK ||
+            view_kind == E_CAL_VIEW_KIND_MONTH))
                value = time_add_day (value, 1);
 
        cal_shell_view->priv->search_hit_cache =
@@ -1464,7 +685,33 @@ cal_searching_check_candidates (ECalShellView *cal_shell_view)
        }
 
        if (candidate > 0) {
-               gnome_calendar_goto (calendar, candidate);
+               struct icaltimetype tt;
+               icaltimezone *zone;
+               ECalDataModel *data_model;
+               ECalendar *calendar;
+
+               calendar = e_cal_base_shell_sidebar_get_date_navigator 
(cal_shell_view->priv->cal_shell_sidebar);
+               data_model = e_cal_base_shell_content_get_data_model (E_CAL_BASE_SHELL_CONTENT 
(cal_shell_view->priv->cal_shell_content));
+               zone = e_cal_data_model_get_timezone (data_model);
+
+               if (zone)
+                       tt = icaltime_from_timet_with_zone (candidate, FALSE, zone);
+               else
+                       tt = icaltime_from_timet (candidate, FALSE);
+
+               if (icaltime_is_valid_time (tt) && !icaltime_is_null_time (tt)) {
+                       ECalendarView *cal_view;
+                       GDate *dt;
+
+                       dt = g_date_new_dmy (tt.day, tt.month, tt.year);
+                       e_calendar_item_set_selection (calendar->calitem, dt, dt);
+                       g_signal_emit_by_name (calendar->calitem, "selection-changed", 0);
+                       g_date_free (dt);
+
+                       cal_view = e_cal_shell_content_get_current_calendar_view 
(cal_shell_view->priv->cal_shell_content);
+                       e_calendar_view_set_selected_time_range (cal_view, candidate, candidate);
+               }
+
                return TRUE;
        }
 
@@ -1513,12 +760,12 @@ cal_iterate_searching (ECalShellView *cal_shell_view)
 {
        ECalShellViewPrivate *priv;
        GList *list, *link;
-       ECalModel *model;
+       ECalDataModel *data_model;
        time_t new_time, range1, range2;
        icaltimezone *timezone;
        const gchar *default_tzloc = NULL;
        GCancellable *cancellable;
-       gchar *sexp, *start, *end;
+       gchar *sexp, *start, *end, *data_filter;
 
        g_return_if_fail (cal_shell_view != NULL);
        g_return_if_fail (cal_shell_view->priv != NULL);
@@ -1596,10 +843,8 @@ cal_iterate_searching (ECalShellView *cal_shell_view)
                return;
        }
 
-       model = gnome_calendar_get_model (
-               e_cal_shell_content_get_calendar (
-               cal_shell_view->priv->cal_shell_content));
-       list = e_cal_model_list_clients (model);
+       data_model = e_cal_base_shell_content_get_data_model (E_CAL_BASE_SHELL_CONTENT 
(cal_shell_view->priv->cal_shell_content));
+       list = e_cal_data_model_get_clients (data_model);
 
        if (list == NULL) {
                e_activity_set_state (
@@ -1616,7 +861,7 @@ cal_iterate_searching (ECalShellView *cal_shell_view)
                return;
        }
 
-       timezone = e_cal_model_get_timezone (model);
+       timezone = e_cal_data_model_get_timezone (data_model);
        range1 = priv->search_time;
        range2 = time_add_day (range1, priv->search_direction);
        if (range1 < range2) {
@@ -1632,12 +877,14 @@ cal_iterate_searching (ECalShellView *cal_shell_view)
        if (!default_tzloc)
                default_tzloc = "";
 
+       data_filter = e_cal_data_model_dup_filter (data_model);
        sexp = g_strdup_printf (
                "(and %s (occur-in-time-range? "
                "(make-time \"%s\") "
                "(make-time \"%s\") \"%s\"))",
-               e_cal_model_get_search_query (model), start, end, default_tzloc);
+               data_filter, start, end, default_tzloc);
 
+       g_free (data_filter);
        g_free (start);
        g_free (end);
 
@@ -1653,7 +900,7 @@ cal_iterate_searching (ECalShellView *cal_shell_view)
                        cal_search_get_object_list_cb, cal_shell_view);
        }
 
-       g_list_free_full (list, (GDestroyNotify) g_object_unref);
+       g_list_free_full (list, g_object_unref);
        g_free (sexp);
 
        e_shell_view_update_actions (E_SHELL_VIEW (cal_shell_view));
@@ -1665,9 +912,7 @@ e_cal_shell_view_search_events (ECalShellView *cal_shell_view,
 {
        ECalShellViewPrivate *priv = cal_shell_view->priv;
        ECalShellContent *cal_shell_content;
-       GnomeCalendarViewType view_type;
        ECalendarView *calendar_view;
-       GnomeCalendar *calendar;
        time_t start_time = 0;
        gint range_years;
 
@@ -1675,9 +920,7 @@ e_cal_shell_view_search_events (ECalShellView *cal_shell_view,
                e_cal_shell_view_search_stop (cal_shell_view);
 
        cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-       view_type = gnome_calendar_get_view (calendar);
-       calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
+       calendar_view = e_cal_shell_content_get_current_calendar_view (cal_shell_content);
 
        if (!e_calendar_view_get_selected_time_range (calendar_view, &start_time, NULL)) {
                e_shell_view_update_actions (E_SHELL_VIEW (cal_shell_view));
diff --git a/modules/calendar/e-cal-shell-view-private.h b/modules/calendar/e-cal-shell-view-private.h
index d0c29c6..ef14640 100644
--- a/modules/calendar/e-cal-shell-view-private.h
+++ b/modules/calendar/e-cal-shell-view-private.h
@@ -24,7 +24,7 @@
 #include "e-cal-shell-view.h"
 
 #include <string.h>
-#include <glib/gi18n.h>
+#include <glib/gi18n-lib.h>
 
 #include <libecal/libecal.h>
 
@@ -37,18 +37,17 @@
 #include <calendar/gui/e-calendar-view.h>
 #include <calendar/gui/e-day-view.h>
 #include <calendar/gui/e-week-view.h>
-#include <calendar/gui/gnome-cal.h>
 #include <calendar/gui/print.h>
-#include <calendar/gui/dialogs/copy-source-dialog.h>
 #include <calendar/gui/dialogs/event-editor.h>
 #include <calendar/gui/dialogs/goto-dialog.h>
 #include <calendar/gui/dialogs/memo-editor.h>
 #include <calendar/gui/dialogs/select-source-dialog.h>
 #include <calendar/gui/dialogs/task-editor.h>
 
+#include "e-cal-base-shell-sidebar.h"
+
 #include "e-cal-shell-backend.h"
 #include "e-cal-shell-content.h"
-#include "e-cal-shell-sidebar.h"
 #include "e-cal-shell-view-actions.h"
 
 #define E_CAL_SHELL_VIEW_GET_PRIVATE(obj) \
@@ -90,11 +89,7 @@ struct _ECalShellViewPrivate {
        /* These are just for convenience. */
        ECalShellBackend *cal_shell_backend;
        ECalShellContent *cal_shell_content;
-       ECalShellSidebar *cal_shell_sidebar;
-
-       /* sidebar signal handlers */
-       gulong client_added_handler_id;
-       gulong client_removed_handler_id;
+       ECalBaseShellSidebar *cal_shell_sidebar;
 
        EShell *shell;
        gulong prepare_for_quit_handler_id;
@@ -102,23 +97,13 @@ struct _ECalShellViewPrivate {
        EClientCache *client_cache;
        gulong backend_error_handler_id;
 
-       GnomeCalendar *calendar;
-       gulong dates_shown_changed_handler_id;
-
        struct {
                ECalendarView *calendar_view;
                gulong popup_event_handler_id;
                gulong selection_changed_handler_id;
-               gulong user_created_handler_id;
-       } views[GNOME_CAL_LAST_VIEW];
+       } views[E_CAL_VIEW_KIND_LAST];
 
        ECalModel *model;
-       gulong status_message_handler_id;
-
-       ECalendar *date_navigator;
-       gulong scroll_event_handler_id;
-       gulong date_range_changed_handler_id;
-       gulong selection_changed_handler_id;
 
        ESourceSelector *selector;
        gulong selector_popup_event_handler_id;
@@ -126,20 +111,14 @@ struct _ECalShellViewPrivate {
        EMemoTable *memo_table;
        gulong memo_table_popup_event_handler_id;
        gulong memo_table_selection_change_handler_id;
-       gulong memo_table_status_message_handler_id;
 
        ETaskTable *task_table;
        gulong task_table_popup_event_handler_id;
        gulong task_table_selection_change_handler_id;
-       gulong task_table_status_message_handler_id;
 
        /* The last time explicitly selected by the user. */
        time_t base_view_time;
 
-       EActivity *calendar_activity;
-       EActivity *memopad_activity;
-       EActivity *taskpad_activity;
-
        /* Time-range searching */
        EActivity *searching_activity;
        gpointer search_alert; /* weak pointer to EAlert * */
@@ -168,20 +147,6 @@ void               e_cal_shell_view_private_finalize
 
 void           e_cal_shell_view_actions_init
                                        (ECalShellView *cal_shell_view);
-void           e_cal_shell_view_execute_search
-                                       (ECalShellView *cal_shell_view);
-void           e_cal_shell_view_open_event
-                                       (ECalShellView *cal_shell_view,
-                                        ECalModelComponent *comp_data);
-void           e_cal_shell_view_set_status_message
-                                       (ECalShellView *cal_shell_view,
-                                        const gchar *status_message,
-                                        gdouble percent);
-void           e_cal_shell_view_transfer_item_to
-                                       (ECalShellView *cal_shell_view,
-                                        ECalendarViewEvent *event,
-                                        ECalClient *destination_client,
-                                        gboolean remove);
 void           e_cal_shell_view_update_sidebar
                                        (ECalShellView *cal_shell_view);
 void           e_cal_shell_view_update_search_filter
@@ -201,10 +166,6 @@ void               e_cal_shell_view_memopad_actions_update
 void           e_cal_shell_view_memopad_open_memo
                                        (ECalShellView *cal_shell_view,
                                         ECalModelComponent *comp_data);
-void           e_cal_shell_view_memopad_set_status_message
-                                       (ECalShellView *cal_shell_view,
-                                        const gchar *status_message,
-                                        gdouble percent);
 
 /* Task Pad Utilities */
 
@@ -215,10 +176,6 @@ void               e_cal_shell_view_taskpad_actions_update
 void           e_cal_shell_view_taskpad_open_task
                                        (ECalShellView *cal_shell_view,
                                         ECalModelComponent *comp_data);
-void           e_cal_shell_view_taskpad_set_status_message
-                                       (ECalShellView *cal_shell_view,
-                                        const gchar *status_message,
-                                        gdouble percent);
 
 G_END_DECLS
 
diff --git a/modules/calendar/e-cal-shell-view-taskpad.c b/modules/calendar/e-cal-shell-view-taskpad.c
index b06f2cd..12bac83 100644
--- a/modules/calendar/e-cal-shell-view-taskpad.c
+++ b/modules/calendar/e-cal-shell-view-taskpad.c
@@ -22,6 +22,8 @@
 #include <config.h>
 #endif
 
+#include <calendar/gui/e-cal-ops.h>
+
 #include "e-cal-shell-view-private.h"
 
 /* Much of this file is based on e-task-shell-view-actions.c. */
@@ -54,22 +56,11 @@ action_calendar_taskpad_forward_cb (GtkAction *action,
                                     ECalShellView *cal_shell_view)
 {
        ECalShellContent *cal_shell_content;
-       EShell *shell;
-       EShellView *shell_view;
-       EShellWindow *shell_window;
-       ESourceRegistry *registry;
        ECalModelComponent *comp_data;
        ETaskTable *task_table;
        ECalComponent *comp;
-       icalcomponent *clone;
        GSList *list;
 
-       shell_view = E_SHELL_VIEW (cal_shell_view);
-       shell_window = e_shell_view_get_shell_window (shell_view);
-       shell = e_shell_window_get_shell (shell_window);
-
-       registry = e_shell_get_registry (shell);
-
        cal_shell_content = cal_shell_view->priv->cal_shell_content;
        task_table = e_cal_shell_content_get_task_table (cal_shell_content);
 
@@ -79,13 +70,12 @@ action_calendar_taskpad_forward_cb (GtkAction *action,
        g_slist_free (list);
 
        /* XXX We only forward the first selected task. */
-       comp = e_cal_component_new ();
-       clone = icalcomponent_new_clone (comp_data->icalcomp);
-       e_cal_component_set_icalcomponent (comp, clone);
+       comp = e_cal_component_new_from_icalcomponent (icalcomponent_new_clone (comp_data->icalcomp));
+       g_return_if_fail (comp != NULL);
 
-       itip_send_comp (
-               registry, E_CAL_COMPONENT_METHOD_PUBLISH, comp,
-               comp_data->client, NULL, NULL, NULL, TRUE, FALSE);
+       itip_send_component (e_task_table_get_model (task_table),
+               E_CAL_COMPONENT_METHOD_PUBLISH, comp, comp_data->client,
+               NULL, NULL, NULL, TRUE, FALSE, TRUE);
 
        g_object_unref (comp);
 }
@@ -140,20 +130,15 @@ static void
 action_calendar_taskpad_new_cb (GtkAction *action,
                                 ECalShellView *cal_shell_view)
 {
-       EShell *shell;
        EShellView *shell_view;
        EShellWindow *shell_window;
        ECalShellContent *cal_shell_content;
        ECalModelComponent *comp_data;
        ETaskTable *task_table;
-       ECalClient *client;
-       ECalComponent *comp;
-       CompEditor *editor;
        GSList *list;
 
        shell_view = E_SHELL_VIEW (cal_shell_view);
        shell_window = e_shell_view_get_shell_window (shell_view);
-       shell = e_shell_window_get_shell (shell_window);
 
        cal_shell_content = cal_shell_view->priv->cal_shell_content;
        task_table = e_cal_shell_content_get_task_table (cal_shell_content);
@@ -163,14 +148,8 @@ action_calendar_taskpad_new_cb (GtkAction *action,
        comp_data = list->data;
        g_slist_free (list);
 
-       client = comp_data->client;
-       editor = task_editor_new (client, shell, COMP_EDITOR_NEW_ITEM);
-       comp = cal_comp_task_new_with_defaults (client);
-       comp_editor_edit_comp (editor, comp);
-
-       gtk_window_present (GTK_WINDOW (editor));
-
-       g_object_unref (comp);
+       e_cal_ops_new_component_editor (shell_window, E_CAL_CLIENT_SOURCE_TYPE_TASKS,
+               e_source_get_uid (e_client_get_source (E_CLIENT (comp_data->client))), FALSE);
 }
 
 static void
@@ -517,92 +496,14 @@ void
 e_cal_shell_view_taskpad_open_task (ECalShellView *cal_shell_view,
                                     ECalModelComponent *comp_data)
 {
-       EShell *shell;
-       EShellView *shell_view;
-       EShellWindow *shell_window;
-       ESourceRegistry *registry;
-       CompEditor *editor;
-       CompEditorFlags flags = 0;
-       ECalComponent *comp;
-       icalcomponent *clone;
-       icalproperty *prop;
-       const gchar *uid;
+       EShellContent *shell_content;
+       ECalModel *model;
 
        g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
        g_return_if_fail (E_IS_CAL_MODEL_COMPONENT (comp_data));
 
-       shell_view = E_SHELL_VIEW (cal_shell_view);
-       shell_window = e_shell_view_get_shell_window (shell_view);
-       shell = e_shell_window_get_shell (shell_window);
-
-       registry = e_shell_get_registry (shell);
-
-       uid = icalcomponent_get_uid (comp_data->icalcomp);
-       editor = comp_editor_find_instance (uid);
-
-       if (editor != NULL)
-               goto exit;
-
-       comp = e_cal_component_new ();
-       clone = icalcomponent_new_clone (comp_data->icalcomp);
-       e_cal_component_set_icalcomponent (comp, clone);
-
-       prop = icalcomponent_get_first_property (
-               comp_data->icalcomp, ICAL_ATTENDEE_PROPERTY);
-       if (prop != NULL)
-               flags |= COMP_EDITOR_IS_ASSIGNED;
-
-       if (itip_organizer_is_user (registry, comp, comp_data->client))
-               flags |= COMP_EDITOR_USER_ORG;
-
-       if (!e_cal_component_has_attendees (comp))
-               flags |= COMP_EDITOR_USER_ORG;
-
-       editor = task_editor_new (comp_data->client, shell, flags);
-       comp_editor_edit_comp (editor, comp);
-
-       g_object_unref (comp);
-
-       if (flags & COMP_EDITOR_IS_ASSIGNED)
-               task_editor_show_assignment (TASK_EDITOR (editor));
-
-exit:
-       gtk_window_present (GTK_WINDOW (editor));
-}
-
-void
-e_cal_shell_view_taskpad_set_status_message (ECalShellView *cal_shell_view,
-                                             const gchar *status_message,
-                                             gdouble percent)
-{
-       EActivity *activity;
-       EShellView *shell_view;
-       EShellBackend *shell_backend;
-
-       g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
-
-       shell_view = E_SHELL_VIEW (cal_shell_view);
-       shell_backend = e_shell_view_get_shell_backend (shell_view);
-
-       activity = cal_shell_view->priv->taskpad_activity;
-
-       if (status_message == NULL || *status_message == '\0') {
-               if (activity != NULL) {
-                       e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
-                       g_object_unref (activity);
-                       activity = NULL;
-               }
-
-       } else if (activity == NULL) {
-               activity = e_activity_new ();
-               e_activity_set_percent (activity, percent);
-               e_activity_set_text (activity, status_message);
-               e_shell_backend_add_activity (shell_backend, activity);
-
-       } else {
-               e_activity_set_percent (activity, percent);
-               e_activity_set_text (activity, status_message);
-       }
+       shell_content = e_shell_view_get_shell_content (E_SHELL_VIEW (cal_shell_view));
+       model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (shell_content));
 
-       cal_shell_view->priv->taskpad_activity = activity;
+       e_cal_ops_open_component_in_editor_sync (model, comp_data->client, comp_data->icalcomp);
 }
diff --git a/modules/calendar/e-cal-shell-view.c b/modules/calendar/e-cal-shell-view.c
index 9bdcfea..6f3a94e 100644
--- a/modules/calendar/e-cal-shell-view.c
+++ b/modules/calendar/e-cal-shell-view.c
@@ -1,5 +1,6 @@
 /*
- * e-cal-shell-view.c
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
@@ -7,29 +8,30 @@
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
  * for more details.
  *
  * You should have received a copy of the GNU Lesser General Public License
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
  */
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
 
+#include <gtk/gtk.h>
+#include <glib/gi18n-lib.h>
+
 #include "e-cal-shell-view-private.h"
 
+#include "calendar/gui/ea-calendar.h"
 #include "calendar/gui/calendar-view.h"
 
-G_DEFINE_DYNAMIC_TYPE (
-       ECalShellView,
-       e_cal_shell_view,
-       E_TYPE_SHELL_VIEW)
+#include "e-cal-base-shell-sidebar.h"
+#include "e-cal-shell-content.h"
+#include "e-cal-shell-view.h"
+
+G_DEFINE_DYNAMIC_TYPE (ECalShellView, e_cal_shell_view, E_TYPE_CAL_BASE_SHELL_VIEW)
 
 static void
 cal_shell_view_add_action_button (GtkBox *box,
@@ -77,82 +79,17 @@ cal_shell_view_prepare_for_quit_cb (EShell *shell,
 }
 
 static void
-cal_shell_view_dispose (GObject *object)
-{
-       e_cal_shell_view_private_dispose (E_CAL_SHELL_VIEW (object));
-
-       /* Chain up to parent's dispose() method. */
-       G_OBJECT_CLASS (e_cal_shell_view_parent_class)->dispose (object);
-}
-
-static void
-cal_shell_view_finalize (GObject *object)
-{
-       e_cal_shell_view_private_finalize (E_CAL_SHELL_VIEW (object));
-
-       /* Chain up to parent's finalize() method. */
-       G_OBJECT_CLASS (e_cal_shell_view_parent_class)->finalize (object);
-}
-
-static void
-cal_shell_view_constructed (GObject *object)
-{
-       EShell *shell;
-       EShellView *shell_view;
-       EShellWindow *shell_window;
-       EShellSearchbar *searchbar;
-       ECalShellView *cal_shell_view;
-       ECalShellContent *cal_shell_content;
-       GtkWidget *container;
-       GtkWidget *widget;
-       gulong handler_id;
-
-       /* Chain up to parent's constructed() method. */
-       G_OBJECT_CLASS (e_cal_shell_view_parent_class)->constructed (object);
-
-       cal_shell_view = E_CAL_SHELL_VIEW (object);
-       e_cal_shell_view_private_constructed (cal_shell_view);
-
-       shell_view = E_SHELL_VIEW (cal_shell_view);
-       shell_window = e_shell_view_get_shell_window (shell_view);
-       shell = e_shell_window_get_shell (shell_window);
-
-       cal_shell_content = cal_shell_view->priv->cal_shell_content;
-       searchbar = e_cal_shell_content_get_searchbar (cal_shell_content);
-       container = e_shell_searchbar_get_search_box (searchbar);
-
-       widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
-       cal_shell_view_add_action_button (
-               GTK_BOX (widget), ACTION (CALENDAR_SEARCH_PREV));
-       cal_shell_view_add_action_button (
-               GTK_BOX (widget), ACTION (CALENDAR_SEARCH_NEXT));
-       cal_shell_view_add_action_button (
-               GTK_BOX (widget), ACTION (CALENDAR_SEARCH_STOP));
-       gtk_container_add (GTK_CONTAINER (container), widget);
-       gtk_widget_show (widget);
-
-       handler_id = g_signal_connect (
-               shell, "prepare-for-quit",
-               G_CALLBACK (cal_shell_view_prepare_for_quit_cb),
-               cal_shell_view);
-
-       cal_shell_view->priv->shell = g_object_ref (shell);
-       cal_shell_view->priv->prepare_for_quit_handler_id = handler_id;
-}
-
-static void
 cal_shell_view_execute_search (EShellView *shell_view)
 {
        ECalShellContent *cal_shell_content;
-       ECalShellSidebar *cal_shell_sidebar;
+       ECalBaseShellSidebar *cal_shell_sidebar;
        EShellWindow *shell_window;
        EShellContent *shell_content;
        EShellSidebar *shell_sidebar;
        EShellSearchbar *searchbar;
        EActionComboBox *combo_box;
-       GnomeCalendar *calendar;
-       ECalendar *date_navigator;
-       ECalModel *model;
+       ECalendar *calendar;
+       ECalDataModel *data_model;
        GtkRadioAction *action;
        icaltimezone *timezone;
        const gchar *default_tzloc = NULL;
@@ -161,7 +98,6 @@ cal_shell_view_execute_search (EShellView *shell_view)
        time_t end_range;
        time_t now_time;
        gboolean range_search;
-       gchar *start, *end;
        gchar *query;
        gchar *temp;
        gint value;
@@ -173,13 +109,12 @@ cal_shell_view_execute_search (EShellView *shell_view)
        shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
 
        cal_shell_content = E_CAL_SHELL_CONTENT (shell_content);
-       cal_shell_sidebar = E_CAL_SHELL_SIDEBAR (shell_sidebar);
+       cal_shell_sidebar = E_CAL_BASE_SHELL_SIDEBAR (shell_sidebar);
 
        searchbar = e_cal_shell_content_get_searchbar (cal_shell_content);
 
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-       model = gnome_calendar_get_model (calendar);
-       timezone = e_cal_model_get_timezone (model);
+       data_model = e_cal_base_shell_content_get_data_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
+       timezone = e_cal_data_model_get_timezone (data_model);
        current_time = icaltime_current_time_with_zone (timezone);
        now_time = time_day_begin (icaltime_as_timet (current_time));
 
@@ -254,34 +189,12 @@ cal_shell_view_execute_search (EShellView *shell_view)
                        /* Show a year's worth of appointments. */
                        start_range = now_time;
                        end_range = time_day_end (time_add_day (start_range, 365));
-                       start = isodate_from_time_t (start_range);
-                       end = isodate_from_time_t (end_range);
-
-                       temp = g_strdup_printf (
-                               "(and %s (occur-in-time-range? "
-                               "(make-time \"%s\") "
-                               "(make-time \"%s\") \"%s\"))",
-                               query, start, end, default_tzloc);
-                       g_free (query);
-                       query = temp;
-
                        range_search = TRUE;
                        break;
 
                case CALENDAR_FILTER_NEXT_7_DAYS_APPOINTMENTS:
                        start_range = now_time;
                        end_range = time_day_end (time_add_day (start_range, 7));
-                       start = isodate_from_time_t (start_range);
-                       end = isodate_from_time_t (end_range);
-
-                       temp = g_strdup_printf (
-                               "(and %s (occur-in-time-range? "
-                               "(make-time \"%s\") "
-                               "(make-time \"%s\") \"%s\"))",
-                               query, start, end, default_tzloc);
-                       g_free (query);
-                       query = temp;
-
                        range_search = TRUE;
                        break;
 
@@ -310,21 +223,23 @@ cal_shell_view_execute_search (EShellView *shell_view)
                }
        }
 
-       date_navigator = e_cal_shell_sidebar_get_date_navigator (cal_shell_sidebar);
+       calendar = e_cal_base_shell_sidebar_get_date_navigator (cal_shell_sidebar);
 
        if (range_search) {
                /* Switch to list view and hide the date navigator. */
                action = GTK_RADIO_ACTION (ACTION (CALENDAR_VIEW_LIST));
                gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
-               gtk_widget_hide (GTK_WIDGET (date_navigator));
+               gtk_widget_hide (GTK_WIDGET (calendar));
        } else {
                /* Ensure the date navigator is visible. */
-               gtk_widget_show (GTK_WIDGET (date_navigator));
+               gtk_widget_show (GTK_WIDGET (calendar));
+               e_cal_shell_content_get_current_range (cal_shell_content, &start_range, &end_range);
+               end_range = time_day_end (end_range) - 1;
        }
 
        /* Submit the query. */
-       gnome_calendar_set_search_query (
-               calendar, query, range_search, start_range, end_range);
+       e_cal_shell_content_update_filters (cal_shell_content, query, start_range, end_range);
+
        g_free (query);
 
        /* Update actions so Find Prev/Next/Stop
@@ -343,13 +258,12 @@ cal_shell_view_update_actions (EShellView *shell_view)
        EShell *shell;
        ESource *source;
        ESourceRegistry *registry;
-       GnomeCalendar *calendar;
        ECalendarView *cal_view;
        EMemoTable *memo_table;
        ETaskTable *task_table;
-       ECalModel *model;
+       ECalDataModel *data_model;
        GtkAction *action;
-       const gchar *model_sexp;
+       gchar *data_filter;
        gboolean is_searching;
        gboolean sensitive;
        guint32 state;
@@ -389,52 +303,51 @@ cal_shell_view_update_actions (EShellView *shell_view)
        }
 
        cal_shell_content = priv->cal_shell_content;
-       calendar = e_cal_shell_content_get_calendar (cal_shell_content);
-       cal_view = gnome_calendar_get_calendar_view (calendar, gnome_calendar_get_view (calendar));
+       cal_view = e_cal_shell_content_get_current_calendar_view (cal_shell_content);
        memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
        task_table = e_cal_shell_content_get_task_table (cal_shell_content);
-       model = gnome_calendar_get_model (calendar);
-       model_sexp = e_cal_model_get_search_query (model);
-       is_searching = model_sexp && *model_sexp &&
-               g_strcmp0 (model_sexp, "#t") != 0 &&
-               g_strcmp0 (model_sexp, "(contains? \"summary\"  \"\")") != 0;
+       data_model = e_cal_base_shell_content_get_data_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
+       data_filter = e_cal_data_model_dup_filter (data_model);
+       is_searching = data_filter && *data_filter &&
+               g_strcmp0 (data_filter, "#t") != 0 &&
+               g_strcmp0 (data_filter, "(contains? \"summary\"  \"\")") != 0;
+       g_free (data_filter);
 
        shell_content = e_shell_view_get_shell_content (shell_view);
        state = e_shell_content_check_state (shell_content);
 
        single_event_selected =
-               (state & E_CAL_SHELL_CONTENT_SELECTION_SINGLE);
+               (state & E_CAL_BASE_SHELL_CONTENT_SELECTION_SINGLE);
        multiple_events_selected =
-               (state & E_CAL_SHELL_CONTENT_SELECTION_MULTIPLE);
+               (state & E_CAL_BASE_SHELL_CONTENT_SELECTION_MULTIPLE);
        selection_is_editable =
-               (state & E_CAL_SHELL_CONTENT_SELECTION_IS_EDITABLE);
+               (state & E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_EDITABLE);
        selection_is_instance =
-               (state & E_CAL_SHELL_CONTENT_SELECTION_IS_INSTANCE);
+               (state & E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_INSTANCE);
        selection_is_meeting =
-               (state & E_CAL_SHELL_CONTENT_SELECTION_IS_MEETING);
+               (state & E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_MEETING);
        selection_is_recurring =
-               (state & E_CAL_SHELL_CONTENT_SELECTION_IS_RECURRING);
+               (state & E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_RECURRING);
        selection_can_delegate =
-               (state & E_CAL_SHELL_CONTENT_SELECTION_CAN_DELEGATE);
+               (state & E_CAL_BASE_SHELL_CONTENT_SELECTION_CAN_DELEGATE);
 
        shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
        state = e_shell_sidebar_check_state (shell_sidebar);
 
        has_primary_source =
-               (state & E_CAL_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE);
+               (state & E_CAL_BASE_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE);
        primary_source_is_writable =
-               (state & E_CAL_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_WRITABLE);
+               (state & E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_WRITABLE);
        primary_source_is_removable =
-               (state & E_CAL_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOVABLE);
+               (state & E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOVABLE);
        primary_source_is_remote_deletable =
-               (state & E_CAL_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_DELETABLE);
+               (state & E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_DELETABLE);
        primary_source_in_collection =
-               (state & E_CAL_SHELL_SIDEBAR_PRIMARY_SOURCE_IN_COLLECTION);
+               (state & E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IN_COLLECTION);
        refresh_supported =
-               (state & E_CAL_SHELL_SIDEBAR_SOURCE_SUPPORTS_REFRESH);
+               (state & E_CAL_BASE_SHELL_SIDEBAR_SOURCE_SUPPORTS_REFRESH);
 
-       any_events_selected =
-               (single_event_selected || multiple_events_selected);
+       any_events_selected = (single_event_selected || multiple_events_selected);
 
        action = ACTION (CALENDAR_COPY);
        sensitive = has_primary_source;
@@ -575,10 +488,75 @@ cal_shell_view_update_actions (EShellView *shell_view)
 }
 
 static void
+cal_shell_view_dispose (GObject *object)
+{
+       e_cal_shell_view_private_dispose (E_CAL_SHELL_VIEW (object));
+
+       /* Chain up to parent's dispose() method. */
+       G_OBJECT_CLASS (e_cal_shell_view_parent_class)->dispose (object);
+}
+
+static void
+cal_shell_view_finalize (GObject *object)
+{
+       e_cal_shell_view_private_finalize (E_CAL_SHELL_VIEW (object));
+
+       /* Chain up to parent's finalize() method. */
+       G_OBJECT_CLASS (e_cal_shell_view_parent_class)->finalize (object);
+}
+
+static void
+cal_shell_view_constructed (GObject *object)
+{
+       EShell *shell;
+       EShellView *shell_view;
+       EShellWindow *shell_window;
+       EShellSearchbar *searchbar;
+       ECalShellView *cal_shell_view;
+       ECalShellContent *cal_shell_content;
+       GtkWidget *container;
+       GtkWidget *widget;
+       gulong handler_id;
+
+       /* Chain up to parent's constructed() method. */
+       G_OBJECT_CLASS (e_cal_shell_view_parent_class)->constructed (object);
+
+       cal_shell_view = E_CAL_SHELL_VIEW (object);
+       e_cal_shell_view_private_constructed (cal_shell_view);
+
+       shell_view = E_SHELL_VIEW (cal_shell_view);
+       shell_window = e_shell_view_get_shell_window (shell_view);
+       shell = e_shell_window_get_shell (shell_window);
+
+       cal_shell_content = cal_shell_view->priv->cal_shell_content;
+       searchbar = e_cal_shell_content_get_searchbar (cal_shell_content);
+       container = e_shell_searchbar_get_search_box (searchbar);
+
+       widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+       cal_shell_view_add_action_button (
+               GTK_BOX (widget), ACTION (CALENDAR_SEARCH_PREV));
+       cal_shell_view_add_action_button (
+               GTK_BOX (widget), ACTION (CALENDAR_SEARCH_NEXT));
+       cal_shell_view_add_action_button (
+               GTK_BOX (widget), ACTION (CALENDAR_SEARCH_STOP));
+       gtk_container_add (GTK_CONTAINER (container), widget);
+       gtk_widget_show (widget);
+
+       handler_id = g_signal_connect (
+               shell, "prepare-for-quit",
+               G_CALLBACK (cal_shell_view_prepare_for_quit_cb),
+               cal_shell_view);
+
+       cal_shell_view->priv->shell = g_object_ref (shell);
+       cal_shell_view->priv->prepare_for_quit_handler_id = handler_id;
+}
+
+static void
 e_cal_shell_view_class_init (ECalShellViewClass *class)
 {
        GObjectClass *object_class;
        EShellViewClass *shell_view_class;
+       ECalBaseShellViewClass *cal_base_shell_view_class;
 
        g_type_class_add_private (class, sizeof (ECalShellViewPrivate));
 
@@ -595,16 +573,21 @@ e_cal_shell_view_class_init (ECalShellViewClass *class)
        shell_view_class->search_options = "/calendar-search-options";
        shell_view_class->search_rules = "caltypes.xml";
        shell_view_class->new_shell_content = e_cal_shell_content_new;
-       shell_view_class->new_shell_sidebar = e_cal_shell_sidebar_new;
+       shell_view_class->new_shell_sidebar = e_cal_base_shell_sidebar_new;
        shell_view_class->execute_search = cal_shell_view_execute_search;
        shell_view_class->update_actions = cal_shell_view_update_actions;
 
+       cal_base_shell_view_class = E_CAL_BASE_SHELL_VIEW_CLASS (class);
+       cal_base_shell_view_class->source_type = E_CAL_CLIENT_SOURCE_TYPE_EVENTS;
+
        /* Ensure the GalView types we need are registered. */
        g_type_ensure (GAL_TYPE_VIEW_CALENDAR_DAY);
        g_type_ensure (GAL_TYPE_VIEW_CALENDAR_WORK_WEEK);
        g_type_ensure (GAL_TYPE_VIEW_CALENDAR_WEEK);
        g_type_ensure (GAL_TYPE_VIEW_CALENDAR_MONTH);
        g_type_ensure (GAL_TYPE_VIEW_ETABLE);
+
+       e_calendar_a11y_init ();
 }
 
 static void
@@ -615,8 +598,7 @@ e_cal_shell_view_class_finalize (ECalShellViewClass *class)
 static void
 e_cal_shell_view_init (ECalShellView *cal_shell_view)
 {
-       cal_shell_view->priv =
-               E_CAL_SHELL_VIEW_GET_PRIVATE (cal_shell_view);
+       cal_shell_view->priv = E_CAL_SHELL_VIEW_GET_PRIVATE (cal_shell_view);
 
        e_cal_shell_view_private_init (cal_shell_view);
 }
@@ -629,87 +611,3 @@ e_cal_shell_view_type_register (GTypeModule *type_module)
         *     order to register types from a separate compilation unit. */
        e_cal_shell_view_register_type (type_module);
 }
-
-static void
-cal_shell_view_allow_auth_prompt_and_refresh_done_cb (GObject *source_object,
-                                                     GAsyncResult *result,
-                                                     gpointer user_data)
-{
-       EClient *client;
-       EActivity *activity;
-       EAlertSink *alert_sink;
-       ESource *source;
-       const gchar *display_name;
-       GError *local_error = NULL;
-
-       g_return_if_fail (E_IS_CAL_CLIENT (source_object));
-
-       client = E_CLIENT (source_object);
-       source = e_client_get_source (client);
-       activity = user_data;
-       alert_sink = e_activity_get_alert_sink (activity);
-       display_name = e_source_get_display_name (source);
-
-       e_util_allow_auth_prompt_and_refresh_client_finish (client, result, &local_error);
-
-       if (e_activity_handle_cancellation (activity, local_error)) {
-               g_error_free (local_error);
-
-       } else if (local_error != NULL) {
-               const gchar *error_message;
-
-               switch (e_cal_client_get_source_type (E_CAL_CLIENT (client))) {
-               default:
-               case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
-                       error_message = "calendar:refresh-error-events";
-                       break;
-               case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
-                       error_message = "calendar:refresh-error-tasks";
-                       break;
-               case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
-                       error_message = "calendar:refresh-error-memos";
-                       break;
-               }
-               e_alert_submit (
-                       alert_sink,
-                       error_message,
-                       display_name, 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_shell_view_allow_auth_prompt_and_refresh (EShellView *shell_view,
-                                               EClient *client)
-{
-       EShellBackend *shell_backend;
-       EShellContent *shell_content;
-       EActivity *activity;
-       EAlertSink *alert_sink;
-       GCancellable *cancellable;
-
-       g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
-       g_return_if_fail (E_IS_CLIENT (client));
-
-       shell_backend = e_shell_view_get_shell_backend (shell_view);
-       shell_content = e_shell_view_get_shell_content (shell_view);
-
-       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);
-
-       e_util_allow_auth_prompt_and_refresh_client (client, cancellable,
-               cal_shell_view_allow_auth_prompt_and_refresh_done_cb, activity);
-
-       e_shell_backend_add_activity (shell_backend, activity);
-
-       g_object_unref (cancellable);
-}
diff --git a/modules/calendar/e-cal-shell-view.h b/modules/calendar/e-cal-shell-view.h
index d01a77e..d6e96c1 100644
--- a/modules/calendar/e-cal-shell-view.h
+++ b/modules/calendar/e-cal-shell-view.h
@@ -1,5 +1,6 @@
 /*
- * e-cal-shell-view.h
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
@@ -7,22 +8,18 @@
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
  * for more details.
  *
  * You should have received a copy of the GNU Lesser General Public License
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
  */
 
 #ifndef E_CAL_SHELL_VIEW_H
 #define E_CAL_SHELL_VIEW_H
 
 #include <e-util/e-util.h>
-#include <shell/e-shell-view.h>
+#include "e-cal-base-shell-view.h"
 
 /* Standard GObject macros */
 #define E_TYPE_CAL_SHELL_VIEW \
@@ -50,20 +47,16 @@ typedef struct _ECalShellViewClass ECalShellViewClass;
 typedef struct _ECalShellViewPrivate ECalShellViewPrivate;
 
 struct _ECalShellView {
-       EShellView parent;
+       ECalBaseShellView parent;
        ECalShellViewPrivate *priv;
 };
 
 struct _ECalShellViewClass {
-       EShellViewClass parent_class;
+       ECalBaseShellViewClass parent_class;
 };
 
-GType          e_cal_shell_view_get_type       (void);
-void           e_cal_shell_view_type_register  (GTypeModule *type_module);
-
-void           e_cal_shell_view_allow_auth_prompt_and_refresh
-                                               (EShellView *shell_view,
-                                                EClient *client);
+GType          e_cal_shell_view_get_type               (void);
+void           e_cal_shell_view_type_register          (GTypeModule *type_module);
 
 G_END_DECLS
 
diff --git a/modules/calendar/e-memo-shell-backend.c b/modules/calendar/e-memo-shell-backend.c
index 88d6cbc..0a4d752 100644
--- a/modules/calendar/e-memo-shell-backend.c
+++ b/modules/calendar/e-memo-shell-backend.c
@@ -1,5 +1,6 @@
 /*
- * e-memo-shell-backend.c
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
@@ -7,40 +8,27 @@
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
  * for more details.
  *
  * You should have received a copy of the GNU Lesser General Public License
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  *
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
+ * Authors: Milan Crha <mcrha redhat com>
  */
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
 
-#include "e-memo-shell-backend.h"
-
 #include <string.h>
 #include <glib/gi18n.h>
-#include <libecal/libecal.h>
-
-#include "shell/e-shell.h"
-#include "shell/e-shell-backend.h"
-#include "shell/e-shell-window.h"
 
-#include "calendar/gui/comp-util.h"
-#include "calendar/gui/dialogs/memo-editor.h"
+#include <calendar/gui/e-cal-ops.h>
 
-#include "e-memo-shell-migrate.h"
+#include "e-cal-base-shell-backend.h"
 #include "e-memo-shell-view.h"
-
-#define E_MEMO_SHELL_BACKEND_GET_PRIVATE(obj) \
-       (G_TYPE_INSTANCE_GET_PRIVATE \
-       ((obj), E_TYPE_MEMO_SHELL_BACKEND, EMemoShellBackendPrivate))
+#include "e-memo-shell-backend.h"
 
 #define E_MEMO_SHELL_BACKEND_GET_PRIVATE(obj) \
        (G_TYPE_INSTANCE_GET_PRIVATE \
@@ -50,163 +38,22 @@ struct _EMemoShellBackendPrivate {
        gint placeholder;
 };
 
-G_DEFINE_DYNAMIC_TYPE (
-       EMemoShellBackend,
-       e_memo_shell_backend,
-       E_TYPE_SHELL_BACKEND)
-
-static void
-memo_shell_backend_new_memo (ECalClient *cal_client,
-                             EShell *shell,
-                             CompEditorFlags flags)
-{
-       ECalComponent *comp;
-       CompEditor *editor;
-
-       comp = cal_comp_memo_new_with_defaults (cal_client);
-       cal_comp_update_time_by_active_window (comp, shell);
-       editor = memo_editor_new (cal_client, shell, flags);
-       comp_editor_edit_comp (editor, comp);
-
-       gtk_window_present (GTK_WINDOW (editor));
-
-       g_object_unref (comp);
-}
-
-static void
-memo_shell_backend_memo_new_cb (GObject *source_object,
-                                GAsyncResult *result,
-                                gpointer user_data)
-{
-       EShell *shell = E_SHELL (user_data);
-       EClient *client;
-       CompEditorFlags flags = 0;
-       GError *error = NULL;
-
-       flags |= COMP_EDITOR_NEW_ITEM;
-
-       client = e_client_cache_get_client_finish (
-               E_CLIENT_CACHE (source_object), result, &error);
-
-       /* Sanity check. */
-       g_return_if_fail (
-               ((client != NULL) && (error == NULL)) ||
-               ((client == NULL) && (error != NULL)));
-
-       if (client != NULL) {
-               memo_shell_backend_new_memo (
-                       E_CAL_CLIENT (client), shell, flags);
-               g_object_unref (client);
-       } else {
-               /* XXX Handle errors better. */
-               g_warning ("%s: %s", G_STRFUNC, error->message);
-               g_error_free (error);
-       }
-
-       g_object_unref (shell);
-}
-
-static void
-memo_shell_backend_memo_shared_new_cb (GObject *source_object,
-                                       GAsyncResult *result,
-                                       gpointer user_data)
-{
-       EShell *shell = E_SHELL (user_data);
-       EClient *client;
-       CompEditorFlags flags = 0;
-       GError *error = NULL;
-
-       flags |= COMP_EDITOR_NEW_ITEM;
-       flags |= COMP_EDITOR_IS_SHARED;
-       flags |= COMP_EDITOR_USER_ORG;
-
-       client = e_client_cache_get_client_finish (
-               E_CLIENT_CACHE (source_object), result, &error);
-
-       /* Sanity check. */
-       g_return_if_fail (
-               ((client != NULL) && (error == NULL)) ||
-               ((client == NULL) && (error != NULL)));
-
-       if (client != NULL) {
-               memo_shell_backend_new_memo (
-                       E_CAL_CLIENT (client), shell, flags);
-               g_object_unref (client);
-       } else {
-               /* XXX Handle errors better. */
-               g_warning ("%s: %s", G_STRFUNC, error->message);
-               g_error_free (error);
-       }
-
-       g_object_unref (shell);
-}
+G_DEFINE_DYNAMIC_TYPE (EMemoShellBackend, e_memo_shell_backend, E_TYPE_CAL_BASE_SHELL_BACKEND)
 
 static void
 action_memo_new_cb (GtkAction *action,
                     EShellWindow *shell_window)
 {
-       EShell *shell;
-       ESource *source;
-       ESourceRegistry *registry;
-       EClientCache *client_cache;
-       const gchar *action_name;
-
-       /* This callback is used for both memos and shared memos. */
-
-       shell = e_shell_window_get_shell (shell_window);
-       client_cache = e_shell_get_client_cache (shell);
-
-       registry = e_shell_get_registry (shell);
-       source = e_source_registry_ref_default_memo_list (registry);
-
-       /* Use a callback function appropriate for the action. */
-       action_name = gtk_action_get_name (action);
-       if (g_strcmp0 (action_name, "memo-shared-new") == 0)
-               e_client_cache_get_client (
-                       client_cache, source,
-                       E_SOURCE_EXTENSION_MEMO_LIST,
-                       NULL,
-                       memo_shell_backend_memo_shared_new_cb,
-                       g_object_ref (shell));
-       else
-               e_client_cache_get_client (
-                       client_cache, source,
-                       E_SOURCE_EXTENSION_MEMO_LIST,
-                       NULL,
-                       memo_shell_backend_memo_new_cb,
-                       g_object_ref (shell));
-
-       g_object_unref (source);
+       e_cal_ops_new_component_editor (shell_window,
+               E_CAL_CLIENT_SOURCE_TYPE_MEMOS, NULL,
+               g_strcmp0 (gtk_action_get_name (action), "memo-shared-new") == 0);
 }
 
 static void
 action_memo_list_new_cb (GtkAction *action,
                          EShellWindow *shell_window)
 {
-       EShell *shell;
-       ESourceRegistry *registry;
-       ECalClientSourceType source_type;
-       GtkWidget *config;
-       GtkWidget *dialog;
-       const gchar *icon_name;
-
-       shell = e_shell_window_get_shell (shell_window);
-
-       registry = e_shell_get_registry (shell);
-       source_type = E_CAL_CLIENT_SOURCE_TYPE_MEMOS;
-       config = e_cal_source_config_new (registry, NULL, source_type);
-
-       dialog = e_source_config_dialog_new (E_SOURCE_CONFIG (config));
-
-       gtk_window_set_transient_for (
-               GTK_WINDOW (dialog), GTK_WINDOW (shell_window));
-
-       icon_name = gtk_action_get_icon_name (action);
-       gtk_window_set_icon_name (GTK_WINDOW (dialog), icon_name);
-
-       gtk_window_set_title (GTK_WINDOW (dialog), _("New Memo List"));
-
-       gtk_widget_show (dialog);
+       e_cal_base_shell_backend_util_new_source (shell_window, E_CAL_CLIENT_SOURCE_TYPE_MEMOS);
 }
 
 static GtkActionEntry item_entries[] = {
@@ -237,220 +84,24 @@ static GtkActionEntry source_entries[] = {
 };
 
 static gboolean
-memo_shell_backend_handle_uri_cb (EShellBackend *shell_backend,
-                                  const gchar *uri)
+e_memo_shell_backend_handle_uri (EShellBackend *shell_backend,
+                                const gchar *uri)
 {
-       EShell *shell;
-       CompEditor *editor;
-       CompEditorFlags flags = 0;
-       EClient *client;
-       EClientCache *client_cache;
-       ECalComponent *comp;
-       ESource *source;
-       ESourceRegistry *registry;
-       SoupURI *soup_uri;
-       icalcomponent *icalcomp;
-       const gchar *cp;
-       gchar *source_uid = NULL;
-       gchar *comp_uid = NULL;
-       gchar *comp_rid = NULL;
-       gboolean handled = FALSE;
-       GError *error = NULL;
-
-       shell = e_shell_backend_get_shell (shell_backend);
-       client_cache = e_shell_get_client_cache (shell);
-
        if (strncmp (uri, "memo:", 5) != 0)
                return FALSE;
 
-       soup_uri = soup_uri_new (uri);
-
-       if (soup_uri == NULL)
-               return FALSE;
-
-       cp = soup_uri_get_query (soup_uri);
-       if (cp == NULL)
-               goto exit;
-
-       while (*cp != '\0') {
-               gchar *header;
-               gchar *content;
-               gsize header_len;
-               gsize content_len;
-
-               header_len = strcspn (cp, "=&");
-
-               /* If it's malformed, give up. */
-               if (cp[header_len] != '=')
-                       break;
-
-               header = (gchar *) cp;
-               header[header_len] = '\0';
-               cp += header_len + 1;
-
-               content_len = strcspn (cp, "&");
-
-               content = g_strndup (cp, content_len);
-               if (g_ascii_strcasecmp (header, "source-uid") == 0)
-                       source_uid = g_strdup (content);
-               else if (g_ascii_strcasecmp (header, "comp-uid") == 0)
-                       comp_uid = g_strdup (content);
-               else if (g_ascii_strcasecmp (header, "comp-rid") == 0)
-                       comp_rid = g_strdup (content);
-               g_free (content);
-
-               cp += content_len;
-               if (*cp == '&') {
-                       cp++;
-                       if (strcmp (cp, "amp;") == 0)
-                               cp += 4;
-               }
-       }
-
-       if (source_uid == NULL || comp_uid == NULL)
-               goto exit;
-
-       /* URI is valid, so consider it handled.  Whether
-        * we successfully open it is another matter... */
-       handled = TRUE;
-
-       registry = e_shell_get_registry (shell);
-       source = e_source_registry_ref_source (registry, source_uid);
-       if (source == NULL) {
-               g_printerr ("No source for UID '%s'\n", source_uid);
-               goto exit;
-       }
-
-       client = e_client_cache_get_client_sync (
-               client_cache, source,
-               E_SOURCE_EXTENSION_MEMO_LIST,
-               NULL, &error);
-
-       /* Sanity check. */
-       g_return_val_if_fail (
-               ((client != NULL) && (error == NULL)) ||
-               ((client == NULL) && (error != NULL)), FALSE);
-
-       if (error != NULL) {
-               g_warning (
-                       "%s: Failed to create/open client: %s",
-                       G_STRFUNC, error->message);
-               g_object_unref (source);
-               g_error_free (error);
-               goto exit;
-       }
-
-       g_object_unref (source);
-       source = NULL;
-
-       /* XXX Copied from e_memo_shell_view_open_memo().
-        *     Clearly a new utility function is needed. */
-
-       editor = comp_editor_find_instance (comp_uid);
-
-       if (editor != NULL)
-               goto present;
-
-       e_cal_client_get_object_sync (
-               E_CAL_CLIENT (client), comp_uid,
-               comp_rid, &icalcomp, NULL, &error);
-
-       if (error != NULL) {
-               g_warning (
-                       "%s: Failed to get object: %s",
-                       G_STRFUNC, error->message);
-               g_object_unref (client);
-               g_error_free (error);
-               goto exit;
-       }
-
-       comp = e_cal_component_new ();
-       if (!e_cal_component_set_icalcomponent (comp, icalcomp)) {
-               g_warning ("%s: Failed to set icalcomp to comp\n", G_STRFUNC);
-               icalcomponent_free (icalcomp);
-               icalcomp = NULL;
-       }
-
-       if (e_cal_component_has_organizer (comp))
-               flags |= COMP_EDITOR_IS_SHARED;
-
-       if (itip_organizer_is_user (registry, comp, E_CAL_CLIENT (client)))
-               flags |= COMP_EDITOR_USER_ORG;
-
-       editor = memo_editor_new (E_CAL_CLIENT (client), shell, flags);
-       comp_editor_edit_comp (editor, comp);
-
-       g_object_unref (comp);
-
-present:
-       gtk_window_present (GTK_WINDOW (editor));
-
-       g_object_unref (client);
-
-exit:
-       g_free (source_uid);
-       g_free (comp_uid);
-       g_free (comp_rid);
-
-       soup_uri_free (soup_uri);
-
-       return handled;
-}
-
-static void
-memo_shell_backend_window_added_cb (EShellBackend *shell_backend,
-                                    GtkWindow *window)
-{
-       const gchar *module_name;
-
-       if (!E_IS_SHELL_WINDOW (window))
-               return;
-
-       module_name = E_SHELL_BACKEND_GET_CLASS (shell_backend)->name;
-
-       e_shell_window_register_new_item_actions (
-               E_SHELL_WINDOW (window), module_name,
-               item_entries, G_N_ELEMENTS (item_entries));
-
-       e_shell_window_register_new_source_actions (
-               E_SHELL_WINDOW (window), module_name,
-               source_entries, G_N_ELEMENTS (source_entries));
-}
-
-static void
-memo_shell_backend_constructed (GObject *object)
-{
-       EShell *shell;
-       EShellBackend *shell_backend;
-
-       shell_backend = E_SHELL_BACKEND (object);
-       shell = e_shell_backend_get_shell (shell_backend);
-
-       g_signal_connect_swapped (
-               shell, "handle-uri",
-               G_CALLBACK (memo_shell_backend_handle_uri_cb),
-               shell_backend);
-
-       g_signal_connect_swapped (
-               shell, "window-added",
-               G_CALLBACK (memo_shell_backend_window_added_cb),
-               shell_backend);
-
-       /* Chain up to parent's constructed() method. */
-       G_OBJECT_CLASS (e_memo_shell_backend_parent_class)->constructed (object);
+       return e_cal_base_shell_backend_util_handle_uri (shell_backend,
+               E_CAL_CLIENT_SOURCE_TYPE_MEMOS, uri, NULL);
 }
 
 static void
 e_memo_shell_backend_class_init (EMemoShellBackendClass *class)
 {
-       GObjectClass *object_class;
        EShellBackendClass *shell_backend_class;
+       ECalBaseShellBackendClass *cal_base_shell_backend_class;
 
        g_type_class_add_private (class, sizeof (EMemoShellBackendPrivate));
 
-       object_class = G_OBJECT_CLASS (class);
-       object_class->constructed = memo_shell_backend_constructed;
-
        shell_backend_class = E_SHELL_BACKEND_CLASS (class);
        shell_backend_class->shell_view_type = E_TYPE_MEMO_SHELL_VIEW;
        shell_backend_class->name = "memos";
@@ -459,22 +110,24 @@ e_memo_shell_backend_class_init (EMemoShellBackendClass *class)
        shell_backend_class->sort_order = 600;
        shell_backend_class->preferences_page = "calendar-and-tasks";
        shell_backend_class->start = NULL;
-       shell_backend_class->migrate = e_memo_shell_backend_migrate;
 
-       /* Register relevant ESource extensions. */
-       E_TYPE_SOURCE_MEMO_LIST;
+       cal_base_shell_backend_class = E_CAL_BASE_SHELL_BACKEND_CLASS (class);
+       cal_base_shell_backend_class->new_item_entries = item_entries;
+       cal_base_shell_backend_class->new_item_n_entries = G_N_ELEMENTS (item_entries);
+       cal_base_shell_backend_class->source_entries = source_entries;
+       cal_base_shell_backend_class->source_n_entries = G_N_ELEMENTS (source_entries);
+       cal_base_shell_backend_class->handle_uri = e_memo_shell_backend_handle_uri;
 }
 
 static void
-e_memo_shell_backend_class_finalize (EMemoShellBackendClass *class)
+e_memo_shell_backend_init (EMemoShellBackend *memo_shell_backend)
 {
+       memo_shell_backend->priv = E_MEMO_SHELL_BACKEND_GET_PRIVATE (memo_shell_backend);
 }
 
 static void
-e_memo_shell_backend_init (EMemoShellBackend *memo_shell_backend)
+e_memo_shell_backend_class_finalize (EMemoShellBackendClass *class)
 {
-       memo_shell_backend->priv =
-               E_MEMO_SHELL_BACKEND_GET_PRIVATE (memo_shell_backend);
 }
 
 void
diff --git a/modules/calendar/e-memo-shell-backend.h b/modules/calendar/e-memo-shell-backend.h
index a05d709..2a77f4c 100644
--- a/modules/calendar/e-memo-shell-backend.h
+++ b/modules/calendar/e-memo-shell-backend.h
@@ -1,5 +1,6 @@
 /*
- * e-memo-shell-backend.h
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
@@ -7,21 +8,17 @@
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
  * for more details.
  *
  * You should have received a copy of the GNU Lesser General Public License
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
  */
 
 #ifndef E_MEMO_SHELL_BACKEND_H
 #define E_MEMO_SHELL_BACKEND_H
 
-#include <shell/e-shell-backend.h>
+#include "e-cal-base-shell-backend.h"
 
 /* Standard GObject macros */
 #define E_TYPE_MEMO_SHELL_BACKEND \
@@ -49,17 +46,16 @@ typedef struct _EMemoShellBackendClass EMemoShellBackendClass;
 typedef struct _EMemoShellBackendPrivate EMemoShellBackendPrivate;
 
 struct _EMemoShellBackend {
-       EShellBackend parent;
+       ECalBaseShellBackend parent;
        EMemoShellBackendPrivate *priv;
 };
 
 struct _EMemoShellBackendClass {
-       EShellBackendClass parent_class;
+       ECalBaseShellBackendClass parent_class;
 };
 
-GType          e_memo_shell_backend_get_type   (void);
-void           e_memo_shell_backend_type_register
-                                       (GTypeModule *type_module);
+GType          e_memo_shell_backend_get_type           (void);
+void           e_memo_shell_backend_type_register      (GTypeModule *type_module);
 
 G_END_DECLS
 
diff --git a/modules/calendar/e-memo-shell-content.c b/modules/calendar/e-memo-shell-content.c
index 4b0c4b5..e1ff53f 100644
--- a/modules/calendar/e-memo-shell-content.c
+++ b/modules/calendar/e-memo-shell-content.c
@@ -1,5 +1,6 @@
 /*
- * e-memo-shell-content.c
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
@@ -7,31 +8,29 @@
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
  * for more details.
  *
  * You should have received a copy of the GNU Lesser General Public License
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
  */
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
 
-#include "e-memo-shell-content.h"
+#include <string.h>
+#include <glib/gi18n-lib.h>
 
-#include <glib/gi18n.h>
+#include <calendar/gui/e-cal-model-memos.h>
 
-#include "shell/e-shell-utils.h"
+#include <calendar/gui/comp-util.h>
+#include <calendar/gui/e-cal-component-preview.h>
+#include <calendar/gui/e-cal-model-memos.h>
+#include <calendar/gui/e-memo-table.h>
 
-#include "calendar/gui/comp-util.h"
-#include "calendar/gui/e-cal-component-preview.h"
-#include "calendar/gui/e-cal-model-memos.h"
-#include "calendar/gui/e-memo-table.h"
+#include "e-cal-base-shell-sidebar.h"
+#include "e-memo-shell-content.h"
 
 #define E_MEMO_SHELL_CONTENT_GET_PRIVATE(obj) \
        (G_TYPE_INSTANCE_GET_PRIVATE \
@@ -42,7 +41,6 @@ struct _EMemoShellContentPrivate {
        GtkWidget *memo_table;
        GtkWidget *preview_pane;
 
-       ECalModel *memo_model;
        GtkOrientation orientation;
 
        gchar *current_uid;
@@ -52,18 +50,12 @@ struct _EMemoShellContentPrivate {
 
 enum {
        PROP_0,
-       PROP_MODEL,
        PROP_ORIENTATION,
        PROP_PREVIEW_VISIBLE
 };
 
-G_DEFINE_DYNAMIC_TYPE_EXTENDED (
-       EMemoShellContent,
-       e_memo_shell_content,
-       E_TYPE_SHELL_CONTENT,
-       0,
-       G_IMPLEMENT_INTERFACE_DYNAMIC (
-               GTK_TYPE_ORIENTABLE, NULL))
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (EMemoShellContent, e_memo_shell_content, E_TYPE_CAL_BASE_SHELL_CONTENT, 0,
+       G_IMPLEMENT_INTERFACE_DYNAMIC (GTK_TYPE_ORIENTABLE, NULL))
 
 static void
 memo_shell_content_display_view_cb (EMemoShellContent *memo_shell_content,
@@ -183,7 +175,7 @@ memo_shell_content_cursor_change_cb (EMemoShellContent *memo_shell_content,
        EWebView *web_view;
        const gchar *uid;
 
-       memo_model = e_memo_shell_content_get_memo_model (memo_shell_content);
+       memo_model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (memo_shell_content));
        preview_pane = e_memo_shell_content_get_preview_pane (memo_shell_content);
 
        web_view = e_preview_pane_get_web_view (preview_pane);
@@ -265,40 +257,68 @@ memo_shell_content_model_row_changed_cb (EMemoShellContent *memo_shell_content,
 }
 
 static void
-memo_shell_content_restore_state_cb (EShellWindow *shell_window,
-                                     EShellView *shell_view,
-                                     EShellContent *shell_content)
+memo_shell_content_is_editing_changed_cb (EMemoTable *memo_table,
+                                          GParamSpec *param,
+                                          EShellView *shell_view)
 {
-       EMemoShellContentPrivate *priv;
-       GSettings *settings;
+       g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
 
-       priv = E_MEMO_SHELL_CONTENT_GET_PRIVATE (shell_content);
+       e_shell_view_update_actions (shell_view);
+}
 
-       /* Bind GObject properties to settings keys. */
+static guint32
+memo_shell_content_check_state (EShellContent *shell_content)
+{
+       EMemoShellContent *memo_shell_content;
+       EMemoTable *memo_table;
+       GSList *list, *iter;
+       gboolean editable = TRUE;
+       gboolean has_url = FALSE;
+       gint n_selected;
+       guint32 state = 0;
 
-       settings = g_settings_new ("org.gnome.evolution.calendar");
+       memo_shell_content = E_MEMO_SHELL_CONTENT (shell_content);
+       memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
 
-       g_settings_bind (
-               settings, "memo-hpane-position",
-               priv->paned, "hposition",
-               G_SETTINGS_BIND_DEFAULT);
+       n_selected = e_table_selected_count (E_TABLE (memo_table));
 
-       g_settings_bind (
-               settings, "memo-vpane-position",
-               priv->paned, "vposition",
-               G_SETTINGS_BIND_DEFAULT);
+       list = e_memo_table_get_selected (memo_table);
+       for (iter = list; iter != NULL; iter = iter->next) {
+               ECalModelComponent *comp_data = iter->data;
+               icalproperty *prop;
+               gboolean read_only;
 
-       g_object_unref (settings);
+               if (!comp_data)
+                       continue;
+
+               read_only = e_client_is_readonly (E_CLIENT (comp_data->client));
+               editable &= !read_only;
+
+               prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_URL_PROPERTY);
+               has_url |= (prop != NULL);
+       }
+       g_slist_free (list);
+
+       if (n_selected == 1)
+               state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_SINGLE;
+       if (n_selected > 1)
+               state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_MULTIPLE;
+       if (editable)
+               state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_EDITABLE;
+       if (has_url)
+               state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_HAS_URL;
+
+       return state;
 }
 
 static void
-memo_shell_content_is_editing_changed_cb (EMemoTable *memo_table,
-                                          GParamSpec *param,
-                                          EShellView *shell_view)
+memo_shell_content_focus_search_results (EShellContent *shell_content)
 {
-       g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
+       EMemoShellContent *memo_shell_content;
 
-       e_shell_view_update_actions (shell_view);
+       memo_shell_content = E_MEMO_SHELL_CONTENT (shell_content);
+
+       gtk_widget_grab_focus (memo_shell_content->priv->memo_table);
 }
 
 static GtkOrientation
@@ -320,6 +340,41 @@ memo_shell_content_set_orientation (EMemoShellContent *memo_shell_content,
 }
 
 static void
+memo_shell_content_view_created (ECalBaseShellContent *cal_base_shell_content)
+{
+       EMemoShellContent *memo_shell_content;
+       EShellView *shell_view;
+       GalViewInstance *view_instance;
+       GSettings *settings;
+
+       memo_shell_content = E_MEMO_SHELL_CONTENT (cal_base_shell_content);
+       shell_view = e_shell_content_get_shell_view (E_SHELL_CONTENT (memo_shell_content));
+
+       /* Bind GObject properties to settings keys. */
+
+       settings = g_settings_new ("org.gnome.evolution.calendar");
+
+       g_settings_bind (
+               settings, "memo-hpane-position",
+               memo_shell_content->priv->paned, "hposition",
+               G_SETTINGS_BIND_DEFAULT);
+
+       g_settings_bind (
+               settings, "memo-vpane-position",
+               memo_shell_content->priv->paned, "vposition",
+               G_SETTINGS_BIND_DEFAULT);
+
+       g_object_unref (settings);
+
+       /* Finally load the view instance */
+       view_instance = e_shell_view_get_view_instance (shell_view);
+       gal_view_instance_load (view_instance);
+
+       /* Show everything known by default */
+       e_cal_model_set_time_range (e_cal_base_shell_content_get_model (cal_base_shell_content), 0, 0);
+}
+
+static void
 memo_shell_content_set_property (GObject *object,
                                  guint property_id,
                                  const GValue *value,
@@ -344,18 +399,11 @@ memo_shell_content_set_property (GObject *object,
 
 static void
 memo_shell_content_get_property (GObject *object,
-                                 guint property_id,
-                                 GValue *value,
-                                 GParamSpec *pspec)
+                                guint property_id,
+                                GValue *value,
+                                GParamSpec *pspec)
 {
        switch (property_id) {
-               case PROP_MODEL:
-                       g_value_set_object (
-                               value,
-                               e_memo_shell_content_get_memo_model (
-                               E_MEMO_SHELL_CONTENT (object)));
-                       return;
-
                case PROP_ORIENTATION:
                        g_value_set_enum (
                                value,
@@ -377,57 +425,27 @@ memo_shell_content_get_property (GObject *object,
 static void
 memo_shell_content_dispose (GObject *object)
 {
-       EMemoShellContentPrivate *priv;
-
-       priv = E_MEMO_SHELL_CONTENT_GET_PRIVATE (object);
-
-       if (priv->paned != NULL) {
-               g_object_unref (priv->paned);
-               priv->paned = NULL;
-       }
+       EMemoShellContent *memo_shell_content = E_MEMO_SHELL_CONTENT (object);
 
-       if (priv->memo_table != NULL) {
-               g_object_unref (priv->memo_table);
-               priv->memo_table = NULL;
-       }
-
-       if (priv->preview_pane != NULL) {
-               g_object_unref (priv->preview_pane);
-               priv->preview_pane = NULL;
-       }
+       g_clear_object (&memo_shell_content->priv->paned);
+       g_clear_object (&memo_shell_content->priv->memo_table);
+       g_clear_object (&memo_shell_content->priv->preview_pane);
 
-       if (priv->memo_model != NULL) {
-               g_object_unref (priv->memo_model);
-               priv->memo_model = NULL;
-       }
+       g_free (memo_shell_content->priv->current_uid);
+       memo_shell_content->priv->current_uid = NULL;
 
        /* Chain up to parent's dispose() method. */
        G_OBJECT_CLASS (e_memo_shell_content_parent_class)->dispose (object);
 }
 
 static void
-memo_shell_content_finalize (GObject *object)
-{
-       EMemoShellContentPrivate *priv;
-
-       priv = E_MEMO_SHELL_CONTENT_GET_PRIVATE (object);
-
-       g_free (priv->current_uid);
-
-       /* Chain up to parent's finalize() method. */
-       G_OBJECT_CLASS (e_memo_shell_content_parent_class)->finalize (object);
-}
-
-static void
 memo_shell_content_constructed (GObject *object)
 {
-       EMemoShellContentPrivate *priv;
-       EShell *shell;
+       EMemoShellContent *memo_shell_content;
        EShellView *shell_view;
        EShellContent *shell_content;
        EShellTaskbar *shell_taskbar;
-       EShellWindow *shell_window;
-       ESourceRegistry *registry;
+       ECalModel *model;
        GalViewInstance *view_instance;
        GtkTargetList *target_list;
        GtkTargetEntry *targets;
@@ -435,19 +453,16 @@ memo_shell_content_constructed (GObject *object)
        GtkWidget *widget;
        gint n_targets;
 
-       priv = E_MEMO_SHELL_CONTENT_GET_PRIVATE (object);
+       memo_shell_content = E_MEMO_SHELL_CONTENT (object);
 
        /* Chain up to parent's constructed() method. */
        G_OBJECT_CLASS (e_memo_shell_content_parent_class)->constructed (object);
 
+       model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (memo_shell_content));
+
        shell_content = E_SHELL_CONTENT (object);
        shell_view = e_shell_content_get_shell_view (shell_content);
        shell_taskbar = e_shell_view_get_shell_taskbar (shell_view);
-       shell_window = e_shell_view_get_shell_window (shell_view);
-       shell = e_shell_window_get_shell (shell_window);
-
-       registry = e_shell_get_registry (shell);
-       priv->memo_model = e_cal_model_memos_new (registry);
 
        /* Build content widgets. */
 
@@ -455,7 +470,7 @@ memo_shell_content_constructed (GObject *object)
 
        widget = e_paned_new (GTK_ORIENTATION_VERTICAL);
        gtk_container_add (GTK_CONTAINER (container), widget);
-       priv->paned = g_object_ref (widget);
+       memo_shell_content->priv->paned = g_object_ref (widget);
        gtk_widget_show (widget);
 
        g_object_bind_property (
@@ -463,7 +478,7 @@ memo_shell_content_constructed (GObject *object)
                widget, "orientation",
                G_BINDING_SYNC_CREATE);
 
-       container = priv->paned;
+       container = memo_shell_content->priv->paned;
 
        widget = gtk_scrolled_window_new (NULL, NULL);
        gtk_scrolled_window_set_policy (
@@ -476,12 +491,12 @@ memo_shell_content_constructed (GObject *object)
 
        container = widget;
 
-       widget = e_memo_table_new (shell_view, priv->memo_model);
+       widget = e_memo_table_new (shell_view, model);
        gtk_container_add (GTK_CONTAINER (container), widget);
-       priv->memo_table = g_object_ref (widget);
+       memo_shell_content->priv->memo_table = g_object_ref (widget);
        gtk_widget_show (widget);
 
-       container = priv->paned;
+       container = memo_shell_content->priv->paned;
 
        widget = e_cal_component_preview_new ();
        gtk_widget_show (widget);
@@ -493,7 +508,7 @@ memo_shell_content_constructed (GObject *object)
 
        widget = e_preview_pane_new (E_WEB_VIEW (widget));
        gtk_paned_pack2 (GTK_PANED (container), widget, FALSE, FALSE);
-       priv->preview_pane = g_object_ref (widget);
+       memo_shell_content->priv->preview_pane = g_object_ref (widget);
        gtk_widget_show (widget);
 
        g_object_bind_property (
@@ -506,7 +521,7 @@ memo_shell_content_constructed (GObject *object)
        targets = gtk_target_table_new_from_list (target_list, &n_targets);
 
        e_table_drag_source_set (
-               E_TABLE (priv->memo_table),
+               E_TABLE (memo_shell_content->priv->memo_table),
                GDK_BUTTON1_MASK, targets, n_targets,
                GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_ASK);
 
@@ -514,35 +529,35 @@ memo_shell_content_constructed (GObject *object)
        gtk_target_list_unref (target_list);
 
        g_signal_connect_swapped (
-               priv->memo_table, "table-drag-data-get",
+               memo_shell_content->priv->memo_table, "table-drag-data-get",
                G_CALLBACK (memo_shell_content_table_drag_data_get_cb),
                object);
 
        g_signal_connect_swapped (
-               priv->memo_table, "table-drag-data-delete",
+               memo_shell_content->priv->memo_table, "table-drag-data-delete",
                G_CALLBACK (memo_shell_content_table_drag_data_delete_cb),
                object);
 
        g_signal_connect_swapped (
-               priv->memo_table, "cursor-change",
+               memo_shell_content->priv->memo_table, "cursor-change",
                G_CALLBACK (memo_shell_content_cursor_change_cb),
                object);
 
        g_signal_connect_swapped (
-               priv->memo_table, "selection-change",
+               memo_shell_content->priv->memo_table, "selection-change",
                G_CALLBACK (memo_shell_content_selection_change_cb),
                object);
 
        e_signal_connect_notify (
-               priv->memo_table, "notify::is-editing",
+               memo_shell_content->priv->memo_table, "notify::is-editing",
                G_CALLBACK (memo_shell_content_is_editing_changed_cb), shell_view);
 
        g_signal_connect_swapped (
-               priv->memo_model, "model-row-changed",
+               model, "model-row-changed",
                G_CALLBACK (memo_shell_content_model_row_changed_cb),
                object);
 
-       /* Load the view instance. */
+       /* Prepare the view instance. */
 
        view_instance = e_shell_view_new_view_instance (shell_view, NULL);
        g_signal_connect_swapped (
@@ -550,68 +565,7 @@ memo_shell_content_constructed (GObject *object)
                G_CALLBACK (memo_shell_content_display_view_cb),
                object);
        e_shell_view_set_view_instance (shell_view, view_instance);
-       gal_view_instance_load (view_instance);
        g_object_unref (view_instance);
-
-       /* Restore pane positions from the last session once
-        * the shell view is fully initialized and visible. */
-       g_signal_connect (
-               shell_window, "shell-view-created::memos",
-               G_CALLBACK (memo_shell_content_restore_state_cb),
-               shell_content);
-}
-
-static guint32
-memo_shell_content_check_state (EShellContent *shell_content)
-{
-       EMemoShellContent *memo_shell_content;
-       EMemoTable *memo_table;
-       GSList *list, *iter;
-       gboolean editable = TRUE;
-       gboolean has_url = FALSE;
-       gint n_selected;
-       guint32 state = 0;
-
-       memo_shell_content = E_MEMO_SHELL_CONTENT (shell_content);
-       memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
-
-       n_selected = e_table_selected_count (E_TABLE (memo_table));
-
-       list = e_memo_table_get_selected (memo_table);
-       for (iter = list; iter != NULL; iter = iter->next) {
-               ECalModelComponent *comp_data = iter->data;
-               icalproperty *prop;
-               gboolean read_only;
-
-               read_only = e_client_is_readonly (E_CLIENT (comp_data->client));
-               editable &= !read_only;
-
-               prop = icalcomponent_get_first_property (
-                       comp_data->icalcomp, ICAL_URL_PROPERTY);
-               has_url |= (prop != NULL);
-       }
-       g_slist_free (list);
-
-       if (n_selected == 1)
-               state |= E_MEMO_SHELL_CONTENT_SELECTION_SINGLE;
-       if (n_selected > 1)
-               state |= E_MEMO_SHELL_CONTENT_SELECTION_MULTIPLE;
-       if (editable)
-               state |= E_MEMO_SHELL_CONTENT_SELECTION_CAN_EDIT;
-       if (has_url)
-               state |= E_MEMO_SHELL_CONTENT_SELECTION_HAS_URL;
-
-       return state;
-}
-
-static void
-memo_shell_content_focus_search_results (EShellContent *shell_content)
-{
-       EMemoShellContentPrivate *priv;
-
-       priv = E_MEMO_SHELL_CONTENT_GET_PRIVATE (shell_content);
-
-       gtk_widget_grab_focus (priv->memo_table);
 }
 
 static void
@@ -619,6 +573,7 @@ e_memo_shell_content_class_init (EMemoShellContentClass *class)
 {
        GObjectClass *object_class;
        EShellContentClass *shell_content_class;
+       ECalBaseShellContentClass *cal_base_shell_content_class;
 
        g_type_class_add_private (class, sizeof (EMemoShellContentPrivate));
 
@@ -626,23 +581,15 @@ e_memo_shell_content_class_init (EMemoShellContentClass *class)
        object_class->set_property = memo_shell_content_set_property;
        object_class->get_property = memo_shell_content_get_property;
        object_class->dispose = memo_shell_content_dispose;
-       object_class->finalize = memo_shell_content_finalize;
        object_class->constructed = memo_shell_content_constructed;
 
        shell_content_class = E_SHELL_CONTENT_CLASS (class);
        shell_content_class->check_state = memo_shell_content_check_state;
-       shell_content_class->focus_search_results =
-               memo_shell_content_focus_search_results;
+       shell_content_class->focus_search_results = memo_shell_content_focus_search_results;
 
-       g_object_class_install_property (
-               object_class,
-               PROP_MODEL,
-               g_param_spec_object (
-                       "model",
-                       "Model",
-                       "The memo table model",
-                       E_TYPE_CAL_MODEL,
-                       G_PARAM_READABLE));
+       cal_base_shell_content_class = E_CAL_BASE_SHELL_CONTENT_CLASS (class);
+       cal_base_shell_content_class->new_cal_model = e_cal_model_memos_new;
+       cal_base_shell_content_class->view_created = memo_shell_content_view_created;
 
        g_object_class_install_property (
                object_class,
@@ -667,8 +614,7 @@ e_memo_shell_content_class_finalize (EMemoShellContentClass *class)
 static void
 e_memo_shell_content_init (EMemoShellContent *memo_shell_content)
 {
-       memo_shell_content->priv =
-               E_MEMO_SHELL_CONTENT_GET_PRIVATE (memo_shell_content);
+       memo_shell_content->priv = E_MEMO_SHELL_CONTENT_GET_PRIVATE (memo_shell_content);
 
        /* Postpone widget construction until we have a shell view. */
 }
@@ -692,20 +638,10 @@ e_memo_shell_content_new (EShellView *shell_view)
                "shell-view", shell_view, NULL);
 }
 
-ECalModel *
-e_memo_shell_content_get_memo_model (EMemoShellContent *memo_shell_content)
-{
-       g_return_val_if_fail (
-               E_IS_MEMO_SHELL_CONTENT (memo_shell_content), NULL);
-
-       return memo_shell_content->priv->memo_model;
-}
-
 EMemoTable *
 e_memo_shell_content_get_memo_table (EMemoShellContent *memo_shell_content)
 {
-       g_return_val_if_fail (
-               E_IS_MEMO_SHELL_CONTENT (memo_shell_content), NULL);
+       g_return_val_if_fail (E_IS_MEMO_SHELL_CONTENT (memo_shell_content), NULL);
 
        return E_MEMO_TABLE (memo_shell_content->priv->memo_table);
 }
@@ -713,8 +649,7 @@ e_memo_shell_content_get_memo_table (EMemoShellContent *memo_shell_content)
 EPreviewPane *
 e_memo_shell_content_get_preview_pane (EMemoShellContent *memo_shell_content)
 {
-       g_return_val_if_fail (
-               E_IS_MEMO_SHELL_CONTENT (memo_shell_content), NULL);
+       g_return_val_if_fail (E_IS_MEMO_SHELL_CONTENT (memo_shell_content), NULL);
 
        return E_PREVIEW_PANE (memo_shell_content->priv->preview_pane);
 }
@@ -722,8 +657,7 @@ e_memo_shell_content_get_preview_pane (EMemoShellContent *memo_shell_content)
 gboolean
 e_memo_shell_content_get_preview_visible (EMemoShellContent *memo_shell_content)
 {
-       g_return_val_if_fail (
-               E_IS_MEMO_SHELL_CONTENT (memo_shell_content), FALSE);
+       g_return_val_if_fail (E_IS_MEMO_SHELL_CONTENT (memo_shell_content), FALSE);
 
        return memo_shell_content->priv->preview_visible;
 }
@@ -755,8 +689,7 @@ e_memo_shell_content_get_searchbar (EMemoShellContent *memo_shell_content)
        EShellContent *shell_content;
        GtkWidget *widget;
 
-       g_return_val_if_fail (
-               E_IS_MEMO_SHELL_CONTENT (memo_shell_content), NULL);
+       g_return_val_if_fail (E_IS_MEMO_SHELL_CONTENT (memo_shell_content), NULL);
 
        shell_content = E_SHELL_CONTENT (memo_shell_content);
        shell_view = e_shell_content_get_shell_view (shell_content);
@@ -764,4 +697,3 @@ e_memo_shell_content_get_searchbar (EMemoShellContent *memo_shell_content)
 
        return E_SHELL_SEARCHBAR (widget);
 }
-
diff --git a/modules/calendar/e-memo-shell-content.h b/modules/calendar/e-memo-shell-content.h
index d283e9e..aa06f37 100644
--- a/modules/calendar/e-memo-shell-content.h
+++ b/modules/calendar/e-memo-shell-content.h
@@ -1,5 +1,6 @@
 /*
- * e-memo-shell-content.h
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
@@ -7,15 +8,11 @@
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
  * for more details.
  *
  * You should have received a copy of the GNU Lesser General Public License
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
  */
 
 #ifndef E_MEMO_SHELL_CONTENT_H
@@ -27,6 +24,8 @@
 
 #include <calendar/gui/e-memo-table.h>
 
+#include "e-cal-base-shell-content.h"
+
 /* Standard GObject macros */
 #define E_TYPE_MEMO_SHELL_CONTENT \
        (e_memo_shell_content_get_type ())
@@ -52,41 +51,26 @@ typedef struct _EMemoShellContent EMemoShellContent;
 typedef struct _EMemoShellContentClass EMemoShellContentClass;
 typedef struct _EMemoShellContentPrivate EMemoShellContentPrivate;
 
-enum {
-       E_MEMO_SHELL_CONTENT_SELECTION_SINGLE = 1 << 0,
-       E_MEMO_SHELL_CONTENT_SELECTION_MULTIPLE = 1 << 1,
-       E_MEMO_SHELL_CONTENT_SELECTION_CAN_EDIT = 1 << 2,
-       E_MEMO_SHELL_CONTENT_SELECTION_HAS_URL = 1 << 3
-};
-
 struct _EMemoShellContent {
-       EShellContent parent;
+       ECalBaseShellContent parent;
        EMemoShellContentPrivate *priv;
 };
 
 struct _EMemoShellContentClass {
-       EShellContentClass parent_class;
+       ECalBaseShellContentClass parent_class;
 };
 
-GType          e_memo_shell_content_get_type   (void);
-void           e_memo_shell_content_type_register
-                                       (GTypeModule *type_module);
-GtkWidget *    e_memo_shell_content_new
-                                       (EShellView *shell_view);
-ECalModel *    e_memo_shell_content_get_memo_model
-                                       (EMemoShellContent *memo_shell_conent);
-EMemoTable *   e_memo_shell_content_get_memo_table
-                                       (EMemoShellContent *memo_shell_content);
-EPreviewPane * e_memo_shell_content_get_preview_pane
-                                       (EMemoShellContent *memo_shell_content);
-gboolean       e_memo_shell_content_get_preview_visible
-                                       (EMemoShellContent *memo_shell_content);
-void           e_memo_shell_content_set_preview_visible
-                                       (EMemoShellContent *memo_shell_content,
-                                        gboolean preview_visible);
+GType          e_memo_shell_content_get_type           (void);
+void           e_memo_shell_content_type_register      (GTypeModule *type_module);
+GtkWidget *    e_memo_shell_content_new                (EShellView *shell_view);
+
+EMemoTable *   e_memo_shell_content_get_memo_table     (EMemoShellContent *memo_shell_content);
+EPreviewPane * e_memo_shell_content_get_preview_pane   (EMemoShellContent *memo_shell_content);
+gboolean       e_memo_shell_content_get_preview_visible(EMemoShellContent *memo_shell_content);
+void           e_memo_shell_content_set_preview_visible(EMemoShellContent *memo_shell_content,
+                                                        gboolean preview_visible);
 EShellSearchbar *
-               e_memo_shell_content_get_searchbar
-                                       (EMemoShellContent *memo_shell_content);
+               e_memo_shell_content_get_searchbar      (EMemoShellContent *memo_shell_content);
 
 G_END_DECLS
 
diff --git a/modules/calendar/e-memo-shell-view-actions.c b/modules/calendar/e-memo-shell-view-actions.c
index 35ab8cc..7cfb7c8 100644
--- a/modules/calendar/e-memo-shell-view-actions.c
+++ b/modules/calendar/e-memo-shell-view-actions.c
@@ -22,6 +22,9 @@
 #include <config.h>
 #endif
 
+#include <calendar/gui/e-cal-ops.h>
+
+#include "e-cal-base-shell-view.h"
 #include "e-memo-shell-view-private.h"
 #include "e-cal-shell-view.h"
 
@@ -56,22 +59,11 @@ action_memo_forward_cb (GtkAction *action,
                         EMemoShellView *memo_shell_view)
 {
        EMemoShellContent *memo_shell_content;
-       EShell *shell;
-       EShellView *shell_view;
-       EShellWindow *shell_window;
-       ESourceRegistry *registry;
        EMemoTable *memo_table;
        ECalModelComponent *comp_data;
        ECalComponent *comp;
-       icalcomponent *clone;
        GSList *list;
 
-       shell_view = E_SHELL_VIEW (memo_shell_view);
-       shell_window = e_shell_view_get_shell_window (shell_view);
-       shell = e_shell_window_get_shell (shell_window);
-
-       registry = e_shell_get_registry (shell);
-
        memo_shell_content = memo_shell_view->priv->memo_shell_content;
        memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
 
@@ -81,52 +73,28 @@ action_memo_forward_cb (GtkAction *action,
        g_slist_free (list);
 
        /* XXX We only forward the first selected memo. */
-       comp = e_cal_component_new ();
-       clone = icalcomponent_new_clone (comp_data->icalcomp);
-       e_cal_component_set_icalcomponent (comp, clone);
+       comp = e_cal_component_new_from_icalcomponent (icalcomponent_new_clone (comp_data->icalcomp));
+       g_return_if_fail (comp != NULL);
 
-       itip_send_comp (
-               registry, E_CAL_COMPONENT_METHOD_PUBLISH, comp,
-               comp_data->client, NULL, NULL, NULL, TRUE, FALSE);
+       itip_send_component (e_memo_table_get_model (memo_table),
+               E_CAL_COMPONENT_METHOD_PUBLISH, comp,
+               comp_data->client, NULL, NULL, NULL, TRUE, FALSE, TRUE);
 
        g_object_unref (comp);
 }
 
 static void
 action_memo_list_copy_cb (GtkAction *action,
-                          EMemoShellView *memo_shell_view)
+                         EShellView *shell_view)
 {
-       EMemoShellSidebar *memo_shell_sidebar;
-       EShell *shell;
-       EShellView *shell_view;
-       EShellWindow *shell_window;
-       ESourceRegistry *registry;
-       ESourceSelector *selector;
-       ESource *source;
-
-       shell_view = E_SHELL_VIEW (memo_shell_view);
-       shell_window = e_shell_view_get_shell_window (shell_view);
-       shell = e_shell_window_get_shell (shell_window);
-
-       registry = e_shell_get_registry (shell);
-
-       memo_shell_sidebar = memo_shell_view->priv->memo_shell_sidebar;
-       selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
-       source = e_source_selector_ref_primary_selection (selector);
-       g_return_if_fail (source != NULL);
-
-       copy_source_dialog (
-               GTK_WINDOW (shell_window), registry,
-               source, E_CAL_CLIENT_SOURCE_TYPE_MEMOS);
-
-       g_object_unref (source);
+       e_cal_base_shell_view_copy_calendar (shell_view);
 }
 
 static void
 action_memo_list_delete_cb (GtkAction *action,
                             EMemoShellView *memo_shell_view)
 {
-       EMemoShellSidebar *memo_shell_sidebar;
+       ECalBaseShellSidebar *memo_shell_sidebar;
        EShellWindow *shell_window;
        EShellView *shell_view;
        ESource *source;
@@ -137,7 +105,7 @@ action_memo_list_delete_cb (GtkAction *action,
        shell_window = e_shell_view_get_shell_window (shell_view);
 
        memo_shell_sidebar = memo_shell_view->priv->memo_shell_sidebar;
-       selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
+       selector = e_cal_base_shell_sidebar_get_selector (memo_shell_sidebar);
 
        source = e_source_selector_ref_primary_selection (selector);
        g_return_if_fail (source != NULL);
@@ -234,7 +202,7 @@ action_memo_list_properties_cb (GtkAction *action,
 {
        EShellView *shell_view;
        EShellWindow *shell_window;
-       EMemoShellSidebar *memo_shell_sidebar;
+       ECalBaseShellSidebar *memo_shell_sidebar;
        ECalClientSourceType source_type;
        ESource *source;
        ESourceSelector *selector;
@@ -247,7 +215,7 @@ action_memo_list_properties_cb (GtkAction *action,
        shell_window = e_shell_view_get_shell_window (shell_view);
 
        memo_shell_sidebar = memo_shell_view->priv->memo_shell_sidebar;
-       selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
+       selector = e_cal_base_shell_sidebar_get_selector (memo_shell_sidebar);
        source = e_source_selector_ref_primary_selection (selector);
        g_return_if_fail (source != NULL);
 
@@ -274,13 +242,13 @@ static void
 action_memo_list_refresh_cb (GtkAction *action,
                              EMemoShellView *memo_shell_view)
 {
-       EMemoShellSidebar *memo_shell_sidebar;
+       ECalBaseShellSidebar *memo_shell_sidebar;
        ESourceSelector *selector;
        EClient *client = NULL;
        ESource *source;
 
        memo_shell_sidebar = memo_shell_view->priv->memo_shell_sidebar;
-       selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
+       selector = e_cal_base_shell_sidebar_get_selector (memo_shell_sidebar);
 
        source = e_source_selector_ref_primary_selection (selector);
 
@@ -295,7 +263,7 @@ action_memo_list_refresh_cb (GtkAction *action,
 
        g_return_if_fail (e_client_check_refresh_supported (client));
 
-       e_cal_shell_view_allow_auth_prompt_and_refresh (E_SHELL_VIEW (memo_shell_view), client);
+       e_cal_base_shell_view_allow_auth_prompt_and_refresh (E_SHELL_VIEW (memo_shell_view), client);
 
        g_object_unref (client);
 }
@@ -304,11 +272,11 @@ static void
 action_memo_list_rename_cb (GtkAction *action,
                             EMemoShellView *memo_shell_view)
 {
-       EMemoShellSidebar *memo_shell_sidebar;
+       ECalBaseShellSidebar *memo_shell_sidebar;
        ESourceSelector *selector;
 
        memo_shell_sidebar = memo_shell_view->priv->memo_shell_sidebar;
-       selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
+       selector = e_cal_base_shell_sidebar_get_selector (memo_shell_sidebar);
 
        e_source_selector_edit_primary_selection (selector);
 }
@@ -317,12 +285,12 @@ static void
 action_memo_list_select_one_cb (GtkAction *action,
                                 EMemoShellView *memo_shell_view)
 {
-       EMemoShellSidebar *memo_shell_sidebar;
+       ECalBaseShellSidebar *memo_shell_sidebar;
        ESourceSelector *selector;
        ESource *primary;
 
        memo_shell_sidebar = memo_shell_view->priv->memo_shell_sidebar;
-       selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
+       selector = e_cal_base_shell_sidebar_get_selector (memo_shell_sidebar);
 
        primary = e_source_selector_ref_primary_selection (selector);
        g_return_if_fail (primary != NULL);
@@ -336,30 +304,21 @@ static void
 action_memo_new_cb (GtkAction *action,
                     EMemoShellView *memo_shell_view)
 {
-       EShell *shell;
        EShellView *shell_view;
        EShellWindow *shell_window;
        EMemoShellContent *memo_shell_content;
        EMemoTable *memo_table;
-       ECalClient *client;
-       ECalComponent *comp;
-       CompEditor *editor;
+       EClient *client = NULL;
        GSList *list;
 
        shell_view = E_SHELL_VIEW (memo_shell_view);
        shell_window = e_shell_view_get_shell_window (shell_view);
-       shell = e_shell_window_get_shell (shell_window);
 
        memo_shell_content = memo_shell_view->priv->memo_shell_content;
        memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
 
        list = e_memo_table_get_selected (memo_table);
-       if (list == NULL) {
-               ECalModel *model;
-
-               model = e_memo_table_get_model (memo_table);
-               client = e_cal_model_ref_default_client (model);
-       } else {
+       if (list) {
                ECalModelComponent *comp_data;
 
                comp_data = list->data;
@@ -367,18 +326,10 @@ action_memo_new_cb (GtkAction *action,
                g_slist_free (list);
        }
 
-       g_return_if_fail (client != NULL);
+       e_cal_ops_new_component_editor (shell_window, E_CAL_CLIENT_SOURCE_TYPE_MEMOS,
+               client ? e_source_get_uid (e_client_get_source (client)) : NULL, FALSE);
 
-       comp = cal_comp_memo_new_with_defaults (client);
-       cal_comp_update_time_by_active_window (comp, shell);
-       editor = memo_editor_new (client, shell, COMP_EDITOR_NEW_ITEM);
-       comp_editor_edit_comp (editor, comp);
-
-       gtk_window_present (GTK_WINDOW (editor));
-
-       g_object_unref (comp);
-
-       g_object_unref (client);
+       g_clear_object (&client);
 }
 
 static void
diff --git a/modules/calendar/e-memo-shell-view-private.c b/modules/calendar/e-memo-shell-view-private.c
index 8a92ef5..ac6486f 100644
--- a/modules/calendar/e-memo-shell-view-private.c
+++ b/modules/calendar/e-memo-shell-view-private.c
@@ -23,27 +23,11 @@
 #endif
 
 #include "e-util/e-util-private.h"
+#include <calendar/gui/e-cal-ops.h>
 
 #include "e-memo-shell-view-private.h"
 
 static void
-memo_shell_view_model_row_appended_cb (EMemoShellView *memo_shell_view,
-                                       ECalModel *model)
-{
-       EMemoShellSidebar *memo_shell_sidebar;
-       ECalClient *client;
-
-       /* This is the "Click to Add" handler. */
-
-       client = e_cal_model_ref_default_client (model);
-
-       memo_shell_sidebar = memo_shell_view->priv->memo_shell_sidebar;
-       e_memo_shell_sidebar_add_client (memo_shell_sidebar, E_CLIENT (client));
-
-       g_object_unref (client);
-}
-
-static void
 memo_shell_view_table_popup_event_cb (EShellView *shell_view,
                                       GdkEvent *button_event)
 {
@@ -53,36 +37,6 @@ memo_shell_view_table_popup_event_cb (EShellView *shell_view,
        e_shell_view_show_popup_menu (shell_view, widget_path, button_event);
 }
 
-static void
-memo_shell_view_selector_client_added_cb (EMemoShellView *memo_shell_view,
-                                          ECalClient *client)
-{
-       EMemoShellContent *memo_shell_content;
-       EMemoTable *memo_table;
-       ECalModel *model;
-
-       memo_shell_content = memo_shell_view->priv->memo_shell_content;
-       memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
-       model = e_memo_table_get_model (memo_table);
-
-       e_cal_model_add_client (model, client);
-}
-
-static void
-memo_shell_view_selector_client_removed_cb (EMemoShellView *memo_shell_view,
-                                            ECalClient *client)
-{
-       EMemoShellContent *memo_shell_content;
-       EMemoTable *memo_table;
-       ECalModel *model;
-
-       memo_shell_content = memo_shell_view->priv->memo_shell_content;
-       memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
-       model = e_memo_table_get_model (memo_table);
-
-       e_cal_model_remove_client (model, client);
-}
-
 static gboolean
 memo_shell_view_selector_popup_event_cb (EShellView *shell_view,
                                          ESource *primary_source,
@@ -175,18 +129,6 @@ e_memo_shell_view_private_constructed (EMemoShellView *memo_shell_view)
        priv->memo_shell_content = g_object_ref (shell_content);
        priv->memo_shell_sidebar = g_object_ref (shell_sidebar);
 
-       handler_id = g_signal_connect_swapped (
-               priv->memo_shell_sidebar, "client-added",
-               G_CALLBACK (memo_shell_view_selector_client_added_cb),
-               memo_shell_view);
-       priv->client_added_handler_id = handler_id;
-
-       handler_id = g_signal_connect_swapped (
-               priv->memo_shell_sidebar, "client-removed",
-               G_CALLBACK (memo_shell_view_selector_client_removed_cb),
-               memo_shell_view);
-       priv->client_removed_handler_id = handler_id;
-
        /* Keep our own reference to this so we can
         * disconnect our signal handlers in dispose(). */
        priv->client_cache = e_shell_get_client_cache (shell);
@@ -228,12 +170,6 @@ e_memo_shell_view_private_constructed (EMemoShellView *memo_shell_view)
                memo_shell_view);
        priv->selection_change_2_handler_id = handler_id;
 
-       handler_id = g_signal_connect_swapped (
-               priv->memo_table, "status-message",
-               G_CALLBACK (e_memo_shell_view_set_status_message),
-               memo_shell_view);
-       priv->status_message_handler_id = handler_id;
-
        /* Keep our own reference to this so we can
         * disconnect our signal handlers in dispose(). */
        priv->model = e_memo_table_get_model (priv->memo_table);
@@ -259,14 +195,14 @@ e_memo_shell_view_private_constructed (EMemoShellView *memo_shell_view)
 
        handler_id = g_signal_connect_swapped (
                priv->model, "row-appended",
-               G_CALLBACK (memo_shell_view_model_row_appended_cb),
+               G_CALLBACK (e_cal_base_shell_view_model_row_appended),
                memo_shell_view);
        priv->row_appended_handler_id = handler_id;
 
        /* Keep our own reference to this so we can
         * disconnect our signal handlers in dispose(). */
-       priv->selector = e_memo_shell_sidebar_get_selector (
-               E_MEMO_SHELL_SIDEBAR (shell_sidebar));
+       priv->selector = e_cal_base_shell_sidebar_get_selector (
+               E_CAL_BASE_SHELL_SIDEBAR (shell_sidebar));
        g_object_ref (priv->selector);
 
        handler_id = g_signal_connect_swapped (
@@ -285,12 +221,6 @@ e_memo_shell_view_private_constructed (EMemoShellView *memo_shell_view)
                (GHookFunc) e_memo_shell_view_update_search_filter,
                memo_shell_view);
 
-       /* Keep the ECalModel in sync with the sidebar. */
-       g_object_bind_property (
-               shell_sidebar, "default-client",
-               priv->model, "default-client",
-               G_BINDING_SYNC_CREATE);
-
        e_memo_shell_view_actions_init (memo_shell_view);
        e_memo_shell_view_update_sidebar (memo_shell_view);
        e_memo_shell_view_update_search_filter (memo_shell_view);
@@ -301,20 +231,6 @@ e_memo_shell_view_private_dispose (EMemoShellView *memo_shell_view)
 {
        EMemoShellViewPrivate *priv = memo_shell_view->priv;
 
-       if (priv->client_added_handler_id > 0) {
-               g_signal_handler_disconnect (
-                       priv->memo_shell_sidebar,
-                       priv->client_added_handler_id);
-               priv->client_added_handler_id = 0;
-       }
-
-       if (priv->client_removed_handler_id > 0) {
-               g_signal_handler_disconnect (
-                       priv->memo_shell_sidebar,
-                       priv->client_removed_handler_id);
-               priv->client_removed_handler_id = 0;
-       }
-
        if (priv->backend_error_handler_id > 0) {
                g_signal_handler_disconnect (
                        priv->client_cache,
@@ -350,13 +266,6 @@ e_memo_shell_view_private_dispose (EMemoShellView *memo_shell_view)
                priv->selection_change_2_handler_id = 0;
        }
 
-       if (priv->status_message_handler_id > 0) {
-               g_signal_handler_disconnect (
-                       priv->memo_table,
-                       priv->status_message_handler_id);
-               priv->status_message_handler_id = 0;
-       }
-
        if (priv->model_changed_handler_id > 0) {
                g_signal_handler_disconnect (
                        priv->model,
@@ -407,15 +316,6 @@ e_memo_shell_view_private_dispose (EMemoShellView *memo_shell_view)
        g_clear_object (&priv->memo_table);
        g_clear_object (&priv->model);
        g_clear_object (&priv->selector);
-
-       if (memo_shell_view->priv->activity != NULL) {
-               /* XXX Activity is not cancellable. */
-               e_activity_set_state (
-                       memo_shell_view->priv->activity,
-                       E_ACTIVITY_COMPLETED);
-               g_object_unref (memo_shell_view->priv->activity);
-               memo_shell_view->priv->activity = NULL;
-       }
 }
 
 void
@@ -428,84 +328,16 @@ void
 e_memo_shell_view_open_memo (EMemoShellView *memo_shell_view,
                              ECalModelComponent *comp_data)
 {
-       EShell *shell;
-       EShellView *shell_view;
-       EShellWindow *shell_window;
-       ESourceRegistry *registry;
-       CompEditor *editor;
-       CompEditorFlags flags = 0;
-       ECalComponent *comp;
-       icalcomponent *clone;
-       const gchar *uid;
+       EShellContent *shell_content;
+       ECalModel *model;
 
        g_return_if_fail (E_IS_MEMO_SHELL_VIEW (memo_shell_view));
        g_return_if_fail (E_IS_CAL_MODEL_COMPONENT (comp_data));
 
-       shell_view = E_SHELL_VIEW (memo_shell_view);
-       shell_window = e_shell_view_get_shell_window (shell_view);
-       shell = e_shell_window_get_shell (shell_window);
-
-       registry = e_shell_get_registry (shell);
-
-       uid = icalcomponent_get_uid (comp_data->icalcomp);
-       editor = comp_editor_find_instance (uid);
+       shell_content = e_shell_view_get_shell_content (E_SHELL_VIEW (memo_shell_view));
+       model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (shell_content));
 
-       if (editor != NULL)
-               goto exit;
-
-       comp = e_cal_component_new ();
-       clone = icalcomponent_new_clone (comp_data->icalcomp);
-       e_cal_component_set_icalcomponent (comp, clone);
-
-       if (e_cal_component_has_organizer (comp))
-               flags |= COMP_EDITOR_IS_SHARED;
-
-       if (itip_organizer_is_user (registry, comp, comp_data->client))
-               flags |= COMP_EDITOR_USER_ORG;
-
-       editor = memo_editor_new (comp_data->client, shell, flags);
-       comp_editor_edit_comp (editor, comp);
-
-       g_object_unref (comp);
-
-exit:
-       gtk_window_present (GTK_WINDOW (editor));
-}
-
-void
-e_memo_shell_view_set_status_message (EMemoShellView *memo_shell_view,
-                                      const gchar *status_message,
-                                      gdouble percent)
-{
-       EActivity *activity;
-       EShellView *shell_view;
-       EShellBackend *shell_backend;
-
-       g_return_if_fail (E_IS_MEMO_SHELL_VIEW (memo_shell_view));
-
-       activity = memo_shell_view->priv->activity;
-       shell_view = E_SHELL_VIEW (memo_shell_view);
-       shell_backend = e_shell_view_get_shell_backend (shell_view);
-
-       if (status_message == NULL || *status_message == '\0') {
-               if (activity != NULL) {
-                       e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
-                       g_object_unref (activity);
-                       activity = NULL;
-               }
-
-       } else if (activity == NULL) {
-               activity = e_activity_new ();
-               e_activity_set_percent (activity, percent);
-               e_activity_set_text (activity, status_message);
-               e_shell_backend_add_activity (shell_backend, activity);
-
-       } else {
-               e_activity_set_percent (activity, percent);
-               e_activity_set_text (activity, status_message);
-       }
-
-       memo_shell_view->priv->activity = activity;
+       e_cal_ops_open_component_in_editor_sync (model, comp_data->client, comp_data->icalcomp);
 }
 
 void
@@ -547,4 +379,3 @@ e_memo_shell_view_update_sidebar (EMemoShellView *memo_shell_view)
 
        g_string_free (string, TRUE);
 }
-
diff --git a/modules/calendar/e-memo-shell-view-private.h b/modules/calendar/e-memo-shell-view-private.h
index c1f5463..0134080 100644
--- a/modules/calendar/e-memo-shell-view-private.h
+++ b/modules/calendar/e-memo-shell-view-private.h
@@ -24,20 +24,19 @@
 #include "e-memo-shell-view.h"
 
 #include <string.h>
-#include <glib/gi18n.h>
+#include <glib/gi18n-lib.h>
 
 #include "shell/e-shell-utils.h"
 
 #include "calendar/gui/comp-util.h"
 #include "calendar/gui/e-cal-component-preview.h"
-#include "calendar/gui/e-calendar-selector.h"
 #include "calendar/gui/print.h"
-#include "calendar/gui/dialogs/copy-source-dialog.h"
 #include "calendar/gui/dialogs/memo-editor.h"
 
+#include "e-cal-base-shell-sidebar.h"
+
 #include "e-memo-shell-backend.h"
 #include "e-memo-shell-content.h"
-#include "e-memo-shell-sidebar.h"
 #include "e-memo-shell-view-actions.h"
 
 #define E_MEMO_SHELL_VIEW_GET_PRIVATE(obj) \
@@ -75,11 +74,7 @@ struct _EMemoShellViewPrivate {
        /* These are just for convenience. */
        EMemoShellBackend *memo_shell_backend;
        EMemoShellContent *memo_shell_content;
-       EMemoShellSidebar *memo_shell_sidebar;
-
-       /* sidebar signal handlers */
-       gulong client_added_handler_id;
-       gulong client_removed_handler_id;
+       ECalBaseShellSidebar *memo_shell_sidebar;
 
        EClientCache *client_cache;
        gulong backend_error_handler_id;
@@ -89,7 +84,6 @@ struct _EMemoShellViewPrivate {
        gulong popup_event_handler_id;
        gulong selection_change_1_handler_id;
        gulong selection_change_2_handler_id;
-       gulong status_message_handler_id;
 
        ECalModel *model;
        gulong model_changed_handler_id;
@@ -100,8 +94,6 @@ struct _EMemoShellViewPrivate {
        ESourceSelector *selector;
        gulong selector_popup_event_handler_id;
        gulong primary_selection_changed_handler_id;
-
-       EActivity *activity;
 };
 
 void           e_memo_shell_view_private_init
@@ -120,10 +112,6 @@ void               e_memo_shell_view_actions_init
 void           e_memo_shell_view_open_memo
                                        (EMemoShellView *memo_shell_view,
                                         ECalModelComponent *comp_data);
-void           e_memo_shell_view_set_status_message
-                                       (EMemoShellView *memo_shell_view,
-                                        const gchar *status_message,
-                                        gdouble percent);
 void           e_memo_shell_view_update_sidebar
                                        (EMemoShellView *memo_shell_view);
 void           e_memo_shell_view_update_search_filter
diff --git a/modules/calendar/e-memo-shell-view.c b/modules/calendar/e-memo-shell-view.c
index 8f8522c..8fc6a2f 100644
--- a/modules/calendar/e-memo-shell-view.c
+++ b/modules/calendar/e-memo-shell-view.c
@@ -1,5 +1,6 @@
 /*
- * e-memo-shell-view.c
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
@@ -7,54 +8,24 @@
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
  * for more details.
  *
  * You should have received a copy of the GNU Lesser General Public License
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
  */
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
 
-#include "e-memo-shell-view-private.h"
-
-G_DEFINE_DYNAMIC_TYPE (
-       EMemoShellView,
-       e_memo_shell_view,
-       E_TYPE_SHELL_VIEW)
-
-static void
-memo_shell_view_dispose (GObject *object)
-{
-       e_memo_shell_view_private_dispose (E_MEMO_SHELL_VIEW (object));
-
-       /* Chain up to parent's dispose() method. */
-       G_OBJECT_CLASS (e_memo_shell_view_parent_class)->dispose (object);
-}
+#include <gtk/gtk.h>
+#include <glib/gi18n-lib.h>
 
-static void
-memo_shell_view_finalize (GObject *object)
-{
-       e_memo_shell_view_private_finalize (E_MEMO_SHELL_VIEW (object));
+#include "e-memo-shell-view-private.h"
+#include "e-memo-shell-view.h"
 
-       /* Chain up to parent's finalize() method. */
-       G_OBJECT_CLASS (e_memo_shell_view_parent_class)->finalize (object);
-}
-
-static void
-memo_shell_view_constructed (GObject *object)
-{
-       /* Chain up to parent's constructed() method. */
-       G_OBJECT_CLASS (e_memo_shell_view_parent_class)->constructed (object);
-
-       e_memo_shell_view_private_constructed (E_MEMO_SHELL_VIEW (object));
-}
+G_DEFINE_DYNAMIC_TYPE (EMemoShellView, e_memo_shell_view, E_TYPE_CAL_BASE_SHELL_VIEW)
 
 static void
 memo_shell_view_execute_search (EShellView *shell_view)
@@ -70,6 +41,7 @@ memo_shell_view_execute_search (EShellView *shell_view)
        EMemoTable *memo_table;
        EWebView *web_view;
        ECalModel *model;
+       ECalDataModel *data_model;
        gchar *query;
        gchar *temp;
        gint value;
@@ -159,7 +131,8 @@ memo_shell_view_execute_search (EShellView *shell_view)
        /* Submit the query. */
        memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
        model = e_memo_table_get_model (memo_table);
-       e_cal_model_set_search_query (model, query);
+       data_model = e_cal_model_get_data_model (model);
+       e_cal_data_model_set_filter (data_model, query);
        g_free (query);
 
        preview_pane =
@@ -204,32 +177,31 @@ memo_shell_view_update_actions (EShellView *shell_view)
        state = e_shell_content_check_state (shell_content);
 
        single_memo_selected =
-               (state & E_MEMO_SHELL_CONTENT_SELECTION_SINGLE);
+               (state & E_CAL_BASE_SHELL_CONTENT_SELECTION_SINGLE);
        multiple_memos_selected =
-               (state & E_MEMO_SHELL_CONTENT_SELECTION_MULTIPLE);
+               (state & E_CAL_BASE_SHELL_CONTENT_SELECTION_MULTIPLE);
        sources_are_editable =
-               (state & E_MEMO_SHELL_CONTENT_SELECTION_CAN_EDIT);
+               (state & E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_EDITABLE);
        selection_has_url =
-               (state & E_MEMO_SHELL_CONTENT_SELECTION_HAS_URL);
+               (state & E_CAL_BASE_SHELL_CONTENT_SELECTION_HAS_URL);
 
        shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
        state = e_shell_sidebar_check_state (shell_sidebar);
 
        has_primary_source =
-               (state & E_MEMO_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE);
+               (state & E_CAL_BASE_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE);
        primary_source_is_writable =
-               (state & E_MEMO_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_WRITABLE);
+               (state & E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_WRITABLE);
        primary_source_is_removable =
-               (state & E_MEMO_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOVABLE);
+               (state & E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOVABLE);
        primary_source_is_remote_deletable =
-               (state & E_MEMO_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_DELETABLE);
+               (state & E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_DELETABLE);
        primary_source_in_collection =
-               (state & E_MEMO_SHELL_SIDEBAR_PRIMARY_SOURCE_IN_COLLECTION);
+               (state & E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IN_COLLECTION);
        refresh_supported =
-               (state & E_MEMO_SHELL_SIDEBAR_SOURCE_SUPPORTS_REFRESH);
+               (state & E_CAL_BASE_SHELL_SIDEBAR_SOURCE_SUPPORTS_REFRESH);
 
-       any_memos_selected =
-               (single_memo_selected || multiple_memos_selected);
+       any_memos_selected = (single_memo_selected || multiple_memos_selected);
 
        action = ACTION (MEMO_DELETE);
        sensitive = any_memos_selected && sources_are_editable;
@@ -290,10 +262,38 @@ memo_shell_view_update_actions (EShellView *shell_view)
 }
 
 static void
+memo_shell_view_dispose (GObject *object)
+{
+       e_memo_shell_view_private_dispose (E_MEMO_SHELL_VIEW (object));
+
+       /* Chain up to parent's dispose() method. */
+       G_OBJECT_CLASS (e_memo_shell_view_parent_class)->dispose (object);
+}
+
+static void
+memo_shell_view_finalize (GObject *object)
+{
+       e_memo_shell_view_private_finalize (E_MEMO_SHELL_VIEW (object));
+
+       /* Chain up to parent's finalize() method. */
+       G_OBJECT_CLASS (e_memo_shell_view_parent_class)->finalize (object);
+}
+
+static void
+memo_shell_view_constructed (GObject *object)
+{
+       /* Chain up to parent's constructed() method. */
+       G_OBJECT_CLASS (e_memo_shell_view_parent_class)->constructed (object);
+
+       e_memo_shell_view_private_constructed (E_MEMO_SHELL_VIEW (object));
+}
+
+static void
 e_memo_shell_view_class_init (EMemoShellViewClass *class)
 {
        GObjectClass *object_class;
        EShellViewClass *shell_view_class;
+       ECalBaseShellViewClass *cal_base_shell_view_class;
 
        g_type_class_add_private (class, sizeof (EMemoShellViewPrivate));
 
@@ -310,10 +310,13 @@ e_memo_shell_view_class_init (EMemoShellViewClass *class)
        shell_view_class->search_options = "/memo-search-options";
        shell_view_class->search_rules = "memotypes.xml";
        shell_view_class->new_shell_content = e_memo_shell_content_new;
-       shell_view_class->new_shell_sidebar = e_memo_shell_sidebar_new;
+       shell_view_class->new_shell_sidebar = e_cal_base_shell_sidebar_new;
        shell_view_class->execute_search = memo_shell_view_execute_search;
        shell_view_class->update_actions = memo_shell_view_update_actions;
 
+       cal_base_shell_view_class = E_CAL_BASE_SHELL_VIEW_CLASS (class);
+       cal_base_shell_view_class->source_type = E_CAL_CLIENT_SOURCE_TYPE_MEMOS;
+
        /* Ensure the GalView types we need are registered. */
        g_type_ensure (GAL_TYPE_VIEW_ETABLE);
 }
@@ -326,10 +329,7 @@ e_memo_shell_view_class_finalize (EMemoShellViewClass *class)
 static void
 e_memo_shell_view_init (EMemoShellView *memo_shell_view)
 {
-       memo_shell_view->priv =
-               E_MEMO_SHELL_VIEW_GET_PRIVATE (memo_shell_view);
-
-       e_memo_shell_view_private_init (memo_shell_view);
+       memo_shell_view->priv = E_MEMO_SHELL_VIEW_GET_PRIVATE (memo_shell_view);
 }
 
 void
@@ -340,4 +340,3 @@ e_memo_shell_view_type_register (GTypeModule *type_module)
         *     order to register types from a separate compilation unit. */
        e_memo_shell_view_register_type (type_module);
 }
-
diff --git a/modules/calendar/e-memo-shell-view.h b/modules/calendar/e-memo-shell-view.h
index 94444a6..fea2341 100644
--- a/modules/calendar/e-memo-shell-view.h
+++ b/modules/calendar/e-memo-shell-view.h
@@ -1,5 +1,6 @@
 /*
- * e-memo-shell-view.h
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
@@ -7,21 +8,18 @@
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
  * for more details.
  *
  * You should have received a copy of the GNU Lesser General Public License
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
  */
 
 #ifndef E_MEMO_SHELL_VIEW_H
 #define E_MEMO_SHELL_VIEW_H
 
-#include <shell/e-shell-view.h>
+#include <e-util/e-util.h>
+#include "e-cal-base-shell-view.h"
 
 /* Standard GObject macros */
 #define E_TYPE_MEMO_SHELL_VIEW \
@@ -49,16 +47,16 @@ typedef struct _EMemoShellViewClass EMemoShellViewClass;
 typedef struct _EMemoShellViewPrivate EMemoShellViewPrivate;
 
 struct _EMemoShellView {
-       EShellView parent;
+       ECalBaseShellView parent;
        EMemoShellViewPrivate *priv;
 };
 
 struct _EMemoShellViewClass {
-       EShellViewClass parent_class;
+       ECalBaseShellViewClass parent_class;
 };
 
-GType          e_memo_shell_view_get_type      (void);
-void           e_memo_shell_view_type_register (GTypeModule *type_module);
+GType          e_memo_shell_view_get_type              (void);
+void           e_memo_shell_view_type_register         (GTypeModule *type_module);
 
 G_END_DECLS
 
diff --git a/modules/calendar/e-task-shell-backend.c b/modules/calendar/e-task-shell-backend.c
index 760aba5..cb10dc7 100644
--- a/modules/calendar/e-task-shell-backend.c
+++ b/modules/calendar/e-task-shell-backend.c
@@ -1,5 +1,6 @@
 /*
- * e-task-shell-backend.c
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
@@ -7,38 +8,26 @@
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
  * for more details.
  *
  * You should have received a copy of the GNU Lesser General Public License
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
  */
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
 
-#include "e-task-shell-backend.h"
-
 #include <string.h>
 #include <glib/gi18n.h>
-#include <libecal/libecal.h>
 
-#include "shell/e-shell.h"
-#include "shell/e-shell-backend.h"
-#include "shell/e-shell-window.h"
+#include <calendar/gui/comp-util.h>
+#include <calendar/gui/e-cal-ops.h>
+#include <calendar/gui/dialogs/task-editor.h>
 
-#include "calendar/gui/comp-util.h"
-#include "calendar/gui/dialogs/task-editor.h"
-
-#include "e-task-shell-content.h"
-#include "e-task-shell-migrate.h"
-#include "e-task-shell-sidebar.h"
 #include "e-task-shell-view.h"
+#include "e-task-shell-backend.h"
 
 #define E_TASK_SHELL_BACKEND_GET_PRIVATE(obj) \
        (G_TYPE_INSTANCE_GET_PRIVATE \
@@ -48,162 +37,22 @@ struct _ETaskShellBackendPrivate {
        gint placeholder;
 };
 
-G_DEFINE_DYNAMIC_TYPE (
-       ETaskShellBackend,
-       e_task_shell_backend,
-       E_TYPE_SHELL_BACKEND)
-
-static void
-task_shell_backend_new_task (ECalClient *cal_client,
-                             EShell *shell,
-                             CompEditorFlags flags)
-{
-       ECalComponent *comp;
-       CompEditor *editor;
-
-       editor = task_editor_new (cal_client, shell, flags);
-       comp = cal_comp_task_new_with_defaults (cal_client);
-       comp_editor_edit_comp (editor, comp);
-
-       gtk_window_present (GTK_WINDOW (editor));
-
-       g_object_unref (comp);
-}
-
-static void
-task_shell_backend_task_new_cb (GObject *source_object,
-                                GAsyncResult *result,
-                                gpointer user_data)
-{
-       EShell *shell = user_data;
-       EClient *client;
-       CompEditorFlags flags = 0;
-       GError *error = NULL;
-
-       flags |= COMP_EDITOR_NEW_ITEM;
-
-       client = e_client_cache_get_client_finish (
-               E_CLIENT_CACHE (source_object), result, &error);
-
-       /* Sanity check. */
-       g_return_if_fail (
-               ((client != NULL) && (error == NULL)) ||
-               ((client == NULL) && (error != NULL)));
-
-       if (client != NULL) {
-               task_shell_backend_new_task (
-                       E_CAL_CLIENT (client), shell, flags);
-               g_object_unref (client);
-       } else {
-               /* XXX Handle errors better. */
-               g_warning ("%s: %s", G_STRFUNC, error->message);
-               g_error_free (error);
-       }
-
-       g_object_unref (shell);
-}
-
-static void
-task_shell_backend_task_assigned_new_cb (GObject *source_object,
-                                         GAsyncResult *result,
-                                         gpointer user_data)
-{
-       EShell *shell = E_SHELL (user_data);
-       EClient *client;
-       CompEditorFlags flags = 0;
-       GError *error = NULL;
-
-       flags |= COMP_EDITOR_NEW_ITEM;
-       flags |= COMP_EDITOR_IS_ASSIGNED;
-       flags |= COMP_EDITOR_USER_ORG;
-
-       client = e_client_cache_get_client_finish (
-               E_CLIENT_CACHE (source_object), result, &error);
-
-       /* Sanity check. */
-       g_return_if_fail (
-               ((client != NULL) && (error == NULL)) ||
-               ((client == NULL) && (error != NULL)));
-
-       if (client != NULL) {
-               task_shell_backend_new_task (
-                       E_CAL_CLIENT (client), shell, flags);
-               g_object_unref (client);
-       } else {
-               /* XXX Handle errors better. */
-               g_warning ("%s: %s", G_STRFUNC, error->message);
-               g_error_free (error);
-       }
-
-       g_object_unref (shell);
-}
+G_DEFINE_DYNAMIC_TYPE (ETaskShellBackend, e_task_shell_backend, E_TYPE_CAL_BASE_SHELL_BACKEND)
 
 static void
 action_task_new_cb (GtkAction *action,
                     EShellWindow *shell_window)
 {
-       EShell *shell;
-       ESource *source;
-       ESourceRegistry *registry;
-       EClientCache *client_cache;
-       const gchar *action_name;
-
-       /* This callback is used for both tasks and assigned tasks. */
-
-       shell = e_shell_window_get_shell (shell_window);
-       client_cache = e_shell_get_client_cache (shell);
-
-       registry = e_shell_get_registry (shell);
-       source = e_source_registry_ref_default_task_list (registry);
-
-       /* Use a callback function appropriate for the action. */
-       action_name = gtk_action_get_name (action);
-       if (strcmp (action_name, "task-assigned-new") == 0)
-               e_client_cache_get_client (
-                       client_cache, source,
-                       E_SOURCE_EXTENSION_TASK_LIST,
-                       NULL,
-                       task_shell_backend_task_assigned_new_cb,
-                       g_object_ref (shell));
-       else
-               e_client_cache_get_client (
-                       client_cache, source,
-                       E_SOURCE_EXTENSION_TASK_LIST,
-                       NULL,
-                       task_shell_backend_task_new_cb,
-                       g_object_ref (shell));
-
-       g_object_unref (source);
+       e_cal_ops_new_component_editor (shell_window,
+               E_CAL_CLIENT_SOURCE_TYPE_TASKS, NULL,
+               g_strcmp0 (gtk_action_get_name (action), "task-assigned-new") == 0);
 }
 
 static void
 action_task_list_new_cb (GtkAction *action,
                          EShellWindow *shell_window)
 {
-       EShell *shell;
-       ESourceRegistry *registry;
-       ECalClientSourceType source_type;
-       GtkWidget *config;
-       GtkWidget *dialog;
-       const gchar *icon_name;
-
-       shell = e_shell_window_get_shell (shell_window);
-
-       registry = e_shell_get_registry (shell);
-       source_type = E_CAL_CLIENT_SOURCE_TYPE_TASKS;
-       config = e_cal_source_config_new (registry, NULL, source_type);
-
-       dialog = e_source_config_dialog_new (E_SOURCE_CONFIG (config));
-
-       gtk_window_set_transient_for (
-               GTK_WINDOW (dialog), GTK_WINDOW (shell_window));
-
-       icon_name = gtk_action_get_icon_name (action);
-       gtk_window_set_icon_name (GTK_WINDOW (dialog), icon_name);
-
-       gtk_window_set_title (GTK_WINDOW (dialog), _("New Task List"));
-
-       gtk_widget_show (dialog);
+       e_cal_base_shell_backend_util_new_source (shell_window, E_CAL_CLIENT_SOURCE_TYPE_TASKS);
 }
 
 static GtkActionEntry item_entries[] = {
@@ -234,226 +83,24 @@ static GtkActionEntry source_entries[] = {
 };
 
 static gboolean
-task_shell_backend_handle_uri_cb (EShellBackend *shell_backend,
-                                  const gchar *uri)
+e_task_shell_backend_handle_uri (EShellBackend *shell_backend,
+                                const gchar *uri)
 {
-       EShell *shell;
-       CompEditor *editor;
-       CompEditorFlags flags = 0;
-       EClient *client;
-       EClientCache *client_cache;
-       ECalComponent *comp;
-       ESource *source;
-       ESourceRegistry *registry;
-       SoupURI *soup_uri;
-       icalcomponent *icalcomp;
-       icalproperty *icalprop;
-       const gchar *cp;
-       gchar *source_uid = NULL;
-       gchar *comp_uid = NULL;
-       gchar *comp_rid = NULL;
-       gboolean handled = FALSE;
-       GError *error = NULL;
-
-       shell = e_shell_backend_get_shell (shell_backend);
-       client_cache = e_shell_get_client_cache (shell);
-
        if (strncmp (uri, "task:", 5) != 0)
                return FALSE;
 
-       soup_uri = soup_uri_new (uri);
-
-       if (soup_uri == NULL)
-               return FALSE;
-
-       cp = soup_uri_get_query (soup_uri);
-       if (cp == NULL)
-               goto exit;
-
-       while (*cp != '\0') {
-               gchar *header;
-               gchar *content;
-               gsize header_len;
-               gsize content_len;
-
-               header_len = strcspn (cp, "=&");
-
-               /* If it's malformed, give up. */
-               if (cp[header_len] != '=')
-                       break;
-
-               header = (gchar *) cp;
-               header[header_len] = '\0';
-               cp += header_len + 1;
-
-               content_len = strcspn (cp, "&");
-
-               content = g_strndup (cp, content_len);
-               if (g_ascii_strcasecmp (header, "source-uid") == 0)
-                       source_uid = g_strdup (content);
-               else if (g_ascii_strcasecmp (header, "comp-uid") == 0)
-                       comp_uid = g_strdup (content);
-               else if (g_ascii_strcasecmp (header, "comp-rid") == 0)
-                       comp_rid = g_strdup (content);
-               g_free (content);
-
-               cp += content_len;
-               if (*cp == '&') {
-                       cp++;
-                       if (strcmp (cp, "amp;") == 0)
-                               cp += 4;
-               }
-       }
-
-       if (source_uid == NULL || comp_uid == NULL)
-               goto exit;
-
-       /* URI is valid, so consider it handled.  Whether
-        * we successfully open it is another matter... */
-       handled = TRUE;
-
-       registry = e_shell_get_registry (shell);
-       source = e_source_registry_ref_source (registry, source_uid);
-       if (source == NULL) {
-               g_printerr ("No source for UID '%s'\n", source_uid);
-               goto exit;
-       }
-
-       client = e_client_cache_get_client_sync (
-               client_cache, source,
-               E_SOURCE_EXTENSION_TASK_LIST,
-               NULL, &error);
-
-       /* Sanity check. */
-       g_return_val_if_fail (
-               ((client != NULL) && (error == NULL)) ||
-               ((client == NULL) && (error != NULL)), FALSE);
-
-       if (error != NULL) {
-               g_warning (
-                       "%s: Failed to create/open client: %s",
-                       G_STRFUNC, error->message);
-               g_object_unref (source);
-               g_error_free (error);
-               goto exit;
-       }
-
-       g_object_unref (source);
-       source = NULL;
-
-       /* XXX Copied from e_task_shell_view_open_task().
-        *     Clearly a new utility function is needed. */
-
-       editor = comp_editor_find_instance (comp_uid);
-
-       if (editor != NULL)
-               goto present;
-
-       e_cal_client_get_object_sync (
-               E_CAL_CLIENT (client), comp_uid,
-               comp_rid, &icalcomp, NULL, &error);
-
-       if (error != NULL) {
-               g_warning (
-                       "%s: Failed to get object: %s",
-                       G_STRFUNC, error->message);
-               g_object_unref (client);
-               g_error_free (error);
-               goto exit;
-       }
-
-       comp = e_cal_component_new ();
-       if (!e_cal_component_set_icalcomponent (comp, icalcomp)) {
-               g_warning ("%s: Failed to set icalcomp to comp\n", G_STRFUNC);
-               icalcomponent_free (icalcomp);
-               icalcomp = NULL;
-       }
-
-       icalprop = icalcomp ? icalcomponent_get_first_property (
-               icalcomp, ICAL_ATTENDEE_PROPERTY) : NULL;
-       if (icalprop != NULL)
-               flags |= COMP_EDITOR_IS_ASSIGNED;
-
-       if (itip_organizer_is_user (registry, comp, E_CAL_CLIENT (client)))
-               flags |= COMP_EDITOR_USER_ORG;
-
-       if (!e_cal_component_has_attendees (comp))
-               flags |= COMP_EDITOR_USER_ORG;
-
-       editor = task_editor_new (E_CAL_CLIENT (client), shell, flags);
-       comp_editor_edit_comp (editor, comp);
-
-       g_object_unref (comp);
-
-present:
-       gtk_window_present (GTK_WINDOW (editor));
-
-       g_object_unref (client);
-
-exit:
-       g_free (source_uid);
-       g_free (comp_uid);
-       g_free (comp_rid);
-
-       soup_uri_free (soup_uri);
-
-       return handled;
-}
-
-static void
-task_shell_backend_window_added_cb (EShellBackend *shell_backend,
-                                    GtkWindow *window)
-{
-       const gchar *module_name;
-
-       if (!E_IS_SHELL_WINDOW (window))
-               return;
-
-       module_name = E_SHELL_BACKEND_GET_CLASS (shell_backend)->name;
-
-       e_shell_window_register_new_item_actions (
-               E_SHELL_WINDOW (window), module_name,
-               item_entries, G_N_ELEMENTS (item_entries));
-
-       e_shell_window_register_new_source_actions (
-               E_SHELL_WINDOW (window), module_name,
-               source_entries, G_N_ELEMENTS (source_entries));
-}
-
-static void
-task_shell_backend_constructed (GObject *object)
-{
-       EShell *shell;
-       EShellBackend *shell_backend;
-
-       shell_backend = E_SHELL_BACKEND (object);
-       shell = e_shell_backend_get_shell (shell_backend);
-
-       g_signal_connect_swapped (
-               shell, "handle-uri",
-               G_CALLBACK (task_shell_backend_handle_uri_cb),
-               shell_backend);
-
-       g_signal_connect_swapped (
-               shell, "window-added",
-               G_CALLBACK (task_shell_backend_window_added_cb),
-               shell_backend);
-
-       /* Chain up to parent's constructed() method. */
-       G_OBJECT_CLASS (e_task_shell_backend_parent_class)->constructed (object);
+       return e_cal_base_shell_backend_util_handle_uri (shell_backend,
+               E_CAL_CLIENT_SOURCE_TYPE_TASKS, uri, NULL);
 }
 
 static void
 e_task_shell_backend_class_init (ETaskShellBackendClass *class)
 {
-       GObjectClass *object_class;
        EShellBackendClass *shell_backend_class;
+       ECalBaseShellBackendClass *cal_base_shell_backend_class;
 
        g_type_class_add_private (class, sizeof (ETaskShellBackendPrivate));
 
-       object_class = G_OBJECT_CLASS (class);
-       object_class->constructed = task_shell_backend_constructed;
-
        shell_backend_class = E_SHELL_BACKEND_CLASS (class);
        shell_backend_class->shell_view_type = E_TYPE_TASK_SHELL_VIEW;
        shell_backend_class->name = "tasks";
@@ -462,19 +109,24 @@ e_task_shell_backend_class_init (ETaskShellBackendClass *class)
        shell_backend_class->sort_order = 500;
        shell_backend_class->preferences_page = "calendar-and-tasks";
        shell_backend_class->start = NULL;
-       shell_backend_class->migrate = e_task_shell_backend_migrate;
+
+       cal_base_shell_backend_class = E_CAL_BASE_SHELL_BACKEND_CLASS (class);
+       cal_base_shell_backend_class->new_item_entries = item_entries;
+       cal_base_shell_backend_class->new_item_n_entries = G_N_ELEMENTS (item_entries);
+       cal_base_shell_backend_class->source_entries = source_entries;
+       cal_base_shell_backend_class->source_n_entries = G_N_ELEMENTS (source_entries);
+       cal_base_shell_backend_class->handle_uri = e_task_shell_backend_handle_uri;
 }
 
 static void
-e_task_shell_backend_class_finalize (ETaskShellBackendClass *class)
+e_task_shell_backend_init (ETaskShellBackend *task_shell_backend)
 {
+       task_shell_backend->priv = E_TASK_SHELL_BACKEND_GET_PRIVATE (task_shell_backend);
 }
 
 static void
-e_task_shell_backend_init (ETaskShellBackend *task_shell_backend)
+e_task_shell_backend_class_finalize (ETaskShellBackendClass *class)
 {
-       task_shell_backend->priv =
-               E_TASK_SHELL_BACKEND_GET_PRIVATE (task_shell_backend);
 }
 
 void
diff --git a/modules/calendar/e-task-shell-backend.h b/modules/calendar/e-task-shell-backend.h
index 65ef349..3b5eb17 100644
--- a/modules/calendar/e-task-shell-backend.h
+++ b/modules/calendar/e-task-shell-backend.h
@@ -1,5 +1,6 @@
 /*
- * e-task-shell-backend.h
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
@@ -7,21 +8,17 @@
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
  * for more details.
  *
  * You should have received a copy of the GNU Lesser General Public License
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
  */
 
 #ifndef E_TASK_SHELL_BACKEND_H
 #define E_TASK_SHELL_BACKEND_H
 
-#include <shell/e-shell-backend.h>
+#include "e-cal-base-shell-backend.h"
 
 /* Standard GObject macros */
 #define E_TYPE_TASK_SHELL_BACKEND \
@@ -49,17 +46,16 @@ typedef struct _ETaskShellBackendClass ETaskShellBackendClass;
 typedef struct _ETaskShellBackendPrivate ETaskShellBackendPrivate;
 
 struct _ETaskShellBackend {
-       EShellBackend parent;
+       ECalBaseShellBackend parent;
        ETaskShellBackendPrivate *priv;
 };
 
 struct _ETaskShellBackendClass {
-       EShellBackendClass parent_class;
+       ECalBaseShellBackendClass parent_class;
 };
 
-GType          e_task_shell_backend_get_type   (void);
-void           e_task_shell_backend_type_register
-                                       (GTypeModule *type_module);
+GType          e_task_shell_backend_get_type           (void);
+void           e_task_shell_backend_type_register      (GTypeModule *type_module);
 
 G_END_DECLS
 
diff --git a/modules/calendar/e-task-shell-content.c b/modules/calendar/e-task-shell-content.c
index aa31281..9a87f7e 100644
--- a/modules/calendar/e-task-shell-content.c
+++ b/modules/calendar/e-task-shell-content.c
@@ -1,5 +1,6 @@
 /*
- * e-task-shell-content.c
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
@@ -7,30 +8,26 @@
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
  * for more details.
  *
  * You should have received a copy of the GNU Lesser General Public License
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
  */
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
 
-#include "e-task-shell-content.h"
-
+#include <string.h>
 #include <glib/gi18n.h>
 
-#include "shell/e-shell-utils.h"
+#include <calendar/gui/comp-util.h>
+#include <calendar/gui/e-cal-component-preview.h>
+#include <calendar/gui/e-cal-model-tasks.h>
 
-#include "calendar/gui/comp-util.h"
-#include "calendar/gui/e-cal-component-preview.h"
-#include "calendar/gui/e-cal-model-tasks.h"
+#include "e-cal-base-shell-sidebar.h"
+#include "e-task-shell-content.h"
 
 #define E_TASK_SHELL_CONTENT_GET_PRIVATE(obj) \
        (G_TYPE_INSTANCE_GET_PRIVATE \
@@ -41,7 +38,6 @@ struct _ETaskShellContentPrivate {
        GtkWidget *task_table;
        GtkWidget *preview_pane;
 
-       ECalModel *task_model;
        GtkOrientation orientation;
 
        gchar *current_uid;
@@ -51,18 +47,12 @@ struct _ETaskShellContentPrivate {
 
 enum {
        PROP_0,
-       PROP_MODEL,
        PROP_ORIENTATION,
        PROP_PREVIEW_VISIBLE
 };
 
-G_DEFINE_DYNAMIC_TYPE_EXTENDED (
-       ETaskShellContent,
-       e_task_shell_content,
-       E_TYPE_SHELL_CONTENT,
-       0,
-       G_IMPLEMENT_INTERFACE_DYNAMIC (
-               GTK_TYPE_ORIENTABLE, NULL))
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (ETaskShellContent, e_task_shell_content, E_TYPE_CAL_BASE_SHELL_CONTENT, 0,
+       G_IMPLEMENT_INTERFACE_DYNAMIC (GTK_TYPE_ORIENTABLE, NULL))
 
 static void
 task_shell_content_display_view_cb (ETaskShellContent *task_shell_content,
@@ -182,7 +172,7 @@ task_shell_content_cursor_change_cb (ETaskShellContent *task_shell_content,
        EWebView *web_view;
        const gchar *uid;
 
-       task_model = e_task_shell_content_get_task_model (task_shell_content);
+       task_model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (task_shell_content));
        preview_pane = e_task_shell_content_get_preview_pane (task_shell_content);
 
        web_view = e_preview_pane_get_web_view (preview_pane);
@@ -262,40 +252,94 @@ task_shell_content_model_row_changed_cb (ETaskShellContent *task_shell_content,
 }
 
 static void
-task_shell_content_restore_state_cb (EShellWindow *shell_window,
-                                     EShellView *shell_view,
-                                     EShellContent *shell_content)
+task_shell_content_is_editing_changed_cb (ETaskTable *task_table,
+                                          GParamSpec *param,
+                                          EShellView *shell_view)
 {
-       ETaskShellContentPrivate *priv;
-       GSettings *settings;
+       g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
 
-       priv = E_TASK_SHELL_CONTENT_GET_PRIVATE (shell_content);
+       e_shell_view_update_actions (shell_view);
+}
 
-       /* Bind GObject properties to settings keys. */
+static guint32
+task_shell_content_check_state (EShellContent *shell_content)
+{
+       ETaskShellContent *task_shell_content;
+       ETaskTable *task_table;
+       GSList *list, *iter;
+       gboolean assignable = TRUE;
+       gboolean editable = TRUE;
+       gboolean has_url = FALSE;
+       gint n_selected;
+       gint n_complete = 0;
+       gint n_incomplete = 0;
+       guint32 state = 0;
 
-       settings = g_settings_new ("org.gnome.evolution.calendar");
+       task_shell_content = E_TASK_SHELL_CONTENT (shell_content);
+       task_table = e_task_shell_content_get_task_table (task_shell_content);
 
-       g_settings_bind (
-               settings, "task-hpane-position",
-               priv->paned, "hposition",
-               G_SETTINGS_BIND_DEFAULT);
+       n_selected = e_table_selected_count (E_TABLE (task_table));
 
-       g_settings_bind (
-               settings, "task-vpane-position",
-               priv->paned, "vposition",
-               G_SETTINGS_BIND_DEFAULT);
+       list = e_task_table_get_selected (task_table);
+       for (iter = list; iter != NULL; iter = iter->next) {
+               ECalModelComponent *comp_data = iter->data;
+               icalproperty *prop;
+               const gchar *cap;
+               gboolean read_only;
 
-       g_object_unref (settings);
+               if (!comp_data)
+                       continue;
+
+               read_only = e_client_is_readonly (E_CLIENT (comp_data->client));
+               editable &= !read_only;
+
+               cap = CAL_STATIC_CAPABILITY_NO_TASK_ASSIGNMENT;
+               if (e_client_check_capability (E_CLIENT (comp_data->client), cap))
+                       assignable = FALSE;
+
+               cap = CAL_STATIC_CAPABILITY_NO_CONV_TO_ASSIGN_TASK;
+               if (e_client_check_capability (E_CLIENT (comp_data->client), cap))
+                       assignable = FALSE;
+
+               prop = icalcomponent_get_first_property (
+                       comp_data->icalcomp, ICAL_URL_PROPERTY);
+               has_url |= (prop != NULL);
+
+               prop = icalcomponent_get_first_property (
+                       comp_data->icalcomp, ICAL_COMPLETED_PROPERTY);
+               if (prop != NULL)
+                       n_complete++;
+               else
+                       n_incomplete++;
+       }
+       g_slist_free (list);
+
+       if (n_selected == 1)
+               state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_SINGLE;
+       if (n_selected > 1)
+               state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_MULTIPLE;
+       if (assignable)
+               state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_CAN_ASSIGN;
+       if (editable)
+               state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_EDITABLE;
+       if (n_complete > 0)
+               state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_HAS_COMPLETE;
+       if (n_incomplete > 0)
+               state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_HAS_INCOMPLETE;
+       if (has_url)
+               state |= E_CAL_BASE_SHELL_CONTENT_SELECTION_HAS_URL;
+
+       return state;
 }
 
 static void
-task_shell_content_is_editing_changed_cb (ETaskTable *task_table,
-                                          GParamSpec *param,
-                                          EShellView *shell_view)
+task_shell_content_focus_search_results (EShellContent *shell_content)
 {
-       g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
+       ETaskShellContent *task_shell_content;
 
-       e_shell_view_update_actions (shell_view);
+       task_shell_content = E_TASK_SHELL_CONTENT (shell_content);
+
+       gtk_widget_grab_focus (task_shell_content->priv->task_table);
 }
 
 static GtkOrientation
@@ -317,10 +361,45 @@ task_shell_content_set_orientation (ETaskShellContent *task_shell_content,
 }
 
 static void
+task_shell_content_view_created (ECalBaseShellContent *cal_base_shell_content)
+{
+       ETaskShellContent *task_shell_content;
+       EShellView *shell_view;
+       GalViewInstance *view_instance;
+       GSettings *settings;
+
+       task_shell_content = E_TASK_SHELL_CONTENT (cal_base_shell_content);
+       shell_view = e_shell_content_get_shell_view (E_SHELL_CONTENT (task_shell_content));
+
+       /* Bind GObject properties to settings keys. */
+
+       settings = g_settings_new ("org.gnome.evolution.calendar");
+
+       g_settings_bind (
+               settings, "task-hpane-position",
+               task_shell_content->priv->paned, "hposition",
+               G_SETTINGS_BIND_DEFAULT);
+
+       g_settings_bind (
+               settings, "task-vpane-position",
+               task_shell_content->priv->paned, "vposition",
+               G_SETTINGS_BIND_DEFAULT);
+
+       g_object_unref (settings);
+
+       /* Finally load the view instance */
+       view_instance = e_shell_view_get_view_instance (shell_view);
+       gal_view_instance_load (view_instance);
+
+       /* Show everything known by default */
+       e_cal_model_set_time_range (e_cal_base_shell_content_get_model (cal_base_shell_content), 0, 0);
+}
+
+static void
 task_shell_content_set_property (GObject *object,
-                                 guint property_id,
-                                 const GValue *value,
-                                 GParamSpec *pspec)
+                                guint property_id,
+                                const GValue *value,
+                                GParamSpec *pspec)
 {
        switch (property_id) {
                case PROP_ORIENTATION:
@@ -341,18 +420,11 @@ task_shell_content_set_property (GObject *object,
 
 static void
 task_shell_content_get_property (GObject *object,
-                                 guint property_id,
-                                 GValue *value,
-                                 GParamSpec *pspec)
+                                guint property_id,
+                                GValue *value,
+                                GParamSpec *pspec)
 {
        switch (property_id) {
-               case PROP_MODEL:
-                       g_value_set_object (
-                               value,
-                               e_task_shell_content_get_task_model (
-                               E_TASK_SHELL_CONTENT (object)));
-                       return;
-
                case PROP_ORIENTATION:
                        g_value_set_enum (
                                value,
@@ -374,57 +446,27 @@ task_shell_content_get_property (GObject *object,
 static void
 task_shell_content_dispose (GObject *object)
 {
-       ETaskShellContentPrivate *priv;
-
-       priv = E_TASK_SHELL_CONTENT_GET_PRIVATE (object);
+       ETaskShellContent *task_shell_content = E_TASK_SHELL_CONTENT (object);
 
-       if (priv->paned != NULL) {
-               g_object_unref (priv->paned);
-               priv->paned = NULL;
-       }
+       g_clear_object (&task_shell_content->priv->paned);
+       g_clear_object (&task_shell_content->priv->task_table);
+       g_clear_object (&task_shell_content->priv->preview_pane);
 
-       if (priv->task_table != NULL) {
-               g_object_unref (priv->task_table);
-               priv->task_table = NULL;
-       }
-
-       if (priv->preview_pane != NULL) {
-               g_object_unref (priv->preview_pane);
-               priv->preview_pane = NULL;
-       }
-
-       if (priv->task_model != NULL) {
-               g_object_unref (priv->task_model);
-               priv->task_model = NULL;
-       }
+       g_free (task_shell_content->priv->current_uid);
+       task_shell_content->priv->current_uid = NULL;
 
        /* Chain up to parent's dispose() method. */
        G_OBJECT_CLASS (e_task_shell_content_parent_class)->dispose (object);
 }
 
 static void
-task_shell_content_finalize (GObject *object)
-{
-       ETaskShellContentPrivate *priv;
-
-       priv = E_TASK_SHELL_CONTENT_GET_PRIVATE (object);
-
-       g_free (priv->current_uid);
-
-       /* Chain up to parent's finalize() method. */
-       G_OBJECT_CLASS (e_task_shell_content_parent_class)->finalize (object);
-}
-
-static void
 task_shell_content_constructed (GObject *object)
 {
-       ETaskShellContentPrivate *priv;
-       EShell *shell;
+       ETaskShellContent *task_shell_content;
        EShellView *shell_view;
-       EShellWindow *shell_window;
        EShellContent *shell_content;
        EShellTaskbar *shell_taskbar;
-       ESourceRegistry *registry;
+       ECalModel *model;
        GalViewInstance *view_instance;
        GtkTargetList *target_list;
        GtkTargetEntry *targets;
@@ -432,19 +474,16 @@ task_shell_content_constructed (GObject *object)
        GtkWidget *widget;
        gint n_targets;
 
-       priv = E_TASK_SHELL_CONTENT_GET_PRIVATE (object);
+       task_shell_content = E_TASK_SHELL_CONTENT (object);
 
        /* Chain up to parent's constructed() method. */
        G_OBJECT_CLASS (e_task_shell_content_parent_class)->constructed (object);
 
+       model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (task_shell_content));
+
        shell_content = E_SHELL_CONTENT (object);
        shell_view = e_shell_content_get_shell_view (shell_content);
        shell_taskbar = e_shell_view_get_shell_taskbar (shell_view);
-       shell_window = e_shell_view_get_shell_window (shell_view);
-       shell = e_shell_window_get_shell (shell_window);
-
-       registry = e_shell_get_registry (shell);
-       priv->task_model = e_cal_model_tasks_new (registry);
 
        /* Build content widgets. */
 
@@ -452,7 +491,7 @@ task_shell_content_constructed (GObject *object)
 
        widget = e_paned_new (GTK_ORIENTATION_VERTICAL);
        gtk_container_add (GTK_CONTAINER (container), widget);
-       priv->paned = g_object_ref (widget);
+       task_shell_content->priv->paned = g_object_ref (widget);
        gtk_widget_show (widget);
 
        g_object_bind_property (
@@ -460,7 +499,7 @@ task_shell_content_constructed (GObject *object)
                widget, "orientation",
                G_BINDING_SYNC_CREATE);
 
-       container = priv->paned;
+       container = task_shell_content->priv->paned;
 
        widget = gtk_scrolled_window_new (NULL, NULL);
        gtk_scrolled_window_set_policy (
@@ -473,12 +512,12 @@ task_shell_content_constructed (GObject *object)
 
        container = widget;
 
-       widget = e_task_table_new (shell_view, priv->task_model);
+       widget = e_task_table_new (shell_view, model);
        gtk_container_add (GTK_CONTAINER (container), widget);
-       priv->task_table = g_object_ref (widget);
+       task_shell_content->priv->task_table = g_object_ref (widget);
        gtk_widget_show (widget);
 
-       container = priv->paned;
+       container = task_shell_content->priv->paned;
 
        widget = e_cal_component_preview_new ();
        gtk_widget_show (widget);
@@ -490,7 +529,7 @@ task_shell_content_constructed (GObject *object)
 
        widget = e_preview_pane_new (E_WEB_VIEW (widget));
        gtk_paned_pack2 (GTK_PANED (container), widget, FALSE, FALSE);
-       priv->preview_pane = g_object_ref (widget);
+       task_shell_content->priv->preview_pane = g_object_ref (widget);
        gtk_widget_show (widget);
 
        g_object_bind_property (
@@ -503,7 +542,7 @@ task_shell_content_constructed (GObject *object)
        targets = gtk_target_table_new_from_list (target_list, &n_targets);
 
        e_table_drag_source_set (
-               E_TABLE (priv->task_table),
+               E_TABLE (task_shell_content->priv->task_table),
                GDK_BUTTON1_MASK, targets, n_targets,
                GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_ASK);
 
@@ -511,35 +550,34 @@ task_shell_content_constructed (GObject *object)
        gtk_target_list_unref (target_list);
 
        g_signal_connect_swapped (
-               priv->task_table, "table-drag-data-get",
+               task_shell_content->priv->task_table, "table-drag-data-get",
                G_CALLBACK (task_shell_content_table_drag_data_get_cb),
                object);
 
        g_signal_connect_swapped (
-               priv->task_table, "table-drag-data-delete",
+               task_shell_content->priv->task_table, "table-drag-data-delete",
                G_CALLBACK (task_shell_content_table_drag_data_delete_cb),
                object);
 
        g_signal_connect_swapped (
-               priv->task_table, "cursor-change",
+               task_shell_content->priv->task_table, "cursor-change",
                G_CALLBACK (task_shell_content_cursor_change_cb),
                object);
 
        g_signal_connect_swapped (
-               priv->task_table, "selection-change",
+               task_shell_content->priv->task_table, "selection-change",
                G_CALLBACK (task_shell_content_selection_change_cb),
                object);
 
        e_signal_connect_notify (
-               priv->task_table, "notify::is-editing",
+               task_shell_content->priv->task_table, "notify::is-editing",
                G_CALLBACK (task_shell_content_is_editing_changed_cb), shell_view);
 
        g_signal_connect_swapped (
-               priv->task_model, "model-row-changed",
-               G_CALLBACK (task_shell_content_model_row_changed_cb),
-               object);
+               model, "model-row-changed",
+               G_CALLBACK (task_shell_content_model_row_changed_cb), object);
 
-       /* Load the view instance. */
+       /* Prepare the view instance. */
 
        view_instance = e_shell_view_new_view_instance (shell_view, NULL);
        g_signal_connect_swapped (
@@ -547,93 +585,7 @@ task_shell_content_constructed (GObject *object)
                G_CALLBACK (task_shell_content_display_view_cb),
                object);
        e_shell_view_set_view_instance (shell_view, view_instance);
-       gal_view_instance_load (view_instance);
        g_object_unref (view_instance);
-
-       /* Restore pane positions from the last session once
-        * the shell view is fully initialized and visible. */
-       g_signal_connect (
-               shell_window, "shell-view-created::tasks",
-               G_CALLBACK (task_shell_content_restore_state_cb),
-               shell_content);
-}
-
-static guint32
-task_shell_content_check_state (EShellContent *shell_content)
-{
-       ETaskShellContent *task_shell_content;
-       ETaskTable *task_table;
-       GSList *list, *iter;
-       gboolean assignable = TRUE;
-       gboolean editable = TRUE;
-       gboolean has_url = FALSE;
-       gint n_selected;
-       gint n_complete = 0;
-       gint n_incomplete = 0;
-       guint32 state = 0;
-
-       task_shell_content = E_TASK_SHELL_CONTENT (shell_content);
-       task_table = e_task_shell_content_get_task_table (task_shell_content);
-
-       n_selected = e_table_selected_count (E_TABLE (task_table));
-
-       list = e_task_table_get_selected (task_table);
-       for (iter = list; iter != NULL; iter = iter->next) {
-               ECalModelComponent *comp_data = iter->data;
-               icalproperty *prop;
-               const gchar *cap;
-               gboolean read_only;
-
-               read_only = e_client_is_readonly (E_CLIENT (comp_data->client));
-               editable &= !read_only;
-
-               cap = CAL_STATIC_CAPABILITY_NO_TASK_ASSIGNMENT;
-               if (e_client_check_capability (E_CLIENT (comp_data->client), cap))
-                       assignable = FALSE;
-
-               cap = CAL_STATIC_CAPABILITY_NO_CONV_TO_ASSIGN_TASK;
-               if (e_client_check_capability (E_CLIENT (comp_data->client), cap))
-                       assignable = FALSE;
-
-               prop = icalcomponent_get_first_property (
-                       comp_data->icalcomp, ICAL_URL_PROPERTY);
-               has_url |= (prop != NULL);
-
-               prop = icalcomponent_get_first_property (
-                       comp_data->icalcomp, ICAL_COMPLETED_PROPERTY);
-               if (prop != NULL)
-                       n_complete++;
-               else
-                       n_incomplete++;
-       }
-       g_slist_free (list);
-
-       if (n_selected == 1)
-               state |= E_TASK_SHELL_CONTENT_SELECTION_SINGLE;
-       if (n_selected > 1)
-               state |= E_TASK_SHELL_CONTENT_SELECTION_MULTIPLE;
-       if (assignable)
-               state |= E_TASK_SHELL_CONTENT_SELECTION_CAN_ASSIGN;
-       if (editable)
-               state |= E_TASK_SHELL_CONTENT_SELECTION_CAN_EDIT;
-       if (n_complete > 0)
-               state |= E_TASK_SHELL_CONTENT_SELECTION_HAS_COMPLETE;
-       if (n_incomplete > 0)
-               state |= E_TASK_SHELL_CONTENT_SELECTION_HAS_INCOMPLETE;
-       if (has_url)
-               state |= E_TASK_SHELL_CONTENT_SELECTION_HAS_URL;
-
-       return state;
-}
-
-static void
-task_shell_content_focus_search_results (EShellContent *shell_content)
-{
-       ETaskShellContentPrivate *priv;
-
-       priv = E_TASK_SHELL_CONTENT_GET_PRIVATE (shell_content);
-
-       gtk_widget_grab_focus (priv->task_table);
 }
 
 static void
@@ -641,6 +593,7 @@ e_task_shell_content_class_init (ETaskShellContentClass *class)
 {
        GObjectClass *object_class;
        EShellContentClass *shell_content_class;
+       ECalBaseShellContentClass *cal_base_shell_content_class;
 
        g_type_class_add_private (class, sizeof (ETaskShellContentPrivate));
 
@@ -648,23 +601,15 @@ e_task_shell_content_class_init (ETaskShellContentClass *class)
        object_class->set_property = task_shell_content_set_property;
        object_class->get_property = task_shell_content_get_property;
        object_class->dispose = task_shell_content_dispose;
-       object_class->finalize = task_shell_content_finalize;
        object_class->constructed = task_shell_content_constructed;
 
        shell_content_class = E_SHELL_CONTENT_CLASS (class);
        shell_content_class->check_state = task_shell_content_check_state;
-       shell_content_class->focus_search_results =
-               task_shell_content_focus_search_results;
+       shell_content_class->focus_search_results = task_shell_content_focus_search_results;
 
-       g_object_class_install_property (
-               object_class,
-               PROP_MODEL,
-               g_param_spec_object (
-                       "model",
-                       "Model",
-                       "The task table model",
-                       E_TYPE_CAL_MODEL,
-                       G_PARAM_READABLE));
+       cal_base_shell_content_class = E_CAL_BASE_SHELL_CONTENT_CLASS (class);
+       cal_base_shell_content_class->new_cal_model = e_cal_model_tasks_new;
+       cal_base_shell_content_class->view_created = task_shell_content_view_created;
 
        g_object_class_install_property (
                object_class,
@@ -689,8 +634,7 @@ e_task_shell_content_class_finalize (ETaskShellContentClass *class)
 static void
 e_task_shell_content_init (ETaskShellContent *task_shell_content)
 {
-       task_shell_content->priv =
-               E_TASK_SHELL_CONTENT_GET_PRIVATE (task_shell_content);
+       task_shell_content->priv = E_TASK_SHELL_CONTENT_GET_PRIVATE (task_shell_content);
 
        /* Postpone widget construction until we have a shell view. */
 }
@@ -714,20 +658,10 @@ e_task_shell_content_new (EShellView *shell_view)
                "shell-view", shell_view, NULL);
 }
 
-ECalModel *
-e_task_shell_content_get_task_model (ETaskShellContent *task_shell_content)
-{
-       g_return_val_if_fail (
-               E_IS_TASK_SHELL_CONTENT (task_shell_content), NULL);
-
-       return task_shell_content->priv->task_model;
-}
-
 ETaskTable *
 e_task_shell_content_get_task_table (ETaskShellContent *task_shell_content)
 {
-       g_return_val_if_fail (
-               E_IS_TASK_SHELL_CONTENT (task_shell_content), NULL);
+       g_return_val_if_fail (E_IS_TASK_SHELL_CONTENT (task_shell_content), NULL);
 
        return E_TASK_TABLE (task_shell_content->priv->task_table);
 }
@@ -735,8 +669,7 @@ e_task_shell_content_get_task_table (ETaskShellContent *task_shell_content)
 EPreviewPane *
 e_task_shell_content_get_preview_pane (ETaskShellContent *task_shell_content)
 {
-       g_return_val_if_fail (
-               E_IS_TASK_SHELL_CONTENT (task_shell_content), NULL);
+       g_return_val_if_fail (E_IS_TASK_SHELL_CONTENT (task_shell_content), NULL);
 
        return E_PREVIEW_PANE (task_shell_content->priv->preview_pane);
 }
@@ -744,8 +677,7 @@ e_task_shell_content_get_preview_pane (ETaskShellContent *task_shell_content)
 gboolean
 e_task_shell_content_get_preview_visible (ETaskShellContent *task_shell_content)
 {
-       g_return_val_if_fail (
-               E_IS_TASK_SHELL_CONTENT (task_shell_content), FALSE);
+       g_return_val_if_fail (E_IS_TASK_SHELL_CONTENT (task_shell_content), FALSE);
 
        return task_shell_content->priv->preview_visible;
 }
@@ -777,8 +709,7 @@ e_task_shell_content_get_searchbar (ETaskShellContent *task_shell_content)
        EShellContent *shell_content;
        GtkWidget *widget;
 
-       g_return_val_if_fail (
-               E_IS_TASK_SHELL_CONTENT (task_shell_content), NULL);
+       g_return_val_if_fail (E_IS_TASK_SHELL_CONTENT (task_shell_content), NULL);
 
        shell_content = E_SHELL_CONTENT (task_shell_content);
        shell_view = e_shell_content_get_shell_view (shell_content);
@@ -786,4 +717,3 @@ e_task_shell_content_get_searchbar (ETaskShellContent *task_shell_content)
 
        return E_SHELL_SEARCHBAR (widget);
 }
-
diff --git a/modules/calendar/e-task-shell-content.h b/modules/calendar/e-task-shell-content.h
index bc02302..75ba2b3 100644
--- a/modules/calendar/e-task-shell-content.h
+++ b/modules/calendar/e-task-shell-content.h
@@ -1,5 +1,6 @@
 /*
- * e-task-shell-content.h
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
@@ -7,15 +8,11 @@
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
  * for more details.
  *
  * You should have received a copy of the GNU Lesser General Public License
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
  */
 
 #ifndef E_TASK_SHELL_CONTENT_H
@@ -25,9 +22,10 @@
 #include <shell/e-shell-searchbar.h>
 #include <shell/e-shell-view.h>
 
-#include <calendar/gui/e-cal-model.h>
 #include <calendar/gui/e-task-table.h>
 
+#include "e-cal-base-shell-content.h"
+
 /* Standard GObject macros */
 #define E_TYPE_TASK_SHELL_CONTENT \
        (e_task_shell_content_get_type ())
@@ -53,44 +51,27 @@ typedef struct _ETaskShellContent ETaskShellContent;
 typedef struct _ETaskShellContentClass ETaskShellContentClass;
 typedef struct _ETaskShellContentPrivate ETaskShellContentPrivate;
 
-enum {
-       E_TASK_SHELL_CONTENT_SELECTION_SINGLE = 1 << 0,
-       E_TASK_SHELL_CONTENT_SELECTION_MULTIPLE = 1 << 1,
-       E_TASK_SHELL_CONTENT_SELECTION_CAN_ASSIGN = 1 << 2,
-       E_TASK_SHELL_CONTENT_SELECTION_CAN_EDIT = 1 << 3,
-       E_TASK_SHELL_CONTENT_SELECTION_HAS_COMPLETE = 1 << 4,
-       E_TASK_SHELL_CONTENT_SELECTION_HAS_INCOMPLETE = 1 << 5,
-       E_TASK_SHELL_CONTENT_SELECTION_HAS_URL = 1 << 6
-};
-
 struct _ETaskShellContent {
-       EShellContent parent;
+       ECalBaseShellContent parent;
        ETaskShellContentPrivate *priv;
 };
 
 struct _ETaskShellContentClass {
-       EShellContentClass parent_class;
+       ECalBaseShellContentClass parent_class;
 };
 
-GType          e_task_shell_content_get_type   (void);
-void           e_task_shell_content_type_register
-                                       (GTypeModule *type_module);
-GtkWidget *    e_task_shell_content_new
-                                       (EShellView *shell_view);
-ECalModel *    e_task_shell_content_get_task_model
-                                       (ETaskShellContent *task_shell_content);
-ETaskTable *   e_task_shell_content_get_task_table
-                                       (ETaskShellContent *task_shell_content);
-EPreviewPane * e_task_shell_content_get_preview_pane
-                                       (ETaskShellContent *task_shell_content);
+GType          e_task_shell_content_get_type           (void);
+void           e_task_shell_content_type_register      (GTypeModule *type_module);
+GtkWidget *    e_task_shell_content_new                (EShellView *shell_view);
+ETaskTable *   e_task_shell_content_get_task_table     (ETaskShellContent *task_shell_content);
+EPreviewPane * e_task_shell_content_get_preview_pane   (ETaskShellContent *task_shell_content);
 gboolean       e_task_shell_content_get_preview_visible
-                                       (ETaskShellContent *task_shell_content);
+                                                       (ETaskShellContent *task_shell_content);
 void           e_task_shell_content_set_preview_visible
-                                       (ETaskShellContent *task_shell_content,
-                                        gboolean preview_visible);
+                                                       (ETaskShellContent *task_shell_content,
+                                                        gboolean preview_visible);
 EShellSearchbar *
-               e_task_shell_content_get_searchbar
-                                       (ETaskShellContent *task_shell_content);
+               e_task_shell_content_get_searchbar      (ETaskShellContent *task_shell_content);
 
 G_END_DECLS
 
diff --git a/modules/calendar/e-task-shell-view-actions.c b/modules/calendar/e-task-shell-view-actions.c
index 39c7032..26de432 100644
--- a/modules/calendar/e-task-shell-view-actions.c
+++ b/modules/calendar/e-task-shell-view-actions.c
@@ -22,6 +22,9 @@
 #include <config.h>
 #endif
 
+#include <calendar/gui/e-cal-ops.h>
+
+#include "e-cal-base-shell-view.h"
 #include "e-task-shell-view-private.h"
 #include "e-cal-shell-view.h"
 
@@ -79,22 +82,11 @@ action_task_forward_cb (GtkAction *action,
                         ETaskShellView *task_shell_view)
 {
        ETaskShellContent *task_shell_content;
-       EShell *shell;
-       EShellView *shell_view;
-       EShellWindow *shell_window;
-       ESourceRegistry *registry;
        ECalModelComponent *comp_data;
        ETaskTable *task_table;
        ECalComponent *comp;
-       icalcomponent *clone;
        GSList *list;
 
-       shell_view = E_SHELL_VIEW (task_shell_view);
-       shell_window = e_shell_view_get_shell_window (shell_view);
-       shell = e_shell_window_get_shell (shell_window);
-
-       registry = e_shell_get_registry (shell);
-
        task_shell_content = task_shell_view->priv->task_shell_content;
        task_table = e_task_shell_content_get_task_table (task_shell_content);
 
@@ -104,52 +96,28 @@ action_task_forward_cb (GtkAction *action,
        g_slist_free (list);
 
        /* XXX We only forward the first selected task. */
-       comp = e_cal_component_new ();
-       clone = icalcomponent_new_clone (comp_data->icalcomp);
-       e_cal_component_set_icalcomponent (comp, clone);
+       comp = e_cal_component_new_from_icalcomponent (icalcomponent_new_clone (comp_data->icalcomp));
+       g_return_if_fail (comp != NULL);
 
-       itip_send_comp (
-               registry, E_CAL_COMPONENT_METHOD_PUBLISH, comp,
-               comp_data->client, NULL, NULL, NULL, TRUE, FALSE);
+       itip_send_component (e_task_table_get_model (task_table),
+               E_CAL_COMPONENT_METHOD_PUBLISH, comp,
+               comp_data->client, NULL, NULL, NULL, TRUE, FALSE, TRUE);
 
        g_object_unref (comp);
 }
 
 static void
 action_task_list_copy_cb (GtkAction *action,
-                          ETaskShellView *task_shell_view)
+                         EShellView *shell_view)
 {
-       ETaskShellSidebar *task_shell_sidebar;
-       EShell *shell;
-       EShellView *shell_view;
-       EShellWindow *shell_window;
-       ESourceRegistry *registry;
-       ESourceSelector *selector;
-       ESource *source;
-
-       shell_view = E_SHELL_VIEW (task_shell_view);
-       shell_window = e_shell_view_get_shell_window (shell_view);
-       shell = e_shell_window_get_shell (shell_window);
-
-       registry = e_shell_get_registry (shell);
-
-       task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
-       selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
-       source = e_source_selector_ref_primary_selection (selector);
-       g_return_if_fail (source != NULL);
-
-       copy_source_dialog (
-               GTK_WINDOW (shell_window), registry,
-               source, E_CAL_CLIENT_SOURCE_TYPE_TASKS);
-
-       g_object_unref (source);
+       e_cal_base_shell_view_copy_calendar (shell_view);
 }
 
 static void
 action_task_list_delete_cb (GtkAction *action,
                             ETaskShellView *task_shell_view)
 {
-       ETaskShellSidebar *task_shell_sidebar;
+       ECalBaseShellSidebar *task_shell_sidebar;
        EShellWindow *shell_window;
        EShellView *shell_view;
        ESource *source;
@@ -160,7 +128,7 @@ action_task_list_delete_cb (GtkAction *action,
        shell_window = e_shell_view_get_shell_window (shell_view);
 
        task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
-       selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
+       selector = e_cal_base_shell_sidebar_get_selector (task_shell_sidebar);
 
        source = e_source_selector_ref_primary_selection (selector);
        g_return_if_fail (source != NULL);
@@ -257,7 +225,7 @@ action_task_list_properties_cb (GtkAction *action,
 {
        EShellView *shell_view;
        EShellWindow *shell_window;
-       ETaskShellSidebar *task_shell_sidebar;
+       ECalBaseShellSidebar *task_shell_sidebar;
        ECalClientSourceType source_type;
        ESource *source;
        ESourceSelector *selector;
@@ -270,7 +238,7 @@ action_task_list_properties_cb (GtkAction *action,
        shell_window = e_shell_view_get_shell_window (shell_view);
 
        task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
-       selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
+       selector = e_cal_base_shell_sidebar_get_selector (task_shell_sidebar);
        source = e_source_selector_ref_primary_selection (selector);
        g_return_if_fail (source != NULL);
 
@@ -297,13 +265,13 @@ static void
 action_task_list_refresh_cb (GtkAction *action,
                              ETaskShellView *task_shell_view)
 {
-       ETaskShellSidebar *task_shell_sidebar;
+       ECalBaseShellSidebar *task_shell_sidebar;
        ESourceSelector *selector;
        EClient *client = NULL;
        ESource *source;
 
        task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
-       selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
+       selector = e_cal_base_shell_sidebar_get_selector (task_shell_sidebar);
 
        source = e_source_selector_ref_primary_selection (selector);
 
@@ -318,7 +286,7 @@ action_task_list_refresh_cb (GtkAction *action,
 
        g_return_if_fail (e_client_check_refresh_supported (client));
 
-       e_cal_shell_view_allow_auth_prompt_and_refresh (E_SHELL_VIEW (task_shell_view), client);
+       e_cal_base_shell_view_allow_auth_prompt_and_refresh (E_SHELL_VIEW (task_shell_view), client);
 
        g_object_unref (client);
 }
@@ -327,11 +295,11 @@ static void
 action_task_list_rename_cb (GtkAction *action,
                             ETaskShellView *task_shell_view)
 {
-       ETaskShellSidebar *task_shell_sidebar;
+       ECalBaseShellSidebar *task_shell_sidebar;
        ESourceSelector *selector;
 
        task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
-       selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
+       selector = e_cal_base_shell_sidebar_get_selector (task_shell_sidebar);
 
        e_source_selector_edit_primary_selection (selector);
 }
@@ -340,12 +308,12 @@ static void
 action_task_list_select_one_cb (GtkAction *action,
                                 ETaskShellView *task_shell_view)
 {
-       ETaskShellSidebar *task_shell_sidebar;
+       ECalBaseShellSidebar *task_shell_sidebar;
        ESourceSelector *selector;
        ESource *primary;
 
        task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
-       selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
+       selector = e_cal_base_shell_sidebar_get_selector (task_shell_sidebar);
 
        primary = e_source_selector_ref_primary_selection (selector);
        g_return_if_fail (primary != NULL);
@@ -405,30 +373,21 @@ static void
 action_task_new_cb (GtkAction *action,
                     ETaskShellView *task_shell_view)
 {
-       EShell *shell;
        EShellView *shell_view;
        EShellWindow *shell_window;
        ETaskShellContent *task_shell_content;
        ETaskTable *task_table;
-       ECalClient *client;
-       ECalComponent *comp;
-       CompEditor *editor;
+       EClient *client = NULL;
        GSList *list;
 
        shell_view = E_SHELL_VIEW (task_shell_view);
        shell_window = e_shell_view_get_shell_window (shell_view);
-       shell = e_shell_window_get_shell (shell_window);
 
        task_shell_content = task_shell_view->priv->task_shell_content;
        task_table = e_task_shell_content_get_task_table (task_shell_content);
 
        list = e_task_table_get_selected (task_table);
-       if (list == NULL) {
-               ECalModel *model;
-
-               model = e_task_table_get_model (task_table);
-               client = e_cal_model_ref_default_client (model);
-       } else {
+       if (list) {
                ECalModelComponent *comp_data;
 
                comp_data = list->data;
@@ -436,17 +395,10 @@ action_task_new_cb (GtkAction *action,
                g_slist_free (list);
        }
 
-       g_return_if_fail (client != NULL);
+       e_cal_ops_new_component_editor (shell_window, E_CAL_CLIENT_SOURCE_TYPE_TASKS,
+               client ? e_source_get_uid (e_client_get_source (client)) : NULL, FALSE);
 
-       editor = task_editor_new (client, shell, COMP_EDITOR_NEW_ITEM);
-       comp = cal_comp_task_new_with_defaults (client);
-       comp_editor_edit_comp (editor, comp);
-
-       gtk_window_present (GTK_WINDOW (editor));
-
-       g_object_unref (comp);
-
-       g_object_unref (client);
+       g_clear_object (&client);
 }
 
 static void
diff --git a/modules/calendar/e-task-shell-view-private.c b/modules/calendar/e-task-shell-view-private.c
index 5a26284..5a8d158 100644
--- a/modules/calendar/e-task-shell-view-private.c
+++ b/modules/calendar/e-task-shell-view-private.c
@@ -22,26 +22,10 @@
 #include <config.h>
 #endif
 
-#include "e-task-shell-view-private.h"
-
 #include "e-util/e-util-private.h"
+#include <calendar/gui/e-cal-ops.h>
 
-static void
-task_shell_view_model_row_appended_cb (ETaskShellView *task_shell_view,
-                                       ECalModel *model)
-{
-       ETaskShellSidebar *task_shell_sidebar;
-       ECalClient *client;
-
-       /* This is the "Click to Add" handler. */
-
-       client = e_cal_model_ref_default_client (model);
-
-       task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
-       e_task_shell_sidebar_add_client (task_shell_sidebar, E_CLIENT (client));
-
-       g_object_unref (client);
-}
+#include "e-task-shell-view-private.h"
 
 static gboolean
 task_shell_view_process_completed_tasks_cb (gpointer user_data)
@@ -115,36 +99,6 @@ task_shell_view_table_popup_event_cb (EShellView *shell_view,
        e_shell_view_show_popup_menu (shell_view, widget_path, button_event);
 }
 
-static void
-task_shell_view_selector_client_added_cb (ETaskShellView *task_shell_view,
-                                          ECalClient *client)
-{
-       ETaskShellContent *task_shell_content;
-       ETaskTable *task_table;
-       ECalModel *model;
-
-       task_shell_content = task_shell_view->priv->task_shell_content;
-       task_table = e_task_shell_content_get_task_table (task_shell_content);
-       model = e_task_table_get_model (task_table);
-
-       e_cal_model_add_client (model, client);
-}
-
-static void
-task_shell_view_selector_client_removed_cb (ETaskShellView *task_shell_view,
-                                            ECalClient *client)
-{
-       ETaskShellContent *task_shell_content;
-       ETaskTable *task_table;
-       ECalModel *model;
-
-       task_shell_content = task_shell_view->priv->task_shell_content;
-       task_table = e_task_shell_content_get_task_table (task_shell_content);
-       model = e_task_table_get_model (task_table);
-
-       e_cal_model_remove_client (model, client);
-}
-
 static gboolean
 task_shell_view_selector_popup_event_cb (EShellView *shell_view,
                                          ESource *primary_source,
@@ -260,18 +214,6 @@ e_task_shell_view_private_constructed (ETaskShellView *task_shell_view)
 
        priv->settings = g_settings_new ("org.gnome.evolution.calendar");
 
-       handler_id = g_signal_connect_object (
-               priv->task_shell_sidebar, "client-added",
-               G_CALLBACK (task_shell_view_selector_client_added_cb),
-               task_shell_view, G_CONNECT_SWAPPED);
-       priv->client_added_handler_id = handler_id;
-
-       handler_id = g_signal_connect_object (
-               priv->task_shell_sidebar, "client-removed",
-               G_CALLBACK (task_shell_view_selector_client_removed_cb),
-               task_shell_view, G_CONNECT_SWAPPED);
-       priv->client_removed_handler_id = handler_id;
-
        /* Keep our own reference to this so we can
         * disconnect our signal handlers in dispose(). */
        priv->client_cache = e_shell_get_client_cache (shell);
@@ -313,12 +255,6 @@ e_task_shell_view_private_constructed (ETaskShellView *task_shell_view)
                task_shell_view);
        priv->selection_change_2_handler_id = handler_id;
 
-       handler_id = g_signal_connect_swapped (
-               priv->task_table, "status-message",
-               G_CALLBACK (e_task_shell_view_set_status_message),
-               task_shell_view);
-       priv->status_message_handler_id = handler_id;
-
        /* Keep our own reference to this so we can
         * disconnect our signal handlers in dispose(). */
        priv->model = e_task_table_get_model (priv->task_table);
@@ -344,14 +280,14 @@ e_task_shell_view_private_constructed (ETaskShellView *task_shell_view)
 
        handler_id = g_signal_connect_swapped (
                priv->model, "row-appended",
-               G_CALLBACK (task_shell_view_model_row_appended_cb),
+               G_CALLBACK (e_cal_base_shell_view_model_row_appended),
                task_shell_view);
        priv->rows_appended_handler_id = handler_id;
 
        /* Keep our own reference to this so we can
         * disconnect our signal handlers in dispose(). */
-       priv->selector = e_task_shell_sidebar_get_selector (
-               E_TASK_SHELL_SIDEBAR (shell_sidebar));
+       priv->selector = e_cal_base_shell_sidebar_get_selector (
+               E_CAL_BASE_SHELL_SIDEBAR (shell_sidebar));
        g_object_ref (priv->selector);
 
        handler_id = g_signal_connect_swapped (
@@ -376,12 +312,6 @@ e_task_shell_view_private_constructed (ETaskShellView *task_shell_view)
                shell_view, "confirm-purge",
                G_SETTINGS_BIND_DEFAULT);
 
-       /* Keep the ECalModel in sync with the sidebar. */
-       g_object_bind_property (
-               shell_sidebar, "default-client",
-               priv->model, "default-client",
-               G_BINDING_SYNC_CREATE);
-
        /* Hide Completed Tasks (enable/units/value) */
        handler_id = g_signal_connect (
                priv->settings, "changed::hide-completed-tasks",
@@ -417,20 +347,6 @@ e_task_shell_view_private_dispose (ETaskShellView *task_shell_view)
 {
        ETaskShellViewPrivate *priv = task_shell_view->priv;
 
-       if (priv->client_added_handler_id > 0) {
-               g_signal_handler_disconnect (
-                       priv->task_shell_sidebar,
-                       priv->client_added_handler_id);
-               priv->client_added_handler_id = 0;
-       }
-
-       if (priv->client_removed_handler_id > 0) {
-               g_signal_handler_disconnect (
-                       priv->task_shell_sidebar,
-                       priv->client_removed_handler_id);
-               priv->client_removed_handler_id = 0;
-       }
-
        if (priv->backend_error_handler_id > 0) {
                g_signal_handler_disconnect (
                        priv->client_cache,
@@ -466,13 +382,6 @@ e_task_shell_view_private_dispose (ETaskShellView *task_shell_view)
                priv->selection_change_2_handler_id = 0;
        }
 
-       if (priv->status_message_handler_id > 0) {
-               g_signal_handler_disconnect (
-                       priv->task_table,
-                       priv->status_message_handler_id);
-               priv->status_message_handler_id = 0;
-       }
-
        if (priv->model_changed_handler_id > 0) {
                g_signal_handler_disconnect (
                        priv->model,
@@ -546,15 +455,6 @@ e_task_shell_view_private_dispose (ETaskShellView *task_shell_view)
        g_clear_object (&priv->selector);
        g_clear_object (&priv->settings);
 
-       if (task_shell_view->priv->activity != NULL) {
-               /* XXX Activity is not cancellable. */
-               e_activity_set_state (
-                       task_shell_view->priv->activity,
-                       E_ACTIVITY_COMPLETED);
-               g_object_unref (task_shell_view->priv->activity);
-               task_shell_view->priv->activity = NULL;
-       }
-
        if (priv->update_timeout > 0) {
                g_source_remove (priv->update_timeout);
                priv->update_timeout = 0;
@@ -580,57 +480,16 @@ void
 e_task_shell_view_open_task (ETaskShellView *task_shell_view,
                              ECalModelComponent *comp_data)
 {
-       EShell *shell;
-       EShellView *shell_view;
-       EShellWindow *shell_window;
-       ESourceRegistry *registry;
-       CompEditor *editor;
-       CompEditorFlags flags = 0;
-       ECalComponent *comp;
-       icalcomponent *clone;
-       icalproperty *prop;
-       const gchar *uid;
+       EShellContent *shell_content;
+       ECalModel *model;
 
        g_return_if_fail (E_IS_TASK_SHELL_VIEW (task_shell_view));
        g_return_if_fail (E_IS_CAL_MODEL_COMPONENT (comp_data));
 
-       shell_view = E_SHELL_VIEW (task_shell_view);
-       shell_window = e_shell_view_get_shell_window (shell_view);
-       shell = e_shell_window_get_shell (shell_window);
-
-       registry = e_shell_get_registry (shell);
-
-       uid = icalcomponent_get_uid (comp_data->icalcomp);
-       editor = comp_editor_find_instance (uid);
-
-       if (editor != NULL)
-               goto exit;
+       shell_content = e_shell_view_get_shell_content (E_SHELL_VIEW (task_shell_view));
+       model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (shell_content));
 
-       comp = e_cal_component_new ();
-       clone = icalcomponent_new_clone (comp_data->icalcomp);
-       e_cal_component_set_icalcomponent (comp, clone);
-
-       prop = icalcomponent_get_first_property (
-               comp_data->icalcomp, ICAL_ATTENDEE_PROPERTY);
-       if (prop != NULL)
-               flags |= COMP_EDITOR_IS_ASSIGNED;
-
-       if (itip_organizer_is_user (registry, comp, comp_data->client))
-               flags |= COMP_EDITOR_USER_ORG;
-
-       if (!e_cal_component_has_attendees (comp))
-               flags |= COMP_EDITOR_USER_ORG;
-
-       editor = task_editor_new (comp_data->client, shell, flags);
-       comp_editor_edit_comp (editor, comp);
-
-       g_object_unref (comp);
-
-       if (flags & COMP_EDITOR_IS_ASSIGNED)
-               task_editor_show_assignment (TASK_EDITOR (editor));
-
-exit:
-       gtk_window_present (GTK_WINDOW (editor));
+       e_cal_ops_open_component_in_editor_sync (model, comp_data->client, comp_data->icalcomp);
 }
 
 void
@@ -638,100 +497,13 @@ e_task_shell_view_delete_completed (ETaskShellView *task_shell_view)
 {
        ETaskShellContent *task_shell_content;
        ECalModel *model;
-       GList *list, *link;
-       const gchar *sexp;
 
        g_return_if_fail (E_IS_TASK_SHELL_VIEW (task_shell_view));
 
-       sexp = "(is-completed?)";
-
        task_shell_content = task_shell_view->priv->task_shell_content;
-       model = e_task_shell_content_get_task_model (task_shell_content);
-
-       e_task_shell_view_set_status_message (
-               task_shell_view, _("Expunging"), -1.0);
-
-       list = e_cal_model_list_clients (model);
-
-       for (link = list; link != NULL; link = g_list_next (link)) {
-               ECalClient *client = E_CAL_CLIENT (link->data);
-               GSList *objects, *obj;
-               GError *error = NULL;
-
-               if (e_client_is_readonly (E_CLIENT (client)))
-                       continue;
+       model = e_cal_base_shell_content_get_model (E_CAL_BASE_SHELL_CONTENT (task_shell_content));
 
-               e_cal_client_get_object_list_sync (
-                       client, sexp, &objects, NULL, &error);
-
-               if (error != NULL) {
-                       g_warning (
-                               "%s: Failed to get object list: %s",
-                               G_STRFUNC, error->message);
-                       g_clear_error (&error);
-                       continue;
-               }
-
-               for (obj = objects; obj != NULL; obj = obj->next) {
-                       icalcomponent *component = obj->data;
-                       const gchar *uid;
-
-                       uid = icalcomponent_get_uid (component);
-
-                       e_cal_client_remove_object_sync (
-                               client, uid, NULL,
-                               CALOBJ_MOD_THIS, NULL, &error);
-
-                       if (error != NULL) {
-                               g_warning (
-                                       "%s: Failed to remove object: %s",
-                                       G_STRFUNC, error->message);
-                               g_clear_error (&error);
-                       }
-               }
-
-               e_cal_client_free_icalcomp_slist (objects);
-       }
-
-       g_list_free_full (list, (GDestroyNotify) g_object_unref);
-
-       e_task_shell_view_set_status_message (task_shell_view, NULL, -1.0);
-}
-
-void
-e_task_shell_view_set_status_message (ETaskShellView *task_shell_view,
-                                      const gchar *status_message,
-                                      gdouble percent)
-{
-       EActivity *activity;
-       EShellView *shell_view;
-       EShellBackend *shell_backend;
-
-       g_return_if_fail (E_IS_TASK_SHELL_VIEW (task_shell_view));
-
-       activity = task_shell_view->priv->activity;
-       shell_view = E_SHELL_VIEW (task_shell_view);
-       shell_backend = e_shell_view_get_shell_backend (shell_view);
-
-       if (status_message == NULL || *status_message == '\0') {
-               if (activity != NULL) {
-                       e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
-                       g_object_unref (activity);
-                       activity = NULL;
-               }
-
-       } else if (activity == NULL) {
-               activity = e_activity_new ();
-               e_activity_set_percent (activity, percent);
-               e_activity_set_text (activity, status_message);
-               e_shell_backend_add_activity (shell_backend, activity);
-
-       } else {
-               e_activity_set_percent (activity, percent);
-               e_activity_set_text (activity, status_message);
-       }
-
-       task_shell_view->priv->activity = activity;
+       e_cal_ops_delete_completed_tasks (model);
 }
 
 void
@@ -773,4 +545,3 @@ e_task_shell_view_update_sidebar (ETaskShellView *task_shell_view)
 
        g_string_free (string, TRUE);
 }
-
diff --git a/modules/calendar/e-task-shell-view-private.h b/modules/calendar/e-task-shell-view-private.h
index d29bd2e..43775dc 100644
--- a/modules/calendar/e-task-shell-view-private.h
+++ b/modules/calendar/e-task-shell-view-private.h
@@ -24,7 +24,7 @@
 #include "e-task-shell-view.h"
 
 #include <string.h>
-#include <glib/gi18n.h>
+#include <glib/gi18n-lib.h>
 #include <libecal/libecal.h>
 
 #include "shell/e-shell-utils.h"
@@ -33,14 +33,13 @@
 #include "calendar/gui/comp-util.h"
 #include "calendar/gui/e-cal-component-preview.h"
 #include "calendar/gui/e-cal-model-tasks.h"
-#include "calendar/gui/e-calendar-selector.h"
 #include "calendar/gui/print.h"
-#include "calendar/gui/dialogs/copy-source-dialog.h"
 #include "calendar/gui/dialogs/task-editor.h"
 
+#include "e-cal-base-shell-sidebar.h"
+
 #include "e-task-shell-backend.h"
 #include "e-task-shell-content.h"
-#include "e-task-shell-sidebar.h"
 #include "e-task-shell-view-actions.h"
 
 #define E_TASK_SHELL_VIEW_GET_PRIVATE(obj) \
@@ -83,11 +82,7 @@ struct _ETaskShellViewPrivate {
        /* These are just for convenience. */
        ETaskShellBackend *task_shell_backend;
        ETaskShellContent *task_shell_content;
-       ETaskShellSidebar *task_shell_sidebar;
-
-       /* sidebar signal handlers */
-       gulong client_added_handler_id;
-       gulong client_removed_handler_id;
+       ECalBaseShellSidebar *task_shell_sidebar;
 
        EClientCache *client_cache;
        gulong backend_error_handler_id;
@@ -97,7 +92,6 @@ struct _ETaskShellViewPrivate {
        gulong popup_event_handler_id;
        gulong selection_change_1_handler_id;
        gulong selection_change_2_handler_id;
-       gulong status_message_handler_id;
 
        ECalModel *model;
        gulong model_changed_handler_id;
@@ -115,7 +109,6 @@ struct _ETaskShellViewPrivate {
        gulong settings_hide_completed_tasks_units_handler_id;
        gulong settings_hide_completed_tasks_value_handler_id;
 
-       EActivity *activity;
        guint update_timeout;
        guint update_completed_timeout;
 
@@ -142,10 +135,6 @@ void               e_task_shell_view_open_task
                                         ECalModelComponent *comp_data);
 void           e_task_shell_view_delete_completed
                                        (ETaskShellView *task_shell_view);
-void           e_task_shell_view_set_status_message
-                                       (ETaskShellView *task_shell_view,
-                                        const gchar *status_message,
-                                        gdouble percent);
 void           e_task_shell_view_update_sidebar
                                        (ETaskShellView *task_shell_view);
 void           e_task_shell_view_update_search_filter
diff --git a/modules/calendar/e-task-shell-view.c b/modules/calendar/e-task-shell-view.c
index 8153869..59cbe9b 100644
--- a/modules/calendar/e-task-shell-view.c
+++ b/modules/calendar/e-task-shell-view.c
@@ -1,5 +1,6 @@
 /*
- * e-task-shell-view.c
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
@@ -7,94 +8,36 @@
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
  * for more details.
  *
  * You should have received a copy of the GNU Lesser General Public License
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
  */
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
 
+#include <gtk/gtk.h>
+
+#include "e-cal-base-shell-sidebar.h"
+#include "e-task-shell-content.h"
+#include "e-task-shell-view.h"
+
 #include "e-task-shell-view-private.h"
 
+#define E_TASK_SHELL_VIEW_GET_PRIVATE(obj) \
+       (G_TYPE_INSTANCE_GET_PRIVATE \
+       ((obj), E_TYPE_TASK_SHELL_VIEW, ETaskShellViewPrivate))
+
+G_DEFINE_DYNAMIC_TYPE (ETaskShellView, e_task_shell_view, E_TYPE_CAL_BASE_SHELL_VIEW)
+
 enum {
        PROP_0,
        PROP_CONFIRM_PURGE
 };
 
-G_DEFINE_DYNAMIC_TYPE (
-       ETaskShellView,
-       e_task_shell_view,
-       E_TYPE_SHELL_VIEW)
-
-static void
-task_shell_view_set_property (GObject *object,
-                              guint property_id,
-                              const GValue *value,
-                              GParamSpec *pspec)
-{
-       switch (property_id) {
-               case PROP_CONFIRM_PURGE:
-                       e_task_shell_view_set_confirm_purge (
-                               E_TASK_SHELL_VIEW (object),
-                               g_value_get_boolean (value));
-                       return;
-       }
-
-       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
-}
-
-static void
-task_shell_view_get_property (GObject *object,
-                              guint property_id,
-                              GValue *value,
-                              GParamSpec *pspec)
-{
-       switch (property_id) {
-               case PROP_CONFIRM_PURGE:
-                       g_value_set_boolean (
-                               value, e_task_shell_view_get_confirm_purge (
-                               E_TASK_SHELL_VIEW (object)));
-                       return;
-       }
-
-       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
-}
-
-static void
-task_shell_view_dispose (GObject *object)
-{
-       e_task_shell_view_private_dispose (E_TASK_SHELL_VIEW (object));
-
-       /* Chain up to parent's dispose() method. */
-       G_OBJECT_CLASS (e_task_shell_view_parent_class)->dispose (object);
-}
-
-static void
-task_shell_view_finalize (GObject *object)
-{
-       e_task_shell_view_private_finalize (E_TASK_SHELL_VIEW (object));
-
-       /* Chain up to parent's finalize() method. */
-       G_OBJECT_CLASS (e_task_shell_view_parent_class)->finalize (object);
-}
-
-static void
-task_shell_view_constructed (GObject *object)
-{
-       /* Chain up to parent's constructed() method. */
-       G_OBJECT_CLASS (e_task_shell_view_parent_class)->constructed (object);
-
-       e_task_shell_view_private_constructed (E_TASK_SHELL_VIEW (object));
-}
-
 static void
 task_shell_view_execute_search (EShellView *shell_view)
 {
@@ -109,6 +52,7 @@ task_shell_view_execute_search (EShellView *shell_view)
        ETaskTable *task_table;
        EWebView *web_view;
        ECalModel *model;
+       ECalDataModel *data_model;
        icaltimezone *timezone;
        struct icaltimetype current_time;
        time_t start_range;
@@ -128,6 +72,7 @@ task_shell_view_execute_search (EShellView *shell_view)
        task_shell_content = E_TASK_SHELL_CONTENT (shell_content);
        task_table = e_task_shell_content_get_task_table (task_shell_content);
        model = e_task_table_get_model (task_table);
+       data_model = e_cal_model_get_data_model (model);
        timezone = e_cal_model_get_timezone (model);
        current_time = icaltime_current_time_with_zone (timezone);
        now_time = time_day_begin (icaltime_as_timet (current_time));
@@ -279,11 +224,10 @@ task_shell_view_execute_search (EShellView *shell_view)
        }
 
        /* Submit the query. */
-       e_cal_model_set_search_query (model, query);
+       e_cal_data_model_set_filter (data_model, query);
        g_free (query);
 
-       preview_pane =
-               e_task_shell_content_get_preview_pane (task_shell_content);
+       preview_pane = e_task_shell_content_get_preview_pane (task_shell_content);
 
        web_view = e_preview_pane_get_web_view (preview_pane);
        task_preview = E_CAL_COMPONENT_PREVIEW (web_view);
@@ -318,8 +262,7 @@ task_shell_view_update_actions (EShellView *shell_view)
        gboolean refresh_supported;
 
        /* Chain up to parent's update_actions() method. */
-       E_SHELL_VIEW_CLASS (e_task_shell_view_parent_class)->
-               update_actions (shell_view);
+       E_SHELL_VIEW_CLASS (e_task_shell_view_parent_class)->update_actions (shell_view);
 
        shell_window = e_shell_view_get_shell_window (shell_view);
 
@@ -327,38 +270,37 @@ task_shell_view_update_actions (EShellView *shell_view)
        state = e_shell_content_check_state (shell_content);
 
        single_task_selected =
-               (state & E_TASK_SHELL_CONTENT_SELECTION_SINGLE);
+               (state & E_CAL_BASE_SHELL_CONTENT_SELECTION_SINGLE);
        multiple_tasks_selected =
-               (state & E_TASK_SHELL_CONTENT_SELECTION_MULTIPLE);
+               (state & E_CAL_BASE_SHELL_CONTENT_SELECTION_MULTIPLE);
        selection_is_assignable =
-               (state & E_TASK_SHELL_CONTENT_SELECTION_CAN_ASSIGN);
+               (state & E_CAL_BASE_SHELL_CONTENT_SELECTION_CAN_ASSIGN);
        sources_are_editable =
-               (state & E_TASK_SHELL_CONTENT_SELECTION_CAN_EDIT);
+               (state & E_CAL_BASE_SHELL_CONTENT_SELECTION_IS_EDITABLE);
        some_tasks_complete =
-               (state & E_TASK_SHELL_CONTENT_SELECTION_HAS_COMPLETE);
+               (state & E_CAL_BASE_SHELL_CONTENT_SELECTION_HAS_COMPLETE);
        some_tasks_incomplete =
-               (state & E_TASK_SHELL_CONTENT_SELECTION_HAS_INCOMPLETE);
+               (state & E_CAL_BASE_SHELL_CONTENT_SELECTION_HAS_INCOMPLETE);
        selection_has_url =
-               (state & E_TASK_SHELL_CONTENT_SELECTION_HAS_URL);
+               (state & E_CAL_BASE_SHELL_CONTENT_SELECTION_HAS_URL);
 
        shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
        state = e_shell_sidebar_check_state (shell_sidebar);
 
        has_primary_source =
-               (state & E_TASK_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE);
+               (state & E_CAL_BASE_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE);
        primary_source_is_writable =
-               (state & E_TASK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_WRITABLE);
+               (state & E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_WRITABLE);
        primary_source_is_removable =
-               (state & E_TASK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOVABLE);
+               (state & E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOVABLE);
        primary_source_is_remote_deletable =
-               (state & E_TASK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_DELETABLE);
+               (state & E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_REMOTE_DELETABLE);
        primary_source_in_collection =
-               (state & E_TASK_SHELL_SIDEBAR_PRIMARY_SOURCE_IN_COLLECTION);
+               (state & E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IN_COLLECTION);
        refresh_supported =
-               (state & E_TASK_SHELL_SIDEBAR_SOURCE_SUPPORTS_REFRESH);
+               (state & E_CAL_BASE_SHELL_SIDEBAR_SOURCE_SUPPORTS_REFRESH);
 
-       any_tasks_selected =
-               (single_task_selected || multiple_tasks_selected);
+       any_tasks_selected = (single_task_selected || multiple_tasks_selected);
 
        action = ACTION (TASK_ASSIGN);
        sensitive =
@@ -443,10 +385,72 @@ task_shell_view_update_actions (EShellView *shell_view)
 }
 
 static void
+task_shell_view_set_property (GObject *object,
+                              guint property_id,
+                              const GValue *value,
+                              GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_CONFIRM_PURGE:
+                       e_task_shell_view_set_confirm_purge (
+                               E_TASK_SHELL_VIEW (object),
+                               g_value_get_boolean (value));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+task_shell_view_get_property (GObject *object,
+                              guint property_id,
+                              GValue *value,
+                              GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_CONFIRM_PURGE:
+                       g_value_set_boolean (
+                               value, e_task_shell_view_get_confirm_purge (
+                               E_TASK_SHELL_VIEW (object)));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+task_shell_view_dispose (GObject *object)
+{
+       e_task_shell_view_private_dispose (E_TASK_SHELL_VIEW (object));
+
+       /* Chain up to parent's dispose() method. */
+       G_OBJECT_CLASS (e_task_shell_view_parent_class)->dispose (object);
+}
+
+static void
+task_shell_view_finalize (GObject *object)
+{
+       e_task_shell_view_private_finalize (E_TASK_SHELL_VIEW (object));
+
+       /* Chain up to parent's finalize() method. */
+       G_OBJECT_CLASS (e_task_shell_view_parent_class)->finalize (object);
+}
+
+static void
+task_shell_view_constructed (GObject *object)
+{
+       /* Chain up to parent's constructed() method. */
+       G_OBJECT_CLASS (e_task_shell_view_parent_class)->constructed (object);
+
+       e_task_shell_view_private_constructed (E_TASK_SHELL_VIEW (object));
+}
+
+static void
 e_task_shell_view_class_init (ETaskShellViewClass *class)
 {
        GObjectClass *object_class;
        EShellViewClass *shell_view_class;
+       ECalBaseShellViewClass *cal_base_shell_view_class;
 
        g_type_class_add_private (class, sizeof (ETaskShellViewPrivate));
 
@@ -465,10 +469,13 @@ e_task_shell_view_class_init (ETaskShellViewClass *class)
        shell_view_class->search_options = "/task-search-options";
        shell_view_class->search_rules = "tasktypes.xml";
        shell_view_class->new_shell_content = e_task_shell_content_new;
-       shell_view_class->new_shell_sidebar = e_task_shell_sidebar_new;
+       shell_view_class->new_shell_sidebar = e_cal_base_shell_sidebar_new;
        shell_view_class->execute_search = task_shell_view_execute_search;
        shell_view_class->update_actions = task_shell_view_update_actions;
 
+       cal_base_shell_view_class = E_CAL_BASE_SHELL_VIEW_CLASS (class);
+       cal_base_shell_view_class->source_type = E_CAL_CLIENT_SOURCE_TYPE_TASKS;
+
        g_object_class_install_property (
                object_class,
                PROP_CONFIRM_PURGE,
@@ -491,8 +498,7 @@ e_task_shell_view_class_finalize (ETaskShellViewClass *class)
 static void
 e_task_shell_view_init (ETaskShellView *task_shell_view)
 {
-       task_shell_view->priv =
-               E_TASK_SHELL_VIEW_GET_PRIVATE (task_shell_view);
+       task_shell_view->priv = E_TASK_SHELL_VIEW_GET_PRIVATE (task_shell_view);
 
        e_task_shell_view_private_init (task_shell_view);
 }
diff --git a/modules/calendar/e-task-shell-view.h b/modules/calendar/e-task-shell-view.h
index 70bd1ff..5974d34 100644
--- a/modules/calendar/e-task-shell-view.h
+++ b/modules/calendar/e-task-shell-view.h
@@ -1,5 +1,6 @@
 /*
- * e-task-shell-view.h
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
@@ -7,21 +8,18 @@
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
  * for more details.
  *
  * You should have received a copy of the GNU Lesser General Public License
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
  */
 
 #ifndef E_TASK_SHELL_VIEW_H
 #define E_TASK_SHELL_VIEW_H
 
-#include <shell/e-shell-view.h>
+#include <e-util/e-util.h>
+#include "e-cal-base-shell-view.h"
 
 /* Standard GObject macros */
 #define E_TYPE_TASK_SHELL_VIEW \
@@ -49,21 +47,19 @@ typedef struct _ETaskShellViewClass ETaskShellViewClass;
 typedef struct _ETaskShellViewPrivate ETaskShellViewPrivate;
 
 struct _ETaskShellView {
-       EShellView parent;
+       ECalBaseShellView parent;
        ETaskShellViewPrivate *priv;
 };
 
 struct _ETaskShellViewClass {
-       EShellViewClass parent_class;
+       ECalBaseShellViewClass parent_class;
 };
 
-GType          e_task_shell_view_get_type      (void);
-void           e_task_shell_view_type_register (GTypeModule *type_module);
-gboolean       e_task_shell_view_get_confirm_purge
-                                               (ETaskShellView *task_shell_view);
-void           e_task_shell_view_set_confirm_purge
-                                               (ETaskShellView *task_shell_view,
-                                                gboolean confirm_purge);
+GType          e_task_shell_view_get_type              (void);
+void           e_task_shell_view_type_register         (GTypeModule *type_module);
+gboolean       e_task_shell_view_get_confirm_purge     (ETaskShellView *task_shell_view);
+void           e_task_shell_view_set_confirm_purge     (ETaskShellView *task_shell_view,
+                                                        gboolean confirm_purge);
 
 G_END_DECLS
 
diff --git a/modules/calendar/evolution-module-calendar.c b/modules/calendar/evolution-module-calendar.c
index 0b55bdd..17e73b1 100644
--- a/modules/calendar/evolution-module-calendar.c
+++ b/modules/calendar/evolution-module-calendar.c
@@ -1,5 +1,6 @@
 /*
- * evolution-module-calendar.c
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
@@ -7,15 +8,11 @@
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
  * for more details.
  *
  * You should have received a copy of the GNU Lesser General Public License
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
  */
 
 #ifdef HAVE_CONFIG_H
@@ -27,23 +24,19 @@
 #include "e-cal-config-hook.h"
 #include "e-cal-event-hook.h"
 
+#include "e-calendar-preferences.h"
+
+#include "e-cal-base-shell-sidebar.h"
 #include "e-cal-shell-backend.h"
 #include "e-cal-shell-content.h"
-#include "e-cal-shell-sidebar.h"
 #include "e-cal-shell-view.h"
-
 #include "e-memo-shell-backend.h"
 #include "e-memo-shell-content.h"
-#include "e-memo-shell-sidebar.h"
 #include "e-memo-shell-view.h"
-
 #include "e-task-shell-backend.h"
 #include "e-task-shell-content.h"
-#include "e-task-shell-sidebar.h"
 #include "e-task-shell-view.h"
 
-#include "e-calendar-preferences.h"
-
 /* Module Entry Points */
 void e_module_load (GTypeModule *type_module);
 void e_module_unload (GTypeModule *type_module);
@@ -58,22 +51,18 @@ e_module_load (GTypeModule *type_module)
        e_cal_config_hook_register_type (type_module);
        e_cal_event_hook_register_type (type_module);
 
-       e_cal_shell_view_type_register (type_module);
+       e_calendar_preferences_type_register (type_module);
+
+       e_cal_base_shell_sidebar_type_register (type_module);
        e_cal_shell_backend_type_register (type_module);
        e_cal_shell_content_type_register (type_module);
-       e_cal_shell_sidebar_type_register (type_module);
-
-       e_memo_shell_view_type_register (type_module);
+       e_cal_shell_view_type_register (type_module);
        e_memo_shell_backend_type_register (type_module);
        e_memo_shell_content_type_register (type_module);
-       e_memo_shell_sidebar_type_register (type_module);
-
-       e_task_shell_view_type_register (type_module);
+       e_memo_shell_view_type_register (type_module);
        e_task_shell_backend_type_register (type_module);
        e_task_shell_content_type_register (type_module);
-       e_task_shell_sidebar_type_register (type_module);
-
-       e_calendar_preferences_type_register (type_module);
+       e_task_shell_view_type_register (type_module);
 }
 
 G_MODULE_EXPORT void
diff --git a/modules/itip-formatter/e-conflict-search-selector.c 
b/modules/itip-formatter/e-conflict-search-selector.c
index da4b93c..229a2ba 100644
--- a/modules/itip-formatter/e-conflict-search-selector.c
+++ b/modules/itip-formatter/e-conflict-search-selector.c
@@ -48,7 +48,7 @@ conflict_search_selector_get_source_selected (ESourceSelector *selector,
        return e_source_conflict_search_get_include_me (extension);
 }
 
-static void
+static gboolean
 conflict_search_selector_set_source_selected (ESourceSelector *selector,
                                            ESource *source,
                                            gboolean selected)
@@ -59,16 +59,20 @@ conflict_search_selector_set_source_selected (ESourceSelector *selector,
        /* Make sure this source is a calendar. */
        extension_name = e_source_selector_get_extension_name (selector);
        if (!e_source_has_extension (source, extension_name))
-               return;
+               return FALSE;
 
        extension_name = E_SOURCE_EXTENSION_CONFLICT_SEARCH;
        extension = e_source_get_extension (source, extension_name);
-       g_return_if_fail (E_IS_SOURCE_CONFLICT_SEARCH (extension));
+       g_return_val_if_fail (E_IS_SOURCE_CONFLICT_SEARCH (extension), FALSE);
 
        if (selected != e_source_conflict_search_get_include_me (extension)) {
                e_source_conflict_search_set_include_me (extension, selected);
                e_source_selector_queue_write (selector, source);
+
+               return TRUE;
        }
+
+       return FALSE;
 }
 
 static void
diff --git a/modules/itip-formatter/itip-view.c b/modules/itip-formatter/itip-view.c
index 64d075e..5e84b60 100644
--- a/modules/itip-formatter/itip-view.c
+++ b/modules/itip-formatter/itip-view.c
@@ -4615,11 +4615,11 @@ finish_message_delete_with_rsvp (EMailPartItip *pitip,
 
                e_cal_component_rescan (comp);
 
-               if (itip_send_comp (
+               if (itip_send_comp_sync (
                                view->priv->registry,
                                E_CAL_COMPONENT_METHOD_REPLY,
                                comp, pitip->current_client,
-                               pitip->top_level, NULL, NULL, TRUE, FALSE) &&
+                               pitip->top_level, NULL, NULL, TRUE, FALSE, NULL, NULL) &&
                                pitip->folder) {
                        camel_folder_set_message_flags (
                                pitip->folder, pitip->uid,
@@ -4922,9 +4922,9 @@ send_comp_to_attendee (ESourceRegistry *registry,
        }
 
        /* FIXME send the attachments in the request */
-       status = itip_send_comp (
+       status = itip_send_comp_sync (
                registry, method, send_comp,
-               client, NULL, NULL, NULL, TRUE, FALSE);
+               client, NULL, NULL, NULL, TRUE, FALSE, NULL, NULL);
 
        g_object_unref (send_comp);
 
@@ -5158,11 +5158,11 @@ update_attendee_status_icalcomp (EMailPartItip *pitip,
 
        if (itip_view_get_update (view)) {
                e_cal_component_commit_sequence (comp);
-               itip_send_comp (
+               itip_send_comp_sync (
                        view->priv->registry,
                        E_CAL_COMPONENT_METHOD_REQUEST,
                        comp, pitip->current_client,
-                       NULL, NULL, NULL, TRUE, FALSE);
+                       NULL, NULL, NULL, TRUE, FALSE, NULL, NULL);
        }
 
        update_item_progress_info (pitip, view, _("Saving changes to the calendar. Please wait..."));
@@ -5293,11 +5293,11 @@ send_item (EMailPartItip *pitip,
        comp = get_real_item (pitip);
 
        if (comp != NULL) {
-               itip_send_comp (
+               itip_send_comp_sync (
                        view->priv->registry,
                        E_CAL_COMPONENT_METHOD_REQUEST,
                        comp, pitip->current_client,
-                       NULL, NULL, NULL, TRUE, FALSE);
+                       NULL, NULL, NULL, TRUE, FALSE, NULL, NULL);
                g_object_unref (comp);
 
                switch (pitip->type) {
diff --git a/po/POTFILES.in b/po/POTFILES.in
index b22c6f9..02cd46f 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -53,7 +53,6 @@ calendar/gui/dialogs/comp-editor-page.c
 calendar/gui/dialogs/comp-editor-util.c
 calendar/gui/dialogs/copy-source-dialog.c
 calendar/gui/dialogs/delete-comp.c
-calendar/gui/dialogs/delete-error.c
 [type: gettext/glade]calendar/gui/dialogs/e-delegate-dialog.ui
 calendar/gui/dialogs/event-editor.c
 calendar/gui/dialogs/event-page.c
@@ -78,13 +77,12 @@ calendar/gui/ea-cal-view.c
 calendar/gui/ea-cal-view-event.c
 calendar/gui/ea-day-view.c
 calendar/gui/ea-day-view-main-item.c
-calendar/gui/ea-gnome-calendar.c
 calendar/gui/ea-jump-button.c
 calendar/gui/e-alarm-list.c
 calendar/gui/ea-week-view.c
 calendar/gui/ea-week-view-main-item.c
 calendar/gui/e-cal-component-preview.c
-calendar/gui/e-calendar-selector.c
+calendar/gui/e-cal-data-model.c
 calendar/gui/e-calendar-table.etspec
 calendar/gui/e-calendar-view.c
 calendar/gui/e-cal-list-view.c
@@ -92,6 +90,7 @@ calendar/gui/e-cal-list-view.etspec
 calendar/gui/e-cal-model.c
 calendar/gui/e-cal-model-calendar.c
 calendar/gui/e-cal-model-tasks.c
+calendar/gui/e-cal-ops.c
 calendar/gui/e-cell-date-edit-text.c
 calendar/gui/e-day-view.c
 calendar/gui/e-day-view-time-item.c
@@ -107,7 +106,6 @@ calendar/gui/e-task-table.c
 calendar/gui/e-timezone-entry.c
 calendar/gui/e-week-view.c
 calendar/gui/e-week-view-main-item.c
-calendar/gui/gnome-cal.c
 calendar/gui/itip-utils.c
 calendar/gui/memotypes.xml
 calendar/gui/misc.c
@@ -182,6 +180,7 @@ e-util/e-activity-proxy.c
 e-util/e-activity.c
 e-util/e-alert-bar.c
 e-util/e-alert-dialog.c
+e-util/e-alert-sink.c
 e-util/e-attachment-bar.c
 e-util/e-attachment-dialog.c
 e-util/e-attachment-handler-image.c
@@ -420,10 +419,11 @@ modules/cal-config-webcal/evolution-cal-config-webcal.c
 modules/calendar/e-cal-attachment-handler.c
 modules/calendar/e-calendar-preferences.c
 [type: gettext/glade]modules/calendar/e-calendar-preferences.ui
+modules/calendar/e-cal-base-shell-backend.c
+modules/calendar/e-cal-base-shell-sidebar.c
 modules/calendar/e-cal-shell-backend.c
 modules/calendar/e-cal-shell-content.c
 modules/calendar/e-cal-shell-migrate.c
-modules/calendar/e-cal-shell-sidebar.c
 modules/calendar/e-cal-shell-view-actions.c
 modules/calendar/e-cal-shell-view.c
 modules/calendar/e-cal-shell-view-memopad.c
@@ -432,14 +432,12 @@ modules/calendar/e-cal-shell-view-taskpad.c
 modules/calendar/e-memo-shell-backend.c
 modules/calendar/e-memo-shell-content.c
 modules/calendar/e-memo-shell-migrate.c
-modules/calendar/e-memo-shell-sidebar.c
 modules/calendar/e-memo-shell-view-actions.c
 modules/calendar/e-memo-shell-view.c
 modules/calendar/e-memo-shell-view-private.c
 modules/calendar/e-task-shell-backend.c
 modules/calendar/e-task-shell-content.c
 modules/calendar/e-task-shell-migrate.c
-modules/calendar/e-task-shell-sidebar.c
 modules/calendar/e-task-shell-view-actions.c
 modules/calendar/e-task-shell-view.c
 modules/calendar/e-task-shell-view-private.c
diff --git a/shell/e-shell-view.c b/shell/e-shell-view.c
index e3885ff..7362a01 100644
--- a/shell/e-shell-view.c
+++ b/shell/e-shell-view.c
@@ -45,6 +45,7 @@
 #define STATE_SAVE_TIMEOUT_SECONDS 3
 
 struct _EShellViewPrivate {
+       GThread *main_thread; /* not referenced */
 
        gpointer shell_window;  /* weak pointer */
 
@@ -1085,6 +1086,7 @@ e_shell_view_init (EShellView *shell_view,
        size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
 
        shell_view->priv = E_SHELL_VIEW_GET_PRIVATE (shell_view);
+       shell_view->priv->main_thread = g_thread_self ();
        shell_view->priv->state_key_file = g_key_file_new ();
        shell_view->priv->size_group = size_group;
 }
@@ -2020,3 +2022,67 @@ e_shell_view_remote_delete_source (EShellView *shell_view,
        e_shell_backend_add_activity (shell_backend, activity);
 }
 
+/**
+ * e_shell_view_submit_thread_job:
+ * @shell_view: an #EShellView instance
+ * @description: user-friendly description of the job, to be shown in UI
+ * @alert_ident: in case of an error, this alert identificator is used
+ *    for EAlert construction
+ * @alert_arg_0: (allow-none): in case of an error, use this string as
+ *    the first argument to the EAlert construction; the second argument
+ *    is the actual error message; can be #NULL, in which case only
+ *    the error message is passed to the EAlert construction
+ * @func: function to be run in a dedicated thread
+ * @user_data: (allow-none): custom data passed into @func; can be #NULL
+ * @free_user_data: (allow-none): function to be called on @user_data,
+ *   when the job is over; can be #NULL
+ *
+ * Runs the @func in a dedicated thread. Any error is propagated to UI.
+ * The cancellable passed into the @func is a #CamelOperation, thus
+ * the caller can overwrite progress and description message on it.
+ *
+ * Returns: (transfer full): Newly created #EActivity on success.
+ *   The caller is responsible to g_object_unref() it when done with it.
+ *
+ * Note: The @free_user_data, if set, is called in the main thread.
+ *
+ * Note: This function can be called only from the main thread.
+ **/
+EActivity *
+e_shell_view_submit_thread_job (EShellView *shell_view,
+                               const gchar *description,
+                               const gchar *alert_ident,
+                               const gchar *alert_arg_0,
+                               EAlertSinkThreadJobFunc func,
+                               gpointer user_data,
+                               GDestroyNotify free_user_data)
+{
+       EShellBackend *shell_backend;
+       EShellContent *shell_content;
+       EActivity *activity;
+       EAlertSink *alert_sink;
+
+       g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
+       g_return_val_if_fail (description != NULL, NULL);
+       g_return_val_if_fail (func != NULL, NULL);
+       g_return_val_if_fail (g_thread_self () == shell_view->priv->main_thread, NULL);
+
+       shell_backend = e_shell_view_get_shell_backend (shell_view);
+       shell_content = e_shell_view_get_shell_content (shell_view);
+
+       alert_sink = E_ALERT_SINK (shell_content);
+
+       activity = e_alert_sink_submit_thread_job (
+               alert_sink,
+               description,
+               alert_ident,
+               alert_arg_0,
+               func,
+               user_data,
+               free_user_data);
+
+       if (activity)
+               e_shell_backend_add_activity (shell_backend, activity);
+
+       return activity;
+}
diff --git a/shell/e-shell-view.h b/shell/e-shell-view.h
index 65df572..cdbebc4 100644
--- a/shell/e-shell-view.h
+++ b/shell/e-shell-view.h
@@ -246,6 +246,14 @@ void               e_shell_view_remote_delete_source
                                                (EShellView *shell_view,
                                                 ESource *source);
 
+EActivity *    e_shell_view_submit_thread_job  (EShellView *shell_view,
+                                                const gchar *description,
+                                                const gchar *alert_ident,
+                                                const gchar *alert_arg_0,
+                                                EAlertSinkThreadJobFunc func,
+                                                gpointer user_data,
+                                                GDestroyNotify free_user_data);
+
 G_END_DECLS
 
 #endif /* E_SHELL_VIEW_H */
diff --git a/shell/e-shell-window.c b/shell/e-shell-window.c
index 70187c9..1b445d3 100644
--- a/shell/e-shell-window.c
+++ b/shell/e-shell-window.c
@@ -1610,6 +1610,122 @@ e_shell_window_set_toolbar_visible (EShellWindow *shell_window,
        g_object_notify (G_OBJECT (shell_window), "toolbar-visible");
 }
 
+typedef struct {
+       EShellWindow *shell_window;
+       ESource *source;
+       gchar *extension_name;
+       EShellWindowConnetClientFunc connected_cb;
+       gpointer user_data;
+       GDestroyNotify destroy_user_data;
+
+       EClient *client;
+} ConnectClientData;
+
+static void
+connect_client_data_free (gpointer ptr)
+{
+       ConnectClientData *cc_data = ptr;
+
+       if (cc_data) {
+               if (cc_data->client && cc_data->connected_cb)
+                       cc_data->connected_cb (cc_data->shell_window, cc_data->client, cc_data->user_data);
+
+               g_clear_object (&cc_data->shell_window);
+               g_clear_object (&cc_data->source);
+               g_clear_object (&cc_data->client);
+               g_free (cc_data->extension_name);
+
+               if (cc_data->destroy_user_data)
+                       cc_data->destroy_user_data (cc_data->user_data);
+
+               g_free (cc_data);
+       }
+}
+
+static void
+shell_window_connect_client_thread (EAlertSinkThreadJobData *job_data,
+                                   gpointer user_data,
+                                   GCancellable *cancellable,
+                                   GError **error)
+{
+       ConnectClientData *cc_data = user_data;
+       EShell *shell;
+       EClientCache *client_cache;
+       GError *local_error = NULL;
+
+       g_return_if_fail (cc_data != NULL);
+
+       shell = e_shell_window_get_shell (cc_data->shell_window);
+       client_cache = e_shell_get_client_cache (shell);
+
+       cc_data->client = e_client_cache_get_client_sync (client_cache,
+               cc_data->source, cc_data->extension_name, cancellable, &local_error);
+
+       e_util_propagate_open_source_job_error (job_data, cc_data->extension_name, local_error, error);
+}
+
+/**
+ * e_shell_window_connect_client:
+ * @shell_window: an #EShellWindow
+ * @source: an #ESource to connect to
+ * @extension_name: an extension name
+ * @connected_cb: a callback to be called when the client is opened
+ * @user_data: a user data passed to @connected_cb
+ * @destroy_user_data: (allow none): callback to free @user_data when no longer needed
+ *
+ * Get's an #EClient from shell's #EClientCache in a dedicated thread, thus
+ * the operation doesn't block UI. The @connected_cb is called in the main thread,
+ * but only when the operation succeeded. Any failure is propageted to UI.
+ *
+ * Since: 3.14
+ **/
+void
+e_shell_window_connect_client (EShellWindow *shell_window,
+                              ESource *source,
+                              const gchar *extension_name,
+                              EShellWindowConnetClientFunc connected_cb,
+                              gpointer user_data,
+                              GDestroyNotify destroy_user_data)
+{
+       ConnectClientData *cc_data;
+       EShellView *shell_view;
+       EActivity *activity;
+       gchar *description = NULL, *alert_ident = NULL, *alert_arg_0 = NULL;
+
+       g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
+       g_return_if_fail (E_IS_SOURCE (source));
+       g_return_if_fail (extension_name != NULL);
+       g_return_if_fail (connected_cb != NULL);
+
+       shell_view = e_shell_window_get_shell_view (shell_window,
+               e_shell_window_get_active_view (shell_window));
+
+       g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
+
+       if (!e_util_get_open_source_job_info (extension_name, e_source_get_display_name (source),
+               &description, &alert_ident, &alert_arg_0)) {
+               g_warn_if_reached ();
+               return;
+       }
+
+       cc_data = g_new0 (ConnectClientData, 1);
+       cc_data->shell_window = g_object_ref (shell_window);
+       cc_data->source = g_object_ref (source);
+       cc_data->extension_name = g_strdup (extension_name);
+       cc_data->connected_cb = connected_cb;
+       cc_data->user_data = user_data;
+       cc_data->destroy_user_data = destroy_user_data;
+       cc_data->client = NULL;
+
+       activity = e_shell_view_submit_thread_job (shell_view, description, alert_ident, alert_arg_0,
+               shell_window_connect_client_thread, cc_data, connect_client_data_free);
+
+       g_clear_object (&activity);
+       g_free (description);
+       g_free (alert_ident);
+       g_free (alert_arg_0);
+}
+
 /**
  * e_shell_window_register_new_item_actions:
  * @shell_window: an #EShellWindow
diff --git a/shell/e-shell-window.h b/shell/e-shell-window.h
index 3025aa0..49754e7 100644
--- a/shell/e-shell-window.h
+++ b/shell/e-shell-window.h
@@ -135,6 +135,20 @@ void               e_shell_window_set_toolbar_visible
                                                (EShellWindow *shell_window,
                                                 gboolean toolbar_visible);
 
+/* Helper function to open clients from shell's client cache in a dedicated
+   thread with a callback being called in the main thread */
+
+typedef void (* EShellWindowConnetClientFunc)  (EShellWindow *shell_window,
+                                                EClient *client,
+                                                gpointer user_data);
+
+void           e_shell_window_connect_client   (EShellWindow *shell_window,
+                                                ESource *source,
+                                                const gchar *extension_name,
+                                                EShellWindowConnetClientFunc connected_cb,
+                                                gpointer user_data,
+                                                GDestroyNotify destroy_user_data);
+
 /* These should be called from the shell backend's window_created() handler. */
 
 void           e_shell_window_register_new_item_actions


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