[gnome-calendar] window: port the calendar popover to GtkListBox



commit cb532bbfbd9b6e7bb192eacae75f41c66b913f75
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Sat Feb 7 22:13:10 2015 -0200

    window: port the calendar popover to GtkListBox
    
    This is a significant rewrite of the calendar popover. Instead of adding actions to the window, it uses a 
internal map to find the corresponding source.

 data/theme/gtk-styles.css |    4 +
 data/ui/window.ui         |   71 ++++++++++++++++
 src/gcal-window.c         |  195 ++++++++++++++++++++++-----------------------
 3 files changed, 172 insertions(+), 98 deletions(-)
---
diff --git a/data/theme/gtk-styles.css b/data/theme/gtk-styles.css
index 96d6bcc..017b621 100644
--- a/data/theme/gtk-styles.css
+++ b/data/theme/gtk-styles.css
@@ -223,3 +223,7 @@ GcalEventWidget.color-light:backdrop {
   background-color: @theme_base_color;
 }
 
+/* calendar popover */
+.calendar-list {
+    background-color: rgba(0, 0, 0, 0);
+}
diff --git a/data/ui/window.ui b/data/ui/window.ui
index dbcccf2..13c0b6f 100644
--- a/data/ui/window.ui
+++ b/data/ui/window.ui
@@ -333,6 +333,77 @@
   </object>
   <object class="GtkPopover" id="calendar_popover">
     <property name="visible">False</property>
+    <property name="can_focus">False</property>
+    <property name="border_width">6</property>
+    <child>
+      <object class="GtkBox" id="calendar_box">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">6</property>
+        <child>
+          <object class="GtkListBox" id="calendar_listbox">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="hexpand">True</property>
+            <property name="vexpand">True</property>
+            <property name="selection_mode">none</property>
+            <style>
+              <class name="calendar-list" />
+            </style>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkButton" id="add_calendar_button">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="relief">none</property>
+            <property name="receives_default">True</property>
+            <child>
+              <object class="GtkBox" id="add_button_box">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="spacing">12</property>
+                <child>
+                  <object class="GtkImage" id="add_image">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="icon_name">list-add-symbolic</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="add_calendar_label">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label" translatable="yes">Add Calendar…</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
   </object>
   <object class="GtkPopover" id="popover">
     <property name="visible">False</property>
diff --git a/src/gcal-window.c b/src/gcal-window.c
index 2467ce0..43cafd0 100644
--- a/src/gcal-window.c
+++ b/src/gcal-window.c
@@ -109,10 +109,12 @@ typedef struct
 
   /* calendar management */
   GtkWidget           *calendar_popover;
-  GMenu               *calendar_menu;
+  GtkWidget           *calendar_listbox;
   gint                 refresh_timeout;
   gint                 refresh_timeout_id;
 
+  GHashTable          *calendar_source_to_row;
+
   /* temp to keep event_creation */
   gboolean             open_edit_dialog;
 } GcalWindowPrivate;
@@ -185,12 +187,15 @@ static void           add_source                         (GcalManager         *m
                                                           gboolean             enabled,
                                                           gpointer             user_data);
 
+static GtkWidget*     make_row_for_source                (GcalWindow          *window,
+                                                          ESource             *source);
+
 static void           remove_source                      (GcalManager         *manager,
                                                           ESource             *source,
                                                           gpointer             user_data);
 
