6
from GTG.core.task import Task
7
from GTG.tools import colors
8
from GTG.taskbrowser.CellRendererTags import CellRendererTags
18
class TagTreeModel(gtk.GenericTreeModel):
23
gobject.TYPE_PYOBJECT,\
28
def __init__(self, requester):
29
gtk.GenericTreeModel.__init__(self)
31
self.tree = self.req.get_tag_tree()
32
self.workable_only = False
34
### MODEL METHODS ############################################################
36
def update_tags_for_task(self, tid):
37
task = self.req.get_task(tid)
38
for t in task.get_tags():
39
path = self.tree.get_path_for_node(t)
40
iter = self.get_iter(path)
41
self.row_changed(path, iter)
43
def set_workable_only(self, val):
44
self.workable_only = val
46
### TREEMODEL INTERFACE ######################################################
48
def on_get_flags(self):
49
return gtk.TREE_MODEL_ITERS_PERSIST|gtk.TREE_MODEL_LIST_ONLY
51
def on_get_n_columns(self):
52
return len(self.column_types)
54
def on_get_column_type(self, n):
55
return self.column_types[n]
57
def on_get_iter(self, path):
58
#print "on_get_iter: %s" % str(path)
59
return self.tree.get_rowref_for_path(path)
61
def on_get_path(self, rowref):
62
#print "on_get_path: %s" % rowref
63
return self.tree.get_path_for_rowref(rowref)
65
def on_get_value(self, rowref, column):
66
#print "on_get_value: %s" % rowref
67
tag = self.tree.get_node_for_rowref(rowref)
70
if column == COL_NAME:
71
return tag.get_name()[1:]
72
if column == COL_LABEL:
73
if tag.get_attribute("label"):
74
return tag.get_attribute("label")
76
if tag.get_attribute("nonworkview"):
77
nwv = eval(tag.get_attribute("nonworkview"))
81
return "<span color='#AAAAAA'>%s</span>"\
84
return tag.get_name()[1:]
87
elif column == COL_COLOR:
88
return task.get_attribute("color")
89
elif column == COL_COUNT:
90
sp_id = tag.get_attribute("special")
92
count = len(self.req.get_active_tasks_list(\
93
tags=[tag], workable=self.workable_only))
97
return len(self.req.get_active_tasks_list(\
98
workable=self.workable_only))
99
elif sp_id == "notag":
100
return len(self.req.get_active_tasks_list(\
101
workable=self.workable_only, notag_only=True))
104
elif column == COL_SEP:
105
sp_id = tag.get_attribute("special")
112
def on_iter_next(self, rowref):
113
#print "on_iter_next: %s" % (rowref)
114
node = self.tree.get_node_for_rowref(rowref)
115
parent_node = node.get_parent()
117
next_idx = parent_node.get_child_index(node.get_id()) + 1
118
if parent_node.get_n_children()-1 < next_idx:
121
return self.tree.get_rowref_for_node(\
122
parent_node.get_nth_child(next_idx))
126
def on_iter_children(self, rowref):
127
#print "on_iter_children: %s" % (rowref)
129
node = self.tree.get_node_for_rowref(rowref)
131
return self.tree.get_rowref_for_node(node.get_nth_child(0))
135
node = self.root.get_nth_child(0)
136
return self.tree.get_rowref_for_node(node)
138
def on_iter_has_child(self, rowref):
139
#print "on_iter_has_child: %s" % (rowref)
140
node = self.tree.get_node_for_rowref(rowref)
141
return node.has_child()
143
def on_iter_n_children(self, rowref):
144
#print "on_iter_n_children: %s" % (rowref)
146
node = self.tree.get_node_for_rowref(rowref)
148
node = self.tree.get_root()
149
return node.get_n_children()
151
def on_iter_nth_child(self, rowref, n):
152
#print "on_iter_nth_child: %s %d" % (rowref, n)
154
node = self.tree.get_node_from_rowref(rowref)
156
node = self.tree.get_root()
157
nth_child = node.get_nth_child(n)
158
return self.tree.get_rowref_for_node(nth_child)
160
def on_iter_parent(self, rowref):
161
#print "on_iter_parent: %s" % (rowref)
162
node = self.tree.get_node_from_rowref(rowref)
163
if node.has_parent():
164
parent = node.get_parent()
165
return self.tree.get_rowref_for_node(parent)
169
def add_tag(self, tname, tag):
170
root = self.tree.get_root()
171
root.add_child(tname, tag)
173
tag_index = root.get_child_index(tname)
174
tag_path = (tag_index,)
175
tag_iter = self.get_iter(tag_path)
176
self.row_inserted(tag_path, tag_iter)
178
# def remove_task(self, tid):
180
# task = self.req.get_task(tid)
181
# # Remove every row of this task
182
# if task.has_parents():
183
# # get every paths leading to this task
184
# path_list = self._get_paths_for_task(task)
185
# # remove every path
186
# for task_path in path_list:
187
# self.row_deleted(task_path)
188
# if tid in self.root_tasks:
189
# task_index = self._get_root_task_index(tid)
190
# task_path = (task_index,)
191
# task_iter = self.get_iter(task_path)
192
# self.row_deleted(task_path)
193
# self.root_tasks.remove(tid)
195
# def move_task(self, parent, child):
196
# #print "Moving %s below %s" % (child, parent)
198
# child_tid = self.get_value(child, COL_TID)
199
# child_task = self.req.get_task(child_tid)
200
# child_path = self.get_path(child)
202
# old_par = self.iter_parent(child)
204
# old_par_tid = self.get_value(old_par, COL_TID)
205
# old_par_task = self.req.get_task(old_par_tid)
207
# old_par_task = None
210
# new_par_tid = self.get_value(parent, COL_TID)
211
# new_par_task = self.req.get_task(new_par_tid)
213
# new_par_task = None
214
# # Remove child from old parent
216
# old_par_task.remove_subtask(child_tid)
218
# self.root_tasks.remove(child_tid)
219
# # Remove old parent from child
221
# child_task.remove_parent(old_par_tid)
222
# # Add child to new parent (add_subtask also add new parent to child)
224
# new_par_task.add_subtask(child_tid)
226
# self.root_tasks.append(child_tid)
227
# # Warn tree about deleted row
228
# self.row_deleted(child_path)
229
# # Warn tree about inserted row
231
# new_child_index = new_par_task.get_subtask_index(child_tid)
233
# new_child_index = self._get_root_task_index(child_tid)
235
# new_child_path = self.get_path(parent) + (new_child_index,)
237
# new_child_path = (new_child_index,)
238
# new_child_iter = self.get_iter(new_child_path)
239
# self.row_inserted(new_child_path, new_child_iter)
241
class TagTreeView(gtk.TreeView):
242
"""TreeView for display of a list of task. Handles DnD primitives too."""
245
('gtg/task-iter-str', gtk.TARGET_SAME_WIDGET, 0)
249
gtk.TreeView.__init__(self)
251
self._init_tree_view()
254
# self.enable_model_drag_source(\
255
# gtk.gdk.BUTTON1_MASK,
257
# gtk.gdk.ACTION_DEFAULT | gtk.gdk.ACTION_MOVE)
258
# self.enable_model_drag_dest(\
260
# gtk.gdk.ACTION_DEFAULT)
262
# self.drag_source_set(\
263
# gtk.gdk.BUTTON1_MASK,
265
# gtk.gdk.ACTION_DEFAULT | gtk.gdk.ACTION_MOVE)
267
# self.drag_dest_set(\
268
# gtk.DEST_DEFAULT_ALL,
270
# gtk.gdk.ACTION_DEFAULT | gtk.gdk.ACTION_MOVE)
272
# self.connect('drag_drop', self.on_drag_drop)
273
# self.connect('drag_data_get', self.on_drag_data_get)
274
# self.connect('drag_data_received', self.on_drag_data_received)
277
self.get_model().foreach(self._refresh_func)
279
def _refresh_func(self, model, path, iter, user_data=None):
280
model.row_changed(path, iter)
282
def _tag_separator_filter(self, model, itera, user_data=None):
283
return self.get_model().get_value(itera, COL_SEP)
285
def _init_tree_view(self):
288
tag_col = gtk.TreeViewColumn()
289
render_text = gtk.CellRendererText()
290
render_count = gtk.CellRendererText()
291
render_tags = CellRendererTags()
292
tag_col.set_title(_("Tags"))
293
tag_col.set_clickable(False)
294
tag_col.pack_start(render_tags, expand=False)
295
tag_col.set_attributes(render_tags, tag=COL_OBJ)
296
tag_col.pack_start(render_text, expand=True)
297
tag_col.set_attributes(render_text, markup=COL_LABEL)
298
tag_col.pack_end(render_count, expand=False)
299
tag_col.set_attributes(render_count, markup=COL_COUNT)
300
render_count.set_property("foreground", "#888a85")
301
render_count.set_property('xalign', 1.0)
302
render_tags.set_property('ypad', 3)
303
render_text.set_property('ypad', 3)
304
render_count.set_property('xpad', 3)
305
render_count.set_property('ypad', 3)
306
tag_col.set_sort_column_id(-1)
307
tag_col.set_expand(True)
308
self.append_column(tag_col)
310
# Global treeview properties
311
self.set_row_separator_func(self._tag_separator_filter)
312
self.set_headers_visible(False)
314
### DRAG AND DROP ########################################################
316
# def on_drag_drop(self, treeview, context, selection, info, timestamp):
317
# self.emit_stop_by_name('drag_drop')
319
# def on_drag_data_get(self, treeview, context, selection, info, timestamp):
320
# """Extract data from the source of the DnD operation. Here the id of
321
# the parent task and the id of the selected task is passed to the
323
# treeselection = treeview.get_selection()
324
# model, iter = treeselection.get_selected()
325
# iter_str = model.get_string_from_iter(iter)
326
# selection.set('gtg/task-iter-str', 0, iter_str)
329
# def on_drag_data_received(self, treeview, context, x, y, selection, info,\
332
# model = treeview.get_model()
333
# model_filter = model.get_model()
334
# tasktree_model = model_filter.get_model()
336
# drop_info = treeview.get_dest_row_at_pos(x, y)
339
# path, position = drop_info
340
# iter = model.get_iter(path)
341
# if position == gtk.TREE_VIEW_DROP_BEFORE or\
342
# position == gtk.TREE_VIEW_DROP_AFTER:
343
# # Must add the task to the parent of the task situated\
345
# # Get sibling parent
346
# par_iter = model.iter_parent(iter)
348
# # Must add task as a child of the dropped-on iter
352
# # Must add the task to the root
353
# # Parent = root => iter=None
356
# # Get parent iter as a TaskTreeModel iter
359
# model.convert_iter_to_child_iter(None, par_iter)
360
# par_iter_tasktree =\
361
# model_filter.convert_iter_to_child_iter(par_iter_filter)
363
# par_iter_tasktree = None
365
# # Get dragged iter as a TaskTreeModel iter
366
# drag_iter = model.get_iter_from_string(selection.data)
367
# drag_iter_filter =\
368
# model.convert_iter_to_child_iter(None, drag_iter)
369
# drag_iter_tasktree =\
370
# model_filter.convert_iter_to_child_iter(drag_iter_filter)
371
# tasktree_model.move_task(par_iter_tasktree, drag_iter_tasktree)
373
# self.emit_stop_by_name('drag_data_received')