[gtk/prop-list: 4/33] inspector: Use a column view for the resource list



commit c021ac1af11f753988a7583ddc208ef4901821c4
Author: Matthias Clasen <mclasen redhat com>
Date:   Sat Dec 7 22:26:35 2019 -0500

    inspector: Use a column view for the resource list
    
    A conversion from tree view to column view.

 gtk/inspector/meson.build       |   3 +-
 gtk/inspector/resource-holder.c | 106 ++++++
 gtk/inspector/resource-holder.h |  24 ++
 gtk/inspector/resource-list.c   | 713 +++++++++++++++++++++++-----------------
 gtk/inspector/resource-list.ui  |  60 ++--
 5 files changed, 568 insertions(+), 338 deletions(-)
---
diff --git a/gtk/inspector/meson.build b/gtk/inspector/meson.build
index f297fe2d0a..ea5d77c09e 100644
--- a/gtk/inspector/meson.build
+++ b/gtk/inspector/meson.build
@@ -35,5 +35,6 @@ inspector_sources = files(
   'updatesoverlay.c',
   'visual.c',
   'window.c',
-  'prop-holder.c'
+  'prop-holder.c',
+  'resource-holder.c'
 )
diff --git a/gtk/inspector/resource-holder.c b/gtk/inspector/resource-holder.c
new file mode 100644
index 0000000000..d9aee9bed2
--- /dev/null
+++ b/gtk/inspector/resource-holder.c
@@ -0,0 +1,106 @@
+#include "resource-holder.h"
+
+struct _ResourceHolder {
+  GObject instance;
+
+  char *name;
+  char *path;
+  int count;
+  gsize size;
+  GListModel *children;
+  ResourceHolder *parent;
+};
+
+G_DEFINE_TYPE (ResourceHolder, resource_holder, G_TYPE_OBJECT)
+
+static void
+resource_holder_init (ResourceHolder *holder)
+{
+}
+
+static void
+resource_holder_finalize (GObject *object)
+{
+  ResourceHolder *holder = RESOURCE_HOLDER (object);
+
+  g_free (holder->name);
+  g_free (holder->path);
+  g_clear_object (&holder->children);
+
+  G_OBJECT_CLASS (resource_holder_parent_class)->finalize (object);
+}
+
+static void
+resource_holder_class_init (ResourceHolderClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+  object_class->finalize = resource_holder_finalize;
+}
+
+ResourceHolder *
+resource_holder_new (const char *name,
+                     const char *path,
+                     int count,
+                     gsize size,
+                     GListModel *children)
+{
+  ResourceHolder *holder;
+
+  holder = g_object_new (RESOURCE_TYPE_HOLDER, NULL);
+
+  holder->name = g_strdup (name);
+  holder->path = g_strdup (path);
+  holder->count = count;
+  holder->size = size;
+  g_set_object (&holder->children, children);
+
+  if (children)
+    {
+      int i;
+      for (i = 0; i < g_list_model_get_n_items (children); i++)
+        {
+          ResourceHolder *child = g_list_model_get_item (children, i);
+          child->parent = holder;
+          g_object_unref (child);
+        }
+    }
+
+  return holder;
+}
+
+const char *
+resource_holder_get_name (ResourceHolder *holder)
+{
+  return holder->name;
+}
+
+const char *
+resource_holder_get_path (ResourceHolder *holder)
+{
+  return holder->path;
+}
+
+int
+resource_holder_get_count (ResourceHolder *holder)
+{
+  return holder->count;
+}
+
+gsize
+resource_holder_get_size (ResourceHolder *holder)
+{
+  return holder->size;
+}
+
+GListModel *
+resource_holder_get_children (ResourceHolder *holder)
+{
+  return holder->children;
+}
+
+ResourceHolder *
+resource_holder_get_parent (ResourceHolder *holder)
+{
+  return holder->parent;
+}
diff --git a/gtk/inspector/resource-holder.h b/gtk/inspector/resource-holder.h
new file mode 100644
index 0000000000..bb847f887f
--- /dev/null
+++ b/gtk/inspector/resource-holder.h
@@ -0,0 +1,24 @@
+#ifndef __RESOURCE_HOLDER_H__
+#define __RESOURCE_HOLDER_H__
+
+#include <gtk/gtk.h>
+
+#define RESOURCE_TYPE_HOLDER (resource_holder_get_type ())
+
+G_DECLARE_FINAL_TYPE (ResourceHolder, resource_holder, RESOURCE, HOLDER, GObject)
+
+ResourceHolder * resource_holder_new         (const char *name,
+                                              const char *path,
+                                              int         count,
+                                              gsize       size,
+                                              GListModel *children);
+
+const char *resource_holder_get_name     (ResourceHolder *holder);
+const char *resource_holder_get_path     (ResourceHolder *holder);
+int         resource_holder_get_count    (ResourceHolder *holder);
+gsize       resource_holder_get_size     (ResourceHolder *holder);
+GListModel *resource_holder_get_children (ResourceHolder *holder);
+ResourceHolder *resource_holder_get_parent   (ResourceHolder *holder);
+
+#endif /* __RESOURCE_HOLDER_H__ */
+
diff --git a/gtk/inspector/resource-list.c b/gtk/inspector/resource-list.c
index 9f413d0ef1..9be6f7387f 100644
--- a/gtk/inspector/resource-list.c
+++ b/gtk/inspector/resource-list.c
@@ -19,8 +19,6 @@
 
 #include "resource-list.h"
 
