This file is indexed.

/usr/share/doc/python-gtk2-tutorial/html/sec-GenericTreeModel.html is in python-gtk2-tutorial 2.4-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>14.11. The Generic TreeModel</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-TreeViewWidget.html" title="Chapter 14. Tree View Widget"><link rel="previous" href="sec-TreeModelSortAndTreeModelFilter.html" title="14.10. TreeModelSort and TreeModelFilter"><link rel="next" href="sec-GenericCellRenderer.html" title="14.12. The Generic CellRenderer"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">14.11. The Generic TreeModel</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-TreeModelSortAndTreeModelFilter.html">Prev</a> </td><th width="60%" align="center">Chapter 14. Tree View Widget</th><td width="20%" align="right"> <a accesskey="n" href="sec-GenericCellRenderer.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-GenericTreeModel"></a>14.11. The Generic TreeModel</h2></div></div><div></div></div><p>When you find that the standard <tt class="classname">TreeModel</tt>s
are not sufficiently powerful for your application needs, you can use the
<tt class="classname">GenericTreeModel</tt> to build your own custom
<tt class="classname">TreeModel</tt> in Python. Creating a
<tt class="classname">GenericTreeModel</tt> may be useful when there are
performance issues with the standard <tt class="classname">TreeStore</tt> and
<tt class="classname">ListStore</tt> objects or when you want to directly
interface to an external data source (say, a database or filesystem) to save
copying the data into and out of a <tt class="classname">TreeStore</tt> or
<tt class="classname">ListStore</tt>.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-GenericTreeModelOverview"></a>14.11.1. GenericTreeModel Overview</h3></div></div><div></div></div><p> With the <tt class="classname">GenericTreeModel</tt> you build and
manage your data model and provide external access though the standard
<tt class="classname">TreeModel</tt> interface by defining a set of class
methods. PyGTK implements the <tt class="classname">TreeModel</tt> interface and
arranges for your <tt class="classname">TreeModel</tt> methods to be called to
provide the actual model data.</p><p>The implementation details of your model should be kept completely
hidden from the external application. This means that the way that your
model identifies, stores and retrieves data is unknown to the
application. In general the only information that is saved outside your
<tt class="classname">GenericTreeModel</tt> are the row references that are
wrapped by the external <tt class="classname">TreeIter</tt>s. And these
references are not visible to the application.</p><p>Let's examine in detail the
<tt class="classname">GenericTreeModel</tt> interface that you have to
provide.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-GenericTreeModelInterface"></a>14.11.2. The GenericTreeModel Interface</h3></div></div><div></div></div><p>The <tt class="classname">GenericTreeModel</tt> interface consists of
the following methods that must be implemented in your custom tree
model:</p><code class="methodsynopsis">    def <span class="methodname">on_get_flags</span>(<span class="methodparam"><span class="parameter"><i class="parameter"><tt>self</tt></i></span></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">on_get_n_columns</span>(<span class="methodparam"><span class="parameter"><i class="parameter"><tt>self</tt></i></span></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">on_get_column_type</span>(<span class="methodparam"><span class="parameter"><i class="parameter"><tt>self</tt></i></span></span>, <span class="methodparam"><span class="parameter"><i class="parameter"><tt>index</tt></i></span></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">on_get_iter</span>(<span class="methodparam"><span class="parameter"><i class="parameter"><tt>self</tt></i></span></span>, <span class="methodparam"><span class="parameter"><i class="parameter"><tt>path</tt></i></span></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">on_get_path</span>(<span class="methodparam"><span class="parameter"><i class="parameter"><tt>self</tt></i></span></span>, <span class="methodparam"><span class="parameter"><i class="parameter"><tt>rowref</tt></i></span></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">on_get_value</span>(<span class="methodparam"><span class="parameter"><i class="parameter"><tt>self</tt></i></span></span>, <span class="methodparam"><span class="parameter"><i class="parameter"><tt>rowref</tt></i></span></span>, <span class="methodparam"><span class="parameter"><i class="parameter"><tt>column</tt></i></span></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">on_iter_next</span>(<span class="methodparam"><span class="parameter"><i class="parameter"><tt>self</tt></i></span></span>, <span class="methodparam"><span class="parameter"><i class="parameter"><tt>rowref</tt></i></span></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">on_iter_children</span>(<span class="methodparam"><span class="parameter"><i class="parameter"><tt>self</tt></i></span></span>, <span class="methodparam"><span class="parameter"><i class="parameter"><tt>parent</tt></i></span></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">on_iter_has_child</span>(<span class="methodparam"><span class="parameter"><i class="parameter"><tt>self</tt></i></span></span>, <span class="methodparam"><span class="parameter"><i class="parameter"><tt>rowref</tt></i></span></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">on_iter_n_children</span>(<span class="methodparam"><span class="parameter"><i class="parameter"><tt>self</tt></i></span></span>, <span class="methodparam"><span class="parameter"><i class="parameter"><tt>rowref</tt></i></span></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">on_iter_nth_child</span>(<span class="methodparam"><span class="parameter"><i class="parameter"><tt>self</tt></i></span></span>, <span class="methodparam"><span class="parameter"><i class="parameter"><tt>parent</tt></i></span></span>, <span class="methodparam"><span class="parameter"><i class="parameter"><tt>n</tt></i></span></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">on_iter_parent</span>(<span class="methodparam"><span class="parameter"><i class="parameter"><tt>self</tt></i></span></span>, <span class="methodparam"><span class="parameter"><i class="parameter"><tt>child</tt></i></span></span>)</code><br><p>You should note that these methods support all of the
<tt class="classname">TreeModel</tt> interface including:</p><code class="methodsynopsis">    def <span class="methodname">get_flags</span>(<span class="methodparam"></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">get_n_columns</span>(<span class="methodparam"></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">get_column_type</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>index</tt></b></span></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">get_iter</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>path</tt></b></span></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">get_iter_from_string</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>path_string</tt></b></span></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">get_string_from_iter</span>(<span class="methodparam"><span class="parameter"><i class="parameter"><tt>iter</tt></i></span></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">get_iter_root</span>(<span class="methodparam"></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">get_iter_first</span>(<span class="methodparam"></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">get_path</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>iter</tt></b></span></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">get_value</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>iter</tt></b></span></span>, <span class="methodparam"><span class="parameter"><b class="parameter"><tt>column</tt></b></span></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">iter_next</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>iter</tt></b></span></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">iter_children</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>parent</tt></b></span></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">iter_has_child</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>iter</tt></b></span></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">iter_n_children</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>iter</tt></b></span></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">iter_nth_child</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>parent</tt></b></span></span>, <span class="methodparam"><span class="parameter"><b class="parameter"><tt>n</tt></b></span></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">iter_parent</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>child</tt></b></span></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">get</span>(<span class="methodparam"><span class="parameter"><i class="parameter"><tt>iter</tt></i></span></span>, <span class="methodparam"><span class="parameter"><i class="parameter"><tt>column</tt></i></span></span>, <span class="methodparam"><span class="parameter"><i class="parameter"><tt>...</tt></i></span></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">foreach</span>(<span class="methodparam"><span class="parameter"><i class="parameter"><tt>func</tt></i></span></span>, <span class="methodparam"><span class="parameter"><i class="parameter"><tt>user_data</tt></i></span></span>)</code><p>To illustrate the use of the
<tt class="classname">GenericTreeModel</tt> I'll change the <a href="examples/filelisting.py" target="_top"><span><b class="command">filelisting.py</b></span></a>
example program and show how the interface methods are created. The <a href="examples/filelisting-gtm.py" target="_top"><span><b class="command">filelisting-gtm.py</b></span></a>
program displays the files in a folder with a pixbuf indicating if the file
is a folder or not, the file name, the file size, mode and time of last
change.</p><p>The <tt class="methodname">on_get_flags</tt>() method 
should return a value that is a combination of:</p><table border="0" width="100%" bgcolor="#FFECCE"><col align="left" valign="top" width="0*"><tbody><tr><td><span class="term"><tt class="literal">gtk.TREE_MODEL_ITERS_PERSIST</tt></span></td><td><tt class="classname">TreeIter</tt>s survive all signals
emitted by the tree.</td></tr><tr><td><span class="term"><tt class="literal">gtk.TREE_MODEL_LIST_ONLY</tt></span></td><td>The model is a list only, and never has
children</td></tr></tbody></table><p>If your model has row references that are valid over row changes
(reorder, addition, deletion) then set
<tt class="literal">gtk.TREE_MODEL_ITERS_PERSIST</tt>. Likewise if your model is a
list only then set <tt class="literal">gtk.TREE_MODEL_LIST_ONLY</tt>. Otherwise,
return 0 if your model doesn't have persistent row references and it's a
tree model. For our example, the model is a list with persistent
<tt class="classname">TreeIter</tt>s.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
    def on_get_flags(self):
        return gtk.TREE_MODEL_LIST_ONLY|gtk.TREE_MODEL_ITERS_PERSIST
</pre></td></tr></table><p>The <tt class="methodname">on_get_n_columns</tt>() method should
return the number of columns that your model exports to the application. Our
example maintains a list of column types so we return the length of the
list:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
class FileListModel(gtk.GenericTreeModel):
    ...
    column_types = (gtk.gdk.Pixbuf, str, long, str, str)
    ...
    def on_get_n_columns(self):
        return len(self.column_types)
</pre></td></tr></table><p>The <tt class="methodname">on_get_column_type</tt>() method should
return the type of the column with the specified
<i class="parameter"><tt>index</tt></i>. This method is usually called from a
<tt class="classname">TreeView</tt> when its model is set. You can either create
a list or tuple containing the column data type info or generate it
on-the-fly. In our example:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
    def on_get_column_type(self, n):
        return self.column_types[n]
</pre></td></tr></table><p>The <tt class="classname">GenericTreeModel</tt> interface converts the
Python type to a GType so the following code:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
  flm = FileListModel()
  print flm.on_get_column_type(1), flm.get_column_type(1)
</pre></td></tr></table><p>would print:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
&lt;type 'str'&gt; &lt;GType gchararray (64)&gt;
</pre></td></tr></table><p>The following methods use row references that are kept as private
data in a <tt class="classname">TreeIter</tt>. The application can't see the row
reference in a <tt class="classname">TreeIter</tt> so you can use any unique
item you want as a row reference. For example in a model containing rows as
tuples you could use the tuple id as the row reference. Another example
would be to use a filename as the row reference in a model representing
files in a directory. In both these cases, the row reference is unchanged by
model changes so the <tt class="classname">TreeIter</tt>s could be flagged as
persistent. The PyGTK <tt class="classname">GenericTreeModel</tt> application
interface will extract your row references from
<tt class="classname">TreeIter</tt>s and wrap your row references in
<tt class="classname">TreeIter</tt>s as needed.</p><p>In the following methods <tt class="literal">rowref</tt> refers to an
internal row reference.</p><p>The <tt class="methodname">on_get_iter</tt>() method should return an
rowref for the tree path specified by <i class="parameter"><tt>path</tt></i>. The tree
path will always be represented using a tuple. Our example uses the file
name string as the rowref. The file names are kept in a list in the model so
we take the first index of the path as an index to the file name:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
    def on_get_iter(self, path):
        return self.files[path[0]]
</pre></td></tr></table><p>You have to be consistent in your row reference usage since you'll
get a row reference back in method calls from the
<tt class="classname">GenericTreeModel</tt> methods that take
<tt class="classname">TreeIter</tt> arguments:
<tt class="methodname">on_get_path</tt>(),
<tt class="methodname">on_get_value</tt>(),
<tt class="methodname">on_iter_next</tt>(),
<tt class="methodname">on_iter_children</tt>(),
<tt class="methodname">on_iter_has_child</tt>(),
<tt class="methodname">on_iter_n_children</tt>(),
<tt class="methodname">on_iter_nth_child</tt>() and
<tt class="methodname">on_iter_parent</tt>().</p><p>The <tt class="methodname">on_get_path</tt>() method should return a
tree path given a rowref. For example, continuing the above example where
the file name is used as the rowref, you could define the
<tt class="methodname">on_get_path</tt>() method as:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
    def on_get_path(self, rowref):
        return self.files.index(rowref)
</pre></td></tr></table><p>This method finds the index of the list containing the file name
in <i class="parameter"><tt>rowref</tt></i>. It's obvious from this example that a
judicious choice of row reference will make the implementation more
efficient. You could, for example, use a Python dict to map
<i class="parameter"><tt>rowref</tt></i> to a path.</p><p>The <tt class="methodname">on_get_value</tt>() method should return
the data stored at the row and column specified by
<i class="parameter"><tt>rowref</tt></i> and <i class="parameter"><tt>column</tt></i>. For our
example:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
    def on_get_value(self, rowref, column):
        fname = os.path.join(self.dirname, rowref)
        try:
            filestat = statcache.stat(fname)
        except OSError:
            return None
        mode = filestat.st_mode
        if column is 0:
            if stat.S_ISDIR(mode):
                return folderpb
            else:
                return filepb
        elif column is 1:
            return rowref
        elif column is 2:
            return filestat.st_size
        elif column is 3:
            return oct(stat.S_IMODE(mode))
        return time.ctime(filestat.st_mtime)
</pre></td></tr></table><p>has to extract the associated file information and return the
appropriate value depending on which column is specified.</p><p>The <tt class="methodname">on_iter_next</tt>() method should return a
row reference to the row (at the same level) after the row specified by
<i class="parameter"><tt>rowref</tt></i>. For our example:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
    def on_iter_next(self, rowref):
        try:
            i = self.files.index(rowref)+1
            return self.files[i]
        except IndexError:
            return None
</pre></td></tr></table><p>The index of the <i class="parameter"><tt>rowref</tt></i> file name is
determined and the next file name is returned or <tt class="literal">None</tt> is
returned if there is no next file.</p><p>The <tt class="methodname">on_iter_children</tt>() method should
return a row reference to the first child row of the row specified by
<i class="parameter"><tt>rowref</tt></i>. If <i class="parameter"><tt>rowref</tt></i> is
<tt class="literal">None</tt>, a reference to the first top level row is
returned. If there is no child row <tt class="literal">None</tt> is returned. For
our example:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
    def on_iter_children(self, rowref):
        if rowref:
            return None
        return self.files[0]
</pre></td></tr></table><p>Since the model is a list model only the top level
(<i class="parameter"><tt>rowref</tt></i>=<tt class="literal">None</tt>) can have child
rows. <tt class="literal">None</tt> is returned if <i class="parameter"><tt>rowref</tt></i>
contains a file name.</p><p>The <tt class="methodname">on_iter_has_child</tt>() method should
return <tt class="literal">TRUE</tt> if the row specified by
<i class="parameter"><tt>rowref</tt></i> has child rows; <tt class="literal">FALSE</tt>
otherwise. Our example returns <tt class="literal">FALSE</tt> since no row can
have a child:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
    def on_iter_has_child(self, rowref):
        return False
</pre></td></tr></table><p>The <tt class="methodname">on_iter_n_children</tt>() method should
return the number of child rows that the row specified by
<i class="parameter"><tt>rowref</tt></i> has. If <i class="parameter"><tt>rowref</tt></i> is
<tt class="literal">None</tt>, the number of top level rows is returned. Our
example returns 0 if <i class="parameter"><tt>rowref</tt></i> is not
<tt class="literal">None</tt>:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
    def on_iter_n_children(self, rowref):
        if rowref:
            return 0
        return len(self.files)
</pre></td></tr></table><p>The <tt class="methodname">on_iter_nth_child</tt>() method should
return a row reference to the nth child row of the row specified by
<i class="parameter"><tt>parent</tt></i>. If <i class="parameter"><tt>parent</tt></i> is
<tt class="literal">None</tt>, a reference to the nth top level row is
returned. Our example returns the nth top level row reference if
<i class="parameter"><tt>parent</tt></i> is <tt class="literal">None</tt>. Otherwise
<tt class="literal">None</tt> is returned:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
    def on_iter_nth_child(self, rowref, n):
        if rowref:
            return None
        try:
            return self.files[n]
        except IndexError:
            return None
</pre></td></tr></table><p>The <tt class="methodname">on_iter_parent</tt>() method should return
a row reference to the parent row of the row specified by
<i class="parameter"><tt>rowref</tt></i>. If <i class="parameter"><tt>rowref</tt></i> points to a
top level row, <tt class="literal">None</tt> should be returned. Our example
always returns <tt class="literal">None</tt> assuming that
<i class="parameter"><tt>rowref</tt></i> must point to a top level row:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
    def on_iter_parent(child):
        return None
</pre></td></tr></table><p>This example is put together in the <a href="examples/filelisting-gtm.py" target="_top">filelisting-gtm.py</a>
program. <a href="sec-GenericTreeModel.html#filelistinggtmfig" title="Figure 14.11. Generic TreeModel Example Program">Figure 14.11, &#8220;Generic TreeModel Example Program&#8221;</a> shows the result of running
the program.</p><div class="figure"><a name="filelistinggtmfig"></a><p class="title"><b>Figure 14.11. Generic TreeModel Example Program</b></p><div class="mediaobject" align="center"><img src="figures/filelisting-gtm.png" align="middle" alt="Generic TreeModel Example Program"></div></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-AddRemoveGenericTreeModelRows"></a>14.11.3. Adding and Removing Rows</h3></div></div><div></div></div><p>The <a href="examples/filelisting-gtm.py" target="_top">filelisting-gtm.py</a> program
calculates the list of file names while creating a
<tt class="classname">FileListModel</tt> instance. If you want to check for new
files periodically and add or remove files from the model you could either
create a new <tt class="classname">FileListModel</tt> for the same folder or you
could add methods to add and remove rows in the model. Depending on the type
of model you are creating you would need to add methods similar to those in
the <tt class="classname">TreeStore</tt> and <tt class="classname">ListStore</tt>
models:</p><div class="itemizedlist"><ul type="disc"><li><tt class="methodname">insert</tt>()</li><li><tt class="methodname">insert_before</tt>()</li><li><tt class="methodname">insert_after</tt>()</li><li><tt class="methodname">prepend</tt>()</li><li><tt class="methodname">append</tt>()</li><li><tt class="methodname">remove</tt>()</li><li><tt class="methodname">clear</tt>()</li></ul></div><p>Of course not all or any of these need to be implemented. You can
create your own methods that are more closely related to your model.</p><p>Using the above example program to illustrate adding methods for
removing and adding files, let's implement the methods:</p><code class="methodsynopsis">    def <span class="methodname">remove</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>iter</tt></b></span></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">add</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>filename</tt></b></span></span>)</code><br><p>The <tt class="methodname">remove</tt>() method removes the file
specified by <i class="parameter"><tt>iter</tt></i>. In addition to removing the row
from the model the method also should remove the file from the folder. Of
course, if the user doesn't have the permissions to remove the file then the
row shouldn't be removed either. For example:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
    def remove(self, iter):
        path = self.get_path(iter)
        pathname = self.get_pathname(path)
        try:
            if os.path.exists(pathname):
                os.remove(pathname)
            del self.files[path[0]]
            self.row_deleted(path)
        except OSError:
            pass
        return
</pre></td></tr></table><p>The method is passed a <tt class="classname">TreeIter</tt> that has to
be converted to a path to use to retrieve the file path using the method
<tt class="methodname">get_pathname</tt>(). It's possible that the file has
already been removed so we check if it exists before trying to remove it. If
an OSError exception is thrown during the file removal it's probably because
the file is a directory or the user doesn't have sufficient privilege to
remove it. Finally, the file is removed and the "row-deleted" signal is
emitted from the <tt class="methodname">rows_deleted</tt>() method. The
"file-deleted" signal notifies the <tt class="classname">TreeView</tt>s using
the model that the model has changed so that they can update their internal
state and display the revised model.</p><p>The <tt class="methodname">add</tt>() method needs to create a file
with the given name in the current folder. If the file was created its name
is added to the list of files in the model. For example:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
    def add(self, filename):
        pathname = os.path.join(self.dirname, filename)
        if os.path.exists(pathname):
            return
        try:
            fd = file(pathname, 'w')
            fd.close()
            self.dir_ctime = os.stat(self.dirname).st_ctime
            files = self.files[1:] + [filename]
            files.sort()
            self.files = ['..'] + files
            path = (self.files.index(filename),)
            iter = self.get_iter(path)
            self.row_inserted(path, iter)
        except OSError:
            pass
        return
</pre></td></tr></table><p>This simple example makes sure that the file doesn't exist then
tries to open the file for writing. If successful, the file is closed and
the file name sorted into the list of files. The path and
<tt class="classname">TreeIter</tt> for the added file row are retrieved to use
in the <tt class="methodname">row_inserted</tt>() method that emits the
"row-inserted" signal. The "row-inserted" signal is used to notify the
<tt class="classname">TreeView</tt>s using the model that they need to update
their internal state and revise their display.</p><p>The other methods mentioned above (for example,
<tt class="methodname">append</tt> and <tt class="methodname">prepend</tt>) don't
make sense for the example since the model keeps the file list
sorted.</p><p>Other methods that may be worth implementing in a
<tt class="classname">TreeModel</tt> subclassing the
<tt class="classname">GenericTreeModel</tt> are:</p><div class="itemizedlist"><ul type="disc"><li><tt class="methodname">set_value</tt>()</li><li><tt class="methodname">reorder</tt>()</li><li><tt class="methodname">swap</tt>()</li><li><tt class="methodname">move_after</tt>()</li><li><tt class="methodname">move_before</tt>()</li></ul></div><p>Implementing these methods is similar to the above methods. You
have to synchronize the model with the external state and then notify the
<tt class="classname">TreeView</tt>s if the model has changed. The following
methods are used to notify the <tt class="classname">TreeView</tt>s of model
changes by emitting the appropriate signal:</p><code class="methodsynopsis">    def <span class="methodname">row_changed</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>path</tt></b></span></span>, <span class="methodparam"><span class="parameter"><b class="parameter"><tt>iter</tt></b></span></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">row_inserted</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>path</tt></b></span></span>, <span class="methodparam"><span class="parameter"><b class="parameter"><tt>iter</tt></b></span></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">row_has_child_toggled</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>path</tt></b></span></span>, <span class="methodparam"><span class="parameter"><b class="parameter"><tt>iter</tt></b></span></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">row_deleted</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>path</tt></b></span></span>)</code><br><code class="methodsynopsis">    def <span class="methodname">rows_reordered</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>path</tt></b></span></span>, <span class="methodparam"><span class="parameter"><b class="parameter"><tt>iter</tt></b></span></span>, <span class="methodparam"><span class="parameter"><b class="parameter"><tt>new_order</tt></b></span></span>)</code><p></p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-GenericTreeModelMemoryManagement"></a>14.11.4. Memory Management</h3></div></div><div></div></div><p>One of the problems with the
<tt class="classname">GenericTreeModel</tt> is that
<tt class="classname">TreeIter</tt>s hold a reference to a Python object
returned from your custom tree model. Since the
<tt class="classname">TreeIter</tt> may be created and initialized in C code and
live on the stack, it's not possible to know when the
<tt class="classname">TreeIter</tt> has been destroyed and the Python object
reference is no longer being used. Therefore, the Python object referenced
in a <tt class="classname">TreeIter</tt> has by default its reference count
incremented but it is not decremented when the
<tt class="classname">TreeIter</tt> is destroyed. This ensures that the Python
object will not be destroyed while being used by a
<tt class="classname">TreeIter</tt> and possibly cause a segfault. Unfortunately
the extra reference counts lead to the situation that, at best, the Python
object will have an excessive reference count and, at worst, it will never
be freed even when it is not being used. The latter case leads to memory
leaks and the former to reference leaks.</p><p>To provide for the situation where the custom
<tt class="classname">TreeModel</tt> holds a reference to the Python object
until it is no longer available (i.e. the <tt class="classname">TreeIter</tt> is
invalid because the model has changed) and there is no need to leak
references, the <tt class="classname">GenericTreeModel</tt> has the
"leak-references" property. By default "leak-references" is
<tt class="literal">TRUE</tt> to indicate that the
<tt class="classname">GenericTreeModel</tt> will leak references. If
"leak-references" is set to <tt class="literal">FALSE</tt>, the reference count of
the Python object will not be incremented when referenced in a
<tt class="classname">TreeIter</tt>. This means that your custom
<tt class="classname">TreeModel</tt> must keep a reference to all Python objects
used in <tt class="classname">TreeIter</tt>s until the model is
destroyed. Unfortunately, even this cannot protect against buggy code that
attempts to use a saved <tt class="classname">TreeIter</tt> on a different
<tt class="classname">GenericTreeModel</tt>. To protect against that case your
application would have to keep references to all Python objects referenced
from a <tt class="classname">TreeIter</tt> for any
<tt class="classname">GenericTreeModel</tt> instance. Of course, this ultimately
has the same result as leaking references.</p><p>In PyGTK 2.4 and above the
<tt class="methodname">invalidate_iters</tt>() and
<tt class="methodname">iter_is_valid</tt>() methods are available to help
manage the <tt class="classname">TreeIter</tt>s and their Python object
references:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
  generictreemodel.invalidate_iters()

  result = generictreemodel.iter_is_valid(<b class="parameter"><tt>iter</tt></b>)
</pre></td></tr></table><p>These are particularly useful when the "leak-references" property
is set to <tt class="literal">FALSE</tt>. Tree models derived from
<tt class="classname">GenericTreeModel</tt> are protected from problems with out
of date<tt class="classname"> TreeIters</tt> because the iters are automatically
checked for validity with the tree model.</p><p>If a custom tree model doesn't support persistent iters
(i.e. <tt class="literal">gtk.TREE_MODEL_ITERS_PERSIST</tt> is not set in the
return from the <tt class="methodname">TreeModel.get_flags</tt>() method), it
can call the <tt class="methodname">invalidate_iters</tt>() method to
invalidate all its outstanding <tt class="classname">TreeIter</tt>s when it
changes the model (e.g. after inserting a new row). The tree model can also
dispose of any Python objects, that were referenced by
<tt class="classname">TreeIter</tt>s, after calling the
<tt class="methodname">invalidate_iters</tt>() method.</p><p>Applications can use the <tt class="methodname">iter_is_valid</tt>()
method to determine if a <tt class="classname">TreeIter</tt> is still valid for
the custom tree model.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-OtherInterfaces"></a>14.11.5. Other Interfaces</h3></div></div><div></div></div><p>The <tt class="classname">ListStore</tt> and
<tt class="classname">TreeStore</tt> models support the
<tt class="classname">TreeSortable</tt>, <tt class="classname">TreeDragSource</tt>
and <tt class="classname">TreeDragDest</tt> interfaces in addition to the
<tt class="classname">TreeModel</tt> interface. The
<tt class="classname">GenericTreeModel</tt> only supports the
<tt class="classname">TreeModel</tt> interface. I believe that this is because
of the direct reference of the model at the C level by
<tt class="classname">TreeView</tt>s and the
<tt class="classname">TreeModelSort</tt> and
<tt class="classname">TreeModelFilter</tt> models. To create and use
<tt class="classname">TreeIter</tt>s requires C glue code to interface with the
Python custom tree model that has the data. That glue code is provided by
the <tt class="classname">GenericTreeModel</tt> and there appears to be no
alternative purely Python way of doing it because the
<tt class="classname">TreeView</tt>s and the other models call the GtkTreeModel
functions in C passing their reference to the custom tree model.</p><p>The <tt class="classname">TreeSortable</tt> interface would need C
glue code as well to work with the default
<tt class="classname">TreeViewColumn</tt> sort mechanism as explained in <a href="sec-TreeModelInterface.html#sec-SortingTreeModelRows" title="14.2.9. Sorting TreeModel Rows">Section 14.2.9, &#8220;Sorting TreeModel Rows&#8221;</a>. However a custom model can do
its own sorting and an application can manage the use of sort criteria by
handling the <tt class="classname">TreeViewColumn</tt> header clicks and calling
the custom tree model sort methods. The model completes the update of the
<tt class="classname">TreeView</tt>s by emitting the "rows-reordered" signal
using the <tt class="classname">TreeModel</tt>'s
<tt class="methodname">rows_reordered</tt>() method. Thus the
<tt class="classname">GenericTreeModel</tt> probably doesn't need to implement
the <tt class="classname">TreeSortable</tt> interface.</p><p>Likewise, the <tt class="classname">GenericTreeModel</tt> doesn't have
to implement the <tt class="classname">TreeDragSource</tt> and
<tt class="classname">TreeDragDest</tt> interfaces because the custom tree model
can implement its own drag and drop interfaces and the application can
handle the appropriate <tt class="classname">TreeView</tt> signals and call the
custom tree model methods as needed.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-ApplyingGenericTreeModel"></a>14.11.6. Applying The GenericTreeModel</h3></div></div><div></div></div><p>I believe that the <tt class="classname">GenericTreeModel</tt> should
only be used as a last resort. There are powerful mechanisms in the standard
group of <tt class="classname">TreeView</tt> objects that should be sufficient
for most applications. Undoubtedly there are applications which may require
the use of the <tt class="classname">GenericTreeModel</tt> but you should
attempt to first use the following instead:</p><table border="0" width="100%" bgcolor="#FFECCE"><col align="left" valign="top" width="0*"><tbody><tr><td><span class="term">Cell Data Functions</span></td><td><p>As illustrated in <a href="sec-CellRenderers.html#sec-CellDataFunction" title="14.4.5. Cell Data Function">Section 14.4.5, &#8220;Cell Data Function&#8221;</a>, cell data functions can be used to
modify and even synthesize the data for a <tt class="classname">TreeView</tt>
column display. You can effectively create as many display columns with
generated data as you wish. This gives you a great deal of control over the
presentation of data from an underlying data source.</p></td></tr><tr><td><span class="term">TreeModelFilter</span></td><td><p>In PyGTK 2.4, the <tt class="classname">TreeModelFilter</tt> as
described in <a href="sec-TreeModelSortAndTreeModelFilter.html#sec-TreeModelFilter" title="14.10.2. TreeModelFilter">Section 14.10.2, &#8220;TreeModelFilter&#8221;</a> provides a great
degree of control over the display of the columns and rows of a child
<tt class="classname">TreeModel</tt> including presenting just the child rows of
a row. Data columns can be synthesized similar to using Cell Data Functions
but here the model appears to be a <tt class="classname">TreeModel</tt> with the
number and type of columns specified whereas a cell data function leaves the
model columns unchanged and just modifies the display in a
<tt class="classname">TreeView</tt>.</p></td></tr></tbody></table><p>If a <tt class="classname">GenericTreeModel</tt> must be used you
should be aware that:</p><div class="itemizedlist"><ul type="disc"><li>the entire <tt class="classname">TreeModel</tt> interface must
be created and made to work as documented. There are subtleties that can
lead to bugs. By contrast, the standard <tt class="classname">TreeModel</tt>s
are thoroughly tested.</li><li>managing the references of Python objects used by
<tt class="classname">TreeIter</tt>s can be difficult especially for long
running programs with lots of variety of display.</li><li>an interface has to be developed for adding, deleting and
changing the contents of rows. There is some awkwardness with the mapping of
<tt class="classname">TreeIter</tt>s to the Python objects and model rows in
this interface.</li><li>there is significant effort in developing sortable and drag
and drop interfaces. The application probably needs to be involved in making
these interfaces fully functional.</li></ul></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-TreeModelSortAndTreeModelFilter.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-TreeViewWidget.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-GenericCellRenderer.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">14.10. TreeModelSort and TreeModelFilter </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 14.12. The Generic CellRenderer</td></tr></table></div></body></html>