[evolution] I#95 - Calendar: Show all calendar events in the List View



commit 41f5e390b5a914a469899fd7ca21254ba86016fe
Author: Milan Crha <mcrha redhat com>
Date:   Fri Nov 13 09:53:45 2020 +0100

    I#95 - Calendar: Show all calendar events in the List View
    
    Closes https://gitlab.gnome.org/GNOME/evolution/-/issues/95

 src/calendar/gui/e-cal-data-model.c             |  33 +++++
 src/calendar/gui/e-cal-data-model.h             |   2 +
 src/calendar/gui/e-cal-list-view.c              | 118 +++++----------
 src/calendar/gui/e-cal-list-view.h              |   3 -
 src/calendar/gui/e-cal-model.c                  |  41 +++---
 src/calendar/gui/e-calendar-view.c              | 116 ++++++++-------
 src/calendar/gui/e-calendar-view.h              |   1 +
 src/modules/calendar/e-cal-base-shell-sidebar.c |  47 ++++--
 src/modules/calendar/e-cal-base-shell-sidebar.h |   8 ++
 src/modules/calendar/e-cal-shell-content.c      | 184 +++++++++++++++++++++++-
 src/modules/calendar/e-cal-shell-content.h      |   2 +
 src/modules/calendar/e-cal-shell-view-private.c |  22 +++
 src/modules/calendar/e-cal-shell-view.c         |  16 ++-
 13 files changed, 423 insertions(+), 170 deletions(-)
---
diff --git a/src/calendar/gui/e-cal-data-model.c b/src/calendar/gui/e-cal-data-model.c
index 325f3b2e01..1bc43627e4 100644
--- a/src/calendar/gui/e-cal-data-model.c
+++ b/src/calendar/gui/e-cal-data-model.c
@@ -2557,6 +2557,39 @@ e_cal_data_model_remove_client (ECalDataModel *data_model,
        UNLOCK_PROPS ();
 }
 
+static gboolean
+cal_data_model_remove_client_cb (gpointer key,
+                                gpointer value,
+                                gpointer user_data)
+{
+       ECalDataModel *data_model = user_data;
+
+       cal_data_model_remove_client_view (data_model, value);
+
+       return TRUE;
+}
+
+/**
+ * e_cal_data_model_remove_all_clients:
+ * @data_model: an #ECalDataModel
+ *
+ * Removes all clients from the @data_model.
+ *
+ * Since: 3.40
+ **/
+void
+e_cal_data_model_remove_all_clients (ECalDataModel *data_model)
+{
+       g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model));
+
+       LOCK_PROPS ();
+
+       g_hash_table_foreach_remove (data_model->priv->clients,
+               cal_data_model_remove_client_cb, data_model);
+
+       UNLOCK_PROPS ();
+}
+
 /**
  * e_cal_data_model_ref_client:
  * @data_model: an #EDataModel instance
diff --git a/src/calendar/gui/e-cal-data-model.h b/src/calendar/gui/e-cal-data-model.h
index 15ce5e708a..ea317e5303 100644
--- a/src/calendar/gui/e-cal-data-model.h
+++ b/src/calendar/gui/e-cal-data-model.h
@@ -117,6 +117,8 @@ 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);
+void           e_cal_data_model_remove_all_clients
+                                               (ECalDataModel *data_model);
 ECalClient *   e_cal_data_model_ref_client     (ECalDataModel *data_model,
                                                 const gchar *uid);
 GList *                e_cal_data_model_get_clients    (ECalDataModel *data_model);
diff --git a/src/calendar/gui/e-cal-list-view.c b/src/calendar/gui/e-cal-list-view.c
index 22430f4b9c..3536376ecd 100644
--- a/src/calendar/gui/e-cal-list-view.c
+++ b/src/calendar/gui/e-cal-list-view.c
@@ -55,7 +55,8 @@ enum {
 /* The icons to represent the event. */
 static const gchar *icon_names[] = {
        "x-office-calendar",
-       "stock_people"
+       "stock_people",
+       "view-refresh"
 };
 
 static void      e_cal_list_view_dispose                (GObject *object);
@@ -96,6 +97,34 @@ e_cal_list_view_get_property (GObject *object,
        }
 }
 