-#include "treewalk.h"
-
 #include "gtkbutton.h"
 #include "gtklabel.h"
 #include "gtksearchbar.h"
@@ -30,6 +28,7 @@
 #include "gtktreeselection.h"
 #include "gtktreestore.h"
 #include "gtkeventcontrollerkey.h"
+#include "resource-holder.h"
 
 #include <glib/gi18n-lib.h>
 
@@ -39,14 +38,6 @@ enum
   PROP_BUTTONS
 };
 
-enum
-{
-  COLUMN_NAME,
-  COLUMN_PATH,
-  COLUMN_COUNT,
-  COLUMN_SIZE
-};
-
 struct _GtkInspectorResourceListPrivate
 {
   GtkTreeStore *model;
@@ -59,35 +50,34 @@ struct _GtkInspectorResourceListPrivate
   GtkWidget *size_label;
   GtkWidget *info_grid;
   GtkWidget *stack;
-  GtkWidget *tree;
   GtkWidget *buttons;
   GtkWidget *open_details_button;
   GtkWidget *close_details_button;
-  GtkTreeViewColumn *path_column;
-  GtkTreeViewColumn *count_column;
-  GtkCellRenderer *count_renderer;
-  GtkTreeViewColumn *size_column;
-  GtkCellRenderer *size_renderer;
   GtkWidget *search_bar;
   GtkWidget *search_entry;
-  GtkTreeWalk *walk;
-  gint search_length;
+
+  GtkWidget *list;
+  GtkColumnViewColumn *path;
+  GtkColumnViewColumn *count;
+  GtkColumnViewColumn *size;
+
+  GtkTreeListModel *tree_model;
+  GtkSingleSelection *selection;
 };
 
 
 G_DEFINE_TYPE_WITH_PRIVATE (GtkInspectorResourceList, gtk_inspector_resource_list, GTK_TYPE_BOX)
 
-static void
-load_resources_recurse (GtkInspectorResourceList *sl,
-                        GtkTreeIter              *parent,
-                        const gchar              *path,
-                        gint                     *count_out,
-                        gsize                    *size_out)
+static GListModel *
+load_resources_recurse (const char *path,
+                        int        *count_out,
+                        gsize      *size_out)
 {
   gchar **names;
   gint i;
-  GtkTreeIter iter;
-  guint64 stored_size;
+  GListStore *result;
+
+  result = g_list_store_new (RESOURCE_TYPE_HOLDER);
 
   names = g_resources_enumerate_children (path, 0, NULL);
   for (i = 0; names[i]; i++)
@@ -97,6 +87,8 @@ load_resources_recurse (GtkInspectorResourceList *sl,
       gboolean has_slash;
       gint count;
       gsize size;
+      GListModel *children;
+      ResourceHolder *holder;
 
       p = g_strconcat (path, names[i], NULL);
 
@@ -106,18 +98,13 @@ load_resources_recurse (GtkInspectorResourceList *sl,
       if (has_slash)
         names[i][len - 1] = '\0';
 
-      gtk_tree_store_append (sl->priv->model, &iter, parent);
-      gtk_tree_store_set (sl->priv->model, &iter,
-                          COLUMN_NAME, names[i],
-                          COLUMN_PATH, p,
-                          -1);
-
       count = 0;
       size = 0;
 
       if (has_slash)
         {
-          load_resources_recurse (sl, &iter, p, &count, &size);
+          children = load_resources_recurse (p, &count, &size);
+
           *count_out += count;
           *size_out += size;
         }
@@ -129,53 +116,41 @@ load_resources_recurse (GtkInspectorResourceList *sl,
               *count_out += 1;
               *size_out += size;
             }
+          children = NULL;
         }
 
-      stored_size = size;
-      gtk_tree_store_set (sl->priv->model, &iter,
-                          COLUMN_COUNT, count,
-                          COLUMN_SIZE, stored_size,
-                          -1);
+      holder = resource_holder_new (names[i], p, count, size, children);
+      g_clear_object (&children);
+      g_list_store_append (result, holder);
+      g_object_unref (holder);
 
       g_free (p);
     }
+
   g_strfreev (names);
 
+  return G_LIST_MODEL (result);
 }
 
 static gboolean
 populate_details (GtkInspectorResourceList *rl,
-                  GtkTreePath              *tree_path)
+                  ResourceHolder           *holder)
 {
-  GtkTreeIter iter;
-  gchar *path;
-  gchar *name;
+  const char *path;
+  const char *name;
   GBytes *bytes;
   gchar *type;
   gconstpointer data;
-  gint count;
   gsize size;
-  guint64 stored_size;
   GError *error = NULL;
   gchar *markup;
 
-
-  gtk_tree_model_get_iter (GTK_TREE_MODEL (rl->priv->model), &iter, tree_path);
- 
-  gtk_tree_model_get (GTK_TREE_MODEL (rl->priv->model), &iter,
-                      COLUMN_PATH, &path,
-                      COLUMN_NAME, &name,
-                      COLUMN_COUNT, &count,
-                      COLUMN_SIZE, &stored_size,
-                      -1);
-  size = stored_size;
+  path = resource_holder_get_path (holder);
+  name = resource_holder_get_name (holder);
+  size = resource_holder_get_size (holder);
 
    if (g_str_has_suffix (path, "/"))
-     {
-       g_free (path);
-       g_free (name);
-       return FALSE;
-     }
+     return FALSE;
 
   markup = g_strconcat ("<span face='Monospace' size='small'>", path, "</span>", NULL);
   gtk_label_set_markup (GTK_LABEL (rl->priv->name_label), markup);
@@ -231,237 +206,145 @@ populate_details (GtkInspectorResourceList *rl,
       g_free (content_text);
     }
 
-  g_free (path);
-  g_free (name);
-
   return TRUE;
 }
 
 static void
