1/*
2 * Copyright (c) 2014 Red Hat, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "treewalk.h"
19
20struct _GtkTreeWalk
21{
22 GtkTreeModel *model;
23 GtkTreeIter position;
24 gboolean visited;
25 RowPredicate predicate;
26 gpointer data;
27 GDestroyNotify destroy;
28};
29
30GtkTreeWalk *
31gtk_tree_walk_new (GtkTreeModel *model,
32 RowPredicate predicate,
33 gpointer data,
34 GDestroyNotify destroy)
35{
36 GtkTreeWalk *walk;
37
38 walk = g_new (GtkTreeWalk, 1);
39 walk->model = g_object_ref (model);
40 walk->visited = FALSE;
41 walk->predicate = predicate;
42 walk->data = data;
43 walk->destroy = destroy;
44
45 return walk;
46}
47
48void
49gtk_tree_walk_free (GtkTreeWalk *walk)
50{
51 g_object_unref (object: walk->model);
52
53 if (walk->destroy)
54 walk->destroy (walk->data);
55
56 g_free (mem: walk);
57}
58
59void
60gtk_tree_walk_reset (GtkTreeWalk *walk,
61 GtkTreeIter *iter)
62{
63 if (iter)
64 {
65 walk->position = *iter;
66 walk->visited = TRUE;
67 }
68 else
69 {
70 walk->visited = FALSE;
71 }
72}
73
74static gboolean
75gtk_tree_walk_step_forward (GtkTreeWalk *walk)
76{
77 GtkTreeIter next, up;
78
79 if (!walk->visited)
80 {
81 if (!gtk_tree_model_get_iter_first (tree_model: walk->model, iter: &walk->position))
82 return FALSE;
83
84 walk->visited = TRUE;
85 return TRUE;
86 }
87
88 if (gtk_tree_model_iter_children (tree_model: walk->model, iter: &next, parent: &walk->position))
89 {
90 walk->position = next;
91 return TRUE;
92 }
93
94 next = walk->position;
95 do
96 {
97 up = next;
98 if (gtk_tree_model_iter_next (tree_model: walk->model, iter: &next))
99 {
100 walk->position = next;
101 return TRUE;
102 }
103 }
104 while (gtk_tree_model_iter_parent (tree_model: walk->model, iter: &next, child: &up));
105
106 return FALSE;
107}
108
109static gboolean
110gtk_tree_model_iter_last_child (GtkTreeModel *model,
111 GtkTreeIter *iter,
112 GtkTreeIter *parent)
113{
114 GtkTreeIter next;
115
116 if (!gtk_tree_model_iter_children (tree_model: model, iter: &next, parent))
117 return FALSE;
118
119 do
120 *iter = next;
121 while (gtk_tree_model_iter_next (tree_model: model, iter: &next));
122
123 return TRUE;
124}
125
126static gboolean
127gtk_tree_model_get_iter_last (GtkTreeModel *model,
128 GtkTreeIter *iter)
129{
130 GtkTreeIter next;
131
132 if (!gtk_tree_model_iter_last_child (model, iter: &next, NULL))
133 return FALSE;
134
135 do
136 *iter = next;
137 while (gtk_tree_model_iter_last_child (model, iter: &next, parent: &next));
138
139 return TRUE;
140}
141
142static gboolean
143gtk_tree_walk_step_back (GtkTreeWalk *walk)
144{
145 GtkTreeIter previous, down;
146
147 if (!walk->visited)
148 {
149 if (!gtk_tree_model_get_iter_last (model: walk->model, iter: &walk->position))
150 return FALSE;
151
152 walk->visited = TRUE;
153 return TRUE;
154 }
155
156 previous = walk->position;
157 if (gtk_tree_model_iter_previous (tree_model: walk->model, iter: &previous))
158 {
159 while (gtk_tree_model_iter_last_child (model: walk->model, iter: &down, parent: &previous))
160 previous = down;
161
162 walk->position = previous;
163 return TRUE;
164 }
165
166 if (gtk_tree_model_iter_parent (tree_model: walk->model, iter: &previous, child: &walk->position))
167 {
168 walk->position = previous;
169 return TRUE;
170 }
171
172 return FALSE;
173}
174
175static gboolean
176gtk_tree_walk_step (GtkTreeWalk *walk, gboolean backwards)
177{
178 if (backwards)
179 return gtk_tree_walk_step_back (walk);
180 else
181 return gtk_tree_walk_step_forward (walk);
182}
183
184static gboolean
185row_is_match (GtkTreeWalk *walk)
186{
187 if (walk->predicate)
188 return walk->predicate (walk->model, &walk->position, walk->data);
189 return TRUE;
190}
191
192gboolean
193gtk_tree_walk_next_match (GtkTreeWalk *walk,
194 gboolean force_move,
195 gboolean backwards,
196 GtkTreeIter *iter)
197{
198 gboolean moved = FALSE;
199 gboolean was_visited;
200 GtkTreeIter position;
201
202 was_visited = walk->visited;
203 position = walk->position;
204
205 do
206 {
207 if (moved || (!force_move && walk->visited))
208 {
209 if (row_is_match (walk))
210 {
211 *iter = walk->position;
212 return TRUE;
213 }
214 }
215 moved = TRUE;
216 }
217 while (gtk_tree_walk_step (walk, backwards));
218
219 walk->visited = was_visited;
220 walk->position = position;
221
222 return FALSE;
223}
224
225gboolean
226gtk_tree_walk_get_position (GtkTreeWalk *walk,
227 GtkTreeIter *iter)
228{
229 *iter = walk->position;
230 return walk->visited;
231}
232

source code of gtk/gtk/inspector/treewalk.c