+static gchar *
+e_cal_list_view_get_description_text (ECalendarView *cal_view)
+{
+       ECalModel *model;
+       GString *string;
+       const gchar *format;
+       gint n_rows;
+       gint n_selected;
+
+       g_return_val_if_fail (E_IS_CAL_LIST_VIEW (cal_view), NULL);
+
+       model = e_calendar_view_get_model (cal_view);
+       n_rows = e_table_model_row_count (E_TABLE_MODEL (model));
+       n_selected = e_table_selected_count (e_cal_list_view_get_table (E_CAL_LIST_VIEW (cal_view)));
+       string = g_string_sized_new (64);
+
+       format = ngettext ("%d appointment", "%d appointments", n_rows);
+       g_string_append_printf (string, format, n_rows);
+
+       if (n_selected > 0) {
+               format = _("%d selected");
+               g_string_append_len (string, ", ", 2);
+               g_string_append_printf (string, format, n_selected);
+       }
+
+       return g_string_free (string, FALSE);
+}
+
 static void
 e_cal_list_view_class_init (ECalListViewClass *class)
 {
@@ -118,6 +147,7 @@ e_cal_list_view_class_init (ECalListViewClass *class)
        view_class->get_selected_events = e_cal_list_view_get_selected_events;
        view_class->get_selected_time_range = e_cal_list_view_get_selected_time_range;
        view_class->get_visible_time_range = e_cal_list_view_get_visible_time_range;
+       view_class->get_description_text = e_cal_list_view_get_description_text;
 
        g_object_class_override_property (
                object_class,
@@ -313,7 +343,7 @@ setup_e_table (ECalListView *cal_list_view)
        gtk_scrolled_window_set_policy (
                GTK_SCROLLED_WINDOW (widget),
                GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-       gtk_grid_attach (GTK_GRID (container), widget, 0, 0, 2, 2);
+       gtk_grid_attach (GTK_GRID (container), widget, 0, 1, 2, 2);
        g_object_set (G_OBJECT (widget),
                "hexpand", TRUE,
                "vexpand", TRUE,
@@ -611,74 +641,12 @@ e_cal_list_view_get_selected_events (ECalendarView *cal_view)
        return event_list;
 }
 
-/* It also frees 'itt' */
-static void
-adjust_range (ICalTime *itt,
-              time_t *earliest,
-              time_t *latest,
-              gboolean *set)
-{
-       time_t t;
-
-       if (!itt || !i_cal_time_is_valid_time (itt)) {
-               g_clear_object (&itt);
-               return;
-       }
-
-       t = i_cal_time_as_timet (itt);
-
-       *earliest = MIN (*earliest, t);
-       *latest   = MAX (*latest, t);
-       *set = TRUE;
-
-       g_clear_object (&itt);
-}
-
-/* NOTE: Time use for this function increases linearly with number of events.
- * This is not ideal, since it's used in a couple of places. We could probably
- * be smarter about it, and use do it less frequently... */
 static gboolean
 e_cal_list_view_get_visible_time_range (ECalendarView *cal_view,
                                         time_t *start_time,
                                         time_t *end_time)
 {
-       time_t   earliest = G_MAXINT, latest = 0;
-       gboolean set = FALSE;
-       gint     n_rows, i;
-
-       n_rows = e_table_model_row_count (E_TABLE_MODEL (e_calendar_view_get_model (cal_view)));
-
-       for (i = 0; i < n_rows; i++) {
-               ECalModelComponent *comp;
-               ICalComponent *icomp;
-
-               comp = e_cal_model_get_component_at (e_calendar_view_get_model (cal_view), i);
-               if (!comp)
-                       continue;
-
-               icomp = comp->icalcomp;
-               if (!icomp)
-                       continue;
-
-               adjust_range (i_cal_component_get_dtstart (icomp), &earliest, &latest, &set);
-               adjust_range (i_cal_component_get_dtend (icomp), &earliest, &latest, &set);
-       }
-
-       if (set) {
-               *start_time = earliest;
-               *end_time   = latest;
-               return TRUE;
-       }
-
-       if (!n_rows) {
-               ECalModel *model = e_calendar_view_get_model (cal_view);
-
-               /* Use time range set in the model when nothing shown in the list view */
-               e_cal_model_get_time_range (model, start_time, end_time);
-
-               return TRUE;
-       }
-
+       /* No time range */
        return FALSE;
 }
 
@@ -690,26 +658,6 @@ e_cal_list_view_get_table (ECalListView *cal_list_view)
        return cal_list_view->priv->table;
 }
 
-gboolean
-e_cal_list_view_get_range_shown (ECalListView *cal_list_view,
-                                 GDate *start_date,
-                                 gint *days_shown)
-{
-       time_t  first, last;
-       GDate   end_date;
-
-       g_return_val_if_fail (E_IS_CAL_LIST_VIEW (cal_list_view), FALSE);
-
-       if (!e_cal_list_view_get_visible_time_range (E_CALENDAR_VIEW (cal_list_view), &first, &last))
-               return FALSE;
-
-       time_to_gdate_with_zone (start_date, first, e_calendar_view_get_timezone (E_CALENDAR_VIEW 
(cal_list_view)));
-       time_to_gdate_with_zone (&end_date, last, e_calendar_view_get_timezone (E_CALENDAR_VIEW 
(cal_list_view)));
-
-       *days_shown = g_date_days_between (start_date, &end_date);
-       return TRUE;
-}
-
 gboolean
 e_cal_list_view_is_editing (ECalListView *eclv)
 {
diff --git a/src/calendar/gui/e-cal-list-view.h b/src/calendar/gui/e-cal-list-view.h
index 985955d4a0..272efa3d5b 100644
--- a/src/calendar/gui/e-cal-list-view.h
+++ b/src/calendar/gui/e-cal-list-view.h
@@ -72,9 +72,6 @@ struct _ECalListViewClass {
 GType          e_cal_list_view_get_type        (void);
 ECalendarView *        e_cal_list_view_new             (ECalModel *cal_model);
 ETable *       e_cal_list_view_get_table       (ECalListView *cal_list_view);
-gboolean       e_cal_list_view_get_range_shown (ECalListView *cal_list_view,
-                                                GDate *start_date,
-                                                gint *days_shown);
 gboolean       e_cal_list_view_is_editing      (ECalListView *eclv);
 
 G_END_DECLS
diff --git a/src/calendar/gui/e-cal-model.c b/src/calendar/gui/e-cal-model.c
index 2a622e3ce4..860683c8e7 100644
--- a/src/calendar/gui/e-cal-model.c
+++ b/src/calendar/gui/e-cal-model.c
@@ -1573,8 +1573,13 @@ cal_model_value_at (ETableModel *etm,
 
                retval = 0;
 
-               if (i_cal_component_isa (comp_data->icalcomp) == I_CAL_VEVENT_COMPONENT ||
-                   i_cal_component_isa (comp_data->icalcomp) == I_CAL_VJOURNAL_COMPONENT) {
+               if (i_cal_component_isa (comp_data->icalcomp) == I_CAL_VEVENT_COMPONENT) {
+                       if (e_cal_util_component_has_attendee (comp_data->icalcomp))
+                               retval = 1;
+                       if (e_cal_util_component_has_recurrences (comp_data->icalcomp) ||
+                           e_cal_util_component_is_instance (comp_data->icalcomp))
+                               retval = 2;
+               } else if (i_cal_component_isa (comp_data->icalcomp) == I_CAL_VJOURNAL_COMPONENT) {
                        if (e_cal_util_component_has_attendee (comp_data->icalcomp))
                                retval = 1;
                } else {
@@ -3630,27 +3635,29 @@ e_cal_model_remove_all_objects (ECalModel *model)
 {
        ECalModelComponent *comp_data;
        ETableModel *table_model;
-       GSList *link;
-       gint index;
+       GSList *comps = NULL;
+       guint ii;
 
        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_remove_index (model->priv->objects, index);
-               if (!comp_data) {
-                       e_table_model_no_change (table_model);
-                       continue;
-               }
+       for (ii = 0; ii < model->priv->objects->len; ii++) {
+               comp_data = g_ptr_array_index (model->priv->objects, ii);
 
-               link = g_slist_append (NULL, comp_data);
-               g_signal_emit (model, signals[COMPS_DELETED], 0, link);
+               if (comp_data)
+                       comps = g_slist_prepend (comps, comp_data);
+       }
 
-               g_slist_free (link);
-               g_object_unref (comp_data);
+       ii = model->priv->objects->len;
 
-               e_table_model_row_deleted (table_model, index);
-       }
+       e_table_model_pre_change (table_model);
+       e_table_model_rows_deleted (table_model, 0, ii);
+
+       g_ptr_array_set_size (model->priv->objects, 0);
+
+       if (comps)
+               g_signal_emit (model, signals[COMPS_DELETED], 0, comps);
+
+       g_slist_free_full (comps, g_object_unref);
 }
 
 void
diff --git a/src/calendar/gui/e-calendar-view.c b/src/calendar/gui/e-calendar-view.c
index 7d9e6e9e34..d0826fd195 100644
--- a/src/calendar/gui/e-calendar-view.c
+++ b/src/calendar/gui/e-calendar-view.c
@@ -1110,6 +1110,66 @@ calendar_view_delete_selection (ESelectable *selectable)
        g_list_free (selected);
 }
 
+static gchar *
+calendar_view_get_description_text (ECalendarView *cal_view)
+{
+       time_t start_time, end_time;
+       struct tm start_tm, end_tm;
+       ICalTime *tt;
+       ICalTimezone *zone;
+       gchar start_buffer[512] = { 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);
+
+       tt = i_cal_time_new_from_timet_with_zone (start_time, FALSE, zone);
+       start_tm = e_cal_util_icaltime_to_tm (tt);
+       g_clear_object (&tt);
+
+       /* Subtract one from end_time so we don't get an extra day. */
+       tt = i_cal_time_new_from_timet_with_zone (end_time - 1, FALSE, zone);
+       end_tm = e_cal_util_icaltime_to_tm (tt);
+       g_clear_object (&tt);
+
+       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 (start_buffer, sizeof (start_buffer), "%d", &start_tm);
+                               e_utf8_strftime (end_buffer, sizeof (end_buffer), _("%d %b %Y"), &end_tm);
+                       } else {
+                               e_utf8_strftime (start_buffer, sizeof (start_buffer), _("%d %b"), &start_tm);
+                               e_utf8_strftime (end_buffer, sizeof (end_buffer), _("%d %b %Y"), &end_tm);
+                       }
+               } else {
+                       e_utf8_strftime (start_buffer, sizeof (start_buffer), _("%d %b %Y"), &start_tm);
+                       e_utf8_strftime (end_buffer, sizeof (end_buffer), _("%d %b %Y"), &end_tm);
+               }
+       } 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 (start_buffer, sizeof (start_buffer), _("%A %d %b %Y"), &start_tm);
+               } else if (start_tm.tm_year == end_tm.tm_year) {
+                       e_utf8_strftime (start_buffer, sizeof (start_buffer), _("%a %d %b"), &start_tm);
+                       e_utf8_strftime (end_buffer, sizeof (end_buffer), _("%a %d %b %Y"), &end_tm);
+               } else {
+                       e_utf8_strftime (start_buffer, sizeof (start_buffer), _("%a %d %b %Y"), &start_tm);
+                       e_utf8_strftime (end_buffer, sizeof (end_buffer), _("%a %d %b %Y"), &end_tm);
+               }
+       }
+
+       if (*start_buffer && *end_buffer)
+               return g_strdup_printf ("%s - %s", start_buffer, end_buffer);
+
+       return g_strdup_printf ("%s%s", start_buffer, end_buffer);
+}
+
 static void
 e_calendar_view_class_init (ECalendarViewClass *class)
 {
@@ -1138,6 +1198,7 @@ e_calendar_view_class_init (ECalendarViewClass *class)
        class->update_query = NULL;
        class->open_event = e_calendar_view_open_event;
        class->paste_text = NULL;
+       class->get_description_text = calendar_view_get_description_text;
 
        /* Inherited from ESelectableInterface */
        g_object_class_override_property (
@@ -2324,60 +2385,17 @@ e_calendar_view_is_editing (ECalendarView *cal_view)
 gchar *
 e_calendar_view_get_description_text (ECalendarView *cal_view)
 {
-       time_t start_time, end_time;
-       struct tm start_tm, end_tm;
-       ICalTime *tt;
-       ICalTimezone *zone;
-       gchar start_buffer[512] = { 0 };
-       gchar end_buffer[512] = { 0 };
+       ECalendarViewClass *klass;
 
        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);
-
-       tt = i_cal_time_new_from_timet_with_zone (start_time, FALSE, zone);
-       start_tm = e_cal_util_icaltime_to_tm (tt);
-       g_clear_object (&tt);
-
-       /* Subtract one from end_time so we don't get an extra day. */
-       tt = i_cal_time_new_from_timet_with_zone (end_time - 1, FALSE, zone);
-       end_tm = e_cal_util_icaltime_to_tm (tt);
-       g_clear_object (&tt);
-
-       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 (start_buffer, sizeof (start_buffer), "%d", &start_tm);
-                               e_utf8_strftime (end_buffer, sizeof (end_buffer), _("%d %b %Y"), &end_tm);
-                       } else {
-                               e_utf8_strftime (start_buffer, sizeof (start_buffer), _("%d %b"), &start_tm);
-                               e_utf8_strftime (end_buffer, sizeof (end_buffer), _("%d %b %Y"), &end_tm);
-                       }
-               } else {
-                       e_utf8_strftime (start_buffer, sizeof (start_buffer), _("%d %b %Y"), &start_tm);
-                       e_utf8_strftime (end_buffer, sizeof (end_buffer), _("%d %b %Y"), &end_tm);
-               }
-       } 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 (start_buffer, sizeof (start_buffer), _("%A %d %b %Y"), &start_tm);
-               } else if (start_tm.tm_year == end_tm.tm_year) {
-                       e_utf8_strftime (start_buffer, sizeof (start_buffer), _("%a %d %b"), &start_tm);
-                       e_utf8_strftime (end_buffer, sizeof (end_buffer), _("%a %d %b %Y"), &end_tm);
-               } else {
-                       e_utf8_strftime (start_buffer, sizeof (start_buffer), _("%a %d %b %Y"), &start_tm);
-                       e_utf8_strftime (end_buffer, sizeof (end_buffer), _("%a %d %b %Y"), &end_tm);
-               }
-       }
+       klass = E_CALENDAR_VIEW_GET_CLASS (cal_view);
+       g_return_val_if_fail (klass != NULL, NULL);
 
