forked from AuroraMiddleware/gtk
inspector: Add search to the object tree
This is also an attempt to figure out a better story for search in treeviews.
This commit is contained in:
parent
69a0b31d2d
commit
992c5f0dd6
@ -62,6 +62,8 @@ libgtkinspector_la_SOURCES = \
|
|||||||
statistics.c \
|
statistics.c \
|
||||||
style-prop-list.h \
|
style-prop-list.h \
|
||||||
style-prop-list.c \
|
style-prop-list.c \
|
||||||
|
treewalk.h \
|
||||||
|
treewalk.c \
|
||||||
visual.h \
|
visual.h \
|
||||||
visual.c \
|
visual.c \
|
||||||
window.h \
|
window.h \
|
||||||
|
@ -46,6 +46,9 @@
|
|||||||
#include "gtktreemodelfilter.h"
|
#include "gtktreemodelfilter.h"
|
||||||
#include "gtkwidgetprivate.h"
|
#include "gtkwidgetprivate.h"
|
||||||
#include "gtkstylecontext.h"
|
#include "gtkstylecontext.h"
|
||||||
|
#include "gtksearchbar.h"
|
||||||
|
#include "gtksearchentry.h"
|
||||||
|
#include "treewalk.h"
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
@ -73,6 +76,11 @@ struct _GtkInspectorObjectTreePrivate
|
|||||||
GHashTable *iters;
|
GHashTable *iters;
|
||||||
gulong map_hook;
|
gulong map_hook;
|
||||||
gulong unmap_hook;
|
gulong unmap_hook;
|
||||||
|
GtkTreeViewColumn *object_column;
|
||||||
|
GtkWidget *search_bar;
|
||||||
|
GtkWidget *search_entry;
|
||||||
|
GtkTreeWalk *walk;
|
||||||
|
gint search_length;
|
||||||
};
|
};
|
||||||
|
|
||||||
static guint signals[LAST_SIGNAL] = { 0 };
|
static guint signals[LAST_SIGNAL] = { 0 };
|
||||||
@ -123,7 +131,12 @@ on_selection_changed (GtkTreeSelection *selection,
|
|||||||
GtkInspectorObjectTree *wt)
|
GtkInspectorObjectTree *wt)
|
||||||
{
|
{
|
||||||
GObject *object;
|
GObject *object;
|
||||||
|
GtkTreeIter iter;
|
||||||
|
|
||||||
|
if (gtk_tree_selection_get_selected (selection, NULL, &iter))
|
||||||
|
gtk_tree_walk_reset (wt->priv->walk, &iter);
|
||||||
|
else
|
||||||
|
gtk_tree_walk_reset (wt->priv->walk, NULL);
|
||||||
object = gtk_inspector_object_tree_get_selected (wt);
|
object = gtk_inspector_object_tree_get_selected (wt);
|
||||||
g_signal_emit (wt, signals[OBJECT_SELECTED], 0, object);
|
g_signal_emit (wt, signals[OBJECT_SELECTED], 0, object);
|
||||||
}
|
}
|
||||||
@ -186,6 +199,214 @@ map_or_unmap (GSignalInvocationHint *ihint,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
move_search_to_row (GtkInspectorObjectTree *wt,
|
||||||
|
GtkTreeIter *iter)
|
||||||
|
{
|
||||||
|
GtkTreeSelection *selection;
|
||||||
|
GtkTreePath *path;
|
||||||
|
|
||||||
|
selection = gtk_tree_view_get_selection (wt->priv->tree);
|
||||||
|
path = gtk_tree_model_get_path (GTK_TREE_MODEL (wt->priv->model), iter);
|
||||||
|
gtk_tree_view_expand_to_path (wt->priv->tree, path);
|
||||||
|
gtk_tree_selection_select_path (selection, path);
|
||||||
|
gtk_tree_view_scroll_to_cell (wt->priv->tree, path, wt->priv->object_column, FALSE, 0.0, 0.0);
|
||||||
|
gtk_tree_path_free (path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
key_press_event (GtkWidget *window,
|
||||||
|
GdkEvent *event,
|
||||||
|
GtkInspectorObjectTree *wt)
|
||||||
|
{
|
||||||
|
if (gtk_widget_get_mapped (GTK_WIDGET (wt)))
|
||||||
|
{
|
||||||
|
GdkModifierType default_accel;
|
||||||
|
gboolean search_started;
|
||||||
|
|
||||||
|
search_started = gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (wt->priv->search_bar));
|
||||||
|
default_accel = gtk_widget_get_modifier_mask (GTK_WIDGET (wt), GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR);
|
||||||
|
|
||||||
|
if (search_started &&
|
||||||
|
(event->key.keyval == GDK_KEY_Return ||
|
||||||
|
event->key.keyval == GDK_KEY_ISO_Enter ||
|
||||||
|
event->key.keyval == GDK_KEY_KP_Enter))
|
||||||
|
{
|
||||||
|
GtkTreeSelection *selection;
|
||||||
|
GtkTreeModel *model;
|
||||||
|
GtkTreeIter iter;
|
||||||
|
GtkTreePath *path;
|
||||||
|
|
||||||
|
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (wt->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 (wt->priv->tree),
|
||||||
|
path,
|
||||||
|
wt->priv->object_column);
|
||||||
|
gtk_tree_path_free (path);
|
||||||
|
|
||||||
|
return GDK_EVENT_STOP;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return GDK_EVENT_PROPAGATE;
|
||||||
|
}
|
||||||
|
else if (search_started &&
|
||||||
|
(event->key.keyval == GDK_KEY_Escape))
|
||||||
|
{
|
||||||
|
gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (wt->priv->search_bar), FALSE);
|
||||||
|
return GDK_EVENT_STOP;
|
||||||
|
}
|
||||||
|
else if (search_started &&
|
||||||
|
((event->key.state & (default_accel | GDK_SHIFT_MASK)) == (default_accel | GDK_SHIFT_MASK)) &&
|
||||||
|
(event->key.keyval == GDK_KEY_g || event->key.keyval == GDK_KEY_G))
|
||||||
|
{
|
||||||
|
GtkTreeIter iter;
|
||||||
|
if (gtk_tree_walk_next_match (wt->priv->walk, TRUE, TRUE, &iter))
|
||||||
|
move_search_to_row (wt, &iter);
|
||||||
|
else
|
||||||
|
gtk_widget_error_bell (GTK_WIDGET (wt));
|
||||||
|
|
||||||
|
return GDK_EVENT_STOP;
|
||||||
|
}
|
||||||
|
else if (search_started &&
|
||||||
|
((event->key.state & (default_accel | GDK_SHIFT_MASK)) == default_accel) &&
|
||||||
|
(event->key.keyval == GDK_KEY_g || event->key.keyval == GDK_KEY_G))
|
||||||
|
{
|
||||||
|
GtkTreeIter iter;
|
||||||
|
|
||||||
|
if (gtk_tree_walk_next_match (wt->priv->walk, TRUE, FALSE, &iter))
|
||||||
|
move_search_to_row (wt, &iter);
|
||||||
|
else
|
||||||
|
gtk_widget_error_bell (GTK_WIDGET (wt));
|
||||||
|
|
||||||
|
return GDK_EVENT_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return gtk_search_bar_handle_event (GTK_SEARCH_BAR (wt->priv->search_bar), event);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return GDK_EVENT_PROPAGATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_hierarchy_changed (GtkWidget *widget,
|
||||||
|
GtkWidget *previous_toplevel)
|
||||||
|
{
|
||||||
|
if (previous_toplevel)
|
||||||
|
g_signal_handlers_disconnect_by_func (previous_toplevel, key_press_event, widget);
|
||||||
|
g_signal_connect (gtk_widget_get_toplevel (widget), "key-press-event",
|
||||||
|
G_CALLBACK (key_press_event), widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_search_changed (GtkSearchEntry *entry,
|
||||||
|
GtkInspectorObjectTree *wt)
|
||||||
|
{
|
||||||
|
GtkTreeIter iter;
|
||||||
|
gint length;
|
||||||
|
gboolean backwards;
|
||||||
|
|
||||||
|
length = strlen (gtk_entry_get_text (GTK_ENTRY (entry)));
|
||||||
|
backwards = length < wt->priv->search_length;
|
||||||
|
wt->priv->search_length = length;
|
||||||
|
|
||||||
|
if (length == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (gtk_tree_walk_next_match (wt->priv->walk, backwards, backwards, &iter))
|
||||||
|
move_search_to_row (wt, &iter);
|
||||||
|
else if (!backwards)
|
||||||
|
gtk_widget_error_bell (GTK_WIDGET (wt));
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
match_string (const gchar *string,
|
||||||
|
const gchar *text)
|
||||||
|
{
|
||||||
|
gchar *lower;
|
||||||
|
gboolean match = FALSE;
|
||||||
|
|
||||||
|
if (string)
|
||||||
|
{
|
||||||
|
lower = g_ascii_strdown (string, -1);
|
||||||
|
match = g_str_has_prefix (lower, text);
|
||||||
|
g_free (lower);
|
||||||
|
}
|
||||||
|
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
match_row (GtkTreeModel *model,
|
||||||
|
GtkTreeIter *iter,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
GtkInspectorObjectTree *wt = data;
|
||||||
|
gchar *type, *name, *label;
|
||||||
|
const gchar *text;
|
||||||
|
gboolean match;
|
||||||
|
|
||||||
|
text = gtk_entry_get_text (GTK_ENTRY (wt->priv->search_entry));
|
||||||
|
gtk_tree_model_get (model, iter,
|
||||||
|
OBJECT_TYPE, &type,
|
||||||
|
OBJECT_NAME, &name,
|
||||||
|
OBJECT_LABEL, &label,
|
||||||
|
-1);
|
||||||
|
|
||||||
|
match = (match_string (type, text) ||
|
||||||
|
match_string (name, text) ||
|
||||||
|
match_string (label, text));
|
||||||
|
|
||||||
|
g_free (type);
|
||||||
|
g_free (name);
|
||||||
|
g_free (label);
|
||||||
|
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
search_mode_changed (GObject *search_bar,
|
||||||
|
GParamSpec *pspec,
|
||||||
|
GtkInspectorObjectTree *wt)
|
||||||
|
{
|
||||||
|
if (!gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (search_bar)))
|
||||||
|
{
|
||||||
|
gtk_tree_walk_reset (wt->priv->walk, NULL);
|
||||||
|
wt->priv->search_length = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
next_match (GtkButton *button,
|
||||||
|
GtkInspectorObjectTree *wt)
|
||||||
|
{
|
||||||
|
if (gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (wt->priv->search_bar)))
|
||||||
|
{
|
||||||
|
GtkTreeIter iter;
|
||||||
|
|
||||||
|
if (gtk_tree_walk_next_match (wt->priv->walk, TRUE, FALSE, &iter))
|
||||||
|
move_search_to_row (wt, &iter);
|
||||||
|
else
|
||||||
|
gtk_widget_error_bell (GTK_WIDGET (wt));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
previous_match (GtkButton *button,
|
||||||
|
GtkInspectorObjectTree *wt)
|
||||||
|
{
|
||||||
|
if (gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (wt->priv->search_bar)))
|
||||||
|
{
|
||||||
|
GtkTreeIter iter;
|
||||||
|
|
||||||
|
if (gtk_tree_walk_next_match (wt->priv->walk, TRUE, TRUE, &iter))
|
||||||
|
move_search_to_row (wt, &iter);
|
||||||
|
else
|
||||||
|
gtk_widget_error_bell (GTK_WIDGET (wt));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gtk_inspector_object_tree_init (GtkInspectorObjectTree *wt)
|
gtk_inspector_object_tree_init (GtkInspectorObjectTree *wt)
|
||||||
{
|
{
|
||||||
@ -198,6 +419,13 @@ gtk_inspector_object_tree_init (GtkInspectorObjectTree *wt)
|
|||||||
(GDestroyNotify) object_data_free);
|
(GDestroyNotify) object_data_free);
|
||||||
gtk_widget_init_template (GTK_WIDGET (wt));
|
gtk_widget_init_template (GTK_WIDGET (wt));
|
||||||
|
|
||||||
|
gtk_search_bar_connect_entry (GTK_SEARCH_BAR (wt->priv->search_bar),
|
||||||
|
GTK_ENTRY (wt->priv->search_entry));
|
||||||
|
|
||||||
|
g_signal_connect (wt->priv->search_bar, "notify::search-mode-enabled",
|
||||||
|
G_CALLBACK (search_mode_changed), wt);
|
||||||
|
wt->priv->walk = gtk_tree_walk_new (GTK_TREE_MODEL (wt->priv->model), match_row, wt, NULL);
|
||||||
|
|
||||||
signal_id = g_signal_lookup ("map", GTK_TYPE_WIDGET);
|
signal_id = g_signal_lookup ("map", GTK_TYPE_WIDGET);
|
||||||
wt->priv->map_hook = g_signal_add_emission_hook (signal_id, 0,
|
wt->priv->map_hook = g_signal_add_emission_hook (signal_id, 0,
|
||||||
map_or_unmap, wt, NULL);
|
map_or_unmap, wt, NULL);
|
||||||
@ -221,6 +449,8 @@ gtk_inspector_object_tree_finalize (GObject *object)
|
|||||||
signal_id = g_signal_lookup ("unmap", GTK_TYPE_WIDGET);
|
signal_id = g_signal_lookup ("unmap", GTK_TYPE_WIDGET);
|
||||||
g_signal_remove_emission_hook (signal_id, wt->priv->unmap_hook);
|
g_signal_remove_emission_hook (signal_id, wt->priv->unmap_hook);
|
||||||
|
|
||||||
|
gtk_tree_walk_free (wt->priv->walk);
|
||||||
|
|
||||||
G_OBJECT_CLASS (gtk_inspector_object_tree_parent_class)->finalize (object);
|
G_OBJECT_CLASS (gtk_inspector_object_tree_parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,8 +483,15 @@ gtk_inspector_object_tree_class_init (GtkInspectorObjectTreeClass *klass)
|
|||||||
gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/inspector/object-tree.ui");
|
gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/inspector/object-tree.ui");
|
||||||
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorObjectTree, model);
|
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorObjectTree, model);
|
||||||
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorObjectTree, tree);
|
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorObjectTree, tree);
|
||||||
|
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorObjectTree, object_column);
|
||||||
|
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorObjectTree, search_bar);
|
||||||
|
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorObjectTree, search_entry);
|
||||||
gtk_widget_class_bind_template_callback (widget_class, on_selection_changed);
|
gtk_widget_class_bind_template_callback (widget_class, on_selection_changed);
|
||||||
gtk_widget_class_bind_template_callback (widget_class, on_row_activated);
|
gtk_widget_class_bind_template_callback (widget_class, on_row_activated);
|
||||||
|
gtk_widget_class_bind_template_callback (widget_class, on_hierarchy_changed);
|
||||||
|
gtk_widget_class_bind_template_callback (widget_class, on_search_changed);
|
||||||
|
gtk_widget_class_bind_template_callback (widget_class, next_match);
|
||||||
|
gtk_widget_class_bind_template_callback (widget_class, previous_match);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -13,6 +13,60 @@
|
|||||||
<template class="GtkInspectorObjectTree" parent="GtkBox">
|
<template class="GtkInspectorObjectTree" parent="GtkBox">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="orientation">vertical</property>
|
<property name="orientation">vertical</property>
|
||||||
|
<signal name="hierarchy-changed" handler="on_hierarchy_changed"/>
|
||||||
|
<child>
|
||||||
|
<object class="GtkSearchBar" id="search_bar">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="orientation">horizontal</property>
|
||||||
|
<style>
|
||||||
|
<class name="linked"/>
|
||||||
|
</style>
|
||||||
|
<child>
|
||||||
|
<object class="GtkSearchEntry" id="search_entry">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="max-width-chars">40</property>
|
||||||
|
<signal name="search-changed" handler="on_search_changed"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<signal name="clicked" handler="next_match"/>
|
||||||
|
<style>
|
||||||
|
<class name="image-button"/>
|
||||||
|
</style>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="icon-name">go-down-symbolic</property>
|
||||||
|
<property name="icon-size">1</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<signal name="clicked" handler="previous_match"/>
|
||||||
|
<style>
|
||||||
|
<class name="image-button"/>
|
||||||
|
</style>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="icon-name">go-up-symbolic</property>
|
||||||
|
<property name="icon-size">1</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkScrolledWindow">
|
<object class="GtkScrolledWindow">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
@ -23,8 +77,7 @@
|
|||||||
<object class="GtkTreeView" id="tree">
|
<object class="GtkTreeView" id="tree">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="model">model</property>
|
<property name="model">model</property>
|
||||||
<property name="enable-search">True</property>
|
<property name="enable-search">False</property>
|
||||||
<property name="search-column">2</property>
|
|
||||||
<signal name="row-activated" handler="on_row_activated"/>
|
<signal name="row-activated" handler="on_row_activated"/>
|
||||||
<child internal-child="selection">
|
<child internal-child="selection">
|
||||||
<object class="GtkTreeSelection">
|
<object class="GtkTreeSelection">
|
||||||
@ -33,7 +86,7 @@
|
|||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkTreeViewColumn">
|
<object class="GtkTreeViewColumn" id="object_column">
|
||||||
<property name="title" translatable="yes">Object</property>
|
<property name="title" translatable="yes">Object</property>
|
||||||
<property name="resizable">True</property>
|
<property name="resizable">True</property>
|
||||||
<child>
|
<child>
|
||||||
|
223
gtk/inspector/treewalk.c
Normal file
223
gtk/inspector/treewalk.c
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "treewalk.h"
|
||||||
|
|
||||||
|
struct _GtkTreeWalk
|
||||||
|
{
|
||||||
|
GtkTreeModel *model;
|
||||||
|
GtkTreeIter position;
|
||||||
|
gboolean visited;
|
||||||
|
RowPredicate predicate;
|
||||||
|
gpointer data;
|
||||||
|
GDestroyNotify destroy;
|
||||||
|
};
|
||||||
|
|
||||||
|
GtkTreeWalk *
|
||||||
|
gtk_tree_walk_new (GtkTreeModel *model,
|
||||||
|
RowPredicate predicate,
|
||||||
|
gpointer data,
|
||||||
|
GDestroyNotify destroy)
|
||||||
|
{
|
||||||
|
GtkTreeWalk *walk;
|
||||||
|
|
||||||
|
walk = g_new (GtkTreeWalk, 1);
|
||||||
|
walk->model = g_object_ref (model);
|
||||||
|
walk->visited = FALSE;
|
||||||
|
walk->predicate = predicate;
|
||||||
|
walk->data = data;
|
||||||
|
walk->destroy = destroy;
|
||||||
|
|
||||||
|
return walk;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gtk_tree_walk_free (GtkTreeWalk *walk)
|
||||||
|
{
|
||||||
|
g_object_unref (walk->model);
|
||||||
|
|
||||||
|
if (walk->destroy)
|
||||||
|
walk->destroy (walk->data);
|
||||||
|
|
||||||
|
g_free (walk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gtk_tree_walk_reset (GtkTreeWalk *walk,
|
||||||
|
GtkTreeIter *iter)
|
||||||
|
{
|
||||||
|
if (iter)
|
||||||
|
{
|
||||||
|
walk->position = *iter;
|
||||||
|
walk->visited = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
walk->visited = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gtk_tree_walk_step_forward (GtkTreeWalk *walk)
|
||||||
|
{
|
||||||
|
GtkTreeIter next, up;
|
||||||
|
|
||||||
|
if (!walk->visited)
|
||||||
|
{
|
||||||
|
if (!gtk_tree_model_get_iter_first (walk->model, &walk->position))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
walk->visited = TRUE;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gtk_tree_model_iter_children (walk->model, &next, &walk->position))
|
||||||
|
{
|
||||||
|
walk->position = next;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
next = walk->position;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
up = next;
|
||||||
|
if (gtk_tree_model_iter_next (walk->model, &next))
|
||||||
|
{
|
||||||
|
walk->position = next;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (gtk_tree_model_iter_parent (walk->model, &next, &up));
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gtk_tree_model_iter_last_child (GtkTreeModel *model,
|
||||||
|
GtkTreeIter *iter,
|
||||||
|
GtkTreeIter *parent)
|
||||||
|
{
|
||||||
|
GtkTreeIter next;
|
||||||
|
|
||||||
|
if (!gtk_tree_model_iter_children (model, &next, parent))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
do
|
||||||
|
*iter = next;
|
||||||
|
while (gtk_tree_model_iter_next (model, &next));
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gtk_tree_model_get_iter_last (GtkTreeModel *model,
|
||||||
|
GtkTreeIter *iter)
|
||||||
|
{
|
||||||
|
GtkTreeIter next;
|
||||||
|
|
||||||
|
if (!gtk_tree_model_iter_last_child (model, &next, NULL))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
do
|
||||||
|
*iter = next;
|
||||||
|
while (gtk_tree_model_iter_last_child (model, &next, &next));
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gtk_tree_walk_step_back (GtkTreeWalk *walk)
|
||||||
|
{
|
||||||
|
GtkTreeIter previous, down;
|
||||||
|
|
||||||
|
if (!walk->visited)
|
||||||
|
{
|
||||||
|
if (!gtk_tree_model_get_iter_last (walk->model, &walk->position))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
walk->visited = TRUE;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
previous = walk->position;
|
||||||
|
if (gtk_tree_model_iter_previous (walk->model, &previous))
|
||||||
|
{
|
||||||
|
while (gtk_tree_model_iter_last_child (walk->model, &down, &previous))
|
||||||
|
previous = down;
|
||||||
|
|
||||||
|
walk->position = previous;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gtk_tree_model_iter_parent (walk->model, &previous, &walk->position))
|
||||||
|
{
|
||||||
|
walk->position = previous;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gtk_tree_walk_step (GtkTreeWalk *walk, gboolean backwards)
|
||||||
|
{
|
||||||
|
if (backwards)
|
||||||
|
return gtk_tree_walk_step_back (walk);
|
||||||
|
else
|
||||||
|
return gtk_tree_walk_step_forward (walk);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
row_is_match (GtkTreeWalk *walk)
|
||||||
|
{
|
||||||
|
if (walk->predicate)
|
||||||
|
return walk->predicate (walk->model, &walk->position, walk->data);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gtk_tree_walk_next_match (GtkTreeWalk *walk,
|
||||||
|
gboolean force_move,
|
||||||
|
gboolean backwards,
|
||||||
|
GtkTreeIter *iter)
|
||||||
|
{
|
||||||
|
gboolean moved = FALSE;
|
||||||
|
gboolean was_visited;
|
||||||
|
GtkTreeIter position;
|
||||||
|
|
||||||
|
was_visited = walk->visited;
|
||||||
|
position = walk->position;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (moved || (!force_move && walk->visited))
|
||||||
|
{
|
||||||
|
if (row_is_match (walk))
|
||||||
|
{
|
||||||
|
*iter = walk->position;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
moved = TRUE;
|
||||||
|
}
|
||||||
|
while (gtk_tree_walk_step (walk, backwards));
|
||||||
|
|
||||||
|
walk->visited = was_visited;
|
||||||
|
walk->position = position;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
41
gtk/inspector/treewalk.h
Normal file
41
gtk/inspector/treewalk.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
//#include "gtktreemodel.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef gboolean (*RowPredicate) (GtkTreeModel *model,
|
||||||
|
GtkTreeIter *iter,
|
||||||
|
gpointer data);
|
||||||
|
|
||||||
|
typedef struct _GtkTreeWalk GtkTreeWalk;
|
||||||
|
|
||||||
|
GtkTreeWalk * gtk_tree_walk_new (GtkTreeModel *model,
|
||||||
|
RowPredicate predicate,
|
||||||
|
gpointer data,
|
||||||
|
GDestroyNotify destroy);
|
||||||
|
|
||||||
|
void gtk_tree_walk_free (GtkTreeWalk *walk);
|
||||||
|
|
||||||
|
void gtk_tree_walk_reset (GtkTreeWalk *walk,
|
||||||
|
GtkTreeIter *iter);
|
||||||
|
|
||||||
|
gboolean gtk_tree_walk_next_match (GtkTreeWalk *walk,
|
||||||
|
gboolean force_move,
|
||||||
|
gboolean backwards,
|
||||||
|
GtkTreeIter *iter);
|
Loading…
Reference in New Issue
Block a user