-row_activated (GtkTreeView              *treeview,
-               GtkTreePath              *path,
-               GtkTreeViewColumn        *column,
-               GtkInspectorResourceList *sl)
+on_row_activated (GtkColumnView            *view,
+                  guint                     position,
+                  GtkInspectorResourceList *rl)
 {
-  if (!populate_details (sl, path))
-    return;
+  gpointer item;
+  ResourceHolder *holder;
 
-  gtk_stack_set_visible_child_name (GTK_STACK (sl->priv->stack), "details");
-  gtk_stack_set_visible_child_name (GTK_STACK (sl->priv->buttons), "details");
+  item = g_list_model_get_item (G_LIST_MODEL (rl->priv->selection), position);
+  holder = gtk_tree_list_row_get_item (item);
+  g_object_unref (item);
+  if (populate_details (rl, holder))
+    {
+      gtk_stack_set_visible_child_name (GTK_STACK (rl->priv->stack), "details");
+      gtk_stack_set_visible_child_name (GTK_STACK (rl->priv->buttons), "details");
+    }
+  g_object_unref (holder);
 }
 
 static gboolean
 can_show_details (GtkInspectorResourceList *rl)
 {
-  GtkTreeSelection *selection;
-  GtkTreeModel *model;
-  GtkTreeIter iter;
-  gchar *path;
+  gpointer item;
+  ResourceHolder *holder;
+  const char *path;
 
-  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (rl->priv->tree));
-  if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+  item = gtk_single_selection_get_selected_item (rl->priv->selection);
+  holder = gtk_tree_list_row_get_item (item);
+  if (holder == NULL)
     return FALSE;
-
-  gtk_tree_model_get (GTK_TREE_MODEL (rl->priv->model), &iter,
-                      COLUMN_PATH, &path,
-                      -1);
-
-   if (g_str_has_suffix (path, "/"))
-     {
-       g_free (path);
-       return FALSE;
-     }
-
-  g_free (path);
-  return TRUE;
+  path = resource_holder_get_path (holder);
+  g_object_unref (holder);
+  return !g_str_has_suffix (path, "/");
 }
 
 static void
-on_selection_changed (GtkTreeSelection         *selection,
+on_selection_changed (GtkSelectionModel        *selection,
+                      guint                     position,
+                      guint                     n_items,
                       GtkInspectorResourceList *rl)
 {
-  GtkTreeIter iter;
-
-  if (gtk_tree_selection_get_selected (selection, NULL, &iter))
-    gtk_tree_walk_reset (rl->priv->walk, &iter);
-  else
-    gtk_tree_walk_reset (rl->priv->walk, NULL);
-
   gtk_widget_set_sensitive (rl->priv->open_details_button, can_show_details (rl));
 }
 
 static void
 open_details (GtkWidget                *button,
-              GtkInspectorResourceList *sl)
+              GtkInspectorResourceList *rl)
 {
-  GtkTreeSelection *selection;
-  GtkTreeModel *model;
-  GtkTreeIter iter;
-  GtkTreePath *path;
+  gpointer item;
+  ResourceHolder *holder;
 
-  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (sl->priv->tree));
-  if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+  item = gtk_single_selection_get_selected_item (rl->priv->selection);
+  holder = gtk_tree_list_row_get_item (item);
+  if (holder == NULL)
     return;
-  
-  path = gtk_tree_model_get_path (model, &iter);
-  if (populate_details (sl, path))
+  if (populate_details (rl, holder))
     {
-      gtk_stack_set_visible_child_name (GTK_STACK (sl->priv->stack), "details");
-      gtk_stack_set_visible_child_name (GTK_STACK (sl->priv->buttons), "details");
+      gtk_stack_set_visible_child_name (GTK_STACK (rl->priv->stack), "details");
+      gtk_stack_set_visible_child_name (GTK_STACK (rl->priv->buttons), "details");
     }
-
-  gtk_tree_path_free (path);
+  g_object_unref (holder);
 }
 
 static void
 close_details (GtkWidget                *button,
-               GtkInspectorResourceList *sl)
+               GtkInspectorResourceList *rl)
 {
-  gtk_stack_set_visible_child_name (GTK_STACK (sl->priv->stack), "list");
-  gtk_stack_set_visible_child_name (GTK_STACK (sl->priv->buttons), "list");
+  gtk_stack_set_visible_child_name (GTK_STACK (rl->priv->stack), "list");
+  gtk_stack_set_visible_child_name (GTK_STACK (rl->priv->buttons), "list");
 }
 