-       if (*start_buffer && *end_buffer)
-               return g_strdup_printf ("%s - %s", start_buffer, end_buffer);
+       if (klass->get_description_text)
+               return klass->get_description_text (cal_view);
 
-       return g_strdup_printf ("%s%s", start_buffer, end_buffer);
+       return NULL;
 }
 
 void
diff --git a/src/calendar/gui/e-calendar-view.h b/src/calendar/gui/e-calendar-view.h
index 8ed9ffd0db..03c56401ab 100644
--- a/src/calendar/gui/e-calendar-view.h
+++ b/src/calendar/gui/e-calendar-view.h
@@ -183,6 +183,7 @@ struct _ECalendarViewClass {
        void            (*update_query)         (ECalendarView *cal_view);
        void            (*open_event)           (ECalendarView *cal_view);
        void            (*paste_text)           (ECalendarView *cal_view);
+       gchar *         (*get_description_text) (ECalendarView *cal_view);
 };
 
 GType          e_calendar_view_get_type        (void);
diff --git a/src/modules/calendar/e-cal-base-shell-sidebar.c b/src/modules/calendar/e-cal-base-shell-sidebar.c
index 5644d7aa39..0ddc5112d4 100644
--- a/src/modules/calendar/e-cal-base-shell-sidebar.c
+++ b/src/modules/calendar/e-cal-base-shell-sidebar.c
@@ -302,6 +302,8 @@ typedef struct _OpenClientData {
        ESource *source;
        EClient *client;
        gboolean was_cancelled;
+       ECalBaseShellSidebarOpenFunc cb;
+       gpointer cb_user_data;
 } OpenClientData;
 
 static void
