[gnome-builder] project-tree: add gbp_project_tree_reveal()



commit 8af719a31e3af77356d91585c15181d7af878840
Author: Christian Hergert <chergert redhat com>
Date:   Mon Oct 26 14:15:21 2020 -0700

    project-tree: add gbp_project_tree_reveal()
    
    This helper handles the asynchronous nature of expanding the file tree to
    find a given file or directory within the project. The tree will be
    expanded up to that node and the node will be selected and scrolled into
    view of the user.
    
    We used ot have something like this before movin to IdeTree, and this
    restores that functionality.
    
    Related #1320

 src/plugins/project-tree/gbp-project-tree.c | 171 ++++++++++++++++++++++++++++
 src/plugins/project-tree/gbp-project-tree.h |   3 +
 2 files changed, 174 insertions(+)
---
diff --git a/src/plugins/project-tree/gbp-project-tree.c b/src/plugins/project-tree/gbp-project-tree.c
index 5fd644118..ffa55aa2d 100644
--- a/src/plugins/project-tree/gbp-project-tree.c
+++ b/src/plugins/project-tree/gbp-project-tree.c
@@ -25,6 +25,8 @@
 #include <libide-gui.h>
 #include <libide-projects.h>
 
+#include "ide-tree-private.h"
+
 #include "gbp-project-tree.h"
 
 struct _GbpProjectTree
@@ -176,3 +178,172 @@ static void
 gbp_project_tree_init (GbpProjectTree *self)
 {
 }
+
+static IdeTreeNode *
+gbp_project_tree_get_project_files (GbpProjectTree *self)
+{
+  IdeTreeModel *model;
+  IdeTreeNode *project_files = NULL;
+
+  g_assert (GBP_IS_PROJECT_TREE (self));
+
+  model = IDE_TREE_MODEL (gtk_tree_view_get_model (GTK_TREE_VIEW (self)));
+  ide_tree_node_traverse (ide_tree_model_get_root (model),
+                          G_PRE_ORDER,
+                          G_TRAVERSE_ALL,
+                          1,
+                          locate_project_files,
+                          &project_files);
+
+  return project_files;
+}
+
+typedef struct
+{
+  GbpProjectTree *tree;
+  IdeTreeNode    *node;
+  GFile          *file;
+} Reveal;
+
+static void reveal_next (Reveal *r);
+
+static void
+reveal_free (Reveal *r)
+{
+  g_clear_object (&r->tree);
+  g_clear_object (&r->node);
+  g_clear_object (&r->file);
+  g_free (r);
+}
+
+static void
+reveal_next_cb (GObject      *object,
+                GAsyncResult *result,
+                gpointer      user_data)
+{
+  IdeTreeModel *model = (IdeTreeModel *)object;
+  Reveal *r = user_data;
+
+  g_assert (IDE_IS_TREE_MODEL (model));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (r != NULL);
+  g_assert (GBP_IS_PROJECT_TREE (r->tree));
+  g_assert (IDE_IS_TREE_NODE (r->node));
+  g_assert (G_IS_FILE (r->file));
+
+  if (!ide_tree_model_expand_finish (model, result, NULL))
+    reveal_free (r);
+  else
+    reveal_next (g_steal_pointer (&r));
+}
+
+static void
+reveal_next (Reveal *r)
+{
+  g_autoptr(GFile) file = NULL;
+  IdeProjectFile *pf;
+
+  g_assert (r != NULL);
+  g_assert (GBP_IS_PROJECT_TREE (r->tree));
+  g_assert (IDE_IS_TREE_NODE (r->node));
+  g_assert (G_IS_FILE (r->file));
+
+  if (!ide_tree_node_holds (r->node, IDE_TYPE_PROJECT_FILE) ||
+      !(pf = ide_tree_node_get_item (r->node)) ||
+      !IDE_IS_PROJECT_FILE (pf) ||
+      !(file = ide_project_file_ref_file (pf)))
+    goto failure;
+
+  if (g_file_has_prefix (r->file, file))
+    {
+      IdeTreeNode *child;
+
+      /* If this node cannot have children, then there is no way we
+       * can expect to find the child there.
+       */
+      if (!ide_tree_node_get_children_possible (r->node))
+        goto failure;
+
+      /* If this node needs to be built, then build it before we
+       * continue processing.
+       */
+      if (_ide_tree_node_get_needs_build_children (r->node))
+        {
+          IdeTreeModel *model;
+
+          if (!(model = IDE_TREE_MODEL (gtk_tree_view_get_model (GTK_TREE_VIEW (r->tree)))))
+            goto failure;
+
+          ide_tree_model_expand_async (model,
+                                       r->node,
+                                       NULL,
+                                       reveal_next_cb,
+                                       r);
+          return;
+        }
+
+      /* Tree to find the first child which is equal to or is a prefix
+       * for the target file.
+       */
+      if (!(child = ide_tree_node_get_nth_child (r->node, 0)))
+        goto failure;
+
+      do
+        {
+          IdeProjectFile *cpf;
+          g_autoptr(GFile) cf = NULL;
+
+          if (!ide_tree_node_holds (child, IDE_TYPE_PROJECT_FILE) ||
+              !(cpf = ide_tree_node_get_item (child)) ||
+              !IDE_IS_PROJECT_FILE (cpf) ||
+              !(cf = ide_project_file_ref_file (cpf)) ||
+              !G_IS_FILE (cf))
+            continue;
+
+          if (g_file_has_prefix (r->file, cf) || g_file_equal (r->file, cf))
+            {
+              g_set_object (&r->node, child);
+              reveal_next (r);
+              return;
+            }
+        }
+      while ((child = ide_tree_node_get_next (child)));
+    }
+  else if (g_file_equal (r->file, file))
+    {
+      g_autoptr(GtkTreePath) path = ide_tree_node_get_path (r->node);
+      gtk_tree_view_expand_to_path (GTK_TREE_VIEW (r->tree), path);
+      ide_tree_select_node (IDE_TREE (r->tree), r->node);
+      gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (r->tree),
+                                    path, NULL, FALSE, 0, 0);
+    }
+
+failure:
+  reveal_free (r);
+}
+
+void
+gbp_project_tree_reveal (GbpProjectTree *self,
+                         GFile          *file)
+{
+  IdeTreeNode *project_files;
+  Reveal *r;
+
+  g_return_if_fail (GBP_IS_PROJECT_TREE (self));
+  g_return_if_fail (!file || G_IS_FILE (file));
+
+  if (file == NULL)
+    return;
+
+  project_files = gbp_project_tree_get_project_files (self);
+
+  if (!IDE_IS_TREE_NODE (project_files))
+    return;
+
+  r = g_new0 (Reveal, 1);
+  r->tree = g_object_ref (self);
+  r->node = g_object_ref (project_files);
+  r->file = g_object_ref (file);
+
+  reveal_next (g_steal_pointer (&r));
+}
diff --git a/src/plugins/project-tree/gbp-project-tree.h b/src/plugins/project-tree/gbp-project-tree.h
index 1a1404dbe..a0ea31968 100644
--- a/src/plugins/project-tree/gbp-project-tree.h
+++ b/src/plugins/project-tree/gbp-project-tree.h
@@ -28,4 +28,7 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (GbpProjectTree, gbp_project_tree, GBP, PROJECT_TREE, IdeTree)
 
+void gbp_project_tree_reveal (GbpProjectTree *self,
+                              GFile          *file);
+
 G_END_DECLS


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