[gtk+] inspector: Add a new page that lists the CSS node tree



commit d55c261079370e3ddd61f3dab6bea9067380480e
Author: Benjamin Otte <otte redhat com>
Date:   Tue Mar 3 00:02:25 2015 +0100

    inspector: Add a new page that lists the CSS node tree

 gtk/Makefile.am                     |    2 +-
 gtk/inspector/Makefile.inc          |    5 +
 gtk/inspector/css-node-tree.c       |  168 ++++++++++
 gtk/inspector/css-node-tree.h       |   61 ++++
 gtk/inspector/css-node-tree.ui      |   58 ++++
 gtk/inspector/gtktreemodelcssnode.c |  626 +++++++++++++++++++++++++++++++++++
 gtk/inspector/gtktreemodelcssnode.h |   80 +++++
 gtk/inspector/init.c                |    2 +
 gtk/inspector/window.c              |    3 +
 gtk/inspector/window.h              |    1 +
 gtk/inspector/window.ui             |    9 +
 gtk/inspector/window.ui.h           |    1 +
 12 files changed, 1015 insertions(+), 1 deletions(-)
---
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 1af8ecb..c59f63e 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -1130,7 +1130,7 @@ gtktypebuiltins.c: $(gtk_public_h_sources) $(a11y_h_sources) $(deprecated_h_sour
        && cp xgen-gtbc gtktypebuiltins.c  \
        && rm -f xgen-gtbc
 
-gtk.gresource.xml: Makefile.am
+gtk.gresource.xml: Makefile.am inspector/Makefile.inc
        $(AM_V_GEN) echo "<?xml version='1.0' encoding='UTF-8'?>" > $@; \
        echo "<gresources>" >> $@; \
        echo "  <gresource prefix='/org/gtk/libgtk'>" >> $@; \
diff --git a/gtk/inspector/Makefile.inc b/gtk/inspector/Makefile.inc
index 464e809..92fb1b9 100644
--- a/gtk/inspector/Makefile.inc
+++ b/gtk/inspector/Makefile.inc
@@ -4,10 +4,12 @@ inspector_c_sources =                         \
        inspector/cellrenderergraph.c   \
        inspector/classes-list.c        \
        inspector/css-editor.c          \
+       inspector/css-node-tree.c       \
        inspector/data-list.c           \
        inspector/general.c             \
        inspector/gestures.c            \
        inspector/graphdata.c           \
+       inspector/gtktreemodelcssnode.c \
        inspector/init.c                \
        inspector/inspect-button.c      \
        inspector/magnifier.c           \
@@ -33,10 +35,12 @@ inspector_h_sources =                       \
        inspector/cellrenderergraph.h   \
        inspector/classes-list.h        \
        inspector/css-editor.h          \
+       inspector/css-node-tree.h       \
        inspector/data-list.h           \
        inspector/general.h             \
        inspector/gestures.h            \
        inspector/graphdata.h           \
+       inspector/gtktreemodelcssnode.h \
        inspector/init.h                \
        inspector/magnifier.h           \
        inspector/menu.h                \
@@ -59,6 +63,7 @@ inspector_templates =                 \
        inspector/actions.ui            \
        inspector/classes-list.ui       \
        inspector/css-editor.ui         \
+       inspector/css-node-tree.ui      \
        inspector/data-list.ui          \
        inspector/general.ui            \
        inspector/magnifier.ui          \
diff --git a/gtk/inspector/css-node-tree.c b/gtk/inspector/css-node-tree.c
new file mode 100644
index 0000000..ca48f2b
--- /dev/null
+++ b/gtk/inspector/css-node-tree.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2014 Benjamin Otte <otte gnome org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicntnse,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright noticnt and this permission noticnt shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#include "css-node-tree.h"
+
+#include <strings.h>
+
+#include "gtktreemodelcssnode.h"
+#include <gtk/gtktreeview.h>
+#include "gtk/gtkwidgetprivate.h"
+
+enum {
+  COLUMN_NAME,
+  COLUMN_VISIBLE,
+  COLUMN_CLASSES,
+  COLUMN_ID,
+  /* add more */
+  N_COLUMNS
+};
+
+struct _GtkInspectorCssNodeTreePrivate
+{
+  GtkWidget *tree_view;
+  GtkTreeModel *model;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GtkInspectorCssNodeTree, gtk_inspector_css_node_tree, GTK_TYPE_BOX)
+
+static void
+gtk_inspector_css_node_tree_finalize (GObject *object)
+{
+  //GtkInspectorCssNodeTree *cnt = GTK_INSPECTOR_CSS_NODE_TREE (object);
+
+  G_OBJECT_CLASS (gtk_inspector_css_node_tree_parent_class)->finalize (object);
+}
+
+static void
+gtk_inspector_css_node_tree_class_init (GtkInspectorCssNodeTreeClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  object_class->finalize = gtk_inspector_css_node_tree_finalize;
+
+  gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/libgtk/inspector/css-node-tree.ui");
+  gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorCssNodeTree, tree_view);
+}
+
+static int
+sort_strv (gconstpointer a,
+           gconstpointer b,
+           gpointer      data)
+{
+  char **ap = (char **) a;
+  char **bp = (char **) b;
+
+  return strcasecmp (*ap, *bp);
+}
+
+static void
+strv_sort (char **strv)
+{
+  g_qsort_with_data (strv,
+                    g_strv_length (strv),
+                     sizeof (char *),
+                     sort_strv,
+                     NULL);
+}
+
+static void
+gtk_inspector_css_node_tree_get_node_value (GtkTreeModelCssNode *model,
+                                            GtkCssNode          *node,
+                                            int                  column,
+                                            GValue              *value)
+{
+  char **strv;
+  char *s;
+
+  switch (column)
+    {
+    case COLUMN_NAME:
+      g_value_set_string (value, g_type_name (gtk_css_node_get_widget_type (node)));
+      break;
+
+    case COLUMN_VISIBLE:
+      g_value_set_boolean (value, gtk_css_node_get_visible (node));
+      break;
+
+    case COLUMN_CLASSES:
+      strv = gtk_css_node_get_classes (node);
+      strv_sort (strv);
+      s = g_strjoinv (" ", strv);
+      g_value_take_string (value, s);
+      g_strfreev (strv);
+      break;
+
+    case COLUMN_ID:
+      g_value_set_string (value, gtk_css_node_get_id (node));
+      break;
+
+    default:
+      g_assert_not_reached ();
+      break;
+    }
+}
+
+static void
+gtk_inspector_css_node_tree_init (GtkInspectorCssNodeTree *cnt)
+{
+  GtkInspectorCssNodeTreePrivate *priv;
+  
+  cnt->priv = gtk_inspector_css_node_tree_get_instance_private (cnt);
+  gtk_widget_init_template (GTK_WIDGET (cnt));
+  priv = cnt->priv;
+
+  priv->model = gtk_tree_model_css_node_new (gtk_inspector_css_node_tree_get_node_value,
+                                             N_COLUMNS,
+                                             G_TYPE_STRING,
+                                             G_TYPE_BOOLEAN,
+                                             G_TYPE_STRING,
+                                             G_TYPE_STRING);
+  gtk_tree_view_set_model (GTK_TREE_VIEW (priv->tree_view), priv->model);
+  g_object_unref (priv->model);
+}
+
+void
+gtk_inspector_css_node_tree_set_object (GtkInspectorCssNodeTree *cnt,
+                                        GObject                 *object)
+{
+  GtkInspectorCssNodeTreePrivate *priv;
+  
+  g_return_if_fail (GTK_INSPECTOR_IS_CSS_NODE_TREE (cnt));
+
+  priv = cnt->priv;
+
+  if (!GTK_IS_WIDGET (object))
+    {
+      gtk_tree_model_css_node_set_root_node (GTK_TREE_MODEL_CSS_NODE (priv->model), NULL);
+      return;
+    }
+
+  gtk_tree_model_css_node_set_root_node (GTK_TREE_MODEL_CSS_NODE (priv->model),
+                                         gtk_widget_get_css_node (GTK_WIDGET (object)));
+}
+
+// vim: set et sw=2 ts=2:
diff --git a/gtk/inspector/css-node-tree.h b/gtk/inspector/css-node-tree.h
new file mode 100644
index 0000000..8de2c8e
--- /dev/null
+++ b/gtk/inspector/css-node-tree.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2014 Benjamin Otte <otte gnome org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef _GTK_INSPECTOR_CSS_NODE_TREE_H_
+#define _GTK_INSPECTOR_CSS_NODE_TREE_H_
+
+#include <gtk/gtkbox.h>
+
+#include "gtk/gtkcssnodeprivate.h"
+
+#define GTK_TYPE_INSPECTOR_CSS_NODE_TREE            (gtk_inspector_css_node_tree_get_type())
+#define GTK_INSPECTOR_CSS_NODE_TREE(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), 
GTK_TYPE_INSPECTOR_CSS_NODE_TREE, GtkInspectorCssNodeTree))
+#define GTK_INSPECTOR_CSS_NODE_TREE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), 
GTK_TYPE_INSPECTOR_CSS_NODE_TREE, GtkInspectorCssNodeTreeClass))
+#define GTK_INSPECTOR_IS_CSS_NODE_TREE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), 
GTK_TYPE_INSPECTOR_CSS_NODE_TREE))
+#define GTK_INSPECTOR_IS_CSS_NODE_TREE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), 
GTK_TYPE_INSPECTOR_CSS_NODE_TREE))
+#define GTK_INSPECTOR_CSS_NODE_TREE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), 
GTK_TYPE_INSPECTOR_CSS_NODE_TREE, GtkInspectorCssNodeTreeClass))
+
+
+typedef struct _GtkInspectorCssNodeTreePrivate GtkInspectorCssNodeTreePrivate;
+
+typedef struct _GtkInspectorCssNodeTree
+{
+  GtkBox parent;
+  GtkInspectorCssNodeTreePrivate *priv;
+} GtkInspectorCssNodeTree;
+
+typedef struct _GtkInspectorCssNodeTreeClass
+{
+  GtkBoxClass parent;
+} GtkInspectorCssNodeTreeClass;
+
+G_BEGIN_DECLS
+
+GType      gtk_inspector_css_node_tree_get_type       (void);
+void       gtk_inspector_css_node_tree_set_object     (GtkInspectorCssNodeTree *cnt,
+                                                       GObject                 *object);
+
+G_END_DECLS
+
+#endif // _GTK_INSPECTOR_CSS_NODE_TREE_H_
+
+// vim: set et sw=2 ts=2:
diff --git a/gtk/inspector/css-node-tree.ui b/gtk/inspector/css-node-tree.ui
new file mode 100644
index 0000000..f2cbab0
--- /dev/null
+++ b/gtk/inspector/css-node-tree.ui
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface domain="gtk30">
+  <template class="GtkInspectorCssNodeTree" parent="GtkBox">
+    <property name="orientation">vertical</property>
+    <child>
+      <object class="GtkScrolledWindow">
+        <property name="visible">True</property>
+        <property name="hscrollbar-policy">never</property>
+        <property name="vscrollbar-policy">automatic</property>
+        <property name="expand">True</property>
+        <child>
+          <object class="GtkTreeView" id="tree_view">
+            <property name="visible">True</property>
+            <child>
+              <object class="GtkTreeViewColumn" id="treeviewcolumn1">
+                <property name="resizable">True</property>
+                <property name="title" translatable="yes">Name</property>
+                <child>
+                  <object class="GtkCellRendererText"/>
+                  <attributes>
+                    <attribute name="text">0</attribute>
+                    <attribute name="sensitive">1</attribute>
+                  </attributes>
+                </child>
+              </object>
+            </child>
+            <child>
+              <object class="GtkTreeViewColumn" id="treeviewcolumn2">
+                <property name="resizable">True</property>
+                <property name="title" translatable="yes">ID</property>
+                <child>
+                  <object class="GtkCellRendererText"/>
+                  <attributes>
+                    <attribute name="text">3</attribute>
+                    <attribute name="sensitive">1</attribute>
+                  </attributes>
+                </child>
+              </object>
+            </child>
+            <child>
+              <object class="GtkTreeViewColumn" id="treeviewcolumn3">
+                <property name="resizable">True</property>
+                <property name="title" translatable="yes">Classes</property>
+                <child>
+                  <object class="GtkCellRendererText"/>
+                  <attributes>
+                    <attribute name="text">2</attribute>
+                    <attribute name="sensitive">1</attribute>
+                  </attributes>
+                </child>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/gtk/inspector/gtktreemodelcssnode.c b/gtk/inspector/gtktreemodelcssnode.c
new file mode 100644
index 0000000..196335e
--- /dev/null
+++ b/gtk/inspector/gtktreemodelcssnode.c
@@ -0,0 +1,626 @@
+/* gtktreestore.c
+ * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb redhat com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "gtktreemodelcssnode.h"
+
+struct _GtkTreeModelCssNodePrivate
+{
+  GtkTreeModelCssNodeGetFunc    get_func;
+  gint                          n_columns;
+  GType                        *column_types;
+
+  GtkCssNode                   *root;
+};
+
+static void gtk_tree_model_css_node_connect_node    (GtkTreeModelCssNode *model,
+                                                     GtkCssNode          *node,
+                                                     gboolean             emit_signal);
+
+static void gtk_tree_model_css_node_disconnect_node (GtkTreeModelCssNode *model,
+                                                     GtkCssNode          *node,
+                                                     gboolean             emit_signal,
+                                                     GtkCssNode          *parent,
+                                                     GtkCssNode          *previous);
+
+static void gtk_tree_model_css_node_tree_model_init (GtkTreeModelIface   *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GtkTreeModelCssNode, gtk_tree_model_css_node, G_TYPE_OBJECT,
+                         G_ADD_PRIVATE (GtkTreeModelCssNode)
+                        G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
+                                               gtk_tree_model_css_node_tree_model_init))
+
+static GtkCssNode *
+get_nth_child (GtkCssNode *node,
+               gint        i)
+{
+  for (node = gtk_css_node_get_first_child (node);
+       node != NULL && i > 0;
+       node = gtk_css_node_get_next_sibling (node))
+    i--;
+
+  return node;
+}
+
+static int
+get_node_index (GtkCssNode *node)
+{
+  int result = 0;
+
+  while ((node = gtk_css_node_get_previous_sibling (node)))
+    result++;
+
+  return result;
+}
+
+static GtkTreeModelFlags
+gtk_tree_model_css_node_get_flags (GtkTreeModel *tree_model)
+{
+  return GTK_TREE_MODEL_ITERS_PERSIST;
+}
+
+static gint
+gtk_tree_model_css_node_get_n_columns (GtkTreeModel *tree_model)
+{
+  GtkTreeModelCssNode *nodemodel = GTK_TREE_MODEL_CSS_NODE (tree_model);
+  GtkTreeModelCssNodePrivate *priv = nodemodel->priv;
+
+  return priv->n_columns;
+}
+
+static GType
+gtk_tree_model_css_node_get_column_type (GtkTreeModel *tree_model,
+                                         gint          column)
+{
+  GtkTreeModelCssNode *nodemodel = GTK_TREE_MODEL_CSS_NODE (tree_model);
+  GtkTreeModelCssNodePrivate *priv = nodemodel->priv;
+
+  g_return_val_if_fail (column < priv->n_columns, G_TYPE_INVALID);
+
+  return priv->column_types[column];
+}
+
+static gboolean
+gtk_tree_model_css_node_get_iter (GtkTreeModel *tree_model,
+                                  GtkTreeIter  *iter,
+                                  GtkTreePath  *path)
+{
+  GtkTreeModelCssNode *nodemodel = GTK_TREE_MODEL_CSS_NODE (tree_model);
+  GtkTreeModelCssNodePrivate *priv = nodemodel->priv;
+  GtkCssNode *node;
+  int *indices;
+  int depth, i;
+
+  if (priv->root == NULL)
+    return FALSE;
+
+  indices = gtk_tree_path_get_indices (path);
+  depth = gtk_tree_path_get_depth (path);
+
+  if (depth < 1 || indices[0] != 0)
+    return FALSE;
+
+  node = priv->root;
+  for (i = 1; i < depth; i++)
+    {
+      node = get_nth_child (node, indices[i]);
+      if (node == NULL)
+        return FALSE;
+    }
+
+  gtk_tree_model_css_node_get_iter_from_node (nodemodel, iter, node);
+  return TRUE;
+}
+
+static GtkTreePath *
+gtk_tree_model_css_node_get_path (GtkTreeModel *tree_model,
+                                 GtkTreeIter  *iter)
+{
+  GtkTreeModelCssNode *nodemodel = GTK_TREE_MODEL_CSS_NODE (tree_model);
+  GtkTreeModelCssNodePrivate *priv = nodemodel->priv;
+  GtkCssNode *node;
+  GtkTreePath *path;
+
+  g_return_val_if_fail (priv->root != NULL, NULL);
+
+  path = gtk_tree_path_new ();
+  node = gtk_tree_model_css_node_get_node_from_iter (nodemodel, iter);
+
+  while (node != priv->root)
+    {
+      gtk_tree_path_prepend_index (path, get_node_index (node));
+      node = gtk_css_node_get_parent (node);
+    }
+
+  gtk_tree_path_prepend_index (path, 0);
+
+  return path;
+}
+
+static void
+gtk_tree_model_css_node_get_value (GtkTreeModel *tree_model,
+                                   GtkTreeIter  *iter,
+                                   gint          column,
+                                   GValue       *value)
+{
+  GtkTreeModelCssNode *nodemodel = GTK_TREE_MODEL_CSS_NODE (tree_model);
+  GtkTreeModelCssNodePrivate *priv = nodemodel->priv;
+
+  g_value_init (value, priv->column_types[column]);
+  priv->get_func (nodemodel,
+                  gtk_tree_model_css_node_get_node_from_iter (nodemodel, iter),
+                  column,
+                  value);
+}
+
+static gboolean
+gtk_tree_model_css_node_iter_next (GtkTreeModel  *tree_model,
+                                  GtkTreeIter   *iter)
+{
+  GtkTreeModelCssNode *nodemodel = GTK_TREE_MODEL_CSS_NODE (tree_model);
+  GtkTreeModelCssNodePrivate *priv = nodemodel->priv;
+  GtkCssNode *node;
+
+  node = gtk_tree_model_css_node_get_node_from_iter (nodemodel, iter);
+  if (node == priv->root)
+    return FALSE;
+  
+  node = gtk_css_node_get_next_sibling (node);
+  if (node == NULL)
+    return FALSE;
+
+  gtk_tree_model_css_node_get_iter_from_node (nodemodel, iter, node);
+  return TRUE;
+}
+
+static gboolean
+gtk_tree_model_css_node_iter_previous (GtkTreeModel  *tree_model,
+                                      GtkTreeIter   *iter)
+{
+  GtkTreeModelCssNode *nodemodel = GTK_TREE_MODEL_CSS_NODE (tree_model);
+  GtkTreeModelCssNodePrivate *priv = nodemodel->priv;
+  GtkCssNode *node;
+
+  node = gtk_tree_model_css_node_get_node_from_iter (nodemodel, iter);
+  if (node == priv->root)
+    return FALSE;
+  
+  node = gtk_css_node_get_previous_sibling (node);
+  if (node == NULL)
+    return FALSE;
+
+  gtk_tree_model_css_node_get_iter_from_node (nodemodel, iter, node);
+  return TRUE;
+}
+
+static gboolean
+gtk_tree_model_css_node_iter_children (GtkTreeModel *tree_model,
+                                       GtkTreeIter  *iter,
+                                       GtkTreeIter  *parent)
+{
+  GtkTreeModelCssNode *nodemodel = GTK_TREE_MODEL_CSS_NODE (tree_model);
+  GtkTreeModelCssNodePrivate *priv = nodemodel->priv;
+  GtkCssNode *node;
+
+  if (parent == NULL)
+    {
+      node = priv->root;
+    }
+  else
+    {
+      node = gtk_tree_model_css_node_get_node_from_iter (nodemodel, parent);
+      node = gtk_css_node_get_first_child (node);
+    }
+  if (node == NULL)
+    return FALSE;
+
+  gtk_tree_model_css_node_get_iter_from_node (nodemodel, iter, node);
+  return TRUE;
+}
+
+static gboolean
+gtk_tree_model_css_node_iter_has_child (GtkTreeModel *tree_model,
+                                       GtkTreeIter  *iter)
+{
+  GtkTreeModelCssNode *nodemodel = GTK_TREE_MODEL_CSS_NODE (tree_model);
+  GtkCssNode *node;
+
+  node = gtk_tree_model_css_node_get_node_from_iter (nodemodel, iter);
+
+  return gtk_css_node_get_first_child (node) != NULL;
+}
+
+static gint
+gtk_tree_model_css_node_iter_n_children (GtkTreeModel *tree_model,
+                                         GtkTreeIter  *iter)
+{
+  GtkTreeModelCssNode *nodemodel = GTK_TREE_MODEL_CSS_NODE (tree_model);
+  GtkTreeModelCssNodePrivate *priv = nodemodel->priv;
+  GtkCssNode *node;
+
+  if (iter == NULL)
+    return priv->root ? 1 : 0;
+
+  node = gtk_tree_model_css_node_get_node_from_iter (nodemodel, iter);
+
+  node = gtk_css_node_get_last_child (node);
+  if (node == NULL)
+    return 0;
+
+  return get_node_index (node) + 1;
+}
+
+static gboolean
+gtk_tree_model_css_node_iter_nth_child (GtkTreeModel *tree_model,
+                                        GtkTreeIter  *iter,
+                                        GtkTreeIter  *parent,
+                                        gint          n)
+{
+  GtkTreeModelCssNode *nodemodel = GTK_TREE_MODEL_CSS_NODE (tree_model);
+  GtkTreeModelCssNodePrivate *priv = nodemodel->priv;
+  GtkCssNode *node;
+
+  if (parent == NULL)
+    {
+      if (n > 0)
+        return FALSE;
+      
+      node = priv->root;
+    }
+  else
+    {
+      node = gtk_tree_model_css_node_get_node_from_iter (nodemodel, parent);
+      node = get_nth_child (node, n);
+    }
+
+  if (node == NULL)
+    return FALSE;
+  
+  gtk_tree_model_css_node_get_iter_from_node (nodemodel, iter, node);
+  return TRUE;
+}
+
+static gboolean
+gtk_tree_model_css_node_iter_parent (GtkTreeModel *tree_model,
+                                     GtkTreeIter  *iter,
+                                     GtkTreeIter  *child)
+{
+  GtkTreeModelCssNode *nodemodel = GTK_TREE_MODEL_CSS_NODE (tree_model);
+  GtkTreeModelCssNodePrivate *priv = nodemodel->priv;
+  GtkCssNode *node;
+
+  node = gtk_tree_model_css_node_get_node_from_iter (nodemodel, child);
+  if (node == priv->root)
+    return FALSE;
+
+  node = gtk_css_node_get_parent (node);
+
+  gtk_tree_model_css_node_get_iter_from_node (nodemodel, iter, node);
+  return TRUE;
+}
+
+static void
+gtk_tree_model_css_node_tree_model_init (GtkTreeModelIface *iface)
+{
+  iface->get_flags = gtk_tree_model_css_node_get_flags;
+  iface->get_n_columns = gtk_tree_model_css_node_get_n_columns;
+  iface->get_column_type = gtk_tree_model_css_node_get_column_type;
+  iface->get_iter = gtk_tree_model_css_node_get_iter;
+  iface->get_path = gtk_tree_model_css_node_get_path;
+  iface->get_value = gtk_tree_model_css_node_get_value;
+  iface->iter_next = gtk_tree_model_css_node_iter_next;
+  iface->iter_previous = gtk_tree_model_css_node_iter_previous;
+  iface->iter_children = gtk_tree_model_css_node_iter_children;
+  iface->iter_has_child = gtk_tree_model_css_node_iter_has_child;
+  iface->iter_n_children = gtk_tree_model_css_node_iter_n_children;
+  iface->iter_nth_child = gtk_tree_model_css_node_iter_nth_child;
+  iface->iter_parent = gtk_tree_model_css_node_iter_parent;
+}
+
+static void
+gtk_tree_model_css_node_finalize (GObject *object)
+{
+  GtkTreeModelCssNode *model = GTK_TREE_MODEL_CSS_NODE (object);
+  GtkTreeModelCssNodePrivate *priv = model->priv;
+
+  if (priv->root)
+    {
+      gtk_tree_model_css_node_disconnect_node (model, priv->root, FALSE, NULL, NULL);
+      priv->root = NULL;
+    }
+
+  G_OBJECT_CLASS (gtk_tree_model_css_node_parent_class)->finalize (object);
+}
+
+static void
+gtk_tree_model_css_node_class_init (GtkTreeModelCssNodeClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+  object_class->finalize = gtk_tree_model_css_node_finalize;
+}
+
+static void
+gtk_tree_model_css_node_init (GtkTreeModelCssNode *nodemodel)
+{
+  nodemodel->priv = gtk_tree_model_css_node_get_instance_private (nodemodel);
+}
+
+GtkTreeModel *
+gtk_tree_model_css_node_new (GtkTreeModelCssNodeGetFunc get_func,
+                             gint                       n_columns,
+                            ...)
+{
+  GtkTreeModel *result;
+  va_list args;
+  GType *types;
+  gint i;
+
+  g_return_val_if_fail (get_func != NULL, NULL);
+  g_return_val_if_fail (n_columns > 0, NULL);
+
+  types = g_new (GType, n_columns);
+  va_start (args, n_columns);
+
+  for (i = 0; i < n_columns; i++)
+    {
+      types[i] = va_arg (args, GType);
+    }
+
+  va_end (args);
+
+  result = gtk_tree_model_css_node_newv (get_func, n_columns, types);
+
+  g_free (types);
+
+  return result;
+}
+
+GtkTreeModel *
+gtk_tree_model_css_node_newv (GtkTreeModelCssNodeGetFunc  get_func,
+                              gint                        n_columns,
+                             GType                      *types)
+{
+  GtkTreeModelCssNode *result;
+  GtkTreeModelCssNodePrivate *priv;
+
+  g_return_val_if_fail (get_func != NULL, NULL);
+  g_return_val_if_fail (n_columns > 0, NULL);
+  g_return_val_if_fail (types != NULL, NULL);
+
+  result = g_object_new (GTK_TYPE_TREE_MODEL_CSS_NODE, NULL);
+  priv = result->priv;
+
+  priv->get_func = get_func;
+  priv->n_columns = n_columns;
+  priv->column_types = g_memdup (types, sizeof (GType) * n_columns);
+
+  return GTK_TREE_MODEL (result);
+}
+
+static void
+child_added_cb (GtkCssNode          *node,
+                GtkCssNode          *child,
+                GtkCssNode          *previous,
+                GtkTreeModelCssNode *model)
+{
+  gtk_tree_model_css_node_connect_node (model, child, TRUE);
+}
+
+static void
+child_removed_cb (GtkCssNode          *node,
+                  GtkCssNode          *child,
+                  GtkCssNode          *previous,
+                  GtkTreeModelCssNode *model)
+{
+  gtk_tree_model_css_node_disconnect_node (model, child, TRUE, node, previous);
+}
+
+static void
+notify_cb (GtkCssNode          *node,
+           GParamSpec          *pspec,
+           GtkTreeModelCssNode *model)
+{
+  GtkTreeIter iter;
+  GtkTreePath *path;
+
+  gtk_tree_model_css_node_get_iter_from_node (model, &iter, node);
+  path = gtk_tree_model_css_node_get_path (GTK_TREE_MODEL (model), &iter);
+
+  gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter);
+
+  gtk_tree_path_free (path);
+}
+
+static void
+style_changed_cb (GtkCssNode          *node,
+                  GtkCssStyle         *old_style,
+                  GtkCssStyle         *new_style,
+                  GtkTreeModelCssNode *model)
+{
+  GtkTreeIter iter;
+  GtkTreePath *path;
+
+  gtk_tree_model_css_node_get_iter_from_node (model, &iter, node);
+  path = gtk_tree_model_css_node_get_path (GTK_TREE_MODEL (model), &iter);
+
+  gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter);
+
+  gtk_tree_path_free (path);
+}
+
+static void
+gtk_tree_model_css_node_connect_node (GtkTreeModelCssNode *model,
+                                      GtkCssNode          *node,
+                                      gboolean             emit_signal)
+{
+  GtkCssNode *child;
+
+  g_object_ref (node);
+
+  g_signal_connect_after (node, "node-added", G_CALLBACK (child_added_cb), model);
+  g_signal_connect_after (node, "node-removed", G_CALLBACK (child_removed_cb), model);
+  g_signal_connect_after (node, "notify", G_CALLBACK (notify_cb), model);
+  g_signal_connect_after (node, "style-changed", G_CALLBACK (style_changed_cb), model);
+
+  for (child = gtk_css_node_get_first_child (node);
+       child;
+       child = gtk_css_node_get_next_sibling (child))
+    {
+      gtk_tree_model_css_node_connect_node (model, child, FALSE);
+    }
+
+  if (emit_signal)
+    {
+      GtkTreeIter iter;
+      GtkTreePath *path;
+
+      if (node != model->priv->root &&
+          gtk_css_node_get_previous_sibling (node) == NULL &&
+          gtk_css_node_get_next_sibling (node) == NULL)
+        {
+          /* We're the first child of the parent */
+          gtk_tree_model_css_node_get_iter_from_node (model, &iter, gtk_css_node_get_parent (node));
+          path = gtk_tree_model_css_node_get_path (GTK_TREE_MODEL (model), &iter);
+          gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (model), path, &iter);
+          gtk_tree_path_free (path);
+        }
+
+      gtk_tree_model_css_node_get_iter_from_node (model, &iter, node);
+      path = gtk_tree_model_css_node_get_path (GTK_TREE_MODEL (model), &iter);
+      gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter);
+      if (gtk_css_node_get_first_child (node))
+        gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (model), path, &iter);
+
+      gtk_tree_path_free (path);
+    }
+}
+
+static void
+gtk_tree_model_css_node_disconnect_node (GtkTreeModelCssNode *model,
+                                         GtkCssNode          *node,
+                                         gboolean             emit_signal,
+                                         GtkCssNode          *parent,
+                                         GtkCssNode          *previous)
+{
+  GtkCssNode *child;
+
+  g_signal_handlers_disconnect_by_func (node, G_CALLBACK (child_added_cb), model);
+  g_signal_handlers_disconnect_by_func (node, G_CALLBACK (child_removed_cb), model);
+  g_signal_handlers_disconnect_by_func (node, G_CALLBACK (notify_cb), model);
+  g_signal_handlers_disconnect_by_func (node, G_CALLBACK (style_changed_cb), model);
+
+  for (child = gtk_css_node_get_first_child (node);
+       child;
+       child = gtk_css_node_get_next_sibling (child))
+    {
+      gtk_tree_model_css_node_disconnect_node (model, child, FALSE, NULL, NULL);
+    }
+
+  if (emit_signal)
+    {
+      GtkTreeIter iter;
+      GtkTreePath *path;
+
+      if (parent)
+        {
+          gtk_tree_model_css_node_get_iter_from_node (model, &iter, parent);
+          path = gtk_tree_model_css_node_get_path (GTK_TREE_MODEL (model), &iter);
+        }
+      else
+        {
+          path = gtk_tree_path_new ();
+        }
+      if (previous)
+        gtk_tree_path_append_index (path, get_node_index (previous) + 1);
+      else
+        gtk_tree_path_append_index (path, 0);
+
+      gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
+
+      if (parent && gtk_css_node_get_first_child (parent) == NULL)
+        {
+          gtk_tree_path_up (path);
+          gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (model), path, &iter);
+        }
+
+      gtk_tree_path_free (path);
+    }
+  
+  g_object_unref (node);
+}
+
+void
+gtk_tree_model_css_node_set_root_node (GtkTreeModelCssNode *model,
+                                       GtkCssNode          *node)
+{
+  GtkTreeModelCssNodePrivate *priv;
+
+  g_return_if_fail (GTK_IS_TREE_MODEL_CSS_NODE (model));
+  g_return_if_fail (node == NULL || GTK_IS_CSS_NODE (node));
+
+  priv = model->priv;
+
+  if (priv->root == node)
+    return;
+
+  if (priv->root)
+    {
+      gtk_tree_model_css_node_disconnect_node (model, priv->root, TRUE, NULL, NULL);
+      priv->root = NULL;
+    }
+
+  if (node)
+    {
+      priv->root = node;
+      gtk_tree_model_css_node_connect_node (model, node, TRUE);
+    }
+}
+
+GtkCssNode *
+gtk_tree_model_css_node_get_root_node (GtkTreeModelCssNode *model)
+{
+  g_return_val_if_fail (GTK_IS_TREE_MODEL_CSS_NODE (model), NULL);
+
+  return model->priv->root;
+}
+
+GtkCssNode *
+gtk_tree_model_css_node_get_node_from_iter (GtkTreeModelCssNode *model,
+                                            GtkTreeIter         *iter)
+{
+  g_return_val_if_fail (GTK_IS_TREE_MODEL_CSS_NODE (model), NULL);
+  g_return_val_if_fail (iter != NULL, NULL);
+  g_return_val_if_fail (iter->user_data == model, NULL);
+  g_return_val_if_fail (GTK_IS_CSS_NODE (iter->user_data2), NULL);
+
+  return iter->user_data2;
+}
+
+void
+gtk_tree_model_css_node_get_iter_from_node (GtkTreeModelCssNode *model,
+                                            GtkTreeIter         *iter,
+                                            GtkCssNode          *node)
+{
+  g_return_if_fail (GTK_IS_TREE_MODEL_CSS_NODE (model));
+  g_return_if_fail (iter != NULL);
+  g_return_if_fail (GTK_IS_CSS_NODE (node));
+
+  iter->user_data = model;
+  iter->user_data2 = node;
+}
diff --git a/gtk/inspector/gtktreemodelcssnode.h b/gtk/inspector/gtktreemodelcssnode.h
new file mode 100644
index 0000000..d6cabe1
--- /dev/null
+++ b/gtk/inspector/gtktreemodelcssnode.h
@@ -0,0 +1,80 @@
+/* gtktreestore.h
+ * Copyright (C) 2014 Benjamin Otte <otte gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GTK_TREE_MODEL_CSS_NODE_H__
+#define __GTK_TREE_MODEL_CSS_NODE_H__
+
+#include <gtk/gtktreemodel.h>
+
+#include "gtk/gtkcssnodeprivate.h"
+
+
+G_BEGIN_DECLS
+
+
+#define GTK_TYPE_TREE_MODEL_CSS_NODE                   (gtk_tree_model_css_node_get_type ())
+#define GTK_TREE_MODEL_CSS_NODE(obj)                   (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
GTK_TYPE_TREE_MODEL_CSS_NODE, GtkTreeModelCssNode))
+#define GTK_TREE_MODEL_CSS_NODE_CLASS(klass)           (G_TYPE_CHECK_CLASS_CAST ((klass), 
GTK_TYPE_TREE_MODEL_CSS_NODE, GtkTreeModelCssNodeClass))
+#define GTK_IS_TREE_MODEL_CSS_NODE(obj)                        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
GTK_TYPE_TREE_MODEL_CSS_NODE))
+#define GTK_IS_TREE_MODEL_CSS_NODE_CLASS(klass)                (G_TYPE_CHECK_CLASS_TYPE ((klass), 
GTK_TYPE_TREE_MODEL_CSS_NODE))
+#define GTK_TREE_MODEL_CSS_NODE_GET_CLASS(obj)         (G_TYPE_INSTANCE_GET_CLASS ((obj), 
GTK_TYPE_TREE_MODEL_CSS_NODE, GtkTreeModelCssNodeClass))
+
+typedef struct _GtkTreeModelCssNode        GtkTreeModelCssNode;
+typedef struct _GtkTreeModelCssNodeClass   GtkTreeModelCssNodeClass;
+typedef struct _GtkTreeModelCssNodePrivate GtkTreeModelCssNodePrivate;
+
+typedef void (* GtkTreeModelCssNodeGetFunc)             (GtkTreeModelCssNode   *model,
+                                                         GtkCssNode            *node,
+                                                         int                    column,
+                                                         GValue                *value);
+
+struct _GtkTreeModelCssNode
+{
+  GObject parent;
+
+  GtkTreeModelCssNodePrivate *priv;
+};
+
+struct _GtkTreeModelCssNodeClass
+{
+  GObjectClass parent_class;
+};
+
+
+GType         gtk_tree_model_css_node_get_type          (void) G_GNUC_CONST;
+
+GtkTreeModel *gtk_tree_model_css_node_new               (GtkTreeModelCssNodeGetFunc get_func,
+                                                         gint            n_columns,
+                                                        ...);
+GtkTreeModel *gtk_tree_model_css_node_newv              (GtkTreeModelCssNodeGetFunc get_func,
+                                                         gint            n_columns,
+                                                        GType          *types);
+
+void          gtk_tree_model_css_node_set_root_node     (GtkTreeModelCssNode    *model,
+                                                         GtkCssNode             *node);
+GtkCssNode   *gtk_tree_model_css_node_get_root_node     (GtkTreeModelCssNode    *model);
+GtkCssNode   *gtk_tree_model_css_node_get_node_from_iter(GtkTreeModelCssNode    *model,
+                                                         GtkTreeIter            *iter);
+void          gtk_tree_model_css_node_get_iter_from_node(GtkTreeModelCssNode    *model,
+                                                         GtkTreeIter            *iter,
+                                                         GtkCssNode             *node);
+
+
+G_END_DECLS
+
+
+#endif /* __GTK_TREE_MODEL_CSS_NODE_H__ */
diff --git a/gtk/inspector/init.c b/gtk/inspector/init.c
index 14acd8e..ed8180e 100644
--- a/gtk/inspector/init.c
+++ b/gtk/inspector/init.c
@@ -28,6 +28,7 @@
 #include "cellrenderergraph.h"
 #include "classes-list.h"
 #include "css-editor.h"