@@ -310,12 +312,19 @@ open_client_data_free (gpointer pdata)
        OpenClientData *data = pdata;
 
        if (data) {
-               /* To free the cancellable in the 'value' pair, which is useless now */
-               g_hash_table_insert (data->sidebar->priv->selected_uids,
-                       g_strdup (e_source_get_uid (data->source)),
-                       NULL);
+               if (data->cb || !data->client) {
+                       g_hash_table_remove (data->sidebar->priv->selected_uids, e_source_get_uid 
(data->source));
+               } else {
+                       /* To free the cancellable in the 'value' pair, which is useless now */
+                       g_hash_table_insert (data->sidebar->priv->selected_uids,
+                               g_strdup (e_source_get_uid (data->source)),
+                               NULL);
+               }
 
-               if (data->client) {
+               if (data->cb) {
+                       if (data->client)
+                               data->cb (data->sidebar, data->client, data->cb_user_data);
+               } else if (data->client) {
                        g_signal_emit (data->sidebar, signals[CLIENT_OPENED], 0, data->client);
                } else if (!data->was_cancelled) {
                        ESourceSelector *selector = e_cal_base_shell_sidebar_get_selector (data->sidebar);
@@ -351,7 +360,9 @@ e_cal_base_shell_sidebar_open_client_thread (EAlertSinkThreadJobData *job_data,
 
 static void
 e_cal_base_shell_sidebar_ensure_source_opened (ECalBaseShellSidebar *sidebar,
-                                              ESource *source)
+                                              ESource *source,
+                                              ECalBaseShellSidebarOpenFunc cb,
+                                              gpointer cb_user_data)
 {
        OpenClientData *data;
        EShellView *shell_view;
@@ -362,8 +373,8 @@ e_cal_base_shell_sidebar_ensure_source_opened (ECalBaseShellSidebar *sidebar,
        g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (sidebar));
        g_return_if_fail (E_IS_SOURCE (source));
 
-       /* Skip it when it's already opening or opened */
-       if (g_hash_table_contains (sidebar->priv->selected_uids, e_source_get_uid (source)))
+       /* Skip it when it's already opening or opened and the callback is not set */
+       if (!cb && g_hash_table_contains (sidebar->priv->selected_uids, e_source_get_uid (source)))
                return;
 
        shell_view = e_shell_sidebar_get_shell_view (E_SHELL_SIDEBAR (sidebar));
@@ -398,6 +409,8 @@ e_cal_base_shell_sidebar_ensure_source_opened (ECalBaseShellSidebar *sidebar,
        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);
+       data->cb = cb;
+       data->cb_user_data = cb_user_data;
 
        activity = e_shell_view_submit_thread_job (
                shell_view, description, alert_ident, alert_arg_0,
@@ -440,7 +453,7 @@ e_cal_base_shell_sidebar_source_selected (ESourceSelector *selector,
        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);
+               e_cal_base_shell_sidebar_ensure_source_opened (sidebar, source, NULL, NULL);
        }
 }
 
@@ -961,8 +974,22 @@ e_cal_base_shell_sidebar_ensure_sources_open (ECalBaseShellSidebar *cal_base_she
        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);
+               e_cal_base_shell_sidebar_ensure_source_opened (cal_base_shell_sidebar, source, NULL, NULL);
        }
 
        g_list_free_full (selected, g_object_unref);
 }
+
+/* Opens the client with given uid. Calls the cb only if it succeeded */
+void
+e_cal_base_shell_sidebar_open_source (ECalBaseShellSidebar *cal_base_shell_sidebar,
+                                     ESource *source,
+                                     ECalBaseShellSidebarOpenFunc cb,
+                                     gpointer cb_user_data)
+{
+       g_return_if_fail (E_IS_CAL_BASE_SHELL_SIDEBAR (cal_base_shell_sidebar));
+       g_return_if_fail (E_IS_SOURCE (source));
+       g_return_if_fail (cb != NULL);
+
+       e_cal_base_shell_sidebar_ensure_source_opened (cal_base_shell_sidebar, source, cb, cb_user_data);
+}
diff --git a/src/modules/calendar/e-cal-base-shell-sidebar.h b/src/modules/calendar/e-cal-base-shell-sidebar.h
index ee86ad2b38..7012f1f54d 100644
--- a/src/modules/calendar/e-cal-base-shell-sidebar.h
+++ b/src/modules/calendar/e-cal-base-shell-sidebar.h
@@ -49,6 +49,10 @@ typedef struct _ECalBaseShellSidebar ECalBaseShellSidebar;
 typedef struct _ECalBaseShellSidebarClass ECalBaseShellSidebarClass;
 typedef struct _ECalBaseShellSidebarPrivate ECalBaseShellSidebarPrivate;
 
+typedef void (* ECalBaseShellSidebarOpenFunc)  (ECalBaseShellSidebar *cal_base_shell_sidebar,
+                                                EClient *client,
+                                                gpointer user_data);
+
 enum {
        E_CAL_BASE_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE = 1 << 0,
        E_CAL_BASE_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_WRITABLE = 1 << 1,
@@ -87,6 +91,10 @@ 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);
+void           e_cal_base_shell_sidebar_open_source    (ECalBaseShellSidebar *cal_base_shell_sidebar,
+                                                        ESource *source,
+                                                        ECalBaseShellSidebarOpenFunc cb,
+                                                        gpointer cb_user_data);
 
 G_END_DECLS
 
diff --git a/src/modules/calendar/e-cal-shell-content.c b/src/modules/calendar/e-cal-shell-content.c
index 4a986d46df..7588f1b8af 100644
--- a/src/modules/calendar/e-cal-shell-content.c
+++ b/src/modules/calendar/e-cal-shell-content.c
@@ -56,6 +56,9 @@ struct _ECalShellContentPrivate {
        ECalModel *memo_model;
        ECalDataModel *memo_data_model;
 
+       ECalModel *list_view_model;
+       ECalDataModel *list_view_data_model;
+
        ETagCalendar *tag_calendar;
        gulong datepicker_selection_changed_id;
        gulong datepicker_range_moved_id;
@@ -1268,6 +1271,87 @@ cal_shell_content_move_view_range_cb (ECalendarView *cal_view,
        e_cal_shell_content_move_view_range (cal_shell_content, move_type, (time_t) exact_date);
 }
 
+static void
+cal_shell_content_clear_all_in_list_view (ECalShellContent *cal_shell_content)
+{
+       ECalDataModelSubscriber *subscriber;
+
+       subscriber = E_CAL_DATA_MODEL_SUBSCRIBER (cal_shell_content->priv->list_view_model);
+
+       e_cal_data_model_unsubscribe (cal_shell_content->priv->list_view_data_model, subscriber);
+       e_cal_model_remove_all_objects (cal_shell_content->priv->list_view_model);
+       e_cal_data_model_remove_all_clients (cal_shell_content->priv->list_view_data_model);
+       e_cal_data_model_subscribe (cal_shell_content->priv->list_view_data_model, subscriber, 0, 0);
+}
+
+static void
+cal_shell_content_client_opened_cb (ECalBaseShellSidebar *cal_base_shell_sidebar,
+                                   EClient *client,
+                                   gpointer user_data)
+{
+       ECalShellContent *cal_shell_content = user_data;
+       ESourceSelector *source_selector;
+       ESource *source;
+
+       g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
+
+       if (cal_shell_content->priv->current_view != E_CAL_VIEW_KIND_LIST || !E_IS_CAL_CLIENT (client))
+               return;
+
+       source_selector = e_cal_base_shell_sidebar_get_selector (cal_base_shell_sidebar);
+       source = e_source_selector_ref_primary_selection (source_selector);
+
+       /* It can happen that the previously opening calendar finished its open
+          after the current calendar, in which case this would replace the data,
+          thus ensure the opened calendar is the correct calendar. */
+       if (source == e_client_get_source (client)) {
+               cal_shell_content_clear_all_in_list_view (cal_shell_content);
+               e_cal_data_model_add_client (cal_shell_content->priv->list_view_data_model, E_CAL_CLIENT 
(client));
+       }
+
+       g_clear_object (&source);
+}
+
+static void
+cal_shell_content_update_list_view (ECalShellContent *cal_shell_content)
+{
+       ECalBaseShellSidebar *cal_base_shell_sidebar;
+       ESourceSelector *source_selector;
+       ECalClient *client;
+       ESource *source;
+
+       cal_base_shell_sidebar = E_CAL_BASE_SHELL_SIDEBAR (e_shell_view_get_shell_sidebar (
+               e_shell_content_get_shell_view (E_SHELL_CONTENT (cal_shell_content))));
+
+       source_selector = e_cal_base_shell_sidebar_get_selector (cal_base_shell_sidebar);
+
+       source = e_source_selector_ref_primary_selection (source_selector);
+       if (!source)
+               return;
+
+       e_cal_model_set_default_source_uid (cal_shell_content->priv->list_view_model, e_source_get_uid 
(source));
+
+       client = e_cal_data_model_ref_client (cal_shell_content->priv->list_view_data_model, e_source_get_uid 
(source));
+
+       if (!client)
+               e_cal_base_shell_sidebar_open_source (cal_base_shell_sidebar, source, 
cal_shell_content_client_opened_cb, cal_shell_content);
+
+       g_clear_object (&client);
+       g_clear_object (&source);
+}
+
+static void
+cal_shell_content_primary_selection_changed_cb (ESourceSelector *selector,
+                                               gpointer user_data)
+{
+       ECalShellContent *cal_shell_content = user_data;
+
+       g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
+
+       if (cal_shell_content->priv->current_view == E_CAL_VIEW_KIND_LIST)
+               cal_shell_content_update_list_view (cal_shell_content);
+}
+
 static void
 cal_shell_content_foreign_client_opened_cb (ECalBaseShellSidebar *cal_base_shell_sidebar,
                                            ECalClient *client,
@@ -1388,6 +1472,10 @@ cal_shell_content_view_created (ECalBaseShellContent *cal_base_shell_content)
        /* 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);
+       e_cal_model_set_time_range (cal_shell_content->priv->list_view_model, 0, 0);
+
+       g_signal_connect (e_cal_base_shell_sidebar_get_selector (E_CAL_BASE_SHELL_SIDEBAR (shell_sidebar)), 
"primary-selection-changed",
+               G_CALLBACK (cal_shell_content_primary_selection_changed_cb), cal_shell_content);
 
        cal_shell_content->priv->datepicker_selection_changed_id =
                g_signal_connect (e_calendar_get_item (calendar), "selection-changed",
@@ -1516,7 +1604,7 @@ e_cal_shell_content_create_calendar_views (ECalShellContent *cal_shell_content)
                G_CALLBACK (month_view_adjustment_changed_cb), cal_shell_content);
 
        /* List View */
-       calendar_view = e_cal_list_view_new (model);
+       calendar_view = e_cal_list_view_new (cal_shell_content->priv->list_view_model);
        cal_shell_content->priv->views[E_CAL_VIEW_KIND_LIST] = calendar_view;
        g_object_ref_sink (calendar_view);
 
@@ -1618,6 +1706,12 @@ cal_shell_content_dispose (GObject *object)
                        E_CAL_DATA_MODEL_SUBSCRIBER (cal_shell_content->priv->memo_model));
        }
 
+       if (cal_shell_content->priv->list_view_data_model) {
+               e_cal_data_model_set_disposing (cal_shell_content->priv->list_view_data_model, TRUE);
+               e_cal_data_model_unsubscribe (cal_shell_content->priv->list_view_data_model,
+                       E_CAL_DATA_MODEL_SUBSCRIBER (cal_shell_content->priv->list_view_model));
+       }
+
        if (cal_shell_content->priv->tag_calendar) {
                ECalDataModel *data_model;
 
@@ -1640,6 +1734,8 @@ cal_shell_content_dispose (GObject *object)
        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);
+       g_clear_object (&cal_shell_content->priv->list_view_model);
+       g_clear_object (&cal_shell_content->priv->list_view_data_model);
 
        /* Chain up to parent's dispose() method. */
        G_OBJECT_CLASS (e_cal_shell_content_parent_class)->dispose (object);
@@ -1678,6 +1774,11 @@ cal_shell_content_constructed (GObject *object)
        cal_shell_content->priv->task_model =
                e_cal_model_tasks_new (cal_shell_content->priv->task_data_model, e_shell_get_registry 
(shell), shell);
 
+       cal_shell_content->priv->list_view_data_model =
+               e_cal_base_shell_content_create_new_data_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
+       cal_shell_content->priv->list_view_model =
+               e_cal_model_calendar_new (cal_shell_content->priv->list_view_data_model, e_shell_get_registry 
(shell), shell);
+
        e_binding_bind_property (
                cal_shell_content->priv->memo_model, "timezone",
                cal_shell_content->priv->memo_data_model, "timezone",
@@ -1688,6 +1789,11 @@ cal_shell_content_constructed (GObject *object)
                cal_shell_content->priv->task_data_model, "timezone",
                G_BINDING_SYNC_CREATE);
 
+       e_binding_bind_property (
+               cal_shell_content->priv->list_view_model, "timezone",
+               cal_shell_content->priv->list_view_data_model, "timezone",
+               G_BINDING_SYNC_CREATE);
+
        /* Build content widgets. */
 
        container = GTK_WIDGET (object);
@@ -2027,10 +2133,58 @@ cal_shell_content_resubscribe (ECalendarView *cal_view,
        }
 }
 