-static void
-load_resources (GtkInspectorResourceList *sl)
+static GListModel *
+load_resources (void)
 {
   gint count = 0;
   gsize size = 0;
 
-  load_resources_recurse (sl, NULL, "/", &count, &size);
-}
-
-static void
-count_data_func (GtkTreeViewColumn *col,
-                 GtkCellRenderer   *cell,
-                 GtkTreeModel      *model,
-                 GtkTreeIter       *iter,
-                 gpointer           data)
-{
-  gint count;
-  gchar *text;
-
-  gtk_tree_model_get (model, iter, COLUMN_COUNT, &count, -1);
-  if (count > 0)
-    {
-      text = g_strdup_printf ("%d", count);
-      g_object_set (cell, "text", text, NULL);
-      g_free (text);
-    }
-  else
-    g_object_set (cell, "text", "", NULL);
-}
-
-static void
-size_data_func (GtkTreeViewColumn *col,
-                GtkCellRenderer   *cell,
-                GtkTreeModel      *model,
-                GtkTreeIter       *iter,
-                gpointer           data)
-{
-  gsize size;
-  guint64 stored_size;
-  gchar *text;
-
-  gtk_tree_model_get (model, iter, COLUMN_SIZE, &stored_size, -1);
-  size = stored_size;
-  text = g_format_size (size);
-  g_object_set (cell, "text", text, NULL);
-  g_free (text);
+  return load_resources_recurse ("/", &count, &size);
 }
 
 static void
 on_map (GtkWidget *widget)
 {
-  GtkInspectorResourceList *sl = GTK_INSPECTOR_RESOURCE_LIST (widget);
+  GtkInspectorResourceList *rl = GTK_INSPECTOR_RESOURCE_LIST (widget);
 
-  gtk_tree_view_expand_all (GTK_TREE_VIEW (sl->priv->tree));
-  gtk_stack_set_visible_child_name (GTK_STACK (sl->priv->stack), "list");
-  gtk_widget_set_sensitive (sl->priv->open_details_button, can_show_details (sl));
+  gtk_stack_set_visible_child_name (GTK_STACK (rl->priv->stack), "list");
+  gtk_widget_set_sensitive (rl->priv->open_details_button, can_show_details (rl));
 }
 
-static void
-move_search_to_row (GtkInspectorResourceList *sl,
-                    GtkTreeIter              *iter)
-{
-  GtkTreeSelection *selection;
-  GtkTreePath *path;
-
-  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (sl->priv->tree));
-  path = gtk_tree_model_get_path (GTK_TREE_MODEL (sl->priv->model), iter);
-  gtk_tree_view_expand_to_path (GTK_TREE_VIEW (sl->priv->tree), path);
-  gtk_tree_selection_select_path (selection, path);
-  gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (sl->priv->tree), path, NULL, TRUE, 0.5, 0.0);
-  gtk_tree_path_free (path);
-}
+static gboolean search (GtkInspectorResourceList *rl,
+                        gboolean                  forward,
+                        gboolean                  force_progress);
 
 static gboolean
 key_pressed (GtkEventController       *controller,
              guint                     keyval,
              guint                     keycode,
              GdkModifierType           state,
-             GtkInspectorResourceList *sl)
+             GtkInspectorResourceList *rl)
 {
-  if (gtk_widget_get_mapped (GTK_WIDGET (sl)))
+  if (gtk_widget_get_mapped (GTK_WIDGET (rl)))
     {
       GdkModifierType default_accel;
       gboolean search_started;
 
-      search_started = gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (sl->priv->search_bar));
-      default_accel = gtk_widget_get_modifier_mask (GTK_WIDGET (sl), 
GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR);
+      search_started = gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (rl->priv->search_bar));
+      default_accel = gtk_widget_get_modifier_mask (GTK_WIDGET (rl), 
GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR);
 
       if (search_started &&
           (keyval == GDK_KEY_Return ||
            keyval == GDK_KEY_ISO_Enter ||
            keyval == GDK_KEY_KP_Enter))
         {
-          GtkTreeSelection *selection;
-          GtkTreeModel *model;
-          GtkTreeIter iter;
-          GtkTreePath *path;
-
-          selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (sl->priv->tree));
-          if (gtk_tree_selection_get_selected (selection, &model, &iter))
-            {
-              path = gtk_tree_model_get_path (model, &iter);
-              gtk_tree_view_row_activated (GTK_TREE_VIEW (sl->priv->tree),
-                                           path,
-                                           sl->priv->path_column);
-              gtk_tree_path_free (path);
-
-              return GDK_EVENT_STOP;
-            }
-          else
-            return GDK_EVENT_PROPAGATE;
+          gtk_widget_activate (GTK_WIDGET (rl->priv->list));
+          return GDK_EVENT_PROPAGATE;
         }
       else if (search_started &&
                (keyval == GDK_KEY_Escape))
         {
-          gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (sl->priv->search_bar), FALSE);
+          gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (rl->priv->search_bar), FALSE);
           return GDK_EVENT_STOP;
         }
       else if (search_started &&
                ((state & (default_accel | GDK_SHIFT_MASK)) == (default_accel | GDK_SHIFT_MASK)) &&
                (keyval == GDK_KEY_g || keyval == GDK_KEY_G))
         {
-          GtkTreeIter iter;
-          if (gtk_tree_walk_next_match (sl->priv->walk, TRUE, TRUE, &iter))
-            move_search_to_row (sl, &iter);
-          else
-            gtk_widget_error_bell (GTK_WIDGET (sl));
-
+          if (!search (rl, FALSE, TRUE))
+            gtk_widget_error_bell (GTK_WIDGET (rl));
           return GDK_EVENT_STOP;
         }
       else if (search_started &&
                ((state & (default_accel | GDK_SHIFT_MASK)) == default_accel) &&
                (keyval == GDK_KEY_g || keyval == GDK_KEY_G))
         {
-          GtkTreeIter iter;
-
-          if (gtk_tree_walk_next_match (sl->priv->walk, TRUE, FALSE, &iter))
-            move_search_to_row (sl, &iter);
-          else
-            gtk_widget_error_bell (GTK_WIDGET (sl));
-
+          if (!search (rl, TRUE, TRUE))
+            gtk_widget_error_bell (GTK_WIDGET (rl));
           return GDK_EVENT_STOP;
         }
     }
