[gnome-builder] tree: allow GbTree to be even more lazy with dummy children



commit e550ace0510751ece4e0ca41b2950baf0b8ec122
Author: Christian Hergert <christian hergert me>
Date:   Mon Jun 15 03:07:12 2015 -0700

    tree: allow GbTree to be even more lazy with dummy children
    
    Some nodes may know they might have children, but want to delay the work
    of checking and populating those children until necessary. Setting
    gb_tree_node_set_children_possible() will add a dummy child to the node.
    This causes the expand arrow to be displayed. Upon expansion, the node
    will be fully built.

 src/tree/gb-tree-node.c    |   81 +++++++++++++++++++++++++++++++++++++++++
 src/tree/gb-tree-node.h    |    3 ++
 src/tree/gb-tree-private.h |    1 +
 src/tree/gb-tree.c         |   85 ++++---------------------------------------
 4 files changed, 93 insertions(+), 77 deletions(-)
---
diff --git a/src/tree/gb-tree-node.c b/src/tree/gb-tree-node.c
index 0f08aaa..1764f94 100644
--- a/src/tree/gb-tree-node.c
+++ b/src/tree/gb-tree-node.c
@@ -35,6 +35,8 @@ struct _GbTreeNode
   GQuark             icon_name;
   guint              use_markup : 1;
   guint              needs_build : 1;
+  guint              is_dummy : 1;
+  guint              children_possible : 1;
 };
 
 typedef struct
@@ -814,4 +816,83 @@ _gb_tree_node_set_needs_build (GbTreeNode *self,
   g_assert (GB_IS_TREE_NODE (self));
 
   self->needs_build = !!needs_build;
+
+  if (!needs_build)
+    self->is_dummy = FALSE;
+}
+
+void
+_gb_tree_node_add_dummy_child (GbTreeNode *self)
+{
+  GtkTreeModel *model;
+  GbTreeNode *dummy;
+  GtkTreeIter iter;
+  GtkTreeIter parent;
+
+  g_assert (GB_IS_TREE_NODE (self));
+
+  model = gtk_tree_view_get_model (GTK_TREE_VIEW (self->tree));
+
+  gb_tree_node_get_iter (self, &parent);
+
+  dummy = gb_tree_node_new ();
+  gtk_tree_store_append (GTK_TREE_STORE (model), &iter, &parent);
+  gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
+                      0, g_object_ref_sink (dummy),
+                      -1);
+  g_object_unref (dummy);
+}
+
+void
+_gb_tree_node_remove_dummy_child (GbTreeNode *self)
+{
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+  GtkTreeIter children;
+
+  g_assert (GB_IS_TREE_NODE (self));
+
+  if (self->parent == NULL)
+    return;
+
+  model = gtk_tree_view_get_model (GTK_TREE_VIEW (self->tree));
+
+  if (gb_tree_node_get_iter (self, &iter) &&
+      gtk_tree_model_iter_children (model, &children, &iter))
+    {
+      while (gtk_tree_store_remove (GTK_TREE_STORE (model), &children))
+        {
+        }
+    }
+}
+
+/**
+ * gb_tree_node_set_children_possible:
+ * @self: A #GbTreeNode.
+ * @children_possible: If the node has children.
+ *
+ * If the node has not yet been built, setting this to %TRUE will add a
+ * dummy child node. This dummy node will be removed when when the node
+ * is built by the registered #GbTreeBuilder instances.
+ */
+void
+gb_tree_node_set_children_possible (GbTreeNode *self,
+                                    gboolean    children_possible)
+{
+  g_return_if_fail (GB_IS_TREE_NODE (self));
+
+  children_possible = !!children_possible;
+
+  if (children_possible != self->children_possible)
+    {
+      self->children_possible = children_possible;
+
+      if (self->needs_build)
+        {
+          if (self->children_possible)
+            _gb_tree_node_add_dummy_child (self);
+          else
+            _gb_tree_node_remove_dummy_child (self);
+        }
+    }
 }
diff --git a/src/tree/gb-tree-node.h b/src/tree/gb-tree-node.h
index 828883e..34e3d23 100644
--- a/src/tree/gb-tree-node.h
+++ b/src/tree/gb-tree-node.h
@@ -58,6 +58,9 @@ const gchar   *gb_tree_node_get_text      (GbTreeNode   *node);
 void           gb_tree_node_set_text      (GbTreeNode   *node,
                                            const gchar  *text);
 GbTree        *gb_tree_node_get_tree      (GbTreeNode   *node);
+void           gb_tree_node_set_children_possible
+                                          (GbTreeNode   *self,
+                                           gboolean      children_possible);
 
 G_END_DECLS
 
