[epiphany/wip/bookmarks] bookmarks: Add tags detail stack child



commit 219a309dff3d5b0a3ba5fc96679a8fa9799dde4c
Author: Iulian Radu <iulian radu67 gmail com>
Date:   Fri Jul 29 18:45:01 2016 +0300

    bookmarks: Add tags detail stack child

 src/ephy-bookmark-properties-grid.c    |    1 -
 src/ephy-bookmark.c                    |   16 +++
 src/ephy-bookmark.h                    |    2 +
 src/ephy-bookmarks-manager.c           |   28 +++++
 src/ephy-bookmarks-manager.h           |   36 ++++---
 src/ephy-bookmarks-popover.c           |  173 +++++++++++++++++++++++++++----
 src/resources/gtk/bookmarks-popover.ui |  110 ++++++++++++++++++---
 7 files changed, 312 insertions(+), 54 deletions(-)
---
diff --git a/src/ephy-bookmark-properties-grid.c b/src/ephy-bookmark-properties-grid.c
index c12ceda..a7c2ca7 100644
--- a/src/ephy-bookmark-properties-grid.c
+++ b/src/ephy-bookmark-properties-grid.c
@@ -302,7 +302,6 @@ ephy_bookmark_properties_grid_constructed (GObject *object)
   /* Create tag widgets */
   tags = ephy_bookmarks_manager_get_tags (manager);
   bookmark_tags = ephy_bookmark_get_tags (self->bookmark);
