fixing renderText script
This commit is contained in:
@@ -0,0 +1,438 @@
|
||||
# coding: latin-1
|
||||
# Copyright (c) 2009,2010 Dirk Baechle.
|
||||
# www: https://bitbucket.org/dirkbaechle/dottoxml
|
||||
# mail: dl9obn AT darc.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation; either version 2 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
"""
|
||||
Helper classes and functions for the dottoxml.py tool
|
||||
"""
|
||||
|
||||
import re
|
||||
import X11Colors
|
||||
|
||||
r_label = re.compile(r'label\s*=\s*"\s*\{[^\}]*\}\s*"\s*')
|
||||
r_labelstart = re.compile(r'label\s*=\s*"\s*\{')
|
||||
r_labelclose = re.compile(r'\}\s*"')
|
||||
|
||||
# Default output encoding for the ASCII output formats GML and GDF
|
||||
latinenc = "latin-1"
|
||||
|
||||
def compileAttributes(attribs):
|
||||
""" return the list of attributes as a DOT text string """
|
||||
atxt = ""
|
||||
first = True
|
||||
for key, value in attribs.iteritems():
|
||||
if not first:
|
||||
atxt += ", %s=\"%s\"" % (key, value)
|
||||
else:
|
||||
atxt += "%s=\"%s\"" % (key, value)
|
||||
first = False
|
||||
|
||||
return "[%s]" % atxt
|
||||
|
||||
def parseAttributes(attribs):
|
||||
""" parse the attribute list and return a key/value dict for it """
|
||||
adict = {}
|
||||
tlist = []
|
||||
lmode = False
|
||||
ltext = ''
|
||||
# First pass: split entries by ,
|
||||
for a in attribs.split(','):
|
||||
if r_label.findall(a):
|
||||
tlist.append(a)
|
||||
elif r_labelstart.findall(a):
|
||||
ltext = a
|
||||
lmode = True
|
||||
else:
|
||||
if lmode:
|
||||
ltext += ",%s" % a
|
||||
if r_labelclose.findall(a):
|
||||
lmode = False
|
||||
tlist.append(ltext)
|
||||
else:
|
||||
tlist.append(a)
|
||||
|
||||
# Second pass: split keys from values by =
|
||||
for t in tlist:
|
||||
apos = t.find('=')
|
||||
if apos > 0:
|
||||
adict[t[:apos].strip()] = t[apos+1:].strip().strip('"')
|
||||
|
||||
return adict
|
||||
|
||||
def getLabelAttributes(label):
|
||||
""" return the sections of the label attributes in a list structure """
|
||||
sections = []
|
||||
slist = label.split('|')
|
||||
for s in slist:
|
||||
mlist = []
|
||||
s = s.replace('\\r','\\l')
|
||||
s = s.replace('\\n','\\l')
|
||||
alist = s.split('\\l')
|
||||
for a in alist:
|
||||
a = a.strip()
|
||||
if a != "":
|
||||
mlist.append(a)
|
||||
sections.append(mlist)
|
||||
return sections
|
||||
|
||||
def colorNameToRgb(fcol, defaultcol):
|
||||
""" convert the color name fcol to an RGB string, if required """
|
||||
if not fcol.startswith('#'):
|
||||
return X11Colors.color_map.get(fcol, defaultcol)
|
||||
else:
|
||||
return fcol
|
||||
|
||||
def getColorAttribute(attribs, key, defaultcol, conf):
|
||||
""" extract the color for the attribute key and convert it
|
||||
to RGB format if required
|
||||
"""
|
||||
if conf.Colors:
|
||||
if attribs.has_key(key):
|
||||
return colorNameToRgb(attribs[key], defaultcol)
|
||||
return defaultcol
|
||||
|
||||
def escapeNewlines(label):
|
||||
""" convert the newline escape sequences in the given label """
|
||||
l = label.replace('\\n','\n')
|
||||
l = l.replace('\\l','\n')
|
||||
l = l.replace('\\r','\n')
|
||||
return l
|
||||
|
||||
class Node:
|
||||
""" a single node in the graph """
|
||||
def __init__(self):
|
||||
self.label = ""
|
||||
self.id = 0
|
||||
self.attribs = {}
|
||||
self.referenced = False
|
||||
self.sections = []
|
||||
|
||||
def initFromString(self, line):
|
||||
""" extract node info from the given text line """
|
||||
spos = line.find('[')
|
||||
atts = ""
|
||||
if spos >= 0:
|
||||
atts = line[spos+1:]
|
||||
line = line[:spos].strip()
|
||||
# Process label
|
||||
self.label = line.strip('"')
|
||||
# Process attributes
|
||||
if len(atts):
|
||||
spos = atts.rfind(']')
|
||||
if spos > 0:
|
||||
atts = atts[:spos]
|
||||
self.attribs = parseAttributes(atts)
|
||||
# Process sections
|
||||
if self.attribs.has_key("label"):
|
||||
tlabel = self.attribs["label"]
|
||||
if (tlabel != "" and
|
||||
tlabel.startswith('{') and
|
||||
tlabel.endswith('}')):
|
||||
tlabel = tlabel[1:-1]
|
||||
self.sections = getLabelAttributes(tlabel)
|
||||
|
||||
def getLabel(self, conf, multiline=False):
|
||||
""" return the label of the node """
|
||||
if conf.NodeLabels:
|
||||
if self.attribs.has_key('label'):
|
||||
if len(self.sections) > 0:
|
||||
if multiline:
|
||||
return '\n'.join(self.sections[0])
|
||||
else:
|
||||
return ','.join(self.sections[0])
|
||||
else:
|
||||
return self.attribs['label']
|
||||
else:
|
||||
return self.label
|
||||
else:
|
||||
return ""
|
||||
|
||||
def getLabelWidth(self, conf, multiline=False):
|
||||
""" return the maximum width label of the node label"""
|
||||
if conf.NodeLabels:
|
||||
if self.attribs.has_key('label'):
|
||||
if len(self.sections) > 0:
|
||||
if multiline:
|
||||
# Find maximum label width
|
||||
width = 1
|
||||
for s in self.sections[0]:
|
||||
if len(s) > width:
|
||||
width = len(s)
|
||||
for s in self.sections[1]:
|
||||
if len(s) > width:
|
||||
width = len(s)
|
||||
for s in self.sections[2]:
|
||||
if len(s) > width:
|
||||
width = len(s)
|
||||
return width
|
||||
else:
|
||||
return len(','.join(self.sections[0]))
|
||||
else:
|
||||
return len(self.attribs['label'])
|
||||
else:
|
||||
return len(self.label)
|
||||
else:
|
||||
return 0
|
||||
|
||||
def complementAttributes(self, node):
|
||||
""" from node copy all new attributes, that do not exist in self """
|
||||
for a in node.attribs:
|
||||
if not self.attribs.has_key(a):
|
||||
self.attribs[a] = node.attribs[a]
|
||||
|
||||
def exportDot(self, o, conf):
|
||||
""" write the node in DOT format to the given file """
|
||||
if len(self.attribs) > 0:
|
||||
o.write("\"%s\" %s;\n" % (self.label, compileAttributes(self.attribs)))
|
||||
else:
|
||||
o.write("\"%s\";\n" % (self.label))
|
||||
|
||||
def exportGDF(self, o, conf):
|
||||
""" write the node in GDF format to the given file """
|
||||
tlabel = self.getLabel(conf).encode(latinenc, errors="ignore")
|
||||
if tlabel == "":
|
||||
tlabel = "n%d" % self.id
|
||||
o.write("%s\n" % tlabel)
|
||||
|
||||
def exportGML(self, o, conf):
|
||||
""" write the node in GML format to the given file """
|
||||
o.write(" node [\n")
|
||||
o.write(" id %d\n" % self.id)
|
||||
o.write(" label\n")
|
||||
o.write(" \"%s\"\n" % self.getLabel(conf).encode(latinenc, errors="ignore"))
|
||||
o.write(" ]\n")
|
||||
|
||||
def exportGraphml(self, doc, parent, conf):
|
||||
""" export the node in Graphml format and append it to the parent XML node """
|
||||
node = doc.createElement(u'node')
|
||||
node.setAttribute(u'id',u'n%d' % self.id)
|
||||
|
||||
data0 = doc.createElement(u'data')
|
||||
data0.setAttribute(u'key', u'd0')
|
||||
|
||||
exportUml = False
|
||||
if len(self.sections) > 0 and conf.NodeUml and not conf.LumpAttributes:
|
||||
exportUml = True
|
||||
snode = doc.createElement(u'y:UMLClassNode')
|
||||
else:
|
||||
snode = doc.createElement(u'y:ShapeNode')
|
||||
geom = doc.createElement(u'y:Geometry')
|
||||
geom.setAttribute(u'height',u'30.0')
|
||||
geom.setAttribute(u'width',u'30.0')
|
||||
geom.setAttribute(u'x',u'0.0')
|
||||
geom.setAttribute(u'y',u'0.0')
|
||||
snode.appendChild(geom)
|
||||
color = getColorAttribute(self.attribs, 'color', conf.DefaultNodeColor, conf)
|
||||
fill = doc.createElement(u'y:Fill')
|
||||
fill.setAttribute(u'color',u'%s' % color)
|
||||
fill.setAttribute(u'transparent',u'false')
|
||||
snode.appendChild(fill)
|
||||
border = doc.createElement(u'y:BorderStyle')
|
||||
border.setAttribute(u'color',u'#000000')
|
||||
border.setAttribute(u'type',u'line')
|
||||
border.setAttribute(u'width',u'1.0')
|
||||
snode.appendChild(border)
|
||||
color = getColorAttribute(self.attribs, 'fontcolor', conf.DefaultNodeTextColor, conf)
|
||||
label = doc.createElement(u'y:NodeLabel')
|
||||
if conf.LumpAttributes:
|
||||
label.setAttribute(u'alignment',u'left')
|
||||
else:
|
||||
label.setAttribute(u'alignment',u'center')
|
||||
label.setAttribute(u'autoSizePolicy',u'content')
|
||||
label.setAttribute(u'fontFamily',u'Dialog')
|
||||
label.setAttribute(u'fontSize',u'12')
|
||||
label.setAttribute(u'fontStyle',u'plain')
|
||||
label.setAttribute(u'hasBackgroundColor',u'false')
|
||||
label.setAttribute(u'hasLineColor',u'false')
|
||||
label.setAttribute(u'modelName',u'internal')
|
||||
label.setAttribute(u'modelPosition',u'c')
|
||||
label.setAttribute(u'textColor',u'%s' % color)
|
||||
label.setAttribute(u'visible',u'true')
|
||||
nodeLabelText = escapeNewlines(self.getLabel(conf, True))
|
||||
if conf.LumpAttributes:
|
||||
# Find maximum label width
|
||||
width = self.getLabelWidth(conf, True)
|
||||
nodeLabelText += '\n' + conf.SepChar*width + '\n'
|
||||
nodeLabelText += u'%s\n' % '\n'.join(self.sections[1])
|
||||
nodeLabelText += conf.SepChar*width + '\n'
|
||||
nodeLabelText += u'%s' % '\n'.join(self.sections[2])
|
||||
label.appendChild(doc.createTextNode(u'%s' % nodeLabelText))
|
||||
snode.appendChild(label)
|
||||
if exportUml and not conf.LumpAttributes:
|
||||
shape = doc.createElement(u'y:UML')
|
||||
shape.setAttribute(u'clipContent',u'true')
|
||||
shape.setAttribute(u'constraint',u'')
|
||||
shape.setAttribute(u'omitDetails',u'false')
|
||||
shape.setAttribute(u'stereotype',u'')
|
||||
shape.setAttribute(u'use3DEffect',u'true')
|
||||
|
||||
alabel = doc.createElement(u'y:AttributeLabel')
|
||||
alabel.appendChild(doc.createTextNode(u'%s' % '\n'.join(self.sections[1])))
|
||||
shape.appendChild(alabel)
|
||||
mlabel = doc.createElement(u'y:MethodLabel')
|
||||
mlabel.appendChild(doc.createTextNode(u'%s' % '\n'.join(self.sections[2])))
|
||||
shape.appendChild(mlabel)
|
||||
else:
|
||||
shape = doc.createElement(u'y:Shape')
|
||||
shape.setAttribute(u'type',u'rectangle')
|
||||
snode.appendChild(shape)
|
||||
data0.appendChild(snode)
|
||||
node.appendChild(data0)
|
||||
|
||||
data1 = doc.createElement(u'data')
|
||||
data1.setAttribute(u'key', u'd1')
|
||||
node.appendChild(data1)
|
||||
|
||||
parent.appendChild(node)
|
||||
|
||||
class Edge:
|
||||
""" a single edge in the graph """
|
||||
def __init__(self):
|
||||
self.id = 0
|
||||
self.src = ""
|
||||
self.dest = ""
|
||||
self.attribs = {}
|
||||
|
||||
def initFromString(self, line):
|
||||
""" extract edge info from the given text line """
|
||||
spos = line.find('[')
|
||||
atts = ""
|
||||
if spos >= 0:
|
||||
atts = line[spos+1:]
|
||||
line = line[:spos].strip()
|
||||
|
||||
# Process labels
|
||||
ll = line.replace('->',' ').split()
|
||||
if len(ll) > 1:
|
||||
self.src = ll[0].strip('"')
|
||||
self.dest = ll[1].rstrip(';').strip('"')
|
||||
# Process attributes
|
||||
if len(atts):
|
||||
spos = atts.rfind(']')
|
||||
if spos > 0:
|
||||
atts = atts[:spos]
|
||||
self.attribs = parseAttributes(atts)
|
||||
|
||||
def getLabel(self, nodes, conf):
|
||||
""" return the label of the edge """
|
||||
if conf.EdgeLabels:
|
||||
if self.attribs.has_key('label'):
|
||||
return self.attribs['label']
|
||||
else:
|
||||
if conf.EdgeLabelsAutoComplete:
|
||||
srclink = self.src
|
||||
destlink = self.dest
|
||||
if (nodes[self.src].attribs.has_key('label')):
|
||||
srclink = nodes[self.src].attribs['label']
|
||||
if (nodes[self.dest].attribs.has_key('label')):
|
||||
destlink = nodes[self.dest].attribs['label']
|
||||
return "%s -> %s" % (srclink, destlink)
|
||||
else:
|
||||
return ""
|
||||
else:
|
||||
return ""
|
||||
|
||||
def complementAttributes(self, edge):
|
||||
""" from edge copy all new attributes, that do not exist in self """
|
||||
for a in edge.attribs:
|
||||
if not self.attribs.has_key(a):
|
||||
self.attribs[a] = edge.attribs[a]
|
||||
|
||||
def exportDot(self, o, nodes, conf):
|
||||
""" write the edge in DOT format to the given file """
|
||||
if len(self.attribs) > 0:
|
||||
o.write("\"%s\" -> \"%s\" %s;\n" % (self.src, self.dest, compileAttributes(self.attribs)))
|
||||
else:
|
||||
o.write("\"%s\" -> \"%s\";\n" % (self.src, self.dest))
|
||||
|
||||
def exportGDF(self, o, nodes, conf):
|
||||
""" write the edge in GDF format to the given file """
|
||||
slabel = nodes[self.src].getLabel(conf)
|
||||
if slabel == "":
|
||||
slabel = "n%d" % nodes[self.src].id
|
||||
dlabel = nodes[self.dest].getLabel(conf)
|
||||
if dlabel == "":
|
||||
dlabel = "n%d" % nodes[self.dest].id
|
||||
o.write("%s,%s\n" % (slabel.encode(latinenc, errors="ignore"), dlabel.encode(latinenc, errors="ignore")))
|
||||
|
||||
def exportGML(self, o, nodes, conf):
|
||||
""" write the edge in GML format to the given file """
|
||||
o.write(" edge [\n")
|
||||
o.write(" source %d\n" % nodes[self.src].id)
|
||||
o.write(" target %d\n" % nodes[self.dest].id)
|
||||
o.write(" label\n")
|
||||
o.write(" \"%s\"\n" % self.getLabel(nodes, conf).encode(latinenc, errors="ignore"))
|
||||
o.write(" ]\n")
|
||||
|
||||
def exportGraphml(self, doc, parent, nodes, conf):
|
||||
""" export the edge in Graphml format and append it to the parent XML node """
|
||||
edge = doc.createElement(u'edge')
|
||||
edge.setAttribute(u'id',u'e%d' % self.id)
|
||||
edge.setAttribute(u'source',u'n%d' % nodes[self.src].id)
|
||||
edge.setAttribute(u'target',u'n%d' % nodes[self.dest].id)
|
||||
|
||||
data2 = doc.createElement(u'data')
|
||||
data2.setAttribute(u'key', u'd2')
|
||||
|
||||
pedge = doc.createElement(u'y:PolyLineEdge')
|
||||
line = doc.createElement(u'y:LineStyle')
|
||||
color = getColorAttribute(self.attribs, 'color', conf.DefaultEdgeColor, conf)
|
||||
line.setAttribute(u'color',u'%s' % color)
|
||||
line.setAttribute(u'type', u'line')
|
||||
line.setAttribute(u'width', u'1.0')
|
||||
pedge.appendChild(line)
|
||||
arrow = doc.createElement(u'y:Arrows')
|
||||
arrow_tail = conf.DefaultArrowTail
|
||||
arrow_head = conf.DefaultArrowHead
|
||||
if conf.Arrows:
|
||||
if self.attribs.has_key('arrowtail'):
|
||||
arrow_head = self.attribs['arrowtail']
|
||||
if self.attribs.has_key('arrowhead'):
|
||||
arrow_tail = self.attribs['arrowhead']
|
||||
arrow.setAttribute(u'source',u'%s' % arrow_head)
|
||||
arrow.setAttribute(u'target',u'%s' % arrow_tail)
|
||||
pedge.appendChild(arrow)
|
||||
if conf.EdgeLabels:
|
||||
tlabel = self.getLabel(nodes, conf)
|
||||
if tlabel != "":
|
||||
label = doc.createElement(u'y:EdgeLabel')
|
||||
color = getColorAttribute(self.attribs, 'fontcolor', conf.DefaultEdgeTextColor, conf)
|
||||
label.setAttribute(u'alignment',u'center')
|
||||
label.setAttribute(u'distance',u'2.0')
|
||||
label.setAttribute(u'fontFamily',u'Dialog')
|
||||
label.setAttribute(u'fontSize',u'12')
|
||||
label.setAttribute(u'fontStyle',u'plain')
|
||||
label.setAttribute(u'hasBackgroundColor',u'false')
|
||||
label.setAttribute(u'hasLineColor',u'false')
|
||||
label.setAttribute(u'modelName',u'six_pos')
|
||||
label.setAttribute(u'modelPosition',u'tail')
|
||||
label.setAttribute(u'textColor',u'%s' % color)
|
||||
label.setAttribute(u'visible',u'true')
|
||||
label.setAttribute(u'preferredPlacement',u'anywhere')
|
||||
label.setAttribute(u'ratio',u'0.5')
|
||||
label.appendChild(doc.createTextNode(u'%s' % escapeNewlines(tlabel)))
|
||||
pedge.appendChild(label)
|
||||
bend = doc.createElement(u'y:BendStyle')
|
||||
bend.setAttribute(u'smoothed', u'false')
|
||||
pedge.appendChild(bend)
|
||||
data2.appendChild(pedge)
|
||||
edge.appendChild(data2)
|
||||
|
||||
data3 = doc.createElement(u'data')
|
||||
data3.setAttribute(u'key', u'd3')
|
||||
edge.appendChild(data3)
|
||||
|
||||
parent.appendChild(edge)
|
||||
Reference in New Issue
Block a user