@@ -478,7 +361,7 @@ destroy_controller (GtkEventController *controller)
 static void
 root (GtkWidget *widget)
 {
-  GtkInspectorResourceList *sl = GTK_INSPECTOR_RESOURCE_LIST (widget);
+  GtkInspectorResourceList *rl = GTK_INSPECTOR_RESOURCE_LIST (widget);
   GtkEventController *controller;
   GtkWidget *toplevel;
 
@@ -491,7 +374,7 @@ root (GtkWidget *widget)
   g_signal_connect (controller, "key-pressed", G_CALLBACK (key_pressed), widget);
   gtk_widget_add_controller (toplevel, controller);
 
-  gtk_search_bar_set_key_capture_widget (GTK_SEARCH_BAR (sl->priv->search_bar), toplevel);
+  gtk_search_bar_set_key_capture_widget (GTK_SEARCH_BAR (rl->priv->search_bar), toplevel);
 }
 
 static void
@@ -505,27 +388,6 @@ unroot (GtkWidget *widget)
   GTK_WIDGET_CLASS (gtk_inspector_resource_list_parent_class)->unroot (widget);
 }
 
-static void
-on_search_changed (GtkSearchEntry           *entry,
-                   GtkInspectorResourceList *sl)
-{
-  GtkTreeIter iter;
-  gint length;
-  gboolean backwards;
-
-  length = strlen (gtk_editable_get_text (GTK_EDITABLE (entry)));
-  backwards = length < sl->priv->search_length;
-  sl->priv->search_length = length;
-
-  if (length == 0)
-    return;
-
-  if (gtk_tree_walk_next_match (sl->priv->walk, backwards, backwards, &iter))
-    move_search_to_row (sl, &iter);
-  else if (!backwards)
-    gtk_widget_error_bell (GTK_WIDGET (sl));
-}
-
 static gboolean
 match_string (const gchar *string,
               const gchar *text)
@@ -544,107 +406,247 @@ match_string (const gchar *string,
 }
 
 static gboolean
-match_row (GtkTreeModel *model,
-           GtkTreeIter  *iter,
-           gpointer      data)
+match_object (GObject    *object,
+              const char *text)
 {
-  GtkInspectorResourceList *sl = data;
-  gchar *name, *path;
-  const gchar *text;
-  gboolean match;
+  const char *name = resource_holder_get_name (RESOURCE_HOLDER (object));
 
-  text = gtk_editable_get_text (GTK_EDITABLE (sl->priv->search_entry));
-  gtk_tree_model_get (model, iter,
-                      COLUMN_NAME, &name,
-                      COLUMN_PATH, &path,
-                      -1);
+  if (match_string (name, text))
+    return TRUE;
 
-  match = (match_string (name, text) ||
-           match_string (path, text));
+  return FALSE;
+}
 
-  g_free (name);
-  g_free (path);
+static GObject *
+search_children (GObject    *object,
+                 const char *text,
+                 gboolean    forward)
+{
+  GListModel *children;
+  GObject *child, *result;
+  guint i, n;
 
-  return match;
+  children = resource_holder_get_children (RESOURCE_HOLDER (object));
+  if (children == NULL)
+    return NULL;
+
+  n = g_list_model_get_n_items (children);
+  for (i = 0; i < n; i++)
+    {
+      child = g_list_model_get_item (children, forward ? i : n - i - 1);
+      if (match_object (child, text))
+        return child;
+
+      result = search_children (child, text, forward);
+      g_object_unref (child);
+      if (result)
+        return result;
+    }
+
+  return NULL;
+}
+
+static guint
+model_get_item_index (GListModel *model,
+                      gpointer    item)
+{
+  gpointer cmp;
+  guint i;
+
+  for (i = 0; (cmp = g_list_model_get_item (model, i)); i++)
+    {
+      if (cmp == item)
+        {
+          g_object_unref (cmp);
+          return i;
+        }
+      g_object_unref (cmp);
+    }
+
+  return G_MAXUINT;
+}
+
+static GtkTreeListRow *
+find_and_expand_object (GtkTreeListModel *model,
+                        GObject          *object)
+{
+  GtkTreeListRow *result;
+  GObject *parent;
+  guint pos;
+
+  parent = G_OBJECT (resource_holder_get_parent (RESOURCE_HOLDER (object)));
+  if (parent)
+    {
+      GtkTreeListRow *parent_row = find_and_expand_object (model, parent);
+      if (parent_row == NULL)
+        return NULL;
+
+      gtk_tree_list_row_set_expanded (parent_row, TRUE);
+      pos = model_get_item_index (gtk_tree_list_row_get_children (parent_row), object);
+      result = gtk_tree_list_row_get_child_row (parent_row, pos);
+      g_object_unref (parent_row);
+    }
+  else
+    {
+      pos = model_get_item_index (gtk_tree_list_model_get_model (model), object);
+      result = gtk_tree_list_model_get_child_row (model, pos);
+    }
+
+  return result;
 }
 
 static void