+/* Only helper function */
+static void
+cal_shell_content_switch_list_view (ECalShellContent *cal_shell_content,
+                                   ECalViewKind from_view_kind,
+                                   ECalViewKind to_view_kind)
+{
+       EShellView *shell_view;
+       EShellSidebar *shell_sidebar;
+       ECalBaseShellSidebar *cal_base_shell_sidebar;
+       ECalendar *date_navigator;
+       ESourceSelector *source_selector;
+       ECalModel *model;
+       gchar *cal_filter;
+
+       g_return_if_fail (from_view_kind != to_view_kind);
+
+       if (to_view_kind != E_CAL_VIEW_KIND_LIST &&
+           from_view_kind != E_CAL_VIEW_KIND_LIST)
+               return;
+
+       shell_view = e_shell_content_get_shell_view (E_SHELL_CONTENT (cal_shell_content));
+       shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+       cal_base_shell_sidebar = E_CAL_BASE_SHELL_SIDEBAR (shell_sidebar);
+       date_navigator = e_cal_base_shell_sidebar_get_date_navigator (cal_base_shell_sidebar);
+       source_selector = e_cal_base_shell_sidebar_get_selector (cal_base_shell_sidebar);
+
+       gtk_widget_set_visible (GTK_WIDGET (date_navigator), to_view_kind != E_CAL_VIEW_KIND_LIST);
+       e_source_selector_set_show_toggles (source_selector, to_view_kind != E_CAL_VIEW_KIND_LIST);
+
+       model = e_calendar_view_get_model (cal_shell_content->priv->views[from_view_kind]);
+       cal_filter = e_cal_data_model_dup_filter (e_cal_model_get_data_model (model));
+       if (cal_filter) {
+               model = e_calendar_view_get_model (cal_shell_content->priv->views[to_view_kind]);
+               e_cal_data_model_set_filter (e_cal_model_get_data_model (model), cal_filter);
+               g_free (cal_filter);
+       }
+
+       /* The list view is activated */
+       if (to_view_kind == E_CAL_VIEW_KIND_LIST) {
+               cal_shell_content_update_list_view (cal_shell_content);
+       /* The list view is deactivated */
+       } else if (from_view_kind == E_CAL_VIEW_KIND_LIST) {
+               cal_shell_content_clear_all_in_list_view (cal_shell_content);
+               e_cal_base_shell_sidebar_ensure_sources_open (cal_base_shell_sidebar);
+       }
+}
+
 void
 e_cal_shell_content_set_current_view_id (ECalShellContent *cal_shell_content,
                                         ECalViewKind view_kind)
 {
+       EShellView *shell_view;
        time_t start_time = -1, end_time = -1;
        gint ii;
 
@@ -2069,6 +2223,9 @@ e_cal_shell_content_set_current_view_id (ECalShellContent *cal_shell_content,
 
                cal_view->in_focus = in_focus;
 
+               if (ii == E_CAL_VIEW_KIND_LIST)
+                       continue;
+
                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
@@ -2098,11 +2255,17 @@ e_cal_shell_content_set_current_view_id (ECalShellContent *cal_shell_content,
                }
        }
 
+       cal_shell_content_switch_list_view (cal_shell_content, cal_shell_content->priv->current_view, 
view_kind);
+
        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]));