+#include "css-node-tree.h"
 #include "data-list.h"
 #include "general.h"
 #include "gestures.h"
@@ -61,6 +62,7 @@ gtk_inspector_init (void)
   g_type_ensure (GTK_TYPE_INSPECTOR_ACTIONS);
   g_type_ensure (GTK_TYPE_INSPECTOR_CLASSES_LIST);
   g_type_ensure (GTK_TYPE_INSPECTOR_CSS_EDITOR);
+  g_type_ensure (GTK_TYPE_INSPECTOR_CSS_NODE_TREE);
   g_type_ensure (GTK_TYPE_INSPECTOR_DATA_LIST);
   g_type_ensure (GTK_TYPE_INSPECTOR_GENERAL);
   g_type_ensure (GTK_TYPE_INSPECTOR_GESTURES);
diff --git a/gtk/inspector/window.c b/gtk/inspector/window.c
index 3846ecd..d7b6d22 100644
--- a/gtk/inspector/window.c
+++ b/gtk/inspector/window.c
@@ -31,6 +31,7 @@
 #include "prop-list.h"
 #include "classes-list.h"
 #include "css-editor.h"
+#include "css-node-tree.h"
 #include "object-hierarchy.h"
 #include "object-tree.h"
 #include "selector.h"
@@ -71,6 +72,7 @@ set_selected_object (GtkInspectorWindow *iw,
   gtk_inspector_misc_info_set_object (GTK_INSPECTOR_MISC_INFO (iw->misc_info), selected);
   gtk_inspector_classes_list_set_object (GTK_INSPECTOR_CLASSES_LIST (iw->classes_list), selected);
   gtk_inspector_css_editor_set_object (GTK_INSPECTOR_CSS_EDITOR (iw->widget_css_editor), selected);
+  gtk_inspector_css_node_tree_set_object (GTK_INSPECTOR_CSS_NODE_TREE (iw->widget_css_node_tree), selected);
   gtk_inspector_size_groups_set_object (GTK_INSPECTOR_SIZE_GROUPS (iw->size_groups), selected);
   gtk_inspector_data_list_set_object (GTK_INSPECTOR_DATA_LIST (iw->data_list), selected);
   gtk_inspector_actions_set_object (GTK_INSPECTOR_ACTIONS (iw->actions), selected);
@@ -228,6 +230,7 @@ gtk_inspector_window_class_init (GtkInspectorWindowClass *klass)
   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, classes_list);
   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, style_prop_list);
   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, widget_css_editor);
