[libdazzle] tree: add build-children vfunc for tree builders



commit a05d323871c8108e97cd65a7152ce7321d8db323
Author: Christian Hergert <chergert redhat com>
Date:   Sat Dec 9 01:26:13 2017 -0800

    tree: add build-children vfunc for tree builders
    
    This separates build-node from build-children. This allows
    builders that just add new information to a node vs builders
    that add new children to the builders (when we expand them).

 src/tree/dzl-tree-builder.c |   25 ++++++++++++
 src/tree/dzl-tree-builder.h |    3 +
 src/tree/dzl-tree-node.c    |   24 ++++++------
 src/tree/dzl-tree-private.h |   10 +++-
 src/tree/dzl-tree.c         |   91 ++++++++++++++++++++++++++++++-------------
 tests/test-tree.c           |    6 +-
 6 files changed, 114 insertions(+), 45 deletions(-)
---
diff --git a/src/tree/dzl-tree-builder.c b/src/tree/dzl-tree-builder.c
index c26fc64..95c9ced 100644
--- a/src/tree/dzl-tree-builder.c
+++ b/src/tree/dzl-tree-builder.c
@@ -42,6 +42,7 @@ enum {
 enum {
   ADDED,
   REMOVED,
+  BUILD_CHILDREN,
   BUILD_NODE,
   DRAG_DATA_GET,
   DRAG_DATA_RECEIVED,
@@ -108,6 +109,16 @@ _dzl_tree_builder_node_unselected (DzlTreeBuilder *builder,
 }
 
 void
+_dzl_tree_builder_build_children (DzlTreeBuilder *builder,
+                                  DzlTreeNode    *node)
+{
+  g_return_if_fail (DZL_IS_TREE_BUILDER (builder));
+  g_return_if_fail (DZL_IS_TREE_NODE (node));
+
+  g_signal_emit (builder, signals [BUILD_CHILDREN], 0, node);
+}
+
+void
 _dzl_tree_builder_build_node (DzlTreeBuilder *builder,
                               DzlTreeNode    *node)
 {
@@ -367,6 +378,20 @@ dzl_tree_builder_class_init (DzlTreeBuilderClass *klass)
                               G_TYPE_FROM_CLASS (klass),
                               g_cclosure_marshal_VOID__OBJECTv);
 
+  signals [BUILD_CHILDREN] =
+    g_signal_new ("build-children",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (DzlTreeBuilderClass, build_children),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__OBJECT,
+                  G_TYPE_NONE,
+                  1,
+                  DZL_TYPE_TREE_NODE);
+  g_signal_set_va_marshaller (signals [BUILD_CHILDREN],
+                              G_TYPE_FROM_CLASS (klass),
+                              g_cclosure_marshal_VOID__OBJECTv);
+
   signals [DRAG_NODE_RECEIVED] =
     g_signal_new ("drag-node-received",
                   G_TYPE_FROM_CLASS (klass),
diff --git a/src/tree/dzl-tree-builder.h b/src/tree/dzl-tree-builder.h
index a2904a6..2bfba3b 100644
--- a/src/tree/dzl-tree-builder.h
+++ b/src/tree/dzl-tree-builder.h
@@ -38,6 +38,8 @@ struct _DzlTreeBuilderClass
                                        GtkWidget           *tree);
   void     (*build_node)              (DzlTreeBuilder      *builder,
                                        DzlTreeNode         *node);
+  void     (*build_children)          (DzlTreeBuilder      *builder,
+                                       DzlTreeNode         *parent);
   gboolean (*node_activated)          (DzlTreeBuilder      *builder,
                                        DzlTreeNode         *node);
   void     (*node_selected)           (DzlTreeBuilder      *builder,
@@ -79,6 +81,7 @@ struct _DzlTreeBuilderClass
 
 DZL_AVAILABLE_IN_ALL
 DzlTree        *dzl_tree_builder_get_tree (DzlTreeBuilder *builder);
+
 DZL_AVAILABLE_IN_3_28
 DzlTreeBuilder *dzl_tree_builder_new      (void);
 
diff --git a/src/tree/dzl-tree-node.c b/src/tree/dzl-tree-node.c
index 05b357e..832720d 100644
--- a/src/tree/dzl-tree-node.c
+++ b/src/tree/dzl-tree-node.c
@@ -41,7 +41,7 @@ struct _DzlTreeNode
   GQuark             expanded_icon_name;
 
   guint              use_markup : 1;
-  guint              needs_build : 1;
+  guint              needs_build_children : 1;
   guint              is_dummy : 1;
   guint              children_possible : 1;
   guint              use_dim_label : 1;
@@ -949,7 +949,7 @@ dzl_tree_node_class_init (DzlTreeNodeClass *klass)
 static void
 dzl_tree_node_init (DzlTreeNode *node)
 {
-  node->needs_build = TRUE;
+  node->needs_build_children = TRUE;
 }
 
 static gboolean
@@ -1073,22 +1073,22 @@ _dzl_tree_node_is_dummy (DzlTreeNode *self)
 }
 
 gboolean
-_dzl_tree_node_get_needs_build (DzlTreeNode *self)
+_dzl_tree_node_get_needs_build_children (DzlTreeNode *self)
 {
   g_assert (DZL_IS_TREE_NODE (self));
 
-  return self->needs_build;
+  return self->needs_build_children;
 }
 
 void
-_dzl_tree_node_set_needs_build (DzlTreeNode *self,
-                                gboolean     needs_build)
+_dzl_tree_node_set_needs_build_children (DzlTreeNode *self,
+                                         gboolean     needs_build_children)
 {
   g_assert (DZL_IS_TREE_NODE (self));
 
-  self->needs_build = !!needs_build;
+  self->needs_build_children = !!needs_build_children;
 
-  if (!needs_build)
+  if (!needs_build_children)
     self->is_dummy = FALSE;
 }
 
@@ -1155,7 +1155,7 @@ dzl_tree_node_get_children_possible (DzlTreeNode *self)
  */
 void
 dzl_tree_node_set_children_possible (DzlTreeNode *self,
-                                    gboolean    children_possible)
+                                     gboolean     children_possible)
 {
   g_return_if_fail (DZL_IS_TREE_NODE (self));
 
@@ -1165,7 +1165,7 @@ dzl_tree_node_set_children_possible (DzlTreeNode *self,
     {
       self->children_possible = children_possible;
 
-      if (self->tree && self->needs_build)
+      if (self->tree != NULL && self->needs_build_children)
         {
           if (self->children_possible)
             _dzl_tree_node_add_dummy_child (self);
@@ -1242,7 +1242,7 @@ dzl_tree_node_n_children (DzlTreeNode *self)
 {
   g_return_val_if_fail (DZL_IS_TREE_NODE (self), 0);
 
-  if (!self->needs_build && self->tree != NULL)
+  if (!self->needs_build_children && self->tree != NULL)
     {
       GtkTreeIter iter;
       GtkTreeModel *model;
@@ -1270,7 +1270,7 @@ dzl_tree_node_nth_child (DzlTreeNode *self,
                          guint        nth)
 {
   g_return_val_if_fail (DZL_IS_TREE_NODE (self), NULL);
-  g_return_val_if_fail (!self->needs_build, NULL);
+  g_return_val_if_fail (!self->needs_build_children, NULL);
 
   if (self->tree != NULL)
     {
diff --git a/src/tree/dzl-tree-private.h b/src/tree/dzl-tree-private.h
index ed988fe..169d488 100644
--- a/src/tree/dzl-tree-private.h
+++ b/src/tree/dzl-tree-private.h
@@ -27,6 +27,8 @@ void          _dzl_tree_invalidate                      (DzlTree
                                                          DzlTreeNode            *node);
 GtkTreePath  *_dzl_tree_get_path                        (DzlTree                *tree,
                                                          GList                  *list);
+void          _dzl_tree_build_children                  (DzlTree                *self,
+                                                         DzlTreeNode            *node);
 void          _dzl_tree_build_node                      (DzlTree                *self,
                                                          DzlTreeNode            *node);
 void          _dzl_tree_append                          (DzlTree                *self,
@@ -55,9 +57,9 @@ void          _dzl_tree_node_set_tree                   (DzlTreeNode
 void          _dzl_tree_node_set_parent                 (DzlTreeNode            *node,
                                                          DzlTreeNode            *parent);
 const gchar  *_dzl_tree_node_get_expanded_icon          (DzlTreeNode            *node);
-gboolean      _dzl_tree_node_get_needs_build            (DzlTreeNode            *node);
-void          _dzl_tree_node_set_needs_build            (DzlTreeNode            *node,
-                                                         gboolean                needs_build);
+gboolean      _dzl_tree_node_get_needs_build_children   (DzlTreeNode            *node);
+void          _dzl_tree_node_set_needs_build_children   (DzlTreeNode            *node,
+                                                         gboolean                needs_build_children);
 void          _dzl_tree_node_add_dummy_child            (DzlTreeNode            *node);
 void          _dzl_tree_node_remove_dummy_child         (DzlTreeNode            *node);
 gboolean      _dzl_tree_node_is_dummy                   (DzlTreeNode            *self);
@@ -69,6 +71,8 @@ void          _dzl_tree_builder_removed                 (DzlTreeBuilder
                                                          DzlTree                *tree);
 void          _dzl_tree_builder_build_node              (DzlTreeBuilder         *builder,
                                                          DzlTreeNode            *node);
+void          _dzl_tree_builder_build_children          (DzlTreeBuilder         *builder,
+                                                         DzlTreeNode            *node);
 gboolean      _dzl_tree_builder_drag_data_get           (DzlTreeBuilder         *builder,
                                                          DzlTreeNode            *node,
                                                          GtkSelectionData       *data);
diff --git a/src/tree/dzl-tree.c b/src/tree/dzl-tree.c
index 4231728..3cbe798 100644
--- a/src/tree/dzl-tree.c
+++ b/src/tree/dzl-tree.c
@@ -124,20 +124,40 @@ _dzl_tree_build_node (DzlTree     *self,
                       DzlTreeNode *node)
 {
   DzlTreePrivate *priv = dzl_tree_get_instance_private (self);
-  gsize i;
 
   g_assert (DZL_IS_TREE (self));
   g_assert (DZL_IS_TREE_NODE (node));
 
-  _dzl_tree_node_set_needs_build (node, FALSE);
+  for (guint i = 0; i < priv->builders->len; i++)
+    {
+      DzlTreeBuilder *builder = g_ptr_array_index (priv->builders, i);
+
+      _dzl_tree_builder_build_node (builder, node);
+    }
+
+  if (!priv->always_expand &&
+      dzl_tree_node_get_children_possible (node) &&
+      dzl_tree_node_n_children (node) == 0)
+    _dzl_tree_node_add_dummy_child (node);
+}
+
+void
+_dzl_tree_build_children (DzlTree     *self,
+                          DzlTreeNode *node)
+{
+  DzlTreePrivate *priv = dzl_tree_get_instance_private (self);
+
+  g_assert (DZL_IS_TREE (self));
+  g_assert (DZL_IS_TREE_NODE (node));
+
+  _dzl_tree_node_set_needs_build_children (node, FALSE);
   _dzl_tree_node_remove_dummy_child (node);
 
-  for (i = 0; i < priv->builders->len; i++)
+  for (guint i = 0; i < priv->builders->len; i++)
     {
-      DzlTreeBuilder *builder;
+      DzlTreeBuilder *builder = g_ptr_array_index (priv->builders, i);
 
-      builder = g_ptr_array_index (priv->builders, i);
-      _dzl_tree_builder_build_node (builder, node);
+      _dzl_tree_builder_build_children (builder, node);
     }
 }
 
@@ -314,17 +334,24 @@ dzl_tree_add_builder_foreach_cb (GtkTreeModel *model,
                                  GtkTreeIter  *iter,
                                  gpointer      user_data)
 {
+  g_autoptr(DzlTreeNode) node = NULL;
   DzlTreeBuilder *builder = user_data;
-  DzlTreeNode *node = NULL;
+  DzlTreePrivate *priv;
+  DzlTree *tree;
 
   g_return_val_if_fail (GTK_IS_TREE_MODEL (model), FALSE);
   g_return_val_if_fail (path != NULL, FALSE);
   g_return_val_if_fail (iter != NULL, FALSE);
 
+  tree = dzl_tree_builder_get_tree (builder);
+  priv = dzl_tree_get_instance_private (tree);
+
   gtk_tree_model_get (model, iter, 0, &node, -1);
-  if (!_dzl_tree_node_get_needs_build (node))
-    _dzl_tree_builder_build_node (builder, node);
-  g_clear_object (&node);
+
+  _dzl_tree_builder_build_node (builder, node);
+
+  if (priv->always_expand || !_dzl_tree_node_get_needs_build_children (node))
+    _dzl_tree_builder_build_children (builder, node);
 
   return FALSE;
 }
@@ -484,17 +511,19 @@ dzl_tree_add (DzlTree     *self,
                                      0, child,
                                      -1);
 
+  _dzl_tree_build_node (self, child);
+
   if (dzl_tree_node_get_children_possible (child))
     _dzl_tree_node_add_dummy_child (child);
 
   if (priv->always_expand)
     {
-      _dzl_tree_build_node (self, child);
+      _dzl_tree_build_children (self, child);
       dzl_tree_node_expand (child, TRUE);
     }
   else if (node == priv->root)
     {
-      _dzl_tree_build_node (self, child);
+      _dzl_tree_build_children (self, child);
     }
 
   g_object_unref (child);
@@ -522,7 +551,7 @@ _dzl_tree_insert_sorted (DzlTree                *self,
 
   _dzl_tree_node_set_tree (child, self);
   _dzl_tree_node_set_parent (child, node);
-  _dzl_tree_node_set_needs_build (child, TRUE);
+  _dzl_tree_node_set_needs_build_children (child, TRUE);
 
   g_object_ref_sink (child);
 
@@ -554,8 +583,10 @@ _dzl_tree_insert_sorted (DzlTree                *self,
   gtk_tree_store_set (priv->store, &children, 0, child, -1);
 
 inserted:
-  if (node == priv->root)
-    _dzl_tree_build_node (self, child);
+  _dzl_tree_build_node (self, child);
+
+  if (priv->always_expand || priv->root == child)
+    _dzl_tree_build_children (self, child);
 
   g_object_unref (child);
 }
@@ -618,12 +649,13 @@ dzl_tree_row_expanded (GtkTreeView *tree_view,
   g_assert (DZL_IS_TREE_NODE (node));
 
   /*
-   * If we are expanding a row that has a dummy child, we might need to
-   * build the node immediately, and re-expand it.
+   * If we are expanding a row that has a dummy child, we need to allow
+   * the builders to add children to the node.
    */
-  if (_dzl_tree_node_get_needs_build (node))
+
+  if (_dzl_tree_node_get_needs_build_children (node))
     {
-      _dzl_tree_build_node (self, node);
+      _dzl_tree_build_children (self, node);
       dzl_tree_node_expand (node, FALSE);
       dzl_tree_node_select (node);
     }
@@ -680,7 +712,7 @@ dzl_tree_row_collapsed (GtkTreeView *tree_view,
         }
 
       _dzl_tree_node_add_dummy_child (node);
-      _dzl_tree_node_set_needs_build (node, TRUE);
+      _dzl_tree_node_set_needs_build_children (node, TRUE);
     }
 
   /* Notify builders of collapse */
@@ -1511,7 +1543,7 @@ dzl_tree_set_root (DzlTree     *self,
           priv->root = g_object_ref_sink (root);
           _dzl_tree_node_set_parent (priv->root, NULL);
           _dzl_tree_node_set_tree (priv->root, self);
-          _dzl_tree_build_node (self, priv->root);
+          _dzl_tree_build_children (self, priv->root);
         }
 
       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ROOT]);
@@ -1535,7 +1567,7 @@ dzl_tree_rebuild (DzlTree *self)
   if (priv->root != NULL)
     {
       gtk_tree_store_clear (priv->store);
-      _dzl_tree_build_node (self, priv->root);
+      _dzl_tree_build_children (self, priv->root);
     }
 }
 
@@ -1661,12 +1693,17 @@ _dzl_tree_invalidate (DzlTree     *self,
       gtk_tree_path_free (path);
     }
 
-  _dzl_tree_node_set_needs_build (node, TRUE);
+  _dzl_tree_node_set_needs_build_children (node, TRUE);
 
   parent = dzl_tree_node_get_parent (node);
 
-  if ((parent == NULL) || dzl_tree_node_get_expanded (parent))
+  /* Build the node (unless it's the root */
+  if (parent != NULL)
     _dzl_tree_build_node (self, node);
+
+  /* Now build the children if necessary */
+  if ((parent == NULL) || dzl_tree_node_get_expanded (parent))
+    _dzl_tree_build_children (self, node);
 }
 
 /**
@@ -1707,8 +1744,8 @@ dzl_tree_find_child_node (DzlTree         *self,
       return NULL;
     }
 
-  if (_dzl_tree_node_get_needs_build (node))
-    _dzl_tree_build_node (self, node);
+  if (_dzl_tree_node_get_needs_build_children (node))
+    _dzl_tree_build_children (self, node);
 
   model = GTK_TREE_MODEL (priv->store);
   path = dzl_tree_node_get_path (node);
@@ -1827,7 +1864,7 @@ dzl_tree_model_filter_recursive (GtkTreeModel *model,
               if (filter->filter_func (filter->self, node, filter->filter_data))
                 return TRUE;
 
-              if (!_dzl_tree_node_get_needs_build (node))
+              if (!_dzl_tree_node_get_needs_build_children (node))
                 {
                   if (dzl_tree_model_filter_recursive (model, &child, filter))
                     return TRUE;
diff --git a/tests/test-tree.c b/tests/test-tree.c
index 739794d..3f4ec7e 100644
--- a/tests/test-tree.c
+++ b/tests/test-tree.c
@@ -1,8 +1,8 @@
 #include <dazzle.h>
 
 static void
-build_node_cb (DzlTreeBuilder *builder,
-               DzlTreeNode    *node)
+build_children_cb (DzlTreeBuilder *builder,
+                   DzlTreeNode    *node)
 {
   GFile *file;
 
@@ -215,7 +215,7 @@ main (gint   argc,
   gtk_container_add (GTK_CONTAINER (scroller), tree);
 
   builder = dzl_tree_builder_new ();
-  g_signal_connect (builder, "build-node", G_CALLBACK (build_node_cb), NULL);
+  g_signal_connect (builder, "build-children", G_CALLBACK (build_children_cb), NULL);
   g_signal_connect (builder, "drag-data-get", G_CALLBACK (node_drag_data_get_cb), NULL);
   g_signal_connect (builder, "drag-data-received", G_CALLBACK (drag_data_received_cb), NULL);
   g_signal_connect (builder, "drag-node-received", G_CALLBACK (drag_node_received_cb), NULL);


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