1 """
2 Cotains treeview and treemodel classes for displaying the
3 dataproviders
4
5 Copyright: John Stowers, 2006
6 License: GPLv2
7 """
8
9 import gtk
10 import logging
11 log = logging.getLogger("gtkui.Tree")
12
13 import conduit
14 from conduit.ModuleWrapper import ModuleWrapper
15
16 from gettext import gettext as _
17
19 """
20 Represents a category stored in the treemodel. Not generally intended
21 to be used outside of C{conduit.Tree.DataProviderTreeModel}
22 """
24 ModuleWrapper.__init__(
25 self,
26 klass=None,
27 initargs=(),
28 category=category
29 )
30 self.name=category.name
31 self.classname=category.name
32 self.icon_name=category.icon
33 self.module_type="category"
34
37
38 IDX_ICON = 0
39 IDX_NAME = 1
40 IDX_DESCRIPTION = 2
41 IDX_DND_KEY = 3
42 COLUMN_TYPES = (gtk.gdk.Pixbuf, str, str, str)
43
45 """
46 A treemodel for managing dynamically loaded modules. Manages an internal
47 list of L{conduit.ModuleManager.ModuleWrapper}
48
49 @ivar modules: The array of modules under this treeviews control.
50 @type modules: L{conduit.ModuleManager.ModuleWrapper}[]
51 """
72
74 return rowref.module_type == "category"
75
77 i = 0
78 for j in self.cats:
79 if j.category == category_name:
80 return i
81 i += 1
82 return None
83
87
89 self.pathMappings = {}
90 for i, cat in enumerate(self.cats):
91 self.pathMappings[cat] = (i, )
92 for j, dp in enumerate(self.dataproviders[i]):
93 self.pathMappings[dp] = (i, j)
94
98
101
103 """
104 Adds all enabled dataproviders to the model
105 """
106
107 module_wrapper_list = [m for m in dpw if m.enabled]
108
109
110 for mod in module_wrapper_list:
111
112
113 self.add_dataprovider(mod, False)
114
116 """
117 Adds a dataprovider to the model. Creating a category for it if
118 it does not exist
119
120 @param dpw: The dataproviderwrapper to add
121 @param signal: Whether the associated treeview should be signaled to
122 update the GUI. Set to False for the first time the model is
123 built (in the constructor)
124 @type signal: C{bool}
125 """
126
127 i = self._get_category_index_by_name(dpw.category)
128 if i == None:
129 new_cat = CategoryWrapper(dpw.category)
130 self.cats.append(new_cat)
131 i = self.cats.index(new_cat)
132 self.pathMappings[new_cat] = (i,)
133
134 if signal:
135 path=self.on_get_path(new_cat)
136 self.row_inserted(path, self.get_iter(path))
137
138
139 try:
140 self.dataproviders[i].append(dpw)
141 except IndexError:
142
143 self.dataproviders.insert(i, [dpw])
144
145
146 j = self.dataproviders[i].index(dpw)
147 self.pathMappings[dpw] = (i,j)
148
149
150 if signal:
151 path=self.on_get_path(dpw)
152 self.row_inserted(path, self.get_iter(path))
153
155 """
156 Removes the dataprovider from the treemodel. Also removes the
157 category that it was in if there is no remaining dataproviders in
158 that category
159 """
160 path = self.on_get_path(dpw)
161 self.row_deleted(path)
162 del self.dataproviders[path[0]][path[1]]
163
164
165
166 i = self._get_category_index_by_name(dpw.category)
167 if len(self.dataproviders[i]) == 0:
168 log.info("Category %s empty - removing." % dpw.category)
169 self.row_deleted((i, ))
170 del self.dataproviders[i]
171 del self.cats[i]
172
173 self._rebuild_path_mappings()
174
176 """
177 on_get_flags(
178 """
179 return gtk.TREE_MODEL_ITERS_PERSIST
180
182 """
183 on_get_n_columns(
184 """
185 return len(COLUMN_TYPES)
186
188 """
189 on_get_column_type(
190 """
191 return COLUMN_TYPES[n]
192
194 """
195 on_get_iter(
196 """
197 if len(self.cats) == 0:
198 return None
199
200 if len(path) == 1:
201 if path[0] > len(self.cats):
202 return None
203 if debug:
204 print "on_get_iter: path = %s cat = %s" % (path, self.cats[path[0]])
205 return self.cats[path[0]]
206 else:
207 try:
208 if debug:
209 print "on_get_iter: path = %s dataprovider = %s" % (path, self.dataproviders[path[0]][path[1]])
210 return self.dataproviders[path[0]][path[1]]
211 except IndexError:
212
213 if debug:
214 print "on_get_iter: No modules loaded path = ", path
215 return None
216
218 """
219 on_get_path(
220 """
221
222 path = self.pathMappings[rowref]
223
224 return path
225
251
253 """
254 on_iter_next(
255 """
256 path = self.on_get_path(rowref)
257 try:
258
259
260 if len(path) == 1:
261 return self.cats[path[0]+1]
262 else:
263 return self.dataproviders[path[0]][path[1]+1]
264 except IndexError:
265
266 return None
267
269 """
270 on_iter_children(
271 """
272
273 if rowref is None:
274 return self.cats[0]
275 else:
276 path = self.on_get_path(rowref)
277
278 return self.dataproviders[path[0]][0]
279
286
288 """
289 on_iter_n_children(
290 """
291
292 if rowref:
293 path = self.on_get_path(rowref)
294 return len(self.dataproviders[path[0]])
295 return len(self.cats)
296
298 """
299 on_iter_nth_child(
300 """
301
302 if rowref is None:
303 return self.cats[n]
304 else:
305 path = self.on_get_path(rowref)
306 try:
307 return self.dataproviders[path[0]][n]
308 except IndexError:
309 return None
310
311
325
326
328 """
329 Handles DND of DataProviders onto canvas
330 """
331
332 DND_TARGETS = [
333 ('conduit/element-name', 0, 0)
334 ]
335
337 """
338 Constructor
339 """
340 gtk.TreeView.__init__(self, model)
341 self.set_property("enable-search", False)
342
343 if gtk.pygtk_version >= (2,10,0):
344 self.set_property("enable-tree-lines", True)
345
346
347 pixbufRenderer = gtk.CellRendererPixbuf()
348 textRenderer = gtk.CellRendererText()
349 tvcolumn0 = gtk.TreeViewColumn(_("Name"))
350 tvcolumn0.pack_start(pixbufRenderer, False)
351 tvcolumn0.add_attribute(pixbufRenderer, 'pixbuf', IDX_ICON)
352 tvcolumn0.pack_start(textRenderer, True)
353 tvcolumn0.add_attribute(textRenderer, 'markup', IDX_NAME)
354 self.append_column(tvcolumn0)
355
356
357 if conduit.GLOBALS.settings.get("show_dp_description") == True:
358 tvcolumn1 = gtk.TreeViewColumn(_("Description"), gtk.CellRendererText(), text=IDX_DESCRIPTION)
359 self.append_column(tvcolumn1)
360 self.set_headers_visible(True)
361 else:
362 self.set_headers_visible(False)
363
364
365
366 self.enable_model_drag_source( gtk.gdk.BUTTON1_MASK,
367 self.DND_TARGETS,
368 gtk.gdk.ACTION_DEFAULT | gtk.gdk.ACTION_MOVE)
369 self.drag_source_set( gtk.gdk.BUTTON1_MASK | gtk.gdk.BUTTON3_MASK,
370 self.DND_TARGETS,
371 gtk.gdk.ACTION_COPY | gtk.gdk.ACTION_LINK)
372 self.connect('drag-data-get', self.on_drag_data_get)
373 self.connect('drag-data-delete', self.on_drag_data_delete)
374
376 model = self.get_model()
377 expanded = []
378 for c in model.cats:
379 try:
380 path = model.on_get_path(c)
381 if self.row_expanded(model.on_get_path(c)):
382 expanded.append(c.get_UID())
383 except KeyError: pass
384 return expanded
385
387 if conduit.GLOBALS.settings.get("gui_restore_expanded_rows") == True:
388 model = self.get_model()
389 cols = conduit.GLOBALS.settings.get("gui_expanded_rows")
390 for c in model.cats:
391 try:
392 path = model.on_get_path(c)
393 if c.get_UID() in cols:
394 self.expand_row(path, False)
395 else:
396 self.collapse_row(path)
397 except KeyError:
398
399 break
400 return
401
402 if gtk.pygtk_version >= (2,10,0):
403 gtk.TreeView.expand_all(self)
404
406 """
407 Get the data to be dropped by on_drag_data_received().
408 We send the id of the dragged element.
409 """
410 treeselection = treeview.get_selection()
411 model, iter = treeselection.get_selected()
412
413 data = model.get_value(iter, IDX_DND_KEY)
414 selection.set(selection.target, 8, data)
415
417 """
418 DnD magic. do not touch
419 """
420 self.emit_stop_by_name('drag-data-delete')
421
422