00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 import subprocess
00020 from xml.etree import ElementTree as ET
00021 from airbus_docgen.common.color import RgbColor
00022 from airbus_docgen.digraph.shape import SHAPE
00023 from airbus_docgen.digraph.arrow import ARROWHEAD
00024 from airbus_docgen.digraph.spline import SPLINE
00025 from airbus_docgen.digraph.style import STYLE
00026 from airbus_docgen.digraph.text import ALIGN
00027
00028 from airbus_docgen.common import html
00029
00030 def indent(elem, level=0):
00031
00032 i = "\n" + level*" "
00033 if len(elem):
00034 if not elem.text or not elem.text.strip():
00035 elem.text = i + " "
00036 if not elem.tail or not elem.tail.strip():
00037 elem.tail = i
00038 for elem in elem:
00039 indent(elem, level+1)
00040 if not elem.tail or not elem.tail.strip():
00041 elem.tail = i
00042 else:
00043 if level and (not elem.tail or not elem.tail.strip()):
00044 elem.tail = i
00045
00046 class TD(ET.Element):
00047
00048 ALIGN="ALIGN"
00049 BALIGN="BALIGN"
00050 BGCOLOR="BGCOLOR"
00051 BORDER="BORDER"
00052 CELLPADDING="CELLPADDING"
00053 CELLSPACING="CELLSPACING"
00054 COLOR="COLOR"
00055 COLSPAN="COLSPAN"
00056 FIXEDSIZE="FIXEDSIZE"
00057 GRADIENTANGLE="GRADIENTANGLE"
00058 HEIGHT="HEIGHT"
00059 HREF="HREF"
00060 ID="ID"
00061 PORT="PORT"
00062 ROWSPAN="ROWSPAN"
00063 SIDES="SIDES"
00064 STYLE="STYLE"
00065 TARGET="TARGET"
00066 TITLE="TITLE"
00067 TOOLTIP="TOOLTIP"
00068 VALIGN="VALIGN"
00069 WIDTH="WIDTH"
00070
00071 __ATTRIB_KEYS__ = [ALIGN,BALIGN,BGCOLOR,BORDER,CELLPADDING,CELLSPACING,
00072 COLOR,COLSPAN,FIXEDSIZE,GRADIENTANGLE,HEIGHT,HREF,
00073 ID,PORT,ROWSPAN,SIDES,STYLE,TARGET,TITLE,TOOLTIP,
00074 VALIGN, WIDTH]
00075
00076 def __init__(self):
00077 ET.Element.__init__(self, tag=html.Tables.td)
00078
00079 def setAttrib(self, key, value):
00080 if key in self.__ATTRIB_KEYS__:
00081 self.set(key, str(value).replace("\"", ""))
00082 else:
00083 raise Exception("Invalid key attribute from '%s' !"%str(key))
00084
00085 def setText(self, text):
00086 self.text = text
00087
00088 def __str__(self):
00089 return ET.tostring(self, encoding="us-ascii", method="xml")
00090
00091 class TR(ET.Element):
00092
00093 def __init__(self, td=None):
00094 ET.Element.__init__(self, tag=html.Tables.tr)
00095
00096 if td is not None:
00097 self.addTD(td)
00098
00099 def addTD(self, td):
00100 self.append(td)
00101
00102 def addTDs(self, tds):
00103 for td in tds:
00104 self.addTD(td)
00105
00106 def __str__(self):
00107 return ET.tostring(self, encoding="us-ascii", method="xml")
00108
00109 class TABLE(ET.Element):
00110
00111 ALIGN="ALIGN"
00112 BGCOLOR="BGCOLOR"
00113 BORDER="BORDER"
00114 CELLBORDER="CELLBORDER"
00115 CELLPADDING="CELLPADDING"
00116 CELLSPACING="CELLSPACING"
00117 COLOR="COLOR"
00118 COLUMNS="COLUMNS"
00119 FIXEDSIZE="FIXEDSIZE"
00120 GRADIENTANGLE="GRADIENTANGLE"
00121 HEIGHT="HEIGHT"
00122 HREF="HREF"
00123 ID="ID"
00124 PORT="PORT"
00125 ROWS="ROWS"
00126 SIDES="SIDES"
00127 STYLE="STYLE"
00128 TARGET="TARGET"
00129 TITLE="TITLE"
00130 TOOLTIP="TOOLTIP"
00131 VALIGN="VALIGN"
00132 WIDTH="WIDTH"
00133
00134 __ATTRIB_KEYS__ = [ALIGN, BGCOLOR, BORDER, CELLBORDER, CELLPADDING,
00135 CELLSPACING, COLOR, COLUMNS, FIXEDSIZE,
00136 GRADIENTANGLE, HEIGHT, HREF, ID, PORT, ROWS, SIDES,
00137 STYLE, TARGET, TITLE, TOOLTIP, VALIGN, WIDTH]
00138
00139 def __init__(self):
00140 ET.Element.__init__(self, tag=html.Tables.table)
00141
00142 def setAttrib(self, key, value):
00143 if key in self.__ATTRIB_KEYS__:
00144 self.set(key, str(value).replace("\"", ""))
00145 else:
00146 raise Exception("Invalid key attribute from '%s' !"%str(key))
00147
00148 def addTR(self, tr):
00149 self.append(tr)
00150
00151 def addTRs(self, tr_list):
00152 for tr in tr_list:
00153 self.addTR(tr)
00154
00155 def __str__(self):
00156 indent(self)
00157 return ET.tostring(self, encoding="us-ascii", method="xml")
00158
00159 class NODE:
00160
00161 MARGIN = "margin"
00162 FONTCOLOR = "fontcolor"
00163 FONTSIZE = "fontsize"
00164 WIDTH = "width"
00165 SHAPE = "shape"
00166 STYLE = "style"
00167 LABEL = "label"
00168 DIR = "dir"
00169 COLOR = 'color'
00170
00171 def __init__(self, node_name=""):
00172 self._node_name = NODE.formatNodeName(node_name)
00173 self._attribs = ""
00174
00175 @staticmethod
00176 def formatNodeName(name):
00177 return name.replace('.', '_').replace('-','_').replace('/','_')
00178
00179 def getName(self):
00180 return self._node_name
00181
00182 def setAttrib(self, key, value):
00183 self._attribs += ' %s=%s'%(key, str(value))
00184
00185 def setHtml(self, html):
00186 self._attribs += ' label=<%s>'%str(html)
00187
00188 def setLabel(self, label):
00189 self._attribs += ' label="%s"'%str(label)
00190
00191 def __str__(self):
00192 return "%s [%s];\n"%(self._node_name, self._attribs)
00193
00194 class Edge:
00195
00196 DIR = "dir"
00197
00198 def __init__(self, key=None, value=None):
00199 self._attrib = "["
00200
00201 if key is not None and value is not None:
00202 self.setAttrib(key, value)
00203
00204 def setAttrib(self, key, value):
00205 self._attrib += "%s=%s "%(key, str(value))
00206
00207 return self
00208
00209 def __str__(self):
00210 return "%s];\n"%self._attrib
00211
00212 class Digraph:
00213
00214 ROOT = 'root'
00215 DIGRAPH = "digraph"
00216 SUBGRAPH = "subgraph"
00217 STYLE = "style"
00218 COLOR = "color"
00219 RANKDIR = "rankdir"
00220 SPLINE = "splines"
00221 NODESEP = 'nodesep'
00222
00223 def __init__(self, graph_name, graph_type=DIGRAPH):
00224 self._graph_name = graph_name
00225 self._graph_type = graph_type
00226 self._attribs = ""
00227 self._node_attribs = ""
00228 self._root_node = ""
00229 self._nodes = ""
00230 self._connections = ""
00231 self._dot_src_dir = None
00232
00233 def getType(self):
00234 return self._graph_type
00235
00236 def getName(self):
00237 return self._graph_name
00238
00239 def setAttrib(self, key, value):
00240 self._attribs += '%s=%s;\n'%(key,str(value))
00241
00242 def setLabel(self, label):
00243 self._attribs += 'label="%s";\n'%label
00244
00245 def addNode(self, node):
00246 if isinstance(node, NODE):
00247 self._nodes += str(node)
00248 else:
00249 raise Exception("Bad class instance from NODE !")
00250
00251 def addRootNode(self,node):
00252 self._root_node = node.getName()
00253 self.addNode(node)
00254
00255 def getRootNode(self):
00256 return self._root_node
00257
00258 def addSubGraph(self, graph):
00259 if graph.getType() == self.SUBGRAPH:
00260 self._nodes += str(graph)
00261 else:
00262 raise Exception("Bad class instance from SubGraph !")
00263
00264 def _resolve_(self, obj):
00265
00266 obj_str = ""
00267
00268 if isinstance(obj, NODE) or isinstance(obj, Digraph):
00269 obj_str = obj.getName()
00270 elif isinstance(obj, dict):
00271 k = obj.keys()[0]
00272 v = obj.values()[0]
00273 obj_str = "%s:%s"%(str(k.getName()),v)
00274 else:
00275 obj_str = obj
00276
00277 return obj_str
00278
00279 def connect(self, node1, node2, edge_attrib=None):
00280
00281 if node1 is None or node2 is None:
00282 return
00283
00284 if edge_attrib is not None:
00285 self._connections += "%s -> %s %s"%(self._resolve_(node1),
00286 self._resolve_(node2),
00287 str(edge_attrib))
00288 else:
00289 self._connections +="%s -> %s;\n"%(self._resolve_(node1),
00290 self._resolve_(node2))
00291
00292 def connectRank(self, key, nodes=[], edge=None):
00293
00294 if nodes is None:
00295 return
00296
00297 if len(nodes) >= 2:
00298
00299 self._connections += "{rank=%s;"%key
00300
00301 begin = " "
00302 for i in range(1, len(nodes)):
00303 self._connections += "%s%s"%(begin,self._resolve_(nodes[i-1]))
00304 self._connections += " -> %s"%self._resolve_(nodes[i])
00305 begin = " -> "
00306
00307 self._connections += ";}\n"
00308
00309 def __str__(self):
00310
00311 if self._node_attribs != "":
00312 self._node_attribs = "node [%s]\n"%self._node_attribs
00313
00314 graph_str = "%s %s {\n%s%s%s%s}\n"%(
00315 self._graph_type,
00316 self._graph_name,
00317 self._attribs,
00318 self._node_attribs,
00319 self._nodes,
00320 self._connections)
00321
00322 return graph_str
00323
00324 def saveDot(self, output):
00325
00326 if '.dot' not in output:
00327 output+=".dot"
00328
00329 self._dot_src_dir = output
00330
00331 with open(self._dot_src_dir,'w') as f_dot:
00332 f_dot.write(self.__str__())
00333
00334
00335 def dotToPng(self, output, rm_dot=False):
00336
00337 if '.png' not in output:
00338 output+=".png"
00339
00340 if self._dot_src_dir is None:
00341 raise Exception("You must save dot before converting to png file !")
00342
00343 cmd=["dot", "-Tpng", self._dot_src_dir, "-o", output]
00344 subprocess.Popen(cmd)
00345
00346 def dotToPs(self, output, rm_dot=False):
00347
00348 if '.ps' not in output:
00349 output+=".ps"
00350
00351 if self._dot_src_dir is None:
00352 raise Exception("You must save dot before converting to ps file !")
00353
00354 cmd=["dot", "-Tps", self._dot_src_dir, "-o", output]
00355 subprocess.Popen(cmd)
00356
00357
00358 def digraph_test():
00359
00360 digraph = Digraph("unittest")
00361 digraph.setAttrib('rankdir','LR')
00362
00363 head = NODE("node")
00364 head.setAttrib(NODE.SHAPE, SHAPE.Plaintext)
00365 digraph.addNode(head)
00366
00367 node1 = NODE("node_test")
00368 node1.setAttrib(NODE.SHAPE, SHAPE.Plaintext)
00369 node1.setAttrib(NODE.FONTCOLOR, RgbColor.Red)
00370
00371 table = TABLE()
00372 table.setAttrib(TABLE.BORDER, 0)
00373 table.setAttrib(TABLE.CELLBORDER, 1)
00374 table.setAttrib(TABLE.CELLSPACING, 0)
00375
00376 tr = TR()
00377
00378 td = TD()
00379 td.setAttrib(TD.PORT, "input")
00380 td.setText("test")
00381
00382 td2 = TD()
00383 td2.setAttrib(TD.PORT, "output")
00384 td2.setAttrib(TD.COLOR, RgbColor.Blue)
00385 td2.setText("test2")
00386
00387 tr.addTD(td)
00388 tr.addTD(td2)
00389
00390 table.addTR(tr)
00391
00392 node1.setHtml(table)
00393
00394 node2 = NODE("node_test_2")
00395
00396 table = TABLE()
00397 table.setAttrib(TABLE.BORDER, 0)
00398 table.setAttrib(TABLE.CELLBORDER, 10)
00399
00400 tr = TR()
00401 td = TD()
00402 td.setAttrib(TD.PORT, "input")
00403 td.setText("test")
00404 td2 = TD()
00405 td2.setAttrib(TD.PORT, "output")
00406 td2.setAttrib(TD.COLOR, RgbColor.Red)
00407 td2.setText("test3")
00408
00409 tr.addTD(td)
00410 tr.addTD(td2)
00411
00412 table.addTR(tr)
00413
00414 node2.setHtml(table)
00415
00416 node3 = NODE("test11")
00417 node3.setLabel("Node for testing none html label !")
00418 node3.setAttrib(NODE.SHAPE, SHAPE.Ellipse)
00419
00420 digraph.addNode(node1)
00421 digraph.addNode(node2)
00422 digraph.addNode(node3)
00423
00424
00425
00426
00427 digraph.connectRank("same", [node1, node2, node3])
00428
00429 print str(digraph)
00430
00431 digraph.saveDot("/tmp/digraph_test.dot")
00432 digraph.dotToPng("/tmp/digraph_test.png")
00433
00434 def getSubGraph(name):
00435
00436 subgraph = Digraph(name, Digraph.SUBGRAPH)
00437 subgraph.setLabel(name)
00438 subgraph.setAttrib(Digraph.STYLE, "filled")
00439 subgraph.setAttrib(Digraph.COLOR, RgbColor.Cyan)
00440
00441 node1 = NODE("node1_%s"%name)
00442 node1.setAttrib(NODE.SHAPE, SHAPE.Diamond)
00443 subgraph.addNode(node1)
00444
00445 node2 = NODE("node2_%s"%name)
00446 node2.setAttrib(NODE.SHAPE, SHAPE.House)
00447 subgraph.addNode(node2)
00448
00449 subgraph.connect(node1, node2)
00450
00451 return subgraph
00452
00453 if __name__ == '__main__':
00454
00455 digraph_test()
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478