-static void           on_calendar_toggled                (GSimpleAction       *action,
-                                                          GVariant            *value,
+static void           on_calendar_toggled                (GObject             *object,
+                                                          GParamSpec          *pspec,
                                                           gpointer             user_data);
 
 static gboolean       refresh_sources                    (GcalWindow          *window);
@@ -763,128 +768,121 @@ add_source (GcalManager *manager,
             gpointer     user_data)
 {
   GcalWindowPrivate *priv;
-
-  GdkRGBA color;
-  GdkPixbuf *pix;
-  GMenuItem *item;
-  GSimpleAction *action;
-
-  gchar *item_name;
+  GtkWidget *row;
 
   priv = gcal_window_get_instance_private (GCAL_WINDOW (user_data));
+  row = make_row_for_source (GCAL_WINDOW (user_data), source);
 
-  /* create the action itself */
-  action = g_simple_action_new_stateful (e_source_get_uid (source), NULL, g_variant_new_boolean (enabled));
-  g_signal_connect (action, "change-state", G_CALLBACK (on_calendar_toggled), user_data);
-  g_action_map_add_action (G_ACTION_MAP (user_data), G_ACTION (action));
+  /* add to the hash */
+  g_hash_table_insert (priv->calendar_source_to_row, source, row);
 
-  /* retrieve the source's color & build item name */
-  item_name = g_strdup_printf ("%s", e_source_get_uid (source));
-  get_color_name_from_source (source, &color);
-  pix = gcal_get_pixbuf_from_color (&color, 16);
+  gtk_container_add (GTK_CONTAINER (priv->calendar_listbox), row);
+}
 
-  /* create the menu item */
-  item = g_menu_item_new (e_source_get_display_name (source), item_name);
-  g_menu_item_set_attribute_value (item, "uid", g_variant_new_string (e_source_get_uid (source)));
-  g_menu_item_set_icon (item, G_ICON (pix));
-  g_menu_append_item (priv->calendar_menu, item);
+/**
+ * make_row_for_source:
+ *
+ * Create a GtkListBoxRow for a given
+ * ESource.
+ *
+ * Returns: (transfer full) the new row
+ */
+static GtkWidget*
+make_row_for_source (GcalWindow *window,
+                     ESource    *source)
+{
+  GcalWindowPrivate *priv = gcal_window_get_instance_private (window);
+  GtkWidget *label, *icon, *separator, *checkbox, *box, *row;
+  GdkPixbuf *pixbuf;
+  GdkRGBA color;
 
-  /* HACK: show images of the popover menu */
-  fix_popover_menu_icons (GTK_POPOVER (priv->calendar_popover));
+  row = gtk_list_box_row_new ();
 
-  g_object_unref (pix);
-  g_object_unref (item);
-  g_free (item_name);
-}
+  /* main box */
+  box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+  gtk_container_set_border_width (GTK_CONTAINER (box), 6);
 
-static void
-remove_source (GcalManager *manager,
-               ESource     *source,
-               gpointer     user_data)
-{
-  GcalWindowPrivate *priv;
-  gboolean source_found;
-  gint n_items;
-  gint i;
+  /* source color icon */
+  gdk_rgba_parse (&color, get_color_name_from_source (source));
+  pixbuf = gcal_get_pixbuf_from_color (&color, 16);
+  icon = gtk_image_new_from_pixbuf (pixbuf);
 
-  priv = gcal_window_get_instance_private (GCAL_WINDOW (user_data));
-  n_items = g_menu_model_get_n_items (G_MENU_MODEL (priv->calendar_menu));
-  source_found = FALSE;
+  /* source name label */
+  label = gtk_label_new (e_source_get_display_name (source));
+  gtk_label_set_xalign (GTK_LABEL (label), 0.0);
+  gtk_widget_set_hexpand (label, TRUE);
 
-  for (i = 0; i < n_items; i++)
-    {
-      GMenuAttributeIter *iter;
+  /* vertical separator */
+  separator = gtk_separator_new (GTK_ORIENTATION_VERTICAL);
 
-      iter = g_menu_model_iterate_item_attributes (G_MENU_MODEL (priv->calendar_menu), i);
+  /* checkbox */
+  checkbox = gtk_check_button_new ();
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox), gcal_manager_source_enabled (priv->manager, 
source));
+  g_signal_connect (checkbox, "notify::active", G_CALLBACK (on_calendar_toggled), window);
 
-      /* look for 'uid' attribute */
-      while (g_menu_attribute_iter_next (iter))
-        {
-          if (g_strcmp0 (g_menu_attribute_iter_get_name (iter), "uid") == 0)
-            {
-              GVariant *uid;
-              uid = g_menu_attribute_iter_get_value (iter);
-
-              /* if we find the item with uid == source::uid, remove it */
-              if (g_strcmp0 (g_variant_get_string (uid, NULL), e_source_get_uid (source)) == 0)
-                {
-                  g_menu_remove (priv->calendar_menu, i);
-                  source_found = TRUE;
-                  break;
-                }
-            }
-        }
+  gtk_container_add (GTK_CONTAINER (box), icon);
+  gtk_container_add (GTK_CONTAINER (box), label);
+  gtk_container_add (GTK_CONTAINER (box), separator);
+  gtk_container_add (GTK_CONTAINER (box), checkbox);
+  gtk_container_add (GTK_CONTAINER (row), box);
 
-      g_object_unref (iter);
+  gtk_widget_show_all (row);
 
-      if (source_found)
-        break;
-    }
+  g_object_unref (pixbuf);
 
-  /* remove the action */
-  g_action_map_remove_action (G_ACTION_MAP (user_data), e_source_get_uid (source));
+  return row;
 }
 
 static void
