diff options
author | Jan Pokorný <jpokorny@redhat.com> | 2013-05-13 23:06:56 +0200 |
---|---|---|
committer | Jan Pokorný <jpokorny@redhat.com> | 2013-05-13 23:06:56 +0200 |
commit | b143f3179a87cbdda4c47f149eceb96bd3db9942 (patch) | |
tree | 93d3a12ff2bd97f8d7931275658e3b04f45a51d3 | |
parent | d133ee25c72e4da3e32d1e7d6858a82bd764eadf (diff) | |
download | cluster-overview-b143f3179a87cbdda4c47f149eceb96bd3db9942.tar.gz cluster-overview-b143f3179a87cbdda4c47f149eceb96bd3db9942.tar.xz cluster-overview-b143f3179a87cbdda4c47f149eceb96bd3db9942.zip |
Implement graph elements filter in UI
Signed-off-by: Jan Pokorný <jpokorny@redhat.com>
-rw-r--r-- | lib.py | 157 | ||||
-rwxr-xr-x | overview.py | 4 |
2 files changed, 149 insertions, 12 deletions
@@ -6,7 +6,7 @@ # (to view a copy, visit http://creativecommons.org/licenses/by-sa/3.0/) """Elements library incl. visual aspects""" -from sys import path +#from sys import path from os.path import expanduser, extsep from pydot import Dot, Edge, Node, Subgraph @@ -21,9 +21,25 @@ BLACKLIST = [] # Customization via meta level # -def bl_test(x): - return \ - not set((x.__class__,) + x.__class__.__bases__).intersection(BLACKLIST) +# obfuscation contest in recursively yielding base classes up to given set +bases = lambda x: (lambda f_, *xs_: f_(f_, *xs_)) \ + (lambda f, x=[], *xs: + [x] + f(f, *x.__bases__) + f(f, *xs) + if x not in ([], LibSubgraph, LibNode, LibEdge) + else [], + x) +bl_test = lambda ix: not set(bases(ix.__class__)).intersection(BLACKLIST) + + +def bl_map_nodes_edges(nodes, edges, prev_nnames=None): + nnames = prev_nnames if prev_nnames is not None else set() + for n in nodes: + n.get_attributes()['style'] = 'invis' + nnames.add(n.get_name()) + for e in edges: + if not bl_test(e) \ + or e.get_source() in nnames or e.get_destination() in nnames: + e.get_attributes()['style'] = 'invis' class LibMeta(type): @@ -35,10 +51,24 @@ class LibMeta(type): subgraphs = kwargs.pop('_subgraphs', ()) nodes = kwargs.pop('_nodes', ()) edges = kwargs.pop('_edges', ()) + + if not hasattr(self, 'nnames'): + self.nnames = set() + nnames = self.nnames + map(lambda x: nnames.update(getattr(x, 'nnames')), + tuple(subgraphs) + tuple(nodes) + tuple(edges)) + old_init(self, *args, **kwargs) - for s in filter(bl_test, subgraphs): s and self.add_subgraph(s) - for n in filter(bl_test, nodes): n and self.add_node(n) - for e in filter(bl_test, edges): e and self.add_edge(e) + + bl_map_nodes_edges(filter(lambda x: not bl_test(x), nodes), + edges, nnames) + for n in nodes: + self.add_node(n) + for e in edges: + self.add_edge(e) + + for s in filter(bl_test, subgraphs): + s and self.add_subgraph(s) cls.__init__ = new_init @@ -47,10 +77,14 @@ class LibDot(Dot): def __init__(self, *args, **kwargs): kwargs.setdefault('graph_type', 'digraph') super(LibDot, self).__init__(*args, **kwargs) + self.set_suppress_disconnected(True) class LibSubgraph(Subgraph): __metaclass__ = LibMeta + def __init__(self, *args, **kwargs): + super(LibSubgraph, self).__init__(*args, **kwargs) + #self.set_suppress_disconnected(True) class LibNode(Node): @@ -248,7 +282,6 @@ class DelegateCIM(Delegate, CIM): # main-helpers # - def export(fnc): __all__.append(fnc.__name__) return fnc @@ -272,8 +305,112 @@ def xdot_graph(*args, **kwargs): #import xdot print 'missing xdot; use "pip install xdot" or equivalent' raise - window = xdot.DotWindow() - window.set_dotcode(gen_graph(*args, **kwargs).to_string()) + + class LibDotWindow(xdot.DotWindow): + # heavily inspired from http://zetcode.com/gui/pygtk/menus/ + def on_change_view(self, widget): + label = widget.get_label() + bl = self._kwargs.setdefault('blacklist', []) + change = False + if widget.active and globals()[label] in bl: + bl.remove(globals()[label]) + change = True + elif not widget.active and label not in bl: + bl.append(globals()[label]) + change = True + if change: + self.set_dotcode( + gen_graph(*self._args, **self._kwargs).to_string()) + + def on_clean_all(self, widget): + for item in widget.get_parent().get_children(): + if not isinstance(item, gtk.CheckMenuItem): + continue + item.set_active(False) + item.set_active(True) + item.activate() + + def on_set_all(self, widget): + for item in widget.get_parent().get_children(): + if not isinstance(item, gtk.CheckMenuItem): + continue + item.set_active(True) + item.set_active(False) + item.activate() + + def __init__(self, *args, **kwargs): + self._args = args + self._kwargs = kwargs + super(LibDotWindow, self).__init__() + self.set_dotcode(gen_graph(*args, **kwargs).to_string()) + + mb = gtk.MenuBar() + + filemenu = gtk.Menu() + filem = gtk.MenuItem("File") + filem.set_submenu(filemenu) + + edgemenu = gtk.Menu() + edge = gtk.MenuItem("Edge") + edge.set_submenu(edgemenu) + edgemenuitem = gtk.MenuItem("Clean all") + edgemenuitem.connect("activate", self.on_clean_all) + edgemenu.append(edgemenuitem) + edgemenuitem = gtk.MenuItem("Set all") + edgemenuitem.connect("activate", self.on_set_all) + edgemenu.append(edgemenuitem) + edgemenu.append(gtk.SeparatorMenuItem()) + + nodemenu = gtk.Menu() + node = gtk.MenuItem("Node") + node.set_submenu(nodemenu) + nodemenuitem = gtk.MenuItem("Clean all") + nodemenuitem.connect("activate", self.on_clean_all) + nodemenu.append(nodemenuitem) + nodemenuitem = gtk.MenuItem("Set all") + nodemenuitem.connect("activate", self.on_set_all) + nodemenu.append(nodemenuitem) + nodemenu.append(gtk.SeparatorMenuItem()) + + for i in __all__: + try: + i = globals()[i] + if issubclass(i, LibEdge): + if i is LibEdge: + continue + imenuitem = gtk.CheckMenuItem("%s" % i.__name__) + imenuitem.set_active(True) + imenuitem.connect("activate", self.on_change_view) + edgemenu.append(imenuitem) + elif issubclass(i, LibNode): + if i is LibNode: + continue + imenuitem = gtk.CheckMenuItem("%s" % i.__name__) + imenuitem.set_active(True) + imenuitem.connect("activate", self.on_change_view) + nodemenu.append(imenuitem) + except: + pass + + exit = gtk.MenuItem("Exit") + exit.connect("activate", gtk.main_quit) + filemenu.append(exit) + + mb.append(filem) + mb.append(edge) + mb.append(node) + + #vbox = gtk.VBox(False, 2) + vbox = self.get_children()[0] + vbox.pack_start(mb, False, False, 0) + vbox.reorder_child(mb, 0) + #vbox.pack_start(gtk.Label(), True, False, 0) + #vbox.pack_start(self.statusbar, False, False, 0) + + self.connect("destroy", gtk.main_quit) + self.show_all() + + window = LibDotWindow(*args, **kwargs) window.connect('destroy', gtk.main_quit) gtk.main() diff --git a/overview.py b/overview.py index ae5ddc7..838854a 100755 --- a/overview.py +++ b/overview.py @@ -22,8 +22,8 @@ from lib import * FONT = 'Inconsolata' FONTDEF = map(lambda switch: '-' + switch + 'fontname=' + FONT, "GNE") -BLACKLIST = () -#BLACKLIST = (Daemon,) +BLACKLIST = [] +#BLACKLIST = [Daemon] OUTPUT = splitext(__file__)[0] |