-search_mode_changed (GObject                  *search_bar,
-                     GParamSpec               *pspec,
-                     GtkInspectorResourceList *sl)
+select_object (GtkInspectorResourceList *rl,
+               GObject *object)
+{
+  GtkTreeListRow *row_item;
+
+  row_item = find_and_expand_object (rl->priv->tree_model, object);
+  if (row_item == NULL)
+    return;
+
+  gtk_single_selection_set_selected (rl->priv->selection,
+                                     gtk_tree_list_row_get_position (row_item));
+}
+
+static gboolean
+search (GtkInspectorResourceList *rl,
+        gboolean                  forward,
+        gboolean                  force_progress)
 {
-  if (!gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (search_bar)))
+  GListModel *model = G_LIST_MODEL (rl->priv->tree_model);
+  GtkTreeListRow *row_item;
+  GObject *child, *result;
+  guint i, selected, n, row;
+  const char *text;
+
+  text = gtk_editable_get_text (GTK_EDITABLE (rl->priv->search_entry));
+  selected = gtk_single_selection_get_selected (rl->priv->selection);
+  n = g_list_model_get_n_items (model);
+  if (selected >= n)
+    selected = 0;
+
+  for (i = 0; i < n; i++)
     {
-      gtk_tree_walk_reset (sl->priv->walk, NULL);
-      sl->priv->search_length = 0;
+      row = (selected + (forward ? i : n - i - 1)) % n;
+      row_item = g_list_model_get_item (model, row);
+      child = gtk_tree_list_row_get_item (row_item);
+      if (i > 0 || !force_progress)
+        {
+          if (match_object (child, text))
+            {
+              gtk_single_selection_set_selected (rl->priv->selection, row);
+              g_object_unref (child);
+              g_object_unref (row_item);
+              return TRUE;
+            }
+        }
+
+      if (!gtk_tree_list_row_get_expanded (row_item))
+        {
+          result = search_children (child, text, forward);
+          if (result)
+            {
+              select_object (rl, result);
+              g_object_unref (result);
+              g_object_unref (child);
+              g_object_unref (row_item);
+              return TRUE;
+            }
+        }
+      g_object_unref (child);
+      g_object_unref (row_item);
     }
+
+  return FALSE;
+}
+
+static void
+on_search_changed (GtkSearchEntry           *entry,
+                   GtkInspectorResourceList *rl)
+{
+  if (!search (rl, TRUE, FALSE))
+    gtk_widget_error_bell (GTK_WIDGET (rl));
 }
 
 static void
 next_match (GtkButton                *button,
-            GtkInspectorResourceList *sl)
+            GtkInspectorResourceList *rl)
 {
-  if (gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (sl->priv->search_bar)))
+  if (gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (rl->priv->search_bar)))
     {
-      GtkTreeIter iter;
-
-      if (gtk_tree_walk_next_match (sl->priv->walk, TRUE, FALSE, &iter))
-        move_search_to_row (sl, &iter);
-      else
-        gtk_widget_error_bell (GTK_WIDGET (sl));
+      if (!search (rl, TRUE, TRUE))
+        gtk_widget_error_bell (GTK_WIDGET (rl));
     }
 }
 
 static void
 previous_match (GtkButton                *button,
-                GtkInspectorResourceList *sl)
+                GtkInspectorResourceList *rl)
 {
-  if (gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (sl->priv->search_bar)))
+  if (gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (rl->priv->search_bar)))
     {
-      GtkTreeIter iter;
-
-      if (gtk_tree_walk_next_match (sl->priv->walk, TRUE, TRUE, &iter))
-        move_search_to_row (sl, &iter);
-      else
-        gtk_widget_error_bell (GTK_WIDGET (sl));
+      if (!search (rl, FALSE, TRUE))
+        gtk_widget_error_bell (GTK_WIDGET (rl));
     }
 }
 
 static void
-gtk_inspector_resource_list_init (GtkInspectorResourceList *sl)
+stop_search (GtkWidget                *entry,
+             GtkInspectorResourceList *rl)
 {
-  sl->priv = gtk_inspector_resource_list_get_instance_private (sl);
+  gtk_editable_set_text (GTK_EDITABLE (rl->priv->search_entry), "");
+  gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (rl->priv->search_bar), FALSE);
+}
+
+static void
+gtk_inspector_resource_list_init (GtkInspectorResourceList *rl)
+{
+  rl->priv = gtk_inspector_resource_list_get_instance_private (rl);
 
-  gtk_widget_init_template (GTK_WIDGET (sl));
+  gtk_widget_init_template (GTK_WIDGET (rl));
 
-  gtk_tree_view_column_set_cell_data_func (sl->priv->count_column,
-                                           sl->priv->count_renderer,
-                                           count_data_func, sl, NULL);
-  gtk_tree_view_column_set_cell_data_func (sl->priv->size_column,
-                                           sl->priv->size_renderer,
-                                           size_data_func, sl, NULL);
+  g_signal_connect (rl, "map", G_CALLBACK (on_map), NULL);
 
-  g_signal_connect (sl, "map", G_CALLBACK (on_map), NULL);
+  gtk_search_bar_connect_entry (GTK_SEARCH_BAR (rl->priv->search_bar),
+                                GTK_EDITABLE (rl->priv->search_entry));
+}
 