-on_calendar_toggled (GSimpleAction *action,
-                     GVariant      *value,
-                     gpointer       user_data)
+remove_source (GcalManager *manager,
+               ESource     *source,
+               gpointer     user_data)
 {
-  GcalWindowPrivate *priv;
-  ESource *source;
-  GList *l;
-  GList *aux;
+  GcalWindowPrivate *priv = gcal_window_get_instance_private (GCAL_WINDOW (user_data));
+
+  /**
+   * Since a destroyer function was
+   * defined, simply removing the
+   * source will call gtk_widget_destroy
+   * on the row, which will remove it
+   * from the listbox.
+   */
+  g_hash_table_remove (priv->calendar_source_to_row, source);
+}
 
-  priv = gcal_window_get_instance_private (GCAL_WINDOW (user_data));
+static void
+on_calendar_toggled (GObject    *object,
+                     GParamSpec *pspec,
+                     gpointer    user_data)
+{
+  GcalWindowPrivate *priv = gcal_window_get_instance_private (GCAL_WINDOW (user_data));
+  gboolean active;
+  GtkWidget *row;
+  GList *l, *aux;
 
-  /* lookup source */
-  source = NULL;
-  l = gcal_manager_get_sources_connected (priv->manager);
+  row = gtk_widget_get_parent (gtk_widget_get_parent (GTK_WIDGET (object)));
+  active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (object));
+  l = g_hash_table_get_keys (priv->calendar_source_to_row);
 
   for (aux = l; aux != NULL; aux = aux->next)
     {
-      ESource *tmp;
-      tmp = (ESource *) aux->data;
+      GtkWidget *current_row;
+
+      current_row = g_hash_table_lookup (priv->calendar_source_to_row, aux->data);
 
-      if (g_strcmp0 (e_source_get_uid (tmp), g_action_get_name (G_ACTION (action))) == 0)
+      /* Enable/disable the toggled calendar */
+      if (current_row == row)
         {
-          source = tmp;
+          if (active)
+            gcal_manager_enable_source (priv->manager, E_SOURCE (aux->data));
+          else
+            gcal_manager_disable_source (priv->manager, E_SOURCE (aux->data));
+
           break;
         }
     }
 
   g_list_free (l);
-
-  if (source == NULL)
-    return;
-
-  /* toggle source visibility */
-  if (g_variant_get_boolean (value))
-    gcal_manager_enable_source (priv->manager, source);
-  else
-    gcal_manager_disable_source (priv->manager, source);
-
-  g_simple_action_set_state (action, value);
 }
 
 static gboolean
@@ -1288,6 +1286,7 @@ gcal_window_class_init(GcalWindowClass *klass)
   gtk_widget_class_bind_template_child_private (widget_class, GcalWindow, search_bar);
   gtk_widget_class_bind_template_child_private (widget_class, GcalWindow, search_button);
   gtk_widget_class_bind_template_child_private (widget_class, GcalWindow, calendars_button);
+  gtk_widget_class_bind_template_child_private (widget_class, GcalWindow, calendar_listbox);
   gtk_widget_class_bind_template_child_private (widget_class, GcalWindow, calendar_popover);
   gtk_widget_class_bind_template_child_private (widget_class, GcalWindow, search_entry);
   gtk_widget_class_bind_template_child_private (widget_class, GcalWindow, back_button);
@@ -1386,10 +1385,6 @@ gcal_window_constructed (GObject *object)
 
   g_object_unref (builder);
 
-  /* calendar menu */
-  priv->calendar_menu = g_menu_new ();
-  gtk_popover_bind_model (GTK_POPOVER (priv->calendar_popover), G_MENU_MODEL (priv->calendar_menu), "win");
-
   /* edit dialog initialization */
   priv->edit_dialog = gcal_edit_dialog_new (use_24h_format);
   gtk_window_set_transient_for (GTK_WINDOW (priv->edit_dialog), GTK_WINDOW (object));
@@ -1404,6 +1399,10 @@ gcal_window_constructed (GObject *object)
   g_signal_connect (gtk_bin_get_child (GTK_BIN (priv->search_bar)), "notify::child-revealed",
                     G_CALLBACK (search_bar_revealer_toggled), object);
 
+  /* calendars menu */
+  priv->calendar_source_to_row = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
+                                                        (GDestroyNotify) gtk_widget_destroy);
+
   /* XXX: Week view disabled until after the release when we restart the work on it*/
   //priv->views[GCAL_WINDOW_VIEW_WEEK] = gcal_week_view_new ();
   //gcal_week_view_set_manager (GCAL_WEEK_VIEW (priv->views[GCAL_WINDOW_VIEW_WEEK]), priv->manager);


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