+  gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, widget_css_node_tree);
   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, object_hierarchy);
   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, selector);
   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, size_groups);
diff --git a/gtk/inspector/window.h b/gtk/inspector/window.h
index 07a469d..80de702 100644
--- a/gtk/inspector/window.h
+++ b/gtk/inspector/window.h
@@ -57,6 +57,7 @@ typedef struct
   GtkWidget *style_prop_list;
   GtkWidget *classes_list;
   GtkWidget *widget_css_editor;
+  GtkWidget *widget_css_node_tree;
   GtkWidget *object_hierarchy;
   GtkWidget *size_groups;
   GtkWidget *data_list;
diff --git a/gtk/inspector/window.ui b/gtk/inspector/window.ui
index 272959c..f01dc7c 100644
--- a/gtk/inspector/window.ui
+++ b/gtk/inspector/window.ui
@@ -320,6 +320,15 @@
                           </packing>
                         </child>
                         <child>
+                          <object class="GtkInspectorCssNodeTree" id="widget_css_node_tree">
+                            <property name="visible">True</property>
+                          </object>
+                          <packing>
+                            <property name="name">css-nodes</property>
+                            <property name="title" translatable="yes">CSS nodes</property>
+                          </packing>
+                        </child>
+                        <child>
                           <object class="GtkInspectorCssEditor" id="widget_css_editor">
                             <property name="global">False</property>
                           </object>
diff --git a/gtk/inspector/window.ui.h b/gtk/inspector/window.ui.h
index 05c6b21..a0a356a 100644
--- a/gtk/inspector/window.ui.h
+++ b/gtk/inspector/window.ui.h
@@ -12,6 +12,7 @@ N_("Hierarchy");
 N_("Selector");
 N_("Style Classes");
 N_("Style Properties");
+N_("CSS nodes");
 N_("CSS");
 N_("Size Groups");
 N_("Data");



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