-  gtk_search_bar_connect_entry (GTK_SEARCH_BAR (sl->priv->search_bar),
-                                GTK_EDITABLE (sl->priv->search_entry));
+static GListModel *
+create_model_for_object (gpointer item, gpointer data)
+{
+  GListModel *model = resource_holder_get_children (RESOURCE_HOLDER (item));
 
-  g_signal_connect (sl->priv->search_bar, "notify::search-mode-enabled",
-                    G_CALLBACK (search_mode_changed), sl);
-  sl->priv->walk = gtk_tree_walk_new (GTK_TREE_MODEL (sl->priv->model), match_row, sl, NULL);
+  if (model)
+    return g_object_ref (model);
+
+  return NULL;
 }
 
 static void
 constructed (GObject *object)
 {
   GtkInspectorResourceList *rl = GTK_INSPECTOR_RESOURCE_LIST (object);
-
+  GListModel *root_model;
+ 
   g_signal_connect (rl->priv->open_details_button, "clicked",
                     G_CALLBACK (open_details), rl);
   g_signal_connect (rl->priv->close_details_button, "clicked",
                     G_CALLBACK (close_details), rl);
-  
-  load_resources (rl);
+ 
+  root_model = load_resources ();
+  rl->priv->tree_model = gtk_tree_list_model_new (FALSE,
+                                                  root_model,
+                                                  FALSE,
+                                                  create_model_for_object,
+                                                  NULL,
+                                                  NULL);
+  rl->priv->selection = gtk_single_selection_new (G_LIST_MODEL (rl->priv->tree_model));
+  g_object_unref (root_model);
+
+  gtk_column_view_set_model (GTK_COLUMN_VIEW (rl->priv->list), G_LIST_MODEL (rl->priv->selection));
+
+  g_signal_connect (rl->priv->selection, "selection-changed", G_CALLBACK (on_selection_changed), rl);
 }
 
 static void
@@ -692,13 +694,120 @@ set_property (GObject      *object,
 static void
 finalize (GObject *object)
 {
-  GtkInspectorResourceList *sl = GTK_INSPECTOR_RESOURCE_LIST (object);
+  GtkInspectorResourceList *rl = GTK_INSPECTOR_RESOURCE_LIST (object);
 
-  gtk_tree_walk_free (sl->priv->walk);
+  g_object_unref (rl->priv->selection);
+  g_object_unref (rl->priv->tree_model);
 
   G_OBJECT_CLASS (gtk_inspector_resource_list_parent_class)->finalize (object);
 }
 
+static void
+setup_name_cb (GtkSignalListItemFactory *factory,
+               GtkListItem              *list_item)
+{
+  GtkWidget *expander;
+  GtkWidget *label;
+
+  expander = gtk_tree_expander_new ();
+  gtk_list_item_set_child (list_item, expander);
+
+  label = gtk_label_new (NULL);
+  gtk_widget_set_margin_start (label, 5);
+  gtk_widget_set_margin_end (label, 5);
+  gtk_label_set_xalign (GTK_LABEL (label), 0.0);
+  gtk_tree_expander_set_child (GTK_TREE_EXPANDER (expander), label);
+}
+
+static void
+bind_name_cb (GtkSignalListItemFactory *factory,
+              GtkListItem              *list_item)
+{
+  GtkTreeListRow *list_row;
+  GtkWidget *expander;
+  GtkWidget *label;
+  gpointer item;
+
+  list_row = gtk_list_item_get_item (list_item);
+  expander = gtk_list_item_get_child (list_item);
+  gtk_tree_expander_set_list_row (GTK_TREE_EXPANDER (expander), list_row);
+  item = gtk_tree_list_row_get_item (list_row);
+  label = gtk_tree_expander_get_child (GTK_TREE_EXPANDER (expander));
+
+  gtk_label_set_label (GTK_LABEL (label), resource_holder_get_name (RESOURCE_HOLDER (item)));
+  g_object_unref (item);
+}
+
+static void
+setup_size_cb (GtkSignalListItemFactory *factory,
+               GtkListItem              *list_item)
+{
+  GtkWidget *label;
+
+  label = gtk_label_new (NULL);
+  gtk_widget_set_margin_start (label, 5);
+  gtk_widget_set_margin_end (label, 5);
+  gtk_label_set_xalign (GTK_LABEL (label), 1.0);
+  gtk_list_item_set_child (list_item, label);
+}
+
+static void
+bind_size_cb (GtkSignalListItemFactory *factory,
+              GtkListItem              *list_item)
+{
+  GObject *item;
+  GtkWidget *label;
+  gsize size;
+  char *text;
+
+  item = gtk_tree_list_row_get_item (gtk_list_item_get_item (list_item));
+  label = gtk_list_item_get_child (list_item);
+
+  size = resource_holder_get_size (RESOURCE_HOLDER (item));
+  text = g_format_size (size);
+  gtk_label_set_label (GTK_LABEL (label), text);
+  g_free (text);
+
+  g_object_unref (item);
+}
+
+static void
+setup_count_cb (GtkSignalListItemFactory *factory,
+                GtkListItem              *list_item)
+{
+  GtkWidget *label;
+
+  label = gtk_label_new (NULL);
+  gtk_widget_set_margin_start (label, 5);
+  gtk_widget_set_margin_end (label, 5);
+  gtk_label_set_xalign (GTK_LABEL (label), 1.0);
+  gtk_list_item_set_child (list_item, label);
+}
+
+static void
+bind_count_cb (GtkSignalListItemFactory *factory,
+               GtkListItem              *list_item)
+{
+  GObject *item;
+  GtkWidget *label;
+  int count;
+  char *text;
+
+  item = gtk_tree_list_row_get_item (gtk_list_item_get_item (list_item));
+  label = gtk_list_item_get_child (list_item);
+
+  count = resource_holder_get_count (RESOURCE_HOLDER (item));
+  if (count > 0)
+    {
+      text = g_strdup_printf ("%d", count);
+      gtk_label_set_label (GTK_LABEL (label), text);
+      g_free (text);
+    }
+  else
+    gtk_label_set_label (GTK_LABEL (label), "");
+  g_object_unref (item);
+}
+
 static void
 gtk_inspector_resource_list_class_init (GtkInspectorResourceListClass *klass)
 {
@@ -727,21 +836,25 @@ gtk_inspector_resource_list_class_init (GtkInspectorResourceListClass *klass)
   gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, type);
   gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, size_label);
   gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, info_grid);
