Merge lp:~spud/spud/group-view into lp:spud

Proposed by Fraser Waters
Status: Superseded
Proposed branch: lp:~spud/spud/group-view
Merge into: lp:spud
Prerequisite: lp:~spud/spud/slice-view
Diff against target: 581 lines (+191/-93)
4 files modified
diamond/diamond/choice.py (+6/-0)
diamond/diamond/interface.py (+150/-89)
diamond/diamond/tree.py (+4/-1)
diamond/gui/gui.glade (+31/-3)
To merge this branch: bzr merge lp:~spud/spud/group-view
Reviewer Review Type Date Requested Status
Patrick Farrell Pending
Review via email: mp+69242@code.launchpad.net

This proposal has been superseded by a proposal from 2011-07-26.

Description of the change

Allows nodes to be grouped together in the LHS hiding all other nodes.

To post a comment you must log in.
lp:~spud/spud/group-view updated
449. By Fraser Waters

Merge from trunk.

450. By Fraser Waters

Added edit menu options. Fixed grouping on whole tree.

451. By Fraser Waters

Changed __class__ == to isinstance

452. By Fraser Waters

Choices and optionals show in group view.

453. By Fraser Waters

__str__ on Tree and Choice returns the display name.

454. By Fraser Waters

In group mode use name paths, in normal mode use display names.

455. By Fraser Waters

Refresh fix.

456. By Fraser Waters

Select the node you group or ungroup on.

457. By Fraser Waters

Grouping bug fix for choices.

458. By Fraser Waters

