PageRenderTime 22ms CodeModel.GetById 12ms app.highlight 5ms RepoModel.GetById 1ms app.codeStats 1ms

/src/wrappers/gtk/library/gtk_tree_model.e

http://github.com/tybor/Liberty
Specman e | 615 lines | 252 code | 82 blank | 281 comment | 9 complexity | d06473649b6db42984f8dea851583a92 MD5 | raw file
  1indexing
  2	description: "GtkTreeModel -- The tree interface used by GtkTreeView."
  3	copyright: "[
  4					Copyright (C) 2006 eiffel-libraries team, GTK+ team
  5					
  6					This library is free software; you can redistribute it and/or
  7					modify it under the terms of the GNU Lesser General Public License
  8					as published by the Free Software Foundation; either version 2.1 of
  9					the License, or (at your option) any later version.
 10					
 11					This library is distributed in the hope that it will be useful, but
 12					WITHOUT ANY WARRANTY; without even the implied warranty of
 13					MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 14					Lesser General Public License for more details.
 15
 16					You should have received a copy of the GNU Lesser General Public
 17					License along with this library; if not, write to the Free Software
 18					Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 19					02110-1301 USA
 20				]"
 21
 22deferred class GTK_TREE_MODEL
 23	-- The GtkTreeModel interface defines a generic tree interface for use by the
 24	-- GtkTreeView widget. It is an abstract interface, and is designed to be
 25	-- usable with any appropriate data structure. The programmer just has to
 26	-- implement this interface on their own data type for it to be viewable by a
 27	-- GtkTreeView widget.
 28
 29	-- The model is represented as a hierarchical tree of strongly-typed,
 30	-- columned data. In other words, the model can be seen as a tree where every
 31	-- node has different values depending on which column is being queried. The
 32	-- type of data found in a column is determined by using the GType system
 33	-- (ie. `g_type_int,' `gtk_type_button,' `g_type_pointer,' etc.). The types
 34	-- are homogeneous per column across all nodes. It is important to note that
 35	-- this interface only provides a way of examining a model and observing
 36	-- changes. The implementation of each individual model decides how and if
 37	-- changes are made.
 38
 39	-- In order to make life simpler for programmers who do not need to write
 40	-- their own specialized model, two generic models are provided: the
 41	-- GtkTreeStore and the GtkListStore. To use these, the developer simply
 42	-- pushes data into these models as necessary. These models provide the data
 43	-- structure as well as all appropriate tree interfaces. As a result,
 44	-- implementing drag and drop, sorting, and storing data is trivial. For the
 45	-- vast majority of trees and lists, these two models are sufficient.
 46	
 47	-- Models are accessed on a node/column level of granularity. One can query
 48	-- for the value of a model at a certain node and a certain column on that
 49	-- node. There are two structures used to reference a particular node in a
 50	-- model. They are the GtkTreePath and the GtkTreeIter. Most of the interface
 51	-- consists of operations on a GtkTreeIter.
 52
 53	-- A path is essentially a potential node. It is a location on a model that
 54	-- may or may not actually correspond to a node on a specific model. The
 55	-- GtkTreePath struct can be converted into either an array of unsigned
 56	-- integers or a string. The string form is a list of numbers separated by a
 57	-- colon. Each number refers to the offset at that level. Thus, the path 0:
 58	-- refers to the root node and the path "refers" to the fifth child of
 59	-- the third node.
 60
 61	-- By contrast, a GtkTreeIter is a reference to a specific node on
 62	-- a specific model. It is a generic struct with an integer and
 63	-- three generic pointers. These are filled in by the model in a
 64	-- model-specific way. One can convert a path to an iterator by
 65	-- calling `get_new_iterator'. These iterators are the primary way
 66	-- of accessing a model and are similar to the iterators used by
 67	-- GtkTextBuffer. They are generally statically allocated on the
 68	-- stack and only used for a short time. The model interface
 69	-- defines a set of operations using them for navigating the model.
 70
 71	-- It is expected that models fill in the iterator with private
 72	-- data. For example, the GtkListStore model, which is internally a
 73	-- simple linked list, stores a list node in one of the
 74	-- pointers. The GtkTreeModelSort stores an array and an offset in
 75	-- two of the pointers. Additionally, there is an integer
 76	-- field. This field is generally filled with a unique stamp per
 77	-- model. This stamp is for catching errors resulting from using
 78	-- invalid iterators with a model.
 79
 80	-- The lifecycle of an iterator can be a little confusing at
 81	-- first. Iterators are expected to always be valid for as long as
 82	-- the model is unchanged (and doesn't emit a signal). The model is
 83	-- considered to own all outstanding iterators and nothing needs to
 84	-- be done to free them from the user's point of
 85	-- view. Additionally, some models guarantee that an iterator is
 86	-- valid for as long as the node it refers to is valid (most
 87	-- notably the GtkTreeStore and GtkListStore). Although generally
 88	-- uninteresting, as one always has to allow for the case where
 89	-- iterators do not persist beyond a signal, some very important
 90	-- performance enhancements were made in the sort model. As a
 91	-- result, the GTK_TREE_MODEL_ITERS_PERSIST flag was added to
 92	-- indicate this behavior.
 93
 94inherit
 95	-- G_INTERFACE
 96	-- Prerequisites: GtkTreeModel requires GObject.
 97	G_OBJECT
 98		
 99		-- Known Derived Interfaces: GtkTreeModel is required by
100		-- GtkTreeSortable.
101		
102		-- Known Implementations: GtkTreeModel is implemented by
103		-- GtkTreeModelSort, GtkTreeStore, GtkListStore and
104		-- GtkTreeModelFilter.
105
106insert
107	GTK
108	GTK_TREE_MODEL_EXTERNALS
109	GTK_TREE_MODEL_FLAGS
110
111feature
112	flags: INTEGER is
113			-- The set of flags supported by Current's interface. The
114			-- flags are a bitwise combination of GtkTreeModelFlags. The
115			-- flags supported should not change during the lifecycle of
116			-- the tree_model.
117		do
118			Result :=  gtk_tree_model_get_flags  (handle)
119		ensure are_valid_tree_model_flags (Result)
120		end
121
122	n_columns, columns_count: INTEGER is
123			-- the number of columns supported by tree_model.
124		do
125			Result := gtk_tree_model_get_n_columns (handle)
126		end
127
128	column_type (a_column_number: INTEGER): INTEGER is
129			-- the type of the column; it is a G_TYPE integer
130			-- TODO: require: valid_column_number: a_column_number.in_range (0,columns_count)
131		do
132			Result := gtk_tree_model_get_column_type  (handle, a_column_number)
133			-- TODO: ensure is_g_type (Result)
134		end
135
136	get_new_iterator (a_path: GTK_TREE_PATH): GTK_TREE_ITER is
137			-- Gets a new iterator pointing to `a_path'. If it cannot be
138			-- valid it will be Void (i.e. if `a_path' refers to a not
139			-- existing row)
140		require valid_path: a_path /= Void
141		local gbool: INTEGER
142		do
143			create Result.from_model(Current)
144			gbool := gtk_tree_model_get_iter (handle, Result.handle, a_path.handle)
145			if (gbool = 0) then
146				-- Should be also called by Eiffel's garbage collector but
147				-- it is nevertheless worth to call it: it is safe and avoid a
148				-- memory leak in the case you compile without a GC
149				Result.dispose
150				Result := Void
151			end
152		end
153
154	get_iterator_from_string (a_path_string: STRING): GTK_TREE_ITER is
155			-- Gets a new iterator pointing to `a_path_string', if it exists. If it cannot be
156			-- valid it will be Void
157		require valid_path_string: a_path_string/=Void
158		local gbool: INTEGER
159		do
160			create Result.make
161			gbool := gtk_tree_model_get_iter_from_string (handle, Result.handle, a_path_string.to_external);
162			if (gbool = 0) then
163				Result.dispose -- See get_new_iterator for info
164				Result := Void
165			end
166		end
167
168	get_iterator_first: GTK_TREE_ITER is
169			-- Gets an first iterator to the first element in the tree
170			-- (the one at the path "0"). Void if the tree is empty.
171		local gbool: INTEGER
172		do
173			create Result.from_model (Current)
174			gbool := gtk_tree_model_get_iter_first (handle, Result.handle)
175			if (gbool = 0) then
176				Result.dispose -- See get_new_iterator for info
177				Result := Void
178			end
179		end
180
181	path (an_iterator: GTK_TREE_ITER): GTK_TREE_PATH is
182			-- A newly-created GtkTreePath referenced by `an_iterator'.
183		require valid_iterator: an_iterator/=Void
184		do
185			create Result.from_external_pointer (gtk_tree_model_get_path (handle, an_iterator.handle))
186		end
187
188	value_at,value (an_iterator: GTK_TREE_ITER; a_column: INTEGER): G_VALUE is
189			-- The value at `a_column' on the row referred by `an_iterator'.
190		do
191			create Result.make
192			gtk_tree_model_get_value (handle, an_iterator.handle, a_column, Result.handle)
193			-- Note: When done with value, g_value_unset() needs to be
194			-- called to free any allocated memory. This should be
195			-- already implemented into G_VALUE
196		end
197
198	ref_node (an_iter: GTK_TREE_ITER) is
199			-- Lets the tree ref the node referred by `an_iter'. This is
200			-- an optional method for models to implement. To be more
201			-- specific, models may ignore this call as it exists
202			-- primarily for performance reasons.
203	
204			-- This feature is primarily meant as a way for views to let
205			-- caching model know when nodes are being displayed (and
206			-- hence, whether or not to cache that node.) For example, a
207			-- file-system based model would not want to keep the entire
208			-- file-hierarchy in memory, just the sections that are
209			-- currently being displayed by every current view.
210	
211			-- A model should be expected to be able to get an iter independent
212			-- of its reffed state.
213		require iter_not_void: an_iter /= Void
214		do
215			gtk_tree_model_ref_node (handle, an_iter.handle)
216		end
217	
218	unref_node (an_iter: GTK_TREE_ITER) is
219			-- Lets the tree unref the node referred by `an_iter'. This
220			-- is an optional method for models to implement. To be more
221			-- specific, models may ignore this call as it exists
222			-- primarily for performance reasons.
223	
224			-- For more information on what this means, see
225			-- `ref_node'. Please note that nodes that are deleted are
226			-- not unreffed.
227		require iter_not_void: an_iter /= Void
228		do
229			gtk_tree_model_unref_node (handle, an_iter.handle)
230		end
231	
232	
233	-- Note: gtk_tree_model_get and gtk_tree_model_get_valist are
234	-- unwrappable since variadic or valist-using. They are implemented
235	-- in C as a tight loop around a gtk_tree_model_get_value call. We 
236	-- reimplement it
237	
238	values, get (an_iter: GTK_TREE_ITER; some_columns: COLLECTION[INTEGER]): COLLECTION[G_VALUE] is
239			-- the value of one or more cells in the row referenced by
240			-- `an_iter'. `some_columns' are the integer column
241			-- numbers.
242
243			-- TODO: decide which name is better among `values' and `get'
244		require 
245			iter_not_void: an_iter /= Void
246			valid_columns: some_columns /= Void
247			-- TODO: correct_columns: some_columns.forall
248			-- (is_valid_g_value (?))
249		local columns_iterator: ITERATOR[INTEGER]; col_n: INTEGER
250		do
251			create {LINKED_LIST[G_VALUE]} Result.make
252			columns_iterator:=some_columns.get_new_iterator
253			from columns_iterator.start
254			until columns_iterator.is_off
255			loop
256				col_n:=columns_iterator.item
257				Result.add_last(value(an_iter, col_n))
258				columns_iterator.next
259			end
260		ensure
261			Result /= Void
262			Result.count = some_columns.count
263		end		
264	
265	for_each (a_test: FUNCTION[TUPLE[GTK_TREE_MODEL, GTK_TREE_PATH, GTK_TREE_ITER], BOOLEAN]) is
266			-- Calls `a_test' on each node in model in a depth-first
267			-- fashion. When `a_test' is True, then the tree ceases to
268			-- be walked.		
269		local a_path: GTK_TREE_PATH; an_iter: GTK_TREE_ITER; a_bool: BOOLEAN
270		do
271			-- Note: implementation paraphrased from the original C 
272			create a_path.first
273			an_iter := get_new_iterator (a_path)
274			if an_iter = Void then a_path.dispose
275			else
276				a_bool:=for_each_helper(a_path,an_iter,a_test)
277				-- for_each_helper ultimate result is thrown away
278			end
279		end
280
281	row_changed (a_path: GTK_TREE_PATH; an_iter: GTK_TREE_ITER) is
282			-- Emits the "row_changed" signal on tree_model. `a_path'
283			-- points to the changed row, `an_iter' is a valid
284			-- GtkTreeIter pointing to the changed row
285		require
286			valid_path: a_path/=Void
287			valid_iter: an_iter/=Void
288			-- TODO: path_and_iter_refers_to_the_same_row
289		do
290			gtk_tree_model_row_changed (handle,a_path.handle,an_iter.handle)
291		end
292
293	row_inserted  (a_path: GTK_TREE_PATH; an_iter: GTK_TREE_ITER) is
294			-- Emits the "row_inserted" signal on Current GTK_TREE_MODEL;
295			-- `a_path' points to the inserted row, `an_iter' is a valid
296			-- GtkTreeIter pointing to the inserted row
297		require
298			valid_path: a_path/=Void
299			valid_iter: an_iter/=Void
300			-- TODO: path_and_iter_refers_to_the_same_row
301		do
302			gtk_tree_model_row_inserted (handle,a_path.handle,an_iter.handle)
303		end
304
305	row_has_child_toggled (a_path: GTK_TREE_PATH; an_iter: GTK_TREE_ITER) is
306			-- Emits the "row_has_child_toggled" signal on Current. This
307			-- should be called by models after the child state of a node
308			-- changes.
309			
310			-- `a_path' is a GtkTreePath pointing to the changed row
311			
312			-- `a_iter' is a valid GtkTreeIter pointing to the changed
313			-- row		
314		require
315			valid_path: a_path/=Void
316			valid_iter: an_iter/=Void
317			-- TODO: path_and_iter_refers_to_the_same_row
318		do
319			gtk_tree_model_row_has_child_toggled (handle,a_path.handle,an_iter.handle)
320		end
321
322	row_deleted  (a_path: GTK_TREE_PATH) is
323			-- Emits the "row_deleted" signal on tree_model. This should
324			-- be called by models after a row has been removed. The
325			-- location pointed to by path should be the location that
326			-- the row previously was at. It may not be a valid location
327			-- anymore. `a_path' is a GtkTreePath pointing to the
328			-- previous location of the deleted row.
329		require valid_path: a_path/=Void
330		do
331			gtk_tree_model_row_deleted (handle, a_path.handle)
332		end
333
334	rows_reordered (a_path: GTK_TREE_PATH; an_iter: GTK_TREE_ITER; a_new_order: ARRAY[INTEGER]) is
335			-- Emits the "rows_reordered" signal on tree_model. This
336			-- should be called by models when their rows have been
337			-- reordered.
338			
339			-- `a_path' is a GtkTreePath pointing to the tree node whose
340			-- children have been reordered
341			
342			-- `an_iter' is a valid GtkTreeIter pointing to the node
343			-- whose children have been reordered; Void if the depth of
344			-- path is 0.
345			
346			-- a_new_order: an array of integers mapping the current
347			-- position of each child to its old position before the
348			-- re-ordering, i.e. new_order[newpos] = oldpos.
349		require
350			valid_path: a_path/=Void
351			valid_order: a_new_order /= Void
352		do
353			if an_iter /= Void then
354				gtk_tree_model_rows_reordered (handle, a_path.handle, an_iter.handle,
355				                               a_new_order.to_external)
356			else gtk_tree_model_rows_reordered (handle, a_path.handle, default_pointer,
357			                                    a_new_order.to_external)
358			end
359		end
360
361feature -- The "row-changed" signal
362	
363	-- void user_function (GtkTreeModel *treemodel, GtkTreePath *arg1,
364	-- GtkTreeIter *arg2, gpointer user_data) : Run last
365	
366	-- treemodel : 	the object which received the signal.
367	-- arg1 : 	
368	-- arg2 : 	
369	-- user_data : 	user data set when the signal handler was
370	--	connected.
371
372	row_changed_signal_name: STRING is "row-changed"
373	enable_on_row_changed is
374			-- Connects "row-changed" signal to `on_row_changed' feature.
375		do
376			connect (Current, row_changed_signal_name, $on_row_changed)
377		end
378
379	on_row_changed (a_path: GTK_TREE_PATH; an_iter: GTK_TREE_ITER) is
380			-- Built-in "row-changed" signal handler; empty by design;
381			-- redefine it.
382		do
383		end
384
385	connect_agent_to_row_changed_signal (a_procedure: PROCEDURE [ANY, TUPLE[GTK_TREE_MODEL,GTK_TREE_PATH,GTK_TREE_ITER]]) is
386		require valid_procedure: a_procedure /= Void
387		local
388			row_changed_callback: ROW_CHANGED_CALLBACK
389		do
390			create row_changed_callback.make
391			row_changed_callback.connect (Current, a_procedure)
392		end
393
394feature -- The "row-deleted" signal
395
396	row_deleted_signal_name: STRING is "row-deleted"
397		-- void user_function (GtkTreeModel *treemodel, GtkTreePath
398		-- *arg1, gpointer user_data) : Run first
399
400	on_row_deleted is
401			-- Built-in row_deleted signal handler; empty by design; redefine it.
402		do
403		end
404
405	enable_on_row_deleted is
406			-- Connects "row_deleted" signal to `on_row_deleted' feature.
407		do
408			connect (Current, row_deleted_signal_name, $on_row_deleted)
409		end
410
411	connect_agent_to_row_deleted_signal (a_procedure: PROCEDURE [ANY,
412		                                                          TUPLE[GTK_TREE_PATH, GTK_TREE_MODEL]]) is
413			-- treemodel : 	the object which received the signal.
414			-- arg1 : 	
415			-- user_data : 	user data set when the signal handler was connected.
416		require valid_procedure: a_procedure /= Void
417		local row_deleted_callback: ROW_DELETED_CALLBACK
418		do
419			create row_deleted_callback.make
420			row_deleted_callback.connect (Current, a_procedure)
421		end
422
423feature -- TODO:  "row-has-child-toggled" signal
424	row_has_child_toggled_signal_name: STRING is "row-has-child-toggled"
425			-- void user_function (GtkTreeModel *treemodel, GtkTreePath
426			-- *arg1, GtkTreeIter *arg2, gpointer user_data) : Run last
427
428	on_row_has_child_toggled is
429			-- Built-in row_has_child_toggled signal handler; empty by design; redefine it.
430		do
431		end
432
433	enable_on_row_has_child_toggled is
434			-- Connects "row_has_child_toggled" signal to `on_row_has_child_toggled' feature.
435		do
436			connect (Current, row_has_child_toggled_signal_name, $on_row_has_child_toggled)
437		end
438	connect_agent_to_row_has_child_toggled_signal (a_procedure: PROCEDURE [ANY, TUPLE[GTK_TREE_MODEL, GTK_TREE_PATH, GTK_TREE_ITER]]) is
439			-- treemodel : 	the object which received the signal.
440			-- arg1 : 	
441			-- user_data : 	user data set when the signal handler was connected.
442		require valid_procedure: a_procedure /= Void
443		local row_has_child_toggled_callback: ROW_HAS_CHILD_TOGGLED_CALLBACK
444		do
445			create row_has_child_toggled_callback.make
446			row_has_child_toggled_callback.connect (Current, a_procedure)
447		end
448
449feature -- The "row-inserted" signal
450
451	row_inserted_signal_name: STRING is "row-inserted"
452		-- "row-inserted"
453		-- void        user_function                  (GtkTreeModel *treemodel,
454		--                                             GtkTreePath  *arg1,
455		--                                             GtkTreeIter  *arg2,
456		--                                             gpointer      user_data)      : Run first
457
458	on_row_inserted is
459			-- Built-in row_inserted signal handler; empty by design; redefine it.
460		do
461		end
462
463	enable_on_row_inserted is
464			-- Connects "row_inserted" signal to `on_row_inserted' feature.
465		do
466			connect (Current, row_inserted_signal_name, $on_row_inserted)
467		end
468
469	connect_agent_to_row_inserted_signal (a_procedure: PROCEDURE [ANY,
470		                                                          TUPLE[GTK_TREE_PATH, GTK_TREE_ITER, GTK_TREE_MODEL]]) is
471			-- treemodel : 	the object which received the signal.
472			-- arg1 : 	
473			-- arg2 : 	
474			-- user_data : 	user data set when the signal handler was connected.
475		require valid_procedure: a_procedure /= Void
476		local row_inserted_callback: ROW_INSERTED_CALLBACK
477		do
478			create row_inserted_callback.make
479			row_inserted_callback.connect (Current, a_procedure)
480		end
481
482feature -- The "rows-reordered" signal
483
484-- void        user_function                  (GtkTreeModel *treemodel,
485--                                             GtkTreePath  *arg1,
486--                                             GtkTreeIter  *arg2,
487--                                             gpointer      arg3,
488--                                             gpointer      user_data)      : Run first
489
490-- treemodel : 	the object which received the signal.
491-- arg1 : 	
492-- arg2 : 	
493-- arg3 : 	
494-- user_data : 	user data set when the signal handler was connected.
495
496feature {} -- Moved here from top - unwrapped code 
497
498-- GtkTreeModel
499
500-- typedef struct _GtkTreeModel GtkTreeModel;
501
502-- GtkTreeIter
503
504-- typedef struct {
505--   gint stamp;
506--   gpointer user_data;
507--   gpointer user_data2;
508--   gpointer user_data3;
509-- } GtkTreeIter;
510
511-- The GtkTreeIter is the primary structure for accessing a structure. Models are expected to put a unique integer in the stamp member, and put model-specific data in the three user_data members.
512-- gint stamp; 	A unique stamp to catch invalid iterators
513-- gpointer user_data; 	Model specific data
514-- gpointer user_data2; 	Model specific data
515-- gpointer user_data3; 	Model specific data
516-- GtkTreePath
517
518-- typedef struct _GtkTreePath GtkTreePath;
519
520-- GtkTreeRowReference
521
522-- typedef struct _GtkTreeRowReference GtkTreeRowReference;
523
524-- GtkTreeModelIface
525
526-- typedef struct {
527--   GTypeInterface g_iface;
528
529--   /* Signals */
530--   void         (* row_changed)           (GtkTreeModel *tree_model,
531-- 					  GtkTreePath  *path,
532-- 					  GtkTreeIter  *iter);
533--   void         (* row_inserted)          (GtkTreeModel *tree_model,
534-- 					  GtkTreePath  *path,
535-- 					  GtkTreeIter  *iter);
536--   void         (* row_has_child_toggled) (GtkTreeModel *tree_model,
537-- 					  GtkTreePath  *path,
538-- 					  GtkTreeIter  *iter);
539--   void         (* row_deleted)           (GtkTreeModel *tree_model,
540-- 					  GtkTreePath  *path);
541--   void         (* rows_reordered)        (GtkTreeModel *tree_model,
542-- 					  GtkTreePath  *path,
543-- 					  GtkTreeIter  *iter,
544-- 					  gint         *new_order);
545
546--   /* Virtual Table */
547--   GtkTreeModelFlags (* get_flags)  (GtkTreeModel *tree_model);   
548
549--   gint         (* get_n_columns)   (GtkTreeModel *tree_model);
550--   GType        (* get_column_type) (GtkTreeModel *tree_model,
551-- 				    gint          index_);
552--   gboolean     (* get_iter)        (GtkTreeModel *tree_model,
553-- 				    GtkTreeIter  *iter,
554-- 				    GtkTreePath  *path);
555--   GtkTreePath *(* get_path)        (GtkTreeModel *tree_model,
556-- 				    GtkTreeIter  *iter);
557--   void         (* get_value)       (GtkTreeModel *tree_model,
558-- 				    GtkTreeIter  *iter,
559-- 				    gint          column,
560-- 				    GValue       *value);
561--   gboolean     (* iter_next)       (GtkTreeModel *tree_model,
562-- 				    GtkTreeIter  *iter);
563--   gboolean     (* iter_children)   (GtkTreeModel *tree_model,
564-- 				    GtkTreeIter  *iter,
565-- 				    GtkTreeIter  *parent);
566--   gboolean     (* iter_has_child)  (GtkTreeModel *tree_model,
567-- 				    GtkTreeIter  *iter);
568--   gint         (* iter_n_children) (GtkTreeModel *tree_model,
569-- 				    GtkTreeIter  *iter);
570--   gboolean     (* iter_nth_child)  (GtkTreeModel *tree_model,
571-- 				    GtkTreeIter  *iter,
572-- 				    GtkTreeIter  *parent,
573-- 				    gint          n);
574--   gboolean     (* iter_parent)     (GtkTreeModel *tree_model,
575-- 				    GtkTreeIter  *iter,
576-- 				    GtkTreeIter  *child);
577--   void         (* ref_node)        (GtkTreeModel *tree_model,
578-- 				    GtkTreeIter  *iter);
579--   void         (* unref_node)      (GtkTreeModel *tree_model,
580-- 				    GtkTreeIter  *iter);
581-- } GtkTreeModelIface;
582
583feature {} -- Implementation
584	for_each_helper (a_path: GTK_TREE_PATH; an_iter: GTK_TREE_ITER; 
585						  a_test: FUNCTION[TUPLE[GTK_TREE_MODEL, GTK_TREE_PATH, GTK_TREE_ITER], BOOLEAN]): BOOLEAN is
586			-- Helper function of the `for_each' feature.
587
588			-- Calls `a_test' on node referred by `an_iter' and `a_path',
589			-- then recursively on all its children. When `a_test' is
590			-- True, then the tree ceases to be walked.
591		require
592			iter_not_void: an_iter /= Void
593			path_not_void: a_path /= Void
594			test_not_void: a_test /= Void
595			valid_iter: an_iter.is_valid
596			-- TODO: iter and path refer the same node
597		local a_child: GTK_TREE_ITER; continue: BOOLEAN
598		do
599			check Result_must_be_initially_false: Result=False end
600			from 
601			until Result = False and then an_iter.is_valid 
602			loop
603				Result := a_test.item([Current, a_path, an_iter])
604
605				if not Result and then an_iter.has_children then
606					create a_child.as_children_of(an_iter)
607					a_path.down
608					Result:= for_each_helper (a_path, a_child, a_test)
609					a_path.up
610				end
611				a_path.next
612				an_iter.next
613			end
614		end
615end