-  gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, count_column);
-  gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, count_renderer);
-  gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, size_column);
-  gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, size_renderer);
   gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, stack);
-  gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, tree);
   gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, search_bar);
   gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, search_entry);
-  gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, path_column);
+  gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, list);
+  gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, path);
+  gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, count);
+  gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorResourceList, size);
 
-  gtk_widget_class_bind_template_callback (widget_class, row_activated);
-  gtk_widget_class_bind_template_callback (widget_class, on_selection_changed);
   gtk_widget_class_bind_template_callback (widget_class, on_search_changed);
+  gtk_widget_class_bind_template_callback (widget_class, on_row_activated);
   gtk_widget_class_bind_template_callback (widget_class, next_match);
   gtk_widget_class_bind_template_callback (widget_class, previous_match);
+  gtk_widget_class_bind_template_callback (widget_class, stop_search);
+  gtk_widget_class_bind_template_callback (widget_class, setup_name_cb);
+  gtk_widget_class_bind_template_callback (widget_class, bind_name_cb);
+  gtk_widget_class_bind_template_callback (widget_class, setup_count_cb);
+  gtk_widget_class_bind_template_callback (widget_class, bind_count_cb);
+  gtk_widget_class_bind_template_callback (widget_class, setup_size_cb);
+  gtk_widget_class_bind_template_callback (widget_class, bind_size_cb);
 }
 
 // vim: set et sw=2 ts=2:
diff --git a/gtk/inspector/resource-list.ui b/gtk/inspector/resource-list.ui
index 7493d98f3a..d6db726f54 100644
--- a/gtk/inspector/resource-list.ui
+++ b/gtk/inspector/resource-list.ui
@@ -30,6 +30,9 @@
                           <object class="GtkSearchEntry" id="search_entry">
                             <property name="max-width-chars">40</property>
                             <signal name="search-changed" handler="on_search_changed"/>
+                            <signal name="next-match" handler="next_match"/>
+                            <signal name="previous-match" handler="previous_match"/>
+                            <signal name="stop-search" handler="stop_search"/>
                           </object>
                         </child>
                         <child>
@@ -53,56 +56,39 @@
                     <property name="expand">1</property>
                     <property name="hscrollbar-policy">never</property>
                     <child>
-                      <object class="GtkTreeView" id="tree">
-                        <property name="model">model</property>
-                        <property name="enable-search">0</property>
-                        <property name="enable-grid-lines">vertical</property>
-                        <signal name="row-activated" handler="row_activated"/>
-                        <child internal-child="selection">
-                          <object class="GtkTreeSelection">
-                            <signal name="changed" handler="on_selection_changed"/>
-                          </object>
-                        </child>
+                      <object class="GtkColumnView" id="list">
+                        <signal name="activate" handler="on_row_activated"/>
                         <child>
-                          <object class="GtkTreeViewColumn" id="path_column">
+                          <object class="GtkColumnViewColumn" id="path">
                             <property name="title" translatable="yes">Path</property>
-                            <property name="resizable">1</property>
-                            <property name="sort-column-id">0</property>
-                            <child>
-                              <object class="GtkCellRendererText">
-                                <property name="scale">0.8</property>
-                                <property name="ellipsize">end</property>
-                                <property name="width-chars">10</property>
-                                <property name="max-width-chars">5</property>
+                            <property name="factory">
+                              <object class="GtkSignalListItemFactory">
+                                <signal name="setup" handler="setup_name_cb"/>
+                                <signal name="bind" handler="bind_name_cb"/>
                               </object>
-                              <attributes>
-                                <attribute name="text">0</attribute>
-                              </attributes>
-                            </child>
+                            </property>
                           </object>
                         </child>
                         <child>
-                          <object class="GtkTreeViewColumn" id="count_column">
+                          <object class="GtkColumnViewColumn" id="count">
                             <property name="title" translatable="yes">Count</property>
-                            <property name="resizable">1</property>
-                            <property name="sort-column-id">1</property>
-                            <child>
-                              <object class="GtkCellRendererText" id="count_renderer">
-                                <property name="scale">0.8</property>
+                            <property name="factory">
+                              <object class="GtkSignalListItemFactory">
+                                <signal name="setup" handler="setup_count_cb"/>
+                                <signal name="bind" handler="bind_count_cb"/>
                               </object>
-                            </child>
+                            </property>
                           </object>
                         </child>
                         <child>
-                          <object class="GtkTreeViewColumn" id="size_column">
+                          <object class="GtkColumnViewColumn" id="size">
                             <property name="title" translatable="yes">Size</property>
-                            <property name="resizable">1</property>
-                            <property name="sort-column-id">2</property>
-                            <child>
-                              <object class="GtkCellRendererText" id="size_renderer">
-                                <property name="scale">0.8</property>
+                            <property name="factory">
+                              <object class="GtkSignalListItemFactory">
+                                <signal name="setup" handler="setup_size_cb"/>
+                                <signal name="bind" handler="bind_size_cb"/>
                               </object>
-                            </child>
+                            </property>
                           </object>
                         </child>
                       </object>



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