Fixed long names, and more choice bugs

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'diamond/diamond/choice.py'
2--- diamond/diamond/choice.py 2011-07-25 13:41:47 +0000
3+++ diamond/diamond/choice.py 2011-07-26 16:14:06 +0000
4@@ -196,5 +196,11 @@
5
6 def is_sliceable(self):
7 return self.get_current_tree().is_sliceable()
8+
9+ def __str__(self):
10+ """
11+ Returns the display name of the selected tree.
12+ """
13+ return self.get_display_name()
14
15 gobject.type_register(Choice)
16
17=== modified file 'diamond/diamond/interface.py'
18--- diamond/diamond/interface.py 2011-07-25 13:51:34 +0000
19+++ diamond/diamond/interface.py 2011-07-26 16:14:06 +0000
20@@ -90,7 +90,7 @@
21 treeview: the LHS tree widget
22
23 Important routines:
24- cellcombo_edited: called when a choice is selected on the left-hand pane
25+ cellcombo_changed: called when a choice is selected on the left-hand pane
26 init_treemodel: set up the treemodel and treeview
27 on_treeview_clicked: when a row is clicked, process the consequences (e.g. activate inactive instance)
28 set_treestore: stuff the treestore with a given tree.Tree
29@@ -139,7 +139,10 @@
30 "on_copy_spud_path": self.on_copy_spud_path,
31 "on_copy": self.on_copy,
32 "on_paste": self.on_paste,
33- "on_slice": self.on_slice}
34+ "on_slice": self.on_slice,
35+ "on_group": self.on_group,
36+ "on_ungroup": self.on_ungroup}
37+
38 self.gui.signal_autoconnect(signals)
39
40 self.main_window = self.gui.get_widget("mainWindow")
41@@ -157,6 +160,7 @@
42 self.suffix = suffix
43
44 self.selected_node = None
45+ self.selected_iter = None
46 self.update_options_frame()
47
48 self.file_path = os.getcwd()
49@@ -668,7 +672,7 @@
50 ios = StringIO.StringIO(clipboard.wait_for_text())
51
52 if self.selected_iter is not None:
53- node = self.treestore.get_value(self.selected_iter, 3)
54+ node = self.treestore.get_value(self.selected_iter, 1)
55
56 if node != None:
57
58@@ -729,6 +733,80 @@
59 def _slice_destroy(self, widget):
60 self.on_select_row()
61
62+
63+ groupmode = False
64+
65+ def on_group(self, widget = None):
66+ """
67+ Clears the treeview and then fills it with nodes
68+ with the same type as the selected node.
69+ """
70+
71+ if self.selected_node == self.tree or not self.selected_iter:
72+ self.statusbar.set_statusbar("Cannot group on this element.")
73+ return #Group on the entire tree... ie don't group or nothing selected
74+
75+ self.gui.get_widget("menuitemUngroup").show()
76+ self.gui.get_widget("popupmenuitemUngroup").show()
77+
78+ self.groupmode = True
79+ node, tree = self.treestore.get(self.selected_iter, 0, 1)
80+
81+ self.treeview.freeze_child_notify()
82+ self.treeview.set_model(None)
83+
84+ def get_nodes(node, tree):
85+ nodes = []
86+
87+ if isinstance(tree, choice.Choice):
88+ child = tree.get_current_tree()
89+ if child.name == node.name:
90+ nodes.append(tree)
91+ nodes += get_nodes(node, child)
92+ else:
93+ for child in tree.get_children():
94+ if child.name == node.name:
95+ nodes.append(child)
96+ nodes += get_nodes(node, child)
97+
98+ return nodes
99+
100+ self.set_treestore(None, get_nodes(tree, self.tree), True)
101+
102+ self.treeview.set_model(self.treestore)
103+ self.treeview.thaw_child_notify()
104+
105+ path = self.get_treestore_path_from_node(node)
106+ self.treeview.get_selection().select_path(path)
107+
108+ return
109+
110+ def on_ungroup(self, widget = None):
111+ """
112+ Restores the treeview to normal.
113+ """
114+
115+ self.gui.get_widget("menuitemUngroup").hide()
116+ self.gui.get_widget("popupmenuitemUngroup").hide()
117+
118+ self.groupmode = False
119+ node = self.treestore.get_value(self.selected_iter, 0)
120+
121+ self.treeview.freeze_child_notify()
122+ self.treeview.set_model(None)
123+
124+ self.set_treestore(None, [self.tree], True)
125+
126+ self.treeview.set_model(self.treestore)
127+ self.treeview.thaw_child_notify()
128+
129+ path = self.get_treestore_path_from_node(node)
130+ self.treeview.expand_to_path(path)
131+ self.treeview.scroll_to_cell(path)
132+ self.treeview.get_selection().select_path(path)
133+
134+ return
135+
136 ## LHS ###
137
138 def init_datatree(self):
139@@ -773,16 +851,14 @@
140 self.treeview.get_selection().set_select_function(self.options_tree_select_func)
141 self.options_tree_select_func_enabled = True
142
143- model = gtk.ListStore(str, str, gobject.TYPE_PYOBJECT)
144 self.cellcombo = cellCombo = gtk.CellRendererCombo()
145- cellCombo.set_property("model", model)
146 cellCombo.set_property("text-column", 0)
147 cellCombo.set_property("editable", True)
148 cellCombo.set_property("has-entry", False)
149- cellCombo.connect("edited", self.cellcombo_edited)
150+ cellCombo.connect("changed", self.cellcombo_changed)
151
152 # Node column
153- column = gtk.TreeViewColumn("Node", cellCombo, text=0)
154+ column = gtk.TreeViewColumn("Node", cellCombo)
155 column.set_property("expand", True)
156 column.set_resizable(True)
157 column.set_cell_data_func(cellCombo, self.set_combobox_liststore)
158@@ -800,12 +876,11 @@
159 imgcolumn.set_cell_data_func(cellPicture, self.set_cellpicture_cardinality)
160 optionsTree.append_column(imgcolumn)
161
162- # 0: display name,
163- # 1: gtk.ListStore containing the display names of possible choices
164- # 2: pointer to node in self.tree -- a choice or a tree
165- # 3: pointer to currently active tree
166+ # 0: pointer to node in self.tree -- a choice or a tree
167+ # 1: pointer to currently active tree
168+ # 2: gtk.ListStore containing the display names of possible choices
169
170- self.treestore = gtk.TreeStore(str, gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)
171+ self.treestore = gtk.TreeStore(gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)
172 self.treeview.set_model(self.treestore)
173 self.treeview.set_enable_search(False)
174
175@@ -820,8 +895,7 @@
176 liststore = gtk.ListStore(str, gobject.TYPE_PYOBJECT)
177
178 for t in choice_or_tree.get_choices():
179- name = t.get_display_name()
180- liststore.append([name, t])
181+ liststore.append([str(t), t])
182
183 return liststore
184
185@@ -851,9 +925,9 @@
186 liststore = self.create_liststore(t)
187
188 if replace:
189- child_iter = self.treestore.insert_before(iter, replacediter, [t.get_display_name(), liststore, t, t])
190+ child_iter = self.treestore.insert_before(iter, replacediter, [t, t, liststore])
191 else:
192- child_iter = self.treestore.append(iter, [t.get_display_name(), liststore, t, t])
193+ child_iter = self.treestore.append(iter, [t, t, liststore])
194
195 attrid = t.connect("on-set-attr", self.on_set_attr, self.treestore.get_path(child_iter))
196 dataid = t.connect("on-set-data", self.on_set_data, self.treestore.get_path(child_iter))
197@@ -871,9 +945,9 @@
198 continue
199
200 if replace:
201- child_iter = self.treestore.insert_before(iter, replacediter, [ts_choice.get_display_name(), liststore, t, ts_choice])
202+ child_iter = self.treestore.insert_before(iter, replacediter, [t, ts_choice, liststore])
203 else:
204- child_iter = self.treestore.append(iter, [ts_choice.get_display_name(), liststore, t, ts_choice])
205+ child_iter = self.treestore.append(iter, [t, ts_choice, liststore])
206
207 attrid = t.connect("on-set-attr", self.on_set_attr, self.treestore.get_path(child_iter))
208 dataid = t.connect("on-set-data", self.on_set_data, self.treestore.get_path(child_iter))
209@@ -916,7 +990,7 @@
210 self.set_treestore(iter, [])
211 return
212
213- choice_or_tree, active_tree = self.treestore.get(iter, 2, 3)
214+ choice_or_tree, active_tree = self.treestore.get(iter, 0, 1)
215 if active_tree.active is False or choice_or_tree.active is False:
216 return
217
218@@ -927,7 +1001,7 @@
219 child_iter = self.treestore.iter_children(iter)
220 while child_iter is not None:
221 # fix for recursive schemata!
222- child_active_tree = self.treestore.get_value(child_iter, 3)
223+ child_active_tree = self.treestore.get_value(child_iter, 1)
224 if child_active_tree.schemaname == active_tree.schemaname:
225 debug.deprint("Warning: recursive schema elements not supported: %s" % active_tree.name)
226 child_iter = self.treestore.iter_next(child_iter)
227@@ -961,15 +1035,20 @@
228 foreground colour.
229 """
230
231- liststore, choice_or_tree, active_tree = self.treestore.get(iter, 1, 2, 3)
232-
233- # set the model for the cellcombo, where it gets the possible choices for the name
234+ choice_or_tree, active_tree, liststore = self.treestore.get(iter, 0, 1, 2)
235+
236+ if self.groupmode and self.treestore.iter_parent(iter) is None:
237+ cellCombo.set_property("text", choice_or_tree.get_name_path())
238+ else:
239+ cellCombo.set_property("text", str(choice_or_tree))
240+
241+
242 cellCombo.set_property("model", liststore)
243
244 # set the properties: colour, etc.
245- if choice_or_tree.__class__ is tree.Tree:
246+ if isinstance(choice_or_tree, tree.Tree):
247 cellCombo.set_property("editable", False)
248- elif choice_or_tree.__class__ is choice.Choice:
249+ elif isinstance(choice_or_tree, choice.Choice):
250 cellCombo.set_property("editable", True)
251
252 if self.treestore_iter_is_active(iter):
253@@ -987,8 +1066,8 @@
254 This hook function sets up the other gtk.CellRendererPixbuf, the one that gives
255 the clue to the user whether this is a choice or not.
256 """
257-
258- choice_or_tree = self.treestore.get_value(iter, 2)
259+
260+ choice_or_tree = self.treestore.get_value(iter, 0)
261 if isinstance(choice_or_tree, tree.Tree):
262 cell.set_property("stock-id", None)
263 elif isinstance(choice_or_tree, choice.Choice):
264@@ -1003,7 +1082,7 @@
265 something can be added or removed or has to be there.
266 """
267
268- choice_or_tree = self.treestore.get_value(iter, 2)
269+ choice_or_tree = self.treestore.get_value(iter, 0)
270 if choice_or_tree.cardinality == "":
271 cell.set_property("stock-id", None)
272 elif choice_or_tree.cardinality == "?" or choice_or_tree.cardinality == "*":
273@@ -1029,7 +1108,7 @@
274 Toggles the state of part of the tree.
275 """
276
277- choice_or_tree = self.treestore.get_value(iter, 2)
278+ choice_or_tree = self.treestore.get_value(iter, 0)
279
280 if choice_or_tree.active:
281 self.collapse_tree(iter)
282@@ -1045,13 +1124,8 @@
283 Collapses part of the tree.
284 """
285
286- choice_or_tree, = self.treestore.get(iter, 2)
287- parent_iter = self.treestore.iter_parent(iter)
288-
289- if parent_iter == None:
290- parent_tree = None
291- else:
292- parent_tree = self.treestore.get_value(parent_iter, 3)
293+ choice_or_tree, = self.treestore.get(iter, 0)
294+ parent_tree = choice_or_tree.parent
295
296 if not choice_or_tree.active:
297 return
298@@ -1088,16 +1162,11 @@
299 return
300
301 def delete_tree(self, iter):
302- choice_or_tree, = self.treestore.get(iter, 2)
303- parent_iter = self.treestore.iter_parent(iter)
304+ choice_or_tree, = self.treestore.get(iter, 0)
305+ parent_tree = choice_or_tree.parent
306 isSelected = self.treeview.get_selection().iter_is_selected(iter)
307 sibling = self.treestore.iter_next(iter)
308
309- if parent_iter == None:
310- parent_tree = None
311- else:
312- parent_tree = self.treestore.get_value(parent_iter, 3)
313-
314 confirm = dialogs.prompt(self.main_window, "Are you sure you want to delete this node?")
315 if confirm == gtk.RESPONSE_YES:
316 parent_tree.delete_child_by_ref(choice_or_tree)
317@@ -1114,13 +1183,8 @@
318 Expands part of the tree.
319 """
320
321- choice_or_tree, active_tree = self.treestore.get(iter, 2, 3)
322- parent_iter = self.treestore.iter_parent(iter)
323-
324- if parent_iter == None:
325- parent_tree = None
326- else:
327- parent_tree = self.treestore.get_value(parent_iter, 3)
328+ choice_or_tree, active_tree = self.treestore.get(iter, 0, 1)
329+ parent_tree = choice_or_tree.parent
330
331 if choice_or_tree.active:
332 return
333@@ -1140,8 +1204,7 @@
334 liststore = self.create_liststore(new_tree)
335 self.expand_treestore(iter)
336 iter = self.treestore.insert_after(
337- parent=parent_iter, sibling=iter,
338- row=[new_tree.get_display_name(), liststore, new_tree, new_tree.get_current_tree()])
339+ None, iter, [new_tree, new_tree.get_current_tree(), liststore])
340 attrid = new_tree.connect("on-set-attr", self.on_set_attr, self.treestore.get_path(iter))
341 dataid = new_tree.connect("on-set-data", self.on_set_data, self.treestore.get_path(iter))
342 self.signals[new_tree] = (attrid, dataid)
343@@ -1243,7 +1306,7 @@
344 return
345
346 self.selected_iter = iter = self.treestore.get_iter(path)
347- choice_or_tree, active_tree = self.treestore.get(iter, 2, 3)
348+ choice_or_tree, active_tree = self.treestore.get(iter, 0, 1)
349
350 debug.dprint(active_tree)
351
352@@ -1367,26 +1430,18 @@
353
354 return
355
356- def cellcombo_edited(self, cellrenderertext, path, new_text):
357+ def cellcombo_changed(self, combo, tree_path, combo_iter):
358 """
359 This is called when a cellcombo on the left-hand treeview is edited,
360 i.e. the user chooses between more than one possible choice.
361 """
362
363- iter = self.treestore.get_iter(path)
364- self.treestore.set(iter, 0, new_text)
365- choice = self.treestore.get_value(iter, 2)
366+ tree_iter = self.treestore.get_iter(tree_path)
367+ choice = self.treestore.get_value(tree_iter, 0)
368
369 # get the ref to the new active choice
370- liststore = self.treestore.get_value(iter, 1)
371- list_iter = liststore.get_iter_first()
372- ref = None
373- while list_iter is not None:
374- list_text = liststore.get_value(list_iter, 0)
375- if list_text == new_text:
376- ref = liststore.get_value(list_iter, 1)
377- break
378- list_iter = liststore.iter_next(list_iter)
379+ liststore = self.treestore.get_value(tree_iter, 2)
380+ ref = liststore.get_value(combo_iter, 1)
381
382 # record the choice in the datatree
383 choice.set_active_choice_by_ref(ref)
384@@ -1394,7 +1449,7 @@
385
386 name = self.get_spudpath(new_active_tree)
387 self.statusbar.set_statusbar(name)
388- self.treestore.set(iter, 3, new_active_tree)
389+ self.treestore.set(tree_iter, 1, new_active_tree)
390 self.current_spudpath = name
391 xpath = self.get_xpath(new_active_tree)
392 self.current_xpath = xpath
393@@ -1405,12 +1460,12 @@
394 if plugin.matches(xpath):
395 self.add_plugin_button(plugin)
396
397- self.remove_children(iter)
398- self.expand_treestore(iter)
399- self.treeview.expand_row(path, False)
400+ self.remove_children(tree_iter)
401+ self.expand_treestore(tree_iter)
402+ self.treeview.expand_row(tree_path, False)
403
404 self.set_saved(False)
405- self.selected_node = self.get_painted_tree(iter)
406+ self.selected_node = self.get_painted_tree(tree_iter)
407 self.update_options_frame()
408
409 return
410@@ -1435,20 +1490,7 @@
411 if attr != "name":
412 return
413
414- iter = self.treestore.get_iter(path)
415- liststore = self.treestore.get_value(iter, 1)
416- active_tree = self.treestore.get_value(iter, 3)
417- new_name = active_tree.get_display_name()
418- self.treestore.set_value(iter, 0, new_name)
419-
420- # find the liststore iter corresponding to the painted choice
421- list_iter = liststore.get_iter_first()
422- while list_iter is not None:
423- liststore_tree = liststore.get_value(list_iter, 1)
424- if liststore_tree is active_tree:
425- liststore.set_value(list_iter, 0, new_name)
426- list_iter = liststore.iter_next(list_iter)
427-
428+ self.treeview.queue_draw()
429 self.treeview.queue_resize()
430
431 def get_painted_tree(self, iter_or_tree, lock_geometry_dim = True):
432@@ -1465,7 +1507,7 @@
433 if isinstance(iter_or_tree, tree.Tree):
434 active_tree = iter_or_tree
435 else:
436- active_tree = self.treestore.get_value(iter_or_tree, 3)
437+ active_tree = self.treestore.get_value(iter_or_tree, 1)
438
439 painted_tree = active_tree.get_mixed_data()
440
441@@ -1505,7 +1547,26 @@
442 return None
443
444 return iter
445+
446+ def get_treestore_path_from_node(self, node):
447+ """
448+ Look for the path for the given node.
449+ """
450
451+ def search(iter, node, indent=""):
452+ while iter:
453+ if self.treestore.get_value(iter, 0) is node:
454+ return iter
455+ else:
456+ child = search(self.treestore.iter_children(iter), node, indent + " ")
457+ if child: return child
458+
459+ iter = self.treestore.iter_next(iter)
460+ return iter
461+
462+ iter = search(self.treestore.get_iter_first(), node)
463+ return self.treestore.get_path(iter) if iter else None
464+
465 def set_geometry_dim_tree(self):
466 """
467 Find the iter into the treestore corresponding to the geometry dimension, and
468@@ -1567,8 +1628,8 @@
469 """
470
471 while iter is not None:
472- choice_or_tree = self.treestore.get_value(iter, 2)
473- active_tree = self.treestore.get_value(iter, 3)
474+ choice_or_tree = self.treestore.get_value(iter, 0)
475+ active_tree = self.treestore.get_value(iter, 1)
476 if not choice_or_tree.active or not active_tree.active:
477 return False
478 iter = self.treestore.iter_parent(iter)
479@@ -1629,7 +1690,7 @@
480 iter = self.treestore.get_iter_first()
481 if iter is None:
482 yield None
483- choice_or_tree = self.treestore.get_value(iter, 2)
484+ choice_or_tree = self.treestore.get_value(iter, 0)
485
486 if self.choice_or_tree_matches(text, choice_or_tree, isinstance(choice_or_tree, choice.Choice)):
487 yield iter
488
489=== modified file 'diamond/diamond/tree.py'
490--- diamond/diamond/tree.py 2011-07-25 13:41:47 +0000
491+++ diamond/diamond/tree.py 2011-07-26 16:14:06 +0000
492@@ -301,7 +301,7 @@
493 def unpickle(self, pick):
494 return pickle.loads(bz2.decompress(base64.b64decode(pick)))
495
496- def __str__(self):
497+ def print_str(self):
498 s = "name: %s at %s\n" % (self.name, hex(id(self)))
499 s = s + "schemaname: %s\n" % self.schemaname
500 s = s + "attrs: %s\n" % self.attrs
501@@ -538,6 +538,9 @@
502 return True
503
504 return (self.datatype is not None and self.datatype != "fixed") or self.attrs
505+
506+ def __str__(self):
507+ return self.get_display_name()
508
509 gobject.type_register(Tree)
510
511
512=== modified file 'diamond/gui/gui.glade'
513--- diamond/gui/gui.glade 2011-07-22 15:46:25 +0000
514+++ diamond/gui/gui.glade 2011-07-26 16:14:06 +0000
515@@ -132,6 +132,20 @@
516 <accelerator key="V" signal="activate" modifiers="GDK_CONTROL_MASK"/>
517 </widget>
518 </child>
519+ <child>
520+ <widget class="GtkMenuItem" id="menuitemGroup">
521+ <property name="visible">True</property>
522+ <property name="label" translatable="yes">Group</property>
523+ <signal name="activate" handler="on_group"/>
524+ </widget>
525+ </child>
526+ <child>
527+ <widget class="GtkMenuItem" id="menuitemUngroup">
528+ <property name="visible">False</property>
529+ <property name="label" translatable="yes">Ungroup</property>
530+ <signal name="activate" handler="on_ungroup"/>
531+ </widget>
532+ </child>
533 </widget>
534 </child>
535 </widget>
536@@ -488,7 +502,7 @@
537 <widget class="GtkMenu" id="popupmenu">
538 <property name="visible">True</property>
539 <child>
540- <widget class="GtkMenuItem" id="menuitemCopy">
541+ <widget class="GtkMenuItem" id="popupmenuitemCopy">
542 <property name="visible">True</property>
543 <property name="label" translatable="yes">Copy</property>
544 <property name="use_underline">True</property>
545@@ -496,7 +510,7 @@
546 </widget>
547 </child>
548 <child>
549- <widget class="GtkMenuItem" id="menuitemPaste">
550+ <widget class="GtkMenuItem" id="popupmenuitemPaste">
551 <property name="visible">True</property>
552 <property name="label" translatable="yes">Paste</property>
553 <property name="use_underline">True</property>
554@@ -504,12 +518,26 @@
555 </widget>
556 </child>
557 <child>
558- <widget class="GtkMenuItem" id="menuitemSlice">
559+ <widget class="GtkMenuItem" id="popupmenuitemSlice">
560 <property name="visible">True</property>
561 <property name="label" translatable="yes">Slice</property>
562 <property name="use_underline">True</property>
563 <signal name="activate" handler="on_slice"/>
564 </widget>
565 </child>
566+ <child>
567+ <widget class="GtkMenuItem" id="popupmenuitemGroup">
568+ <property name="visible">True</property>
569+ <property name="label" translatable="yes">Group</property>
570+ <signal name="activate" handler="on_group"/>
571+ </widget>
572+ </child>
573+ <child>
574+ <widget class="GtkMenuItem" id="popupmenuitemUngroup">
575+ <property name="visible">False</property>
576+ <property name="label" translatable="yes">Ungroup</property>
577+ <signal name="activate" handler="on_ungroup"/>
578+ </widget>
579+ </child>
580 </widget>
581 </glade-interface>

Subscribers

People subscribed via source and target branches