diff --git a/src/tree/gb-tree-private.h b/src/tree/gb-tree-private.h
index 08caa39..5aee1e9 100644
--- a/src/tree/gb-tree-private.h
+++ b/src/tree/gb-tree-private.h
@@ -46,6 +46,7 @@ void         _gb_tree_node_set_parent         (GbTreeNode    *node,
 gboolean     _gb_tree_node_get_needs_build    (GbTreeNode    *node);
 void         _gb_tree_node_set_needs_build    (GbTreeNode    *node,
                                                gboolean       needs_build);
+void         _gb_tree_node_remove_dummy_child (GbTreeNode    *node);
 
 void         _gb_tree_builder_set_tree        (GbTreeBuilder *builder,
                                                GbTree        *tree);
diff --git a/src/tree/gb-tree.c b/src/tree/gb-tree.c
index a42adbb..0a1310f 100644
--- a/src/tree/gb-tree.c
+++ b/src/tree/gb-tree.c
@@ -80,6 +80,7 @@ gb_tree_build_node (GbTree     *self,
   g_assert (GB_IS_TREE_NODE (node));
 
   _gb_tree_node_set_needs_build (node, FALSE);
+  _gb_tree_node_remove_dummy_child (node);
 
   for (i = 0; i < priv->builders->len; i++)
     {
@@ -361,48 +362,6 @@ gb_tree_selection_changed (GbTree           *self,
   IDE_EXIT;
 }
 
-#if 0
-static gboolean
-gb_tree_get_iter_for_node (GbTree      *self,
-                           GtkTreeIter *parent,
-                           GtkTreeIter *iter,
-                           GbTreeNode  *node)
-{
-  GbTreePrivate *priv = gb_tree_get_instance_private (self);
-  GtkTreeModel *model;
-  GbTreeNode *that = NULL;
-  gboolean ret;
-
-  g_return_val_if_fail (GB_IS_TREE (self), FALSE);
-  g_return_val_if_fail (iter != NULL, FALSE);
-  g_return_val_if_fail (GB_IS_TREE_NODE (node), FALSE);
-
-  model = GTK_TREE_MODEL (priv->store);
-
-  if (parent)
-    ret = gtk_tree_model_iter_children (model, iter, parent);
-  else
-    ret = gtk_tree_model_get_iter_first (model, iter);
-
-  if (ret)
-    {
-      do
-        {
-          gtk_tree_model_get (model, iter, 0, &that, -1);
-          if (that == node)
-            {
-              g_clear_object (&that);
-              return TRUE;
-            }
-          g_clear_object (&that);
-        }
-      while (gtk_tree_model_iter_next (model, iter));
-    }
-
-  return FALSE;
-}
-#endif
-
 static gboolean
 gb_tree_add_builder_foreach_cb (GtkTreeModel *model,
                                 GtkTreePath  *path,
@@ -556,7 +515,7 @@ gb_tree_add (GbTree     *self,
 
   gtk_tree_store_set (priv->store, &iter, 0, child, -1);
 
-  if (gb_tree_node_get_expanded (node))
+  if (node == priv->root)
     gb_tree_build_node (self, child);
 
   g_object_unref (child);
@@ -613,7 +572,7 @@ _gb_tree_insert_sorted (GbTree                *self,
   gtk_tree_store_set (priv->store, &children, 0, child, -1);
 
 inserted:
-  if (gb_tree_node_get_expanded (node))
+  if (node == priv->root)
     gb_tree_build_node (self, child);
 
   g_object_unref (child);
@@ -677,42 +636,14 @@ gb_tree_row_expanded (GtkTreeView *tree_view,
 
   gtk_tree_model_get (model, iter, 0, &node, -1);
 
-  if (_gb_tree_node_get_needs_build (node))
-    gb_tree_build_node (self, node);
-
   /*
-   * The following code looks like inefficient use of GtkTreeModel as we
-   * are not using iter_children() and iter_next(). However, this is required
-   * since the tree will likely have changes since our last iteration cycle.
-   * This is due to the builders adding children for the individual nodes.
-   * Therefore, we simply require that path is still valid (since builders
-   * cannot change anything but current/child nodes).
+   * If we are expanding a row that has a dummy child, we might need to
+   * build the node immediately, and re-expand it.
    */
-
-  if (gtk_tree_model_iter_has_child (model, iter))
+  if (_gb_tree_node_get_needs_build (node))
     {
-      GtkTreeIter child_iter;
-      guint n_children;
-      guint i;
-
-      n_children = gtk_tree_model_iter_n_children (model, iter);
-
-      for (i = 0; i < n_children; i++)
-        {
-          gtk_tree_model_get_iter (model, iter, path);
-
-          if (gtk_tree_model_iter_nth_child (model, &child_iter, iter, i))
-            {
-              GbTreeNode *child;
-
-              gtk_tree_model_get (model, &child_iter, 0, &child, -1);
-
-              if (_gb_tree_node_get_needs_build (child))
-                gb_tree_build_node (self, child);
-
-              g_clear_object (&child);
-            }
-        }
+      gb_tree_build_node (self, node);
+      gb_tree_node_expand (node, FALSE);
     }
 
   g_clear_object (&node);


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