37
38
('button focused', 'white', 'dark blue'),
38
39
('highlight', 'black', 'dark cyan'),
39
40
('highlight focused', 'white', 'dark blue'),
41
('fail', 'light red', 'dark cyan'),
42
('pass', 'light green', 'dark cyan'),
43
('result', 'light gray', 'dark cyan'),
45
PALETTE_MEMBERS = set(color_spec[0]
46
for color_spec in PALETTE)
369
375
Create a tree node and all its children
371
widget = TreeNodeWidget(name, parent)
377
widget = SelectableTreeNodeWidget(name, parent)
372
378
urwid.signals.connect_signal(widget, 'change',
373
379
widget.changed_cb, self.walker)
375
381
if isinstance(data, dict):
376
items = sorted(data.iteritems(), key=lambda item: item[0])
382
items = sorted(data.iteritems(), key=itemgetter(0))
377
383
for children_name, children_data in items:
378
384
child_widget = self.create_tree(children_name, children_data, widget)
379
385
widget.append(child_widget)
422
429
self.walker.append(buttons_box)
432
class ReportDialog(ChoiceDialog):
434
Display test results dialog
436
footer = urwid.AttrMap(urwid.Columns((urwid.Text('Arrow keys/Page Up/Page Down: Move'),
438
urwid.Text('+/-/Enter/Space: Expand/Collapse'))),
441
def __init__(self, text, results):
442
Dialog.__init__(self, text)
443
self.results = results
446
def _get_tree_node(self, node):
448
Get tree node even if a column is wrapping it
450
if issubclass(type(node), TreeNodeWidget):
452
elif issubclass(type(node), urwid.Columns):
453
for widget in child.widget_list:
454
if issubclass(type(widget), TreeNodeWidget):
459
def expand_all_clicked_cb(self, button):
461
Expand all elements in the tree to see results
463
for tree_node in [self._get_tree_node(node)
464
for node in self.root_nodes]:
465
tree_node.expand(expand_all=True)
468
def collapse_all_clicked_cb(self, button):
470
Collapse all elements in the tree to see results
472
for tree_node in [self._get_tree_node(node)
473
for node in self.root_nodes]:
474
tree_node.collapse(collapse_all=True)
477
def next_button_clicked_cb(self, button):
479
Set direction, response and exit
481
self.direction = NEXT
482
raise urwid.ExitMainLoop
485
def previous_button_clicked_cb(self, button):
487
Set direction, response and exit
489
self.direction = PREV
490
raise urwid.ExitMainLoop
493
def create_tree(self, name, data, parent=None):
495
Create a tree node and all its children
497
widget = TreeNodeWidget(name, parent)
498
urwid.signals.connect_signal(widget, 'change',
499
widget.changed_cb, self.walker)
501
items = sorted(data.iteritems(), key=itemgetter(0))
502
for child_name, child_data in items:
503
is_suite = all(issubclass(type(value), dict)
504
for value in child_data.itervalues())
507
child_widget = self.create_tree(child_name,
511
result=child_data['status']
513
# Use color specification for result
514
# if found or default one
516
if result in self.PALETTE_MEMBERS
519
child_widget = urwid.Columns(
520
(TreeNodeWidget(child_name, widget),
521
urwid.AttrMap(urwid.Text((attr, result)),
522
'highlight', 'highlight focused')))
523
widget.append(child_widget)
530
Display dialog text, options tree and buttons
536
items = sorted(self.results.iteritems(),
538
for name, data in items:
539
widget = self.create_tree(name, data)
540
self.walker.append(widget)
542
self.root_nodes = [node for node in self.walker]
545
labels = ((_('Expand All'), self.expand_all_clicked_cb),
546
(_('Collapse All'), self.collapse_all_clicked_cb),
547
(_('Previous'), self.previous_button_clicked_cb),
548
(_('Next'), self.next_button_clicked_cb))
549
buttons_box = self.create_buttons(labels)
550
self.walker.append(urwid.Divider())
551
self.walker.append(buttons_box)
425
554
class TreeNodeWidget(urwid.WidgetWrap):
427
Implementation of a node in a tree that can be selected/deselected
556
Implementation of a node in a tree that can be expanded/unexpanded
429
558
signals = ['change']
437
566
self.expanded = False
439
# Use a checkbox as internal representation of the widget
440
self.checkbox = urwid.CheckBox(self._get_label())
441
w = urwid.AttrMap(self.checkbox, 'highlight', 'highlight focused')
568
w = self._get_widget()
442
569
super(TreeNodeWidget, self).__init__(w)
572
def _get_widget(self):
574
Create widget that is wrapped by this class
576
self.widget = urwid.Text(self._get_label())
577
w = urwid.AttrMap(self.widget, 'highlight', 'highlight focused')
581
def _update_label(self):
585
self.widget.set_text(self._get_label())
588
def _get_node(self, child):
590
Get TreeNode directly without traversing Columns
592
if issubclass(type(child), TreeNodeWidget):
594
elif issubclass(type(child), urwid.Columns):
595
for widget in child.widget_list:
596
if issubclass(type(widget), TreeNodeWidget):
445
601
def __iter__(self):
447
603
Iterate over children nodes
449
return iter(self.children)
605
return iter([self._get_node(child)
606
for child in self.children])
452
609
def __len__(self):
482
Get state from checkbox widget
484
return self.checkbox.get_state()
488
def state(self, value):
490
Set state to checkbox widget
492
self.checkbox.set_state(value)
495
def set_ancestors_state(self, new_state):
497
Set the state of all ancestors consistently
499
# If child is set, then all ancestors must be set
503
parent.state = new_state
504
parent = parent.parent
505
# If child is not set, then all ancestors mustn't be set
506
# unless another child of the ancestor is set
511
for child in parent)):
513
parent.state = new_state
514
parent = parent.parent
517
def set_children_state(self, new_state):
519
Set the state of all children recursively
521
self.state = new_state
523
child.set_children_state(new_state)
526
636
def keypress(self, size, key):
528
Use key events to select checkbox and expand tree hierarchy
638
Use key events to expand/collapse tree hierarchy
532
new_state = not self.state
533
self.state = new_state
534
self.set_children_state(new_state)
535
self.set_ancestors_state(new_state)
538
if key in ('+', 'enter') and self.expanded == False:
641
if (key in ('+', 'enter', ' ')
642
and self.expanded == False):
539
643
urwid.signals.emit_signal(self, 'change')
541
elif key in ('-', 'enter') and self.expanded == True:
645
elif (key in ('-', 'enter', ' ')
646
and self.expanded == True):
542
647
urwid.signals.emit_signal(self, 'change')
610
725
del_end_position = (del_start_position +
612
727
del walker[del_start_position:del_end_position]
613
self._collapse_children()
728
#self._collapse_children()
614
729
self.expanded = False
616
731
insert_position = position + 1
618
733
# Append widgets to the list
619
walker[insert_position:insert_position] = self.children
734
subtree = list(self._get_subtree())
735
walker[insert_position:insert_position] = subtree
620
736
self.expanded = True
622
738
self._update_label()
741
def _get_subtree(self):
743
Return subtree with expanded children
745
for child in self.children:
748
child_node = self._get_node(child)
749
if child_node.expanded:
750
for descendant in child._get_subtree():
754
class SelectableTreeNodeWidget(TreeNodeWidget):
756
Implementation of a node in a tree that can be selected/deselected
758
def __init__(self, name, parent=None):
759
super(SelectableTreeNodeWidget, self).__init__(name, parent)
762
def _get_widget(self):
764
Create widget that is wrapped by this class
766
# Use a checkbox to preserve widget selection stat
767
self.widget = urwid.CheckBox(self._get_label())
768
w = urwid.AttrMap(self.widget, 'highlight', 'highlight focused')
772
def _update_label(self):
776
self.widget.set_label(self._get_label())
782
Get state from checkbox widget
784
return self.widget.get_state()
788
def state(self, value):
790
Set state to checkbox widget
792
self.widget.set_state(value)
795
def set_ancestors_state(self, new_state):
797
Set the state of all ancestors consistently
799
# If child is set, then all ancestors must be set
803
parent.state = new_state
804
parent = parent.parent
805
# If child is not set, then all ancestors mustn't be set
806
# unless another child of the ancestor is set
811
for child in parent)):
813
parent.state = new_state
814
parent = parent.parent
817
def set_children_state(self, new_state):
819
Set the state of all children recursively
821
self.state = new_state
823
child.set_children_state(new_state)
826
def keypress(self, size, key):
828
Use key events to select checkbox and expand tree hierarchy
832
new_state = not self.state
833
self.state = new_state
834
self.set_children_state(new_state)
835
self.set_ancestors_state(new_state)
838
return super(SelectableTreeNodeWidget, self).keypress(size, key)
841
def mouse_event(self, size, event, button, col, row, focus):
843
Use mouse events to select checkbox and expand tree hierarchy
847
new_state = not self.state
848
self.state = new_state
849
self.set_children_state(new_state)
850
self.set_ancestors_state(new_state)
853
return (super(SelectableTreeNodeWidget, self)
854
.mouse_event(size, event, button, col, row, focus))
625
857
class ProgressDialog(Dialog):
627
859
Show progress through a bar