+
+       shell_view = e_shell_content_get_shell_view (E_SHELL_CONTENT (cal_shell_content));
+       e_shell_view_update_actions (shell_view);
+       e_cal_shell_view_update_sidebar (E_CAL_SHELL_VIEW (shell_view));
 }
 
 ECalViewKind
@@ -2382,8 +2545,15 @@ e_cal_shell_content_update_filters (ECalShellContent *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));
+       if (e_cal_shell_content_get_current_view_id (cal_shell_content) == E_CAL_VIEW_KIND_LIST) {
+               data_model = cal_shell_content->priv->list_view_data_model;
+               model = cal_shell_content->priv->list_view_model;
+               start_range = 0;
+               end_range = 0;
+       } else {
+               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);
        e_cal_shell_content_update_tasks_filter (cal_shell_content, cal_filter);
@@ -2434,3 +2604,11 @@ e_cal_shell_content_update_filters (ECalShellContent *cal_shell_content,
                }
        }
 }
+
+ECalDataModel *
+e_cal_shell_content_get_list_view_data_model (ECalShellContent *cal_shell_content)
+{
+       g_return_val_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
+
+       return cal_shell_content->priv->list_view_data_model;
+}
diff --git a/src/modules/calendar/e-cal-shell-content.h b/src/modules/calendar/e-cal-shell-content.h
index 21a9d2e403..11240d4614 100644
--- a/src/modules/calendar/e-cal-shell-content.h
+++ b/src/modules/calendar/e-cal-shell-content.h
@@ -106,6 +106,8 @@ void                e_cal_shell_content_update_filters      (ECalShellContent 
*cal_shell_content,
                                                         time_t end_range);
 void           e_cal_shell_content_update_tasks_filter (ECalShellContent *cal_shell_content,
                                                         const gchar *cal_filter);