-  g_sequence_sort (bookmark_tags, (GCompareDataFunc)ephy_bookmark_tags_compare, NULL);
   for (iter = g_sequence_get_begin_iter (tags);
        !g_sequence_iter_is_end (iter);
        iter = g_sequence_iter_next (iter)) {
diff --git a/src/ephy-bookmark.c b/src/ephy-bookmark.c
index 194111e..f5b18d2 100644
--- a/src/ephy-bookmark.c
+++ b/src/ephy-bookmark.c
@@ -199,6 +199,22 @@ ephy_bookmark_remove_tag (EphyBookmark *self,
     g_sequence_remove (tag_iter);
 }
 
+gboolean
+ephy_bookmark_has_tag (EphyBookmark *self, const char *tag)
+{
+  GSequenceIter *tag_iter;
+
+  g_return_val_if_fail (EPHY_IS_BOOKMARK (self), FALSE);
+  g_return_val_if_fail (tag != NULL, FALSE);
+
+  tag_iter = g_sequence_lookup (self->tags,
+                                (gpointer)tag,
+                                (GCompareDataFunc)g_strcmp0,
+                                NULL);
+
+  return tag_iter != NULL;
+}
+
 void
 ephy_bookmark_set_tags (EphyBookmark *self, GSequence *tags)
 {
diff --git a/src/ephy-bookmark.h b/src/ephy-bookmark.h
index 9ae8571..7ce719a 100644
--- a/src/ephy-bookmark.h
+++ b/src/ephy-bookmark.h
@@ -35,6 +35,8 @@ void                 ephy_bookmark_add_tag      (EphyBookmark *self,
                                                  const char *tag);
 void                 ephy_bookmark_remove_tag   (EphyBookmark *self,
                                                  const char *tag);
+gboolean             ephy_bookmark_has_tag      (EphyBookmark *self,
+                                                 const char *tag);
 void                 ephy_bookmark_set_tags     (EphyBookmark *self,
                                                  GSequence    *tags);
 GSequence           *ephy_bookmark_get_tags     (EphyBookmark *self);
diff --git a/src/ephy-bookmarks-manager.c b/src/ephy-bookmarks-manager.c
index 7bb4945..1c321dc 100644
--- a/src/ephy-bookmarks-manager.c
+++ b/src/ephy-bookmarks-manager.c
@@ -242,6 +242,34 @@ ephy_bookmarks_manager_get_bookmarks (EphyBookmarksManager *self)
   return self->bookmarks;
 }
 
+GList *
+ephy_bookmarks_manager_get_bookmarks_with_tag (EphyBookmarksManager *self,
+                                               const char           *tag)
+{
+  GList *bookmarks = NULL;
+  GList *l;
+
+  g_return_val_if_fail (EPHY_IS_BOOKMARKS_MANAGER (self), NULL);
+
+  if (tag == NULL) {
+    for (l = self->bookmarks; l != NULL; l = l->next) {
+      EphyBookmark *bookmark = EPHY_BOOKMARK (l->data);
+
+      if (g_sequence_get_length (ephy_bookmark_get_tags (bookmark)) == 0)
+        bookmarks = g_list_prepend (bookmarks, bookmark);
+    }
+  } else {
+    for (l = self->bookmarks; l != NULL; l = l->next) {
+      EphyBookmark *bookmark = EPHY_BOOKMARK (l->data);
+
+      if (ephy_bookmark_has_tag (bookmark, tag))
+        bookmarks = g_list_prepend (bookmarks, bookmark);
+    }
+  }
+
+  return bookmarks;
+}
+
 GSequence *
 ephy_bookmarks_manager_get_tags (EphyBookmarksManager *self)
 {
diff --git a/src/ephy-bookmarks-manager.h b/src/ephy-bookmarks-manager.h
index a16589a..77caa14 100644
--- a/src/ephy-bookmarks-manager.h
+++ b/src/ephy-bookmarks-manager.h
@@ -26,23 +26,25 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (EphyBookmarksManager, ephy_bookmarks_manager, EPHY, BOOKMARKS_MANAGER, GObject)
 
-void         ephy_bookmarks_manager_add_bookmark         (EphyBookmarksManager *self,
-                                                          EphyBookmark         *bookmark);
-void         ephy_bookmarks_manager_remove_bookmark      (EphyBookmarksManager *self,
-                                                          EphyBookmark         *bookmark);
-
-void         ephy_bookmarks_manager_add_tag              (EphyBookmarksManager *self,
-                                                          const char           *tag);
-void         ephy_bookmarks_manager_remove_tag           (EphyBookmarksManager *self,
-                                                          const char           *tag);
-gboolean     ephy_bookmarks_manager_tag_exists           (EphyBookmarksManager *self,
-                                                          const char           *tag);
-
-GList       *ephy_bookmarks_manager_get_bookmarks        (EphyBookmarksManager *self);
-GSequence   *ephy_bookmarks_manager_get_tags             (EphyBookmarksManager *self);
-
-void         ephy_bookmarks_manager_save_to_file         (EphyBookmarksManager *self);
-void         ephy_bookmarks_manager_load_from_file       (EphyBookmarksManager *self);
+void         ephy_bookmarks_manager_add_bookmark           (EphyBookmarksManager *self,
+                                                            EphyBookmark         *bookmark);
+void         ephy_bookmarks_manager_remove_bookmark        (EphyBookmarksManager *self,
+                                                            EphyBookmark         *bookmark);
+
+void         ephy_bookmarks_manager_add_tag                (EphyBookmarksManager *self,
+                                                            const char           *tag);
+void         ephy_bookmarks_manager_remove_tag             (EphyBookmarksManager *self,
+                                                            const char           *tag);
+gboolean     ephy_bookmarks_manager_tag_exists             (EphyBookmarksManager *self,
+                                                            const char           *tag);
+
+GList       *ephy_bookmarks_manager_get_bookmarks          (EphyBookmarksManager *self);
+GList       *ephy_bookmarks_manager_get_bookmarks_with_tag (EphyBookmarksManager *self,
+                                                            const char           *tag);
+GSequence   *ephy_bookmarks_manager_get_tags               (EphyBookmarksManager *self);
+
+void         ephy_bookmarks_manager_save_to_file           (EphyBookmarksManager *self);
+void         ephy_bookmarks_manager_load_from_file         (EphyBookmarksManager *self);
 
 G_END_DECLS
 
diff --git a/src/ephy-bookmarks-popover.c b/src/ephy-bookmarks-popover.c
index 2066308..1a50a1a 100644
--- a/src/ephy-bookmarks-popover.c
+++ b/src/ephy-bookmarks-popover.c
@@ -29,14 +29,21 @@
 struct _EphyBookmarksPopover {
   GtkPopover      parent_instance;
 
+  GtkWidget      *toplevel_stack;
   GtkWidget      *bookmarks_list_box;
   GtkWidget      *tags_list_box;
+  GtkWidget      *tag_detail_list_box;
+  GtkWidget      *tag_detail_back_button;
+  GtkWidget      *tag_detail_label;
 
   EphyWindow     *window;
 };
 
 G_DEFINE_TYPE (EphyBookmarksPopover, ephy_bookmarks_popover, GTK_TYPE_POPOVER)
 
+#define EPHY_LIST_BOX_ROW_TYPE_BOOKMARK "bookmark"
+#define EPHY_LIST_BOX_ROW_TYPE_TAG "tag"
+
 enum {
   PROP_0,
   PROP_WINDOW,
@@ -45,59 +52,150 @@ enum {
 
 static GParamSpec *obj_properties[LAST_PROP];
 
+static int
+tags_list_box_sort_func (GtkListBoxRow *row1, GtkListBoxRow *row2)
+{
+  const char *type1;
+  const char *type2;
+  const char *title1;
+  const char *title2;
+
+  g_assert (GTK_IS_LIST_BOX_ROW (row1));
+  g_assert (GTK_IS_LIST_BOX_ROW (row2));
+
+  type1 = g_object_get_data (G_OBJECT (row1), "type");
+  type2 = g_object_get_data (G_OBJECT (row2), "type");
+
+  title1 = g_object_get_data (G_OBJECT (row1), "title");
+  title2 = g_object_get_data (G_OBJECT (row2), "title");
+
+  if (g_strcmp0 (type1, EPHY_LIST_BOX_ROW_TYPE_TAG) == 0
+      && g_strcmp0 (type2, EPHY_LIST_BOX_ROW_TYPE_TAG) == 0)
+      return ephy_bookmark_tags_compare (title1, title2);
+
+  if (g_strcmp0 (type1, EPHY_LIST_BOX_ROW_TYPE_TAG) == 0)
+    return -1;
+  if (g_strcmp0 (type2, EPHY_LIST_BOX_ROW_TYPE_TAG) == 0)
+    return 1;
+
+  return g_strcmp0 (title1, title2);
+}
+
 static GtkWidget *
 create_bookmark_row (gpointer item,
                      gpointer user_data)
 {
   EphyBookmark *bookmark = EPHY_BOOKMARK (item);
+  GtkWidget *row;
+
+  row = ephy_bookmark_row_new (bookmark);
+  g_object_set_data (G_OBJECT (row), "type", g_strdup (EPHY_LIST_BOX_ROW_TYPE_BOOKMARK));
+  g_object_set_data (G_OBJECT (row), "title", g_strdup (ephy_bookmark_get_title (bookmark)));
+
+  return row;
+}
+
+static void
+ephy_bookmarks_popover_show_tags (EphyBookmarksPopover *self,
+                                  GtkButton            *button)
+{
+  GList *l;
+
+  gtk_stack_set_visible_child_name (GTK_STACK (self->toplevel_stack),
+                                    "default");
+
+  for (l = gtk_container_get_children (GTK_CONTAINER (self->tag_detail_list_box));
+       l != NULL;
+       l = l->next)
+    gtk_container_remove (GTK_CONTAINER (self->tag_detail_list_box), l->data);
+}
 
-  return ephy_bookmark_row_new (bookmark);
+static void
+ephy_bookmarks_popover_show_tag_detail (EphyBookmarksPopover *self,
+                                        const char           *tag)
+{
+  EphyBookmarksManager *manager = ephy_shell_get_bookmarks_manager (ephy_shell_get_default ());
+  GList *bookmarks;
+  GList *l;
+
+  bookmarks = ephy_bookmarks_manager_get_bookmarks_with_tag (manager, tag);
+
+  for (l = bookmarks; l != NULL; l = l->next) {
+    EphyBookmark *bookmark = EPHY_BOOKMARK (l->data);
+    GtkWidget *row;
+
+    row = create_bookmark_row (bookmark, NULL);
+    gtk_list_box_prepend (GTK_LIST_BOX (self->tag_detail_list_box), row);
+  }
+
+  gtk_label_set_label (GTK_LABEL (self->tag_detail_label), tag);
+  g_signal_connect_object (GTK_BUTTON (self->tag_detail_back_button),
+                           "clicked",
+                           G_CALLBACK (ephy_bookmarks_popover_show_tags),
+                           self, G_CONNECT_SWAPPED);
+
+  gtk_stack_set_visible_child_name (GTK_STACK (self->toplevel_stack),
+                                    "tag_detail");
 }
 
 static void
-bookmarks_list_box_row_activated_cb (EphyBookmarksPopover   *self,
-                                     EphyBookmarkRow        *row,
-                                     GtkListBox             *box)
+ephy_bookmarks_popover_list_box_row_activated_cb (EphyBookmarksPopover   *self,
+                                                  GtkListBoxRow          *row,
+                                                  GtkListBox             *box)
 {
-  EphyBookmark *bookmark;
-  GActionGroup *action_group;
-  GAction *action;
-  const char *url;
+  const char *type;
+  const char *tag;
 
   g_assert (EPHY_IS_BOOKMARKS_POPOVER (self));
-  g_assert (EPHY_IS_BOOKMARK_ROW (row));
+  g_assert (GTK_IS_LIST_BOX_ROW (row));
   g_assert (GTK_IS_LIST_BOX (box));
 
-  action_group = gtk_widget_get_action_group (GTK_WIDGET (self->window), "win");
-  action = g_action_map_lookup_action (G_ACTION_MAP (action_group), "open-bookmark");
+  type = g_object_get_data (G_OBJECT (row), "type");
+  if (g_strcmp0 (type, EPHY_LIST_BOX_ROW_TYPE_BOOKMARK) == 0) {
+    EphyBookmark *bookmark;
+    GActionGroup *action_group;
+    GAction *action;
+    const char *url;
 
-  bookmark = ephy_bookmark_row_get_bookmark (row);
-  url = ephy_bookmark_get_url (bookmark);
+    action_group = gtk_widget_get_action_group (GTK_WIDGET (self->window), "win");
+    action = g_action_map_lookup_action (G_ACTION_MAP (action_group), "open-bookmark");
 
-  g_action_activate (action, g_variant_new_string (url));
+    bookmark = ephy_bookmark_row_get_bookmark (EPHY_BOOKMARK_ROW (row));
+    url = ephy_bookmark_get_url (bookmark);
+
+    g_action_activate (action, g_variant_new_string (url));
+  } else {
+    tag = g_object_get_data (G_OBJECT (row), "title");
+    ephy_bookmarks_popover_show_tag_detail (self, tag);
+  }
 }
 
 static GtkWidget *
-create_tag_box (const char *tag)
+create_tag_row (const char *tag)
 {
+  GtkWidget *row;
   GtkWidget *box;
   GtkWidget *image;
   GtkWidget *label;
 
+  row = gtk_list_box_row_new ();
+  g_object_set_data (G_OBJECT (row), "type", g_strdup (EPHY_LIST_BOX_ROW_TYPE_TAG));
+  g_object_set_data (G_OBJECT (row), "title", g_strdup (tag));
+  g_object_set (G_OBJECT (row), "height-request", 40, NULL);
+
   box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
   gtk_widget_set_halign (box, GTK_ALIGN_START);
 
   image = gtk_image_new_from_icon_name ("user-bookmarks-symbolic", GTK_ICON_SIZE_MENU);
   gtk_box_pack_start (GTK_BOX (box), image, FALSE, FALSE, 6);
-  gtk_widget_show (image);
 
   label = gtk_label_new (tag);
   gtk_box_pack_start (GTK_BOX (box),label, TRUE, FALSE, 6);
-  gtk_widget_show (label);
 
-  gtk_widget_show (box);
+  gtk_container_add (GTK_CONTAINER (row), box);
+  gtk_widget_show_all (row);
 
-  return box;
+  return row;
 }
 
 static void
@@ -148,8 +246,12 @@ ephy_bookmarks_popover_class_init (EphyBookmarksPopoverClass *klass)
   g_object_class_install_properties (object_class, LAST_PROP, obj_properties);
 
   gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/epiphany/gtk/bookmarks-popover.ui");
+  gtk_widget_class_bind_template_child (widget_class, EphyBookmarksPopover, toplevel_stack);
   gtk_widget_class_bind_template_child (widget_class, EphyBookmarksPopover, bookmarks_list_box);
   gtk_widget_class_bind_template_child (widget_class, EphyBookmarksPopover, tags_list_box);
+  gtk_widget_class_bind_template_child (widget_class, EphyBookmarksPopover, tag_detail_list_box);
+  gtk_widget_class_bind_template_child (widget_class, EphyBookmarksPopover, tag_detail_back_button);
+  gtk_widget_class_bind_template_child (widget_class, EphyBookmarksPopover, tag_detail_label);
 }
 
 static void
@@ -158,27 +260,52 @@ ephy_bookmarks_popover_init (EphyBookmarksPopover *self)
   EphyBookmarksManager *manager = ephy_shell_get_bookmarks_manager (ephy_shell_get_default ());
   GSequence *tags;
   GSequenceIter *iter;
+  GList *bookmarks;
+  GList *l;
+  EphyBookmark *dummy_bookmark;
+  GSequence *dummy_tags;
 
   gtk_widget_init_template (GTK_WIDGET (self));
 
+  dummy_bookmark = ephy_bookmark_new (g_strdup ("https://facebook.com";), g_strdup ("Facebook"));
+  ephy_bookmark_set_tags (dummy_bookmark, g_sequence_new (g_free));
+  ephy_bookmarks_manager_add_bookmark (manager, dummy_bookmark);
+
   gtk_list_box_bind_model (GTK_LIST_BOX (self->bookmarks_list_box),
                            G_LIST_MODEL (manager),
                            create_bookmark_row,
                            NULL, NULL);
 
+  gtk_list_box_set_sort_func (GTK_LIST_BOX (self->tags_list_box),
+                              (GtkListBoxSortFunc)tags_list_box_sort_func,
+                              NULL, NULL);
+
   tags = ephy_bookmarks_manager_get_tags (manager);
   for (iter = g_sequence_get_begin_iter (tags);
        !g_sequence_iter_is_end (iter);
        iter = g_sequence_iter_next (iter)) {
-    GtkWidget *tag_box;
     const char *tag = g_sequence_get (iter);
+    GtkWidget *tag_row;
 
-    tag_box = create_tag_box (tag);
-    gtk_list_box_prepend (GTK_LIST_BOX (self->tags_list_box), tag_box);
+    tag_row = create_tag_row (tag);
+    gtk_container_add (GTK_CONTAINER (self->tags_list_box), tag_row);
+  }
+
+  bookmarks = ephy_bookmarks_manager_get_bookmarks_with_tag (manager, NULL);
+  for (l = bookmarks; l != NULL; l = l->next) {
+    EphyBookmark *bookmark = EPHY_BOOKMARK (l->data);
+    GtkWidget *bookmark_row;
+
+    bookmark_row = create_bookmark_row (bookmark, NULL);
+    gtk_widget_show_all (bookmark_row);
+    gtk_container_add (GTK_CONTAINER (self->tags_list_box), bookmark_row);
   }
 
   g_signal_connect_object (self->bookmarks_list_box, "row-activated",
-                           G_CALLBACK (bookmarks_list_box_row_activated_cb),
+                           G_CALLBACK (ephy_bookmarks_popover_list_box_row_activated_cb),
+                           self, G_CONNECT_SWAPPED);
+  g_signal_connect_object (self->tags_list_box, "row-activated",
+                           G_CALLBACK (ephy_bookmarks_popover_list_box_row_activated_cb),
                            self, G_CONNECT_SWAPPED);
 }
 
diff --git a/src/resources/gtk/bookmarks-popover.ui b/src/resources/gtk/bookmarks-popover.ui
index 64a1dd0..5bce5ef 100644
--- a/src/resources/gtk/bookmarks-popover.ui
+++ b/src/resources/gtk/bookmarks-popover.ui
@@ -9,30 +9,114 @@
         <property name="spacing">6</property>
         <property name="visible">true</property>
         <child>
-          <object class="GtkStackSwitcher">
-            <property name="stack">stack</property>
-            <property name="visible">true</property>
-          </object>
-        </child>
-        <child>
-          <object class="GtkStack" id="stack">
+          <object class="GtkStack" id="toplevel_stack">
+            <property name="vhomogeneous">false</property>
+            <property name="interpolate-size">true</property>
+            <property name="transition-type">GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT</property>
             <property name="visible">true</property>
             <child>
-              <object class="GtkListBox" id="bookmarks_list_box">
+              <object class="GtkBox">
+                <property name="orientation">vertical</property>
+                <property name="spacing">6</property>
                 <property name="visible">true</property>
+                <child>
+                  <object class="GtkStackSwitcher">
+                    <property name="stack">stack</property>
+                    <property name="visible">true</property>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkStack" id="stack">
+                    <property name="vhomogeneous">false</property>
+                    <property name="interpolate-size">true</property>
+                    <property name="transition-type">GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT</property>
+                    <property name="visible">true</property>
+                    <child>
+                      <object class="GtkListBox" id="bookmarks_list_box">
+                        <property name="selection-mode">none</property>
+                        <property name="visible">true</property>
+                        <style>
+                          <class name="background"/>
+                        </style>
+                      </object>
+                      <packing>
+                        <property name="name">all</property>
+                        <property name="title" translatable="yes">All</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkListBox" id="tags_list_box">
+                        <property name="selection-mode">none</property>
+                        <property name="visible">true</property>
+                        <style>
+                          <class name="background"/>
+                        </style>
+                      </object>
+                      <packing>
+                        <property name="name">tags</property>
+                        <property name="title" translatable="yes">Tags</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
               </object>
               <packing>
-                <property name="name">all</property>
-                <property name="title" translatable="yes">All</property>
+                <property name="name">default</property>
               </packing>
             </child>
             <child>
-              <object class="GtkListBox" id="tags_list_box">
+              <object class="GtkBox">
+                <property name="orientation">vertical</property>
+                <property name="spacing">6</property>
                 <property name="visible">true</property>
+                <child>
+                  <object class="GtkBox">
+                    <property name="spacing">6</property>
+                    <property name="visible">true</property>
+                    <child>
+                      <object class="GtkButton" id="tag_detail_back_button">
+                        <property name="visible">true</property>
+                        <style>
+                          <class name="image-button"/>
+                        </style>
+                        <child>
+                          <object class="GtkImage">
+                            <property name="icon-name">go-previous-symbolic</property>
+                            <property name="visible">true</property>
+                          </object>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="pack-type">start</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="tag_detail_label">
+                        <property name="halign">center</property>
+                        <property name="hexpand">true</property>
+                        <property name="visible">true</property>
+                        <attributes>
+                          <attribute name="weight" value="bold"/>
+                        </attributes>
+                      </object>
+                      <packing>
+                        <property name="pack-type">start</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkListBox" id="tag_detail_list_box">
+                    <property name="selection-mode">none</property>
+                    <property name="visible">true</property>
+                    <style>
+                      <class name="background"/>
+                    </style>
+                  </object>
+                </child>
               </object>
               <packing>
-                <property name="name">tags</property>
-                <property name="title" translatable="yes">Tags</property>
+                <property name="name">tag_detail</property>
               </packing>
             </child>
           </object>


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