Package pyffi :: Package utils :: Module graph
[hide private]
[frames] | no frames]

Source Code for Module pyffi.utils.graph

  1  """Base classes for organizing data (for instance to visualize data 
  2  with Qt, or to run hierarchical checks) in a global graph, and a 
  3  detail tree at each node of the global graph. 
  4   
  5  The classes defined here assume that data can be organized in two 
  6  stages: a global level which only shows 'top-level' objects 
  7  (i.e. large file blocks, chunks, and so on) as nodes and links between 
  8  the nodes via directed arcs, and a detail level which shows the 
  9  details of a top-level object, that is, the actual data they 
 10  contain. 
 11   
 12  :class:`DetailNode` implements the detail side of things. The 
 13  :class:`GlobalNode` class implements the global level, which does not show 
 14  any actual data, but only structure. 
 15   
 16  The global level forms a directed graph where the nodes are data 
 17  blocks and directed edges represent links from one block to 
 18  another. 
 19   
 20  This directed graph is assumed to have a spanning acyclic directed 
 21  subgraph, that is, a subgraph which contains all nodes of the original 
 22  graph, and which contains no cycles. This graph constitutes of those 
 23  edges which have the default edge type. 
 24   
 25  The :class:`pyffi.object_models.Data` class is the root node of 
 26  the graph. Recursing over all edges of default type of this node will 
 27  visit each node (possibly more than once) in a hierarchical order. 
 28   
 29  The base classes are roughly based on the TreeItem example in the Qt docs: 
 30  http://doc.trolltech.com/4.4/itemviews-simpletreemodel.html 
 31  """ 
 32   
 33  # -------------------------------------------------------------------------- 
 34  # ***** BEGIN LICENSE BLOCK ***** 
 35  # 
 36  # Copyright (c) 2007-2011, Python File Format Interface 
 37  # All rights reserved. 
 38  # 
 39  # Redistribution and use in source and binary forms, with or without 
 40  # modification, are permitted provided that the following conditions 
 41  # are met: 
 42  # 
 43  #    * Redistributions of source code must retain the above copyright 
 44  #      notice, this list of conditions and the following disclaimer. 
 45  # 
 46  #    * Redistributions in binary form must reproduce the above 
 47  #      copyright notice, this list of conditions and the following 
 48  #      disclaimer in the documentation and/or other materials provided 
 49  #      with the distribution. 
 50  # 
 51  #    * Neither the name of the Python File Format Interface 
 52  #      project nor the names of its contributors may be used to endorse 
 53  #      or promote products derived from this software without specific 
 54  #      prior written permission. 
 55  # 
 56  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 57  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 58  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 59  # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 60  # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 61  # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 62  # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 63  # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 64  # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 65  # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
 66  # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 67  # POSSIBILITY OF SUCH DAMAGE. 
 68  # 
 69  # ***** END LICENSE BLOCK ***** 
 70  # -------------------------------------------------------------------------- 
 71   
 72  from itertools import repeat 
 73  from operator import itemgetter 
 74   
75 -class EdgeType(tuple):
76 """Represents all possible edge types. By default, there are four 77 types: any edge can be part of the acyclic graph or not, and can 78 be active or not. 79 80 The default edge type is active and acylic. 81 """ 82
83 - def __new__(cls, active=True, acyclic=True):
84 return tuple.__new__(cls, (active, acyclic))
85 86 active = property(itemgetter(0)) 87 acyclic = property(itemgetter(1))
88
89 -class EdgeFilter(tuple):
90 """A simple filter for edges. The default filter only checks the edge's 91 active and acyclic attributes, and accepts them if both are ``True``. 92 """
93 - def __new__(cls, active_filter=True, acyclic_filter=True):
94 return tuple.__new__(cls, (active_filter, acyclic_filter))
95 96 active_filter = property(itemgetter(0)) 97 acyclic_filter = property(itemgetter(1)) 98
99 - def accept(self, edge_type):
100 if not(self.active_filter is None): 101 if edge_type.active != self.active_filter: 102 return False 103 if not(self.acyclic_filter is None): 104 if edge_type.acyclic != self.acyclic_filter: 105 return False
106
107 -class DetailNode(object):
108 """A node of the detail tree which can have children. 109 110 If the data must be editable, also derive the class from one of 111 the delegate classes defined in :mod:`pyffi.object_models.editable`, 112 and make sure that the get_value and set_value functions are 113 implemented. 114 """ 115
116 - def get_detail_child_nodes(self, edge_filter=EdgeFilter()):
117 """Generator which yields all children of this item in the 118 detail view (by default, all acyclic and active ones). 119 120 Override this method if the node has children. 121 122 :param edge_filter: The edge type to include. 123 :type edge_filter: :class:`EdgeFilter` or ``type(None)`` 124 :return: Generator for detail tree child nodes. 125 :rtype: generator yielding :class:`DetailNode`\ s 126 """ 127 return (dummy for dummy in ())
128
129 - def get_detail_child_names(self, edge_filter=EdgeFilter()):
130 """Generator which yields all child names of this item in the detail 131 view. 132 133 Override this method if the node has children. 134 135 :return: Generator for detail tree child names. 136 :rtype: generator yielding ``str``\ s 137 """ 138 return (dummy for dummy in ())
139
140 - def get_detail_child_edge_types(self, edge_filter=EdgeFilter()):
141 """Generator which yields all edge types of this item in the 142 detail view, one edge type for each child. 143 144 Override this method if you rely on more than one edge type. 145 """ 146 return repeat(EdgeType())
147
148 - def get_detail_display(self):
149 """Object used to display the instance in the detail view. 150 151 Override this method if the node has data to display in the detail view. 152 153 :return: A string that can be used to display the instance. 154 :rtype: ``str`` 155 """ 156 return ""
157
158 - def get_detail_iterator(self, edge_filter=EdgeFilter()):
159 """Iterate over self, all children, all grandchildren, and so 160 on (only given edge type is followed). Do not override. 161 """ 162 yield self 163 for child in self.get_detail_child_nodes(edge_filter=edge_filter): 164 for branch in child.get_detail_iterator(edge_filter=edge_filter): 165 yield branch
166
167 - def replace_global_node(self, oldnode, newnode, edge_filter=EdgeFilter()):
168 """Replace a particular branch in the graph.""" 169 raise NotImplementedError
170
171 -class GlobalNode(DetailNode):
172 """A node of the global graph.""" 173
174 - def get_global_display(self):
175 """Very short summary of the data of this global branch for display 176 purposes. Override this method. 177 178 :return: A string. 179 """ 180 return ""
181 # possible implementation: 182 #return self.name if hasattr(self, "name") else "" 183
184 - def get_global_child_nodes(self, edge_filter=EdgeFilter()):
185 """Generator which yields all children of this item in the 186 global view, of given edge type (default is edges of type 0). 187 188 Override this method. 189 190 :return: Generator for global node children. 191 """ 192 return (dummy for dummy in ())
193
194 - def get_global_child_edge_types(self, edge_filter=EdgeFilter()):
195 """Generator which yields all edge types of this item in the 196 global view, one edge type for each child. 197 198 Override this method if you rely on non-default edge types. 199 """ 200 return repeat(EdgeType())
201
202 - def get_global_iterator(self, edge_filter=EdgeFilter()):
203 """Iterate over self, all children, all grandchildren, and so 204 on (only given edge_filter is followed). Do not override. 205 """ 206 yield self 207 for child in self.get_global_child_nodes(edge_filter=edge_filter): 208 for branch in child.get_global_iterator(edge_filter=edge_filter): 209 yield branch
210