+ECalDataModel *        e_cal_shell_content_get_list_view_data_model
+                                                       (ECalShellContent *cal_shell_content);
 
 G_END_DECLS
 
diff --git a/src/modules/calendar/e-cal-shell-view-private.c b/src/modules/calendar/e-cal-shell-view-private.c
index f0cc8b705e..e098b32252 100644
--- a/src/modules/calendar/e-cal-shell-view-private.c
+++ b/src/modules/calendar/e-cal-shell-view-private.c
@@ -428,6 +428,28 @@ 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;
+
+               if (ii == E_CAL_VIEW_KIND_LIST) {
+                       ECalModel *model;
+
+                       model = e_calendar_view_get_model (calendar_view);
+
+                       g_signal_connect_object (calendar_view, "selection-changed",
+                               G_CALLBACK (e_cal_shell_view_update_sidebar), cal_shell_view,
+                               G_CONNECT_SWAPPED);
+
+                       g_signal_connect_object (model, "model-changed",
+                               G_CALLBACK (e_cal_shell_view_update_sidebar), cal_shell_view,
+                               G_CONNECT_SWAPPED);
+
+                       g_signal_connect_object (model, "model-rows-inserted",
+                               G_CALLBACK (e_cal_shell_view_update_sidebar), cal_shell_view,
+                               G_CONNECT_SWAPPED);
+
+                       g_signal_connect_object (model, "model-rows-deleted",
+                               G_CALLBACK (e_cal_shell_view_update_sidebar), cal_shell_view,
+                               G_CONNECT_SWAPPED);
+               }
        }
 
        /* Keep our own reference to this so we can
diff --git a/src/modules/calendar/e-cal-shell-view.c b/src/modules/calendar/e-cal-shell-view.c
index c8f441cd40..b6876fc512 100644
--- a/src/modules/calendar/e-cal-shell-view.c
+++ b/src/modules/calendar/e-cal-shell-view.c
@@ -259,6 +259,7 @@ cal_shell_view_update_actions (EShellView *shell_view)
        GtkAction *action;
        gchar *data_filter;
        gboolean is_searching;
+       gboolean is_list_view;
        gboolean sensitive;
        guint32 state;
 
@@ -303,7 +304,11 @@ cal_shell_view_update_actions (EShellView *shell_view)
        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);
-       data_model = e_cal_base_shell_content_get_data_model (E_CAL_BASE_SHELL_CONTENT (cal_shell_content));
+       is_list_view = E_IS_CAL_LIST_VIEW (cal_view);
+       if (is_list_view)
+               data_model = e_cal_shell_content_get_list_view_data_model (cal_shell_content);
+       else
+               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 &&
@@ -397,10 +402,10 @@ cal_shell_view_update_actions (EShellView *shell_view)
        gtk_action_set_sensitive (action, sensitive);
 
        action = ACTION (CALENDAR_SEARCH_PREV);
-       gtk_action_set_sensitive (action, is_searching);
+       gtk_action_set_sensitive (action, is_searching && !is_list_view);
 
        action = ACTION (CALENDAR_SEARCH_NEXT);
-       gtk_action_set_sensitive (action, is_searching);
+       gtk_action_set_sensitive (action, is_searching && !is_list_view);
 
        action = ACTION (CALENDAR_SEARCH_STOP);
        sensitive = is_searching && priv->searching_activity != NULL;
@@ -489,6 +494,11 @@ cal_shell_view_update_actions (EShellView *shell_view)
        action = ACTION (EVENT_MEETING_NEW);
        gtk_action_set_visible (action, has_mail_identity);
 
+       gtk_action_set_sensitive (ACTION (CALENDAR_GO_BACK), !is_list_view);
+       gtk_action_set_sensitive (ACTION (CALENDAR_GO_FORWARD), !is_list_view);
+       gtk_action_set_sensitive (ACTION (CALENDAR_GO_TODAY), !is_list_view);
+       gtk_action_set_sensitive (ACTION (CALENDAR_JUMP_TO), !is_list_view);
+
        if ((cal_view && e_calendar_view_is_editing (cal_view)) ||
            e_table_is_editing (E_TABLE (memo_table)) ||
            e_table_is_editing (E_TABLE (task_table))) {



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