dia r3940 - in trunk: . app lib objects/UML samples
- From: hans svn gnome org
- To: svn-commits-list gnome org
- Subject: dia r3940 - in trunk: . app lib objects/UML samples
- Date: Sun, 13 Apr 2008 16:33:31 +0100 (BST)
Author: hans
Date: Sun Apr 13 16:33:31 2008
New Revision: 3940
URL: http://svn.gnome.org/viewvc/dia?rev=3940&view=rev
Log:
[more robustness for incomplete (i.e. usually generated) diagrams]
* app/load_save.c : adjust the connections positions automatically,
it is impossible to do so while generating
* lib/element.h lib/object.h lib/orth_conn.h lib/properties.h
objects/UML/generalization.c : marked more properties optional - if
they are properly initialized - to get rid of a lot of g_warnings()
and one step further to fix #56233
* samples/gobj-parse.c : a simple parser to generate a class diagram
out of GObject using headers to test the above
Added:
trunk/samples/gobj-parse.py (contents, props changed)
Modified:
trunk/ChangeLog
trunk/app/load_save.c
trunk/lib/element.h
trunk/lib/object.h
trunk/lib/orth_conn.h
trunk/lib/properties.h
trunk/objects/UML/generalization.c
Modified: trunk/app/load_save.c
==============================================================================
--- trunk/app/load_save.c (original)
+++ trunk/app/load_save.c Sun Apr 13 16:33:31 2008
@@ -275,6 +275,7 @@
if IS_GROUP(obj) {
read_connections(group_objects(obj), obj_node, objects_hash);
} else {
+ gboolean broken = FALSE;
connections = obj_node->xmlChildrenNode;
while ((connections!=NULL) &&
(xmlStrcmp(connections->name, (const xmlChar *)"connections")!=0))
@@ -302,9 +303,11 @@
if (to == NULL) {
message_error(_("Error loading diagram.\n"
"Linked object not found in document."));
+ broken = TRUE;
} else if (handle < 0 || handle >= obj->num_handles) {
message_error(_("Error loading diagram.\n"
"connection handle does not exist."));
+ broken = TRUE;
} else {
if (conn == -1) { /* Find named connpoint */
int i;
@@ -319,10 +322,18 @@
if (conn >= 0 && conn < to->num_connections) {
object_connect(obj, obj->handles[handle],
to->connections[conn]);
+ /* force an update on the connection, helpful with (incomplete) generated files */
+ obj->handles[handle]->pos =
+ to->connections[conn]->last_pos = to->connections[conn]->pos;
+#if 0
+ obj->ops->move_handle(obj, obj->handles[handle], &to->connections[conn]->pos,
+ to->connections[conn], HANDLE_MOVE_CONNECTED,0);
+#endif
} else {
message_error(_("Error loading diagram.\n"
"connection point %s does not exist."),
connstr);
+ broken = TRUE;
}
}
@@ -332,6 +343,22 @@
connection = connection->next;
}
+ /* Fix positions of the connection object for (de)generated files.
+ * Only done for the last point connected otherwise the intermediate posisitions
+ * may screw the auto-routing algorithm.
+ */
+ if (!broken && obj && obj->ops->set_props) {
+ GPtrArray *props = g_ptr_array_new();
+ /* called for it's side-effect of update_data */
+ obj->ops->set_props (obj, props);
+ g_ptr_array_free (props, TRUE);
+
+ for (handle = 0; handle < obj->num_handles; ++handle) {
+ if (obj->handles[handle]->connected_to)
+ obj->ops->move_handle(obj, obj->handles[handle], &obj->handles[handle]->pos,
+ obj->handles[handle]->connected_to, HANDLE_MOVE_CONNECTED,0);
+ }
+ }
}
}
Modified: trunk/lib/element.h
==============================================================================
--- trunk/lib/element.h (original)
+++ trunk/lib/element.h Sun Apr 13 16:33:31 2008
@@ -69,9 +69,9 @@
OBJECT_COMMON_PROPERTIES, \
{ "elem_corner", PROP_TYPE_POINT, PROP_FLAG_NO_DEFAULTS, \
"Element corner", "The corner of the element"}, \
- { "elem_width", PROP_TYPE_REAL, PROP_FLAG_DONT_MERGE | PROP_FLAG_NO_DEFAULTS, \
+ { "elem_width", PROP_TYPE_REAL, PROP_FLAG_DONT_MERGE | PROP_FLAG_NO_DEFAULTS | PROP_FLAG_OPTIONAL, \
"Element width", "The width of the element", &width_range}, \
- { "elem_height", PROP_TYPE_REAL, PROP_FLAG_DONT_MERGE | PROP_FLAG_NO_DEFAULTS, \
+ { "elem_height", PROP_TYPE_REAL, PROP_FLAG_DONT_MERGE | PROP_FLAG_NO_DEFAULTS | PROP_FLAG_OPTIONAL, \
"Element height", "The height of the element", &width_range}
/* Would like to have the frame, but need to figure out why
Modified: trunk/lib/object.h
==============================================================================
--- trunk/lib/object.h (original)
+++ trunk/lib/object.h Sun Apr 13 16:33:31 2008
@@ -550,9 +550,9 @@
/* base property stuff ... */
#define OBJECT_COMMON_PROPERTIES \
- { "obj_pos", PROP_TYPE_POINT, 0, \
+ { "obj_pos", PROP_TYPE_POINT, PROP_FLAG_OPTIONAL, \
"Object position", "Where the object is located"}, \
- { "obj_bb", PROP_TYPE_RECT, 0, \
+ { "obj_bb", PROP_TYPE_RECT, PROP_FLAG_OPTIONAL, \
"Object bounding box", "The bounding box of the object"}
#define OBJECT_COMMON_PROPERTIES_OFFSETS \
Modified: trunk/lib/orth_conn.h
==============================================================================
--- trunk/lib/orth_conn.h (original)
+++ trunk/lib/orth_conn.h Sun Apr 13 16:33:31 2008
@@ -88,7 +88,7 @@
#define ORTHCONN_COMMON_PROPERTIES \
OBJECT_COMMON_PROPERTIES, \
{ "orth_points", PROP_TYPE_POINTARRAY, 0, "orthconn points", NULL}, \
- { "orth_orient", PROP_TYPE_ENUMARRAY, 0, "orthconn orientations", NULL}, \
+ { "orth_orient", PROP_TYPE_ENUMARRAY, PROP_FLAG_OPTIONAL, "orthconn orientations", NULL}, \
{ "orth_autoroute", PROP_TYPE_BOOL, PROP_FLAG_VISIBLE|PROP_FLAG_OPTIONAL, N_("Autoroute"), NULL} \
#define ORTHCONN_COMMON_PROPERTIES_OFFSETS \
Modified: trunk/lib/properties.h
==============================================================================
--- trunk/lib/properties.h (original)
+++ trunk/lib/properties.h Sun Apr 13 16:33:31 2008
@@ -553,7 +553,7 @@
/* Convenience macros */
#define PROP_NOTEBOOK_BEGIN(name) \
{ "nbook_" name, PROP_TYPE_NOTEBOOK_BEGIN, \
- PROP_FLAG_VISIBLE|PROP_FLAG_DONT_SAVE|PROP_FLAG_WIDGET_ONLY, NULL, NULL}
+ PROP_FLAG_VISIBLE|PROP_FLAG_DONT_SAVE|PROP_FLAG_WIDGET_ONLY|PROP_FLAG_DONT_MERGE, NULL, NULL}
#define PROP_STD_NOTEBOOK_BEGIN PROP_NOTEBOOK_BEGIN("std")
#define PROP_OFFSET_NOTEBOOK_BEGIN(name) \
{ "nbook_" name, PROP_TYPE_NOTEBOOK_BEGIN, 0}
@@ -561,7 +561,7 @@
#define PROP_NOTEBOOK_END(name) \
{ "nbook_" name "_end", PROP_TYPE_NOTEBOOK_END, \
- PROP_FLAG_VISIBLE|PROP_FLAG_DONT_SAVE|PROP_FLAG_WIDGET_ONLY, NULL, NULL}
+ PROP_FLAG_VISIBLE|PROP_FLAG_DONT_SAVE|PROP_FLAG_WIDGET_ONLY|PROP_FLAG_DONT_MERGE, NULL, NULL}
#define PROP_STD_NOTEBOOK_END PROP_NOTEBOOK_END("std")
#define PROP_OFFSET_NOTEBOOK_END(name) \
{ "nbook_" name "_end", PROP_TYPE_NOTEBOOK_END, 0}
@@ -569,7 +569,7 @@
#define PROP_NOTEBOOK_PAGE(name,flags,descr) \
{ "nbook_page_" name, PROP_TYPE_NOTEBOOK_PAGE, \
- PROP_FLAG_VISIBLE|PROP_FLAG_DONT_SAVE|PROP_FLAG_WIDGET_ONLY|flags,descr,NULL}
+ PROP_FLAG_VISIBLE|PROP_FLAG_DONT_SAVE|PROP_FLAG_WIDGET_ONLY|PROP_FLAG_DONT_MERGE|flags,descr,NULL}
#define PROP_OFFSET_NOTEBOOK_PAGE(name) \
{ "nbook_page_" name , PROP_TYPE_NOTEBOOK_PAGE, 0}
@@ -586,7 +586,7 @@
PROP_FLAG_VISIBLE|PROP_FLAG_DONT_SAVE|PROP_FLAG_WIDGET_ONLY, NULL, NULL}
#define PROP_STD_MULTICOL_END PROP_MULTICOL_END("std")
#define PROP_OFFSET_MULTICOL_END(name) \
- { "mcol_" name "_end", PROP_TYPE_NOTEBOOK_END, 0}
+ { "mcol_" name "_end", PROP_TYPE_MULTICOL_END, 0}
#define PROP_OFFSET_STD_MULTICOL_END PROP_OFFSET_MULTICOL_END("std")
#define PROP_MULTICOL_COLUMN(name) \
Modified: trunk/objects/UML/generalization.c
==============================================================================
--- trunk/objects/UML/generalization.c (original)
+++ trunk/objects/UML/generalization.c Sun Apr 13 16:33:31 2008
@@ -129,9 +129,9 @@
/* can't use PROP_STD_TEXT_COLOUR_OPTIONAL cause it has PROP_FLAG_DONT_SAVE. It is designed to fill the Text object - not some subset */
PROP_STD_TEXT_COLOUR_OPTIONS(PROP_FLAG_VISIBLE|PROP_FLAG_STANDARD|PROP_FLAG_OPTIONAL),
PROP_STD_LINE_COLOUR_OPTIONAL,
- { "name", PROP_TYPE_STRING, PROP_FLAG_VISIBLE,
+ { "name", PROP_TYPE_STRING, PROP_FLAG_VISIBLE|PROP_FLAG_OPTIONAL,
N_("Name:"), NULL, NULL },
- { "stereotype", PROP_TYPE_STRING, PROP_FLAG_VISIBLE,
+ { "stereotype", PROP_TYPE_STRING, PROP_FLAG_VISIBLE|PROP_FLAG_OPTIONAL,
N_("Stereotype:"), NULL, NULL },
PROP_DESC_END
};
Added: trunk/samples/gobj-parse.py
==============================================================================
--- (empty file)
+++ trunk/samples/gobj-parse.py Sun Apr 13 16:33:31 2008
@@ -0,0 +1,536 @@
+'''
+Parses class definitions out of GObject based headers
+
+ToDo:
+ - better parser aproach ;)
+ - respect /*< public,protected,private >*/
+ - parse *.c
+
+'''
+# Copyright (c) 2006, Hans Breuer <hans breuer org>
+
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+import glob, os, string, re
+
+verbose = 0
+
+def strip_whitespace (s) :
+ s = string.replace (s, " ", "")
+ return string.replace (s, "\t", "")
+
+class CMethod :
+ def __init__ (self, name, type) :
+ self.name = string.strip(name)
+ self.pars = []
+ self.retval = string.replace(type, ' ', '')
+ def AddPar (self, name, type) :
+ self.pars.append ((string.strip(name),
+ strip_whitespace(type)))
+
+class CClass :
+ def __init__ (self, name) :
+ self.name = string.strip(name)
+ self.defs = {'TYPE' : None, 'OBJECT' : None, 'CLASS' : None}
+ self.parent = None
+ self.attrs = []
+ self.methods = {}
+ self.signals = []
+ def AddAttr (self, name, type) :
+ if verbose : print "\t", type, name
+ self.attrs.append ((string.strip(name),
+ strip_whitespace(type)))
+ def AddMethod (self, name, method) :
+ if verbose : print "\t", name, "()"
+ self.methods[string.strip(name)] = method
+ def AddSignal (self, name, type) :
+ self.signals.append ((string.strip(name),
+ strip_whitespace(type)))
+
+class CStripCommentsAndBlankLines :
+ def __init__ (self, name) :
+ f = open (name)
+ lines = f.readlines ()
+ self.lines = []
+ self.cur = -1
+ x1 = -1
+ x2 = -1
+ incom = 0
+ r = re.compile("^\s*$") # to remove empty lines
+ for s in lines :
+ x1 = string.find (s, '/*')
+ x2 = string.find (s, '*/')
+ while x2 > x1 and incom != 1 :
+ s = s[:x1] + s[x2+2:]
+ x1 = string.find (s, '/*')
+ x2 = string.find (s, '*/')
+ else :
+ if x1 > -1 :
+ incom = 1
+ s = s[:x1]
+ elif x2 > - 1 and incom :
+ s = s[x2+2:]
+ incom = 0
+ if r.match (s) or incom :
+ continue
+ self.lines.append (s)
+ self.lines.append ("")
+ f.close ()
+ def readline (self) :
+ self.cur = self.cur + 1
+ try :
+ return self.lines[self.cur]
+ except :
+ return ""
+ def seek (self, toPos) :
+ if toPos == 0 :
+ self.cur = -1
+
+def TestStripFile (name) :
+ f = CStripCommentsAndBlankLines(name)
+ s = f.readline()
+ while s :
+ print s[:-1]
+ s = f.readline()
+
+import sys
+
+sPkg = ''
+sDir = '.'
+if len (sys.argv) < 2 :
+ print sys.argv[0], '<package>', '[directory]'
+ sys.exit(0)
+else :
+ sPkg = sys.argv[1]
+if len (sys.argv) > 2 :
+ sDir = sys.argv[2]
+
+os.chdir (sDir)
+lst = glob.glob ('*.h')
+lst.extend (glob.glob ("*/*.h"))
+lst.extend (glob.glob ("*/*/*.h"))
+
+klasses = []
+no_klass_headers = []
+
+#
+# #define GDK_DRAWABLE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_DRAWABLE, GdkDrawable))
+#
+rClassCast = re.compile ("^#define " + string.upper (sPkg) + "_(?P<n1>\w+)" \
+ "\((?P<par>\w+)\)\s+\(" \
+ "((G_TYPE_CHECK_INSTANCE_CAST)|(GTK_CHECK_CAST))\s+" \
+ "\(\((?P=par)\),\s*(?P<type>\w+),\s+" \
+ "(?P<name>\w+)\)\).*")
+#
+# m.group('type') == 'GDK_TYPE_DRAWABLE'
+# m.group('name') == 'GdkTypeDrawable'
+#
+rVarDecl = re.compile ("\s*(?P<type>(unsigned)*\s*\w+\s*\**)\s*(?P<name>\w+)\s*:*\s*\d*\s*;\.*")
+rSignal = rVarDecl #FIXME: signals are 'methods' to be registered
+rMethod = re.compile ("\s*(?P<type>\w+\s+\**)\s*" \
+ "\(\*\s*(?P<name>\w+)\)\s*\(" \
+ "(?P<ptype>\w+\s*\**)\s*(?P<pname>\w+),*" \
+ "(?P<done>(\);)*)")
+# m.group('type') == retval
+# m.group('name')
+# m.group('ptype'), m.group('pname')
+# m.group('done')
+rPar = re.compile ("\s*(const\s*)*(?P<ptype>\w+\s*\**)\s*(?P<pname>\w+),*" \
+ "(?P<done>(\);)*)")
+
+fout = open (sPkg + '-generated.log', 'w')
+# the type cast is not necessarily in the same header ;(
+unresolved = {}
+for sF in lst :
+ sName = sF[len(sPkg):-2] # without case (approximation)
+ # fin = open (sF)
+ fin = CStripCommentsAndBlankLines(sF)
+ s = fin.readline ()
+ while s :
+ m = rClassCast.match (s)
+ if m :
+ fout.write (m.group('type') + ' ' + m.group('name') + '\n')
+ sName = m.group('name')
+ unresolved[sName] = CClass (sName)
+ s = fin.readline ()
+ if len(unresolved.keys()) == 0 :
+ no_klass_headers.append (sF)
+ else :
+ iFound = 0
+ unresolved_keys = unresolved.keys()
+ for sK in unresolved_keys :
+ klass = unresolved[sK]
+ sK = klass.name
+ # start from the beginning
+ fin.seek (0)
+ rObject = re.compile ("struct\s+_" + sK + "\s*(?P<p>\{*)\s*$")
+ rKlass = re.compile ("struct\s+_" + sK + "Class\s*(?P<p>\{*)\s*$")
+ s = fin.readline ()
+ meth = None
+ while s :
+ mO = rObject.match (s)
+ if mO :
+ if mO.group('p') != '{' :
+ s = fin.readline() # skip line with {
+ s = fin.readline() # read parent line
+ mV = rVarDecl.match(s)
+ try :
+ klass.parent = (mV.group('name'),
+ string.strip(mV.group('type')))
+ if verbose : print "class", sK, ":", mV.group('type')
+ except :
+ print 'klass.parent error (', sF, ') :', s
+ s = fin.readline ()
+ mV = rVarDecl.match(s)
+ if not mV and verbose : print s
+ while mV :
+ klass.AddAttr (mV.group('name'), mV.group('type'))
+ s = fin.readline ()
+ mV = rVarDecl.match(s)
+
+ else :
+ mK = rKlass.match (s)
+ if mK :
+ iFound = iFound + 1
+ klasses.append (unresolved[sK])
+ del unresolved[sK]
+
+ if mK.group('p') != '{' :
+ s = fin.readline() # skip line with {
+ s = fin.readline() # read parent line, validate it?
+ s = fin.readline()
+ mS = rSignal.match(s)
+ mM = rMethod.match(s)
+ while (mS or mM or meth) and s :
+ if mS :
+ klass.AddSignal (mS.group('name'), mS.group('type'))
+ elif mM :
+ meth = CMethod (mM.group('name'), mM.group('type'))
+ klass.AddMethod (mM.group('name'), meth)
+ meth.AddPar (mM.group('pname'), mM.group('ptype'))
+ if mM.group('done') == ');' :
+ meth = None # reset
+ elif meth :
+ mP = rPar.match (s)
+ if mP :
+ meth.AddPar (mP.group('pname'), mP.group('ptype'))
+ if mP.group('done') == ');' :
+ meth = None # reset
+ else :
+ # fixme: too drastic?
+ #meth = None # reset
+ pass
+ else :
+ break
+ s = fin.readline ()
+ mS = rSignal.match(s)
+ mM = rMethod.match(s)
+ s = fin.readline ()
+ if iFound == 0 :
+ no_klass_headers.append (sF)
+ else :
+ print sF + " (" + str(iFound) + ")"
+
+for sF in no_klass_headers :
+ fout.write ("<No Klass>: " + sF + "\n")
+print 'Klasses found:', len(klasses), '\nHeaders w/o classes:', len(no_klass_headers)
+
+def CmpParent (a,b) :
+ 'gets CClass, sort by parent type'
+ if a.parent == None and b.parent == None :
+ return 0
+ elif a.parent == None :
+ return 1
+ elif b.parent == None :
+ return -1
+ try :
+ i = cmp(a.parent[1],b.parent[1])
+ if i == 0 :
+ i = cmp(a.name, b.name)
+ elif cmp(a.name, b.parent[1]) == 0 :
+ #print a.name, ">", b.name
+ return 1
+ elif cmp(b.name, a.parent[1]) == 0 :
+ #print b.name, ">", a.name
+ return -1
+ return i
+ except :
+ print "Sort Error:", str(a.parent), str(b.parent)
+ return 0
+
+klasses.sort(CmpParent)
+# the sorting above does not sort everything, ensure parents are before childs
+sorted = []
+sorted_klasses = []
+# first put in externals
+parents = {}
+for k in klasses :
+ if k.parent :
+ parents[k.parent[1]] = 1
+for k in klasses :
+ if parents.has_key(k.name) :
+ del parents[k.name]
+sorted.extend(parents.keys())
+# sort the rest
+while len(sorted_klasses) < len(klasses) :
+ before = len(sorted_klasses)
+ for k in klasses :
+ sK = k.name
+ sP = k.parent
+ if sK in sorted :
+ continue # don't add tem twice
+ elif k.parent is None :
+ sorted.append(sK)
+ elif k.parent[1] in sorted :
+ sorted.append(sK)
+ else :
+ continue
+ #print sK
+ sorted_klasses.append(k)
+ if len(sorted_klasses) == before :
+ if len(sorted_klasses) < len(klasses) :
+ unsorted = []
+ for k in klasses :
+ if not k.name in sorted :
+ unsorted.append(k.name)
+ print string.join(unsorted, ", "), "not sorted?"
+ break # avoid endless loop
+
+klasses = sorted_klasses
+
+def WritePython (fname) :
+ # generate Python declaration for validation
+ fpy = open (fname, "w")
+ for klass in klasses :
+ sParent = ""
+ if klass.parent :
+ sParent = " (" + klass.parent[1] + ")"
+ fpy.write ('class ' + klass.name + sParent + " :\n")
+ if len (klass.attrs) > 0 :
+ fpy.write ('\tdef __init__ (self) :\n')
+ for attr in klass.attrs :
+ fpy.write ('\t\tself.' + attr[0] + " = None # " + attr[1] + "\n")
+ if len (klass.signals) > 0 :
+ fpy.write ('\t\t # Signals\n')
+ for attr in klass.signals :
+ fpy.write ('\t\tself.' + attr[0] + " = None # " + attr[1] + "\n")
+ for s in klass.methods.keys() :
+ meth = klass.methods[s]
+ fpy.write ('\t#returns: ' + meth.retval + '\n\tdef ' + meth.name + ' (')
+ s1 = ''
+ s2 = ''
+ for par in meth.pars :
+ s1 = s1 + par[0] + ', '
+ s2 = s2 + par[1] + ', '
+ if len(s1) > 0 :
+ s1 = s1[:-2]
+ if len(s2) > 0 :
+ s2 = s2[:-2]
+ fpy.write (s1 + ') :\n')
+ fpy.write ('\t\t# ' + s2 + '\n')
+ fpy.write ('\t\tpass\n')
+ if len (klass.attrs) < 1 and len(klass.signals) < 1 and len(klass.methods) < 1 :
+ fpy.write ('\tpass\n') # make it valid Python
+
+def WriteDia (fname) :
+ sStartDiagram = '''<?xml version="1.0" encoding="UTF-8"?>
+<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/">
+ <dia:layer name="Background" visible="true">'''
+ sStartClass = '''
+ <dia:object type="UML - Class" version="0" id="O%d">
+ <dia:attribute name="elem_corner">
+ <dia:point val="%d,%d"/>
+ </dia:attribute>
+ <dia:attribute name="name">
+ <dia:string>#%s#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="visible_attributes">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="visible_operations">
+ <dia:boolean val="true"/>
+ </dia:attribute>'''
+ sFillColorAttribute = '''
+ <dia:attribute name="fill_color">
+ <dia:color val="%s"/>
+ </dia:attribute>'''
+ sStartAttributes = '''
+ <dia:attribute name="attributes">
+ <dia:composite type="umlattribute">'''
+ sDataAttribute = '''
+ <dia:attribute name="name">
+ <dia:string>#%s#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="type">
+ <dia:string>#%s#</dia:string>
+ </dia:attribute>'''
+ sEndAttributes = '''
+ </dia:composite>
+ </dia:attribute>'''
+ sStartOperations = '''
+ <dia:attribute name="operations">'''
+ sStartOperation = '''
+ <dia:composite type="umloperation">
+ <dia:attribute name="name">
+ <dia:string>#%s#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="type">
+ <dia:string>#%s#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="parameters">
+ <dia:composite type="umlparameter">'''
+ sDataParameter = '''
+ <dia:attribute name="name">
+ <dia:string>#%s#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="type">
+ <dia:string>#%s#</dia:string>
+ </dia:attribute>'''
+ sEndOperation = '''
+ </dia:composite>
+ </dia:attribute>
+ </dia:composite>'''
+ sEndOperations = '''
+ </dia:attribute>'''
+ sStartConnection = '''
+ <dia:object type="UML - Generalization" version="1" id="O%d">
+ <dia:attribute name="obj_pos">
+ <dia:point val="%d,%d"/>
+ </dia:attribute>
+ <dia:attribute name="orth_autoroute">
+ <dia:boolean val="true"/>
+ </dia:attribute>'''
+ sOrthPoints = '''
+ <dia:attribute name="orth_points">
+ <dia:point val="%d,%d"/>
+ <dia:point val="%d,%d"/>
+ <dia:point val="%d,%d"/>
+ <dia:point val="%d,%d"/>
+ </dia:attribute>'''
+ sEndObject = '''
+ </dia:object>'''
+ sEndDiagram = '''
+ </dia:layer>
+</dia:diagram>'''
+
+ fdia = open (fname, "w")
+ nObject = 0
+ x = 0
+ y = 0
+ dx = 10
+ dy = 15
+ # maintain a dictionary of parents positions to at least place not everything above each other
+ positions = {}
+ connectFrom = {}
+ externals = {}
+ fdia.write (sStartDiagram)
+
+ for klass in klasses :
+ if klass.parent : # add every parent ...
+ parentName = klass.parent[1]
+ if externals.has_key (parentName) :
+ externals[parentName] += 1
+ else :
+ externals[parentName] = 1
+ for klass in klasses :
+ if externals.has_key (klass.name) : # ... but remove the internals
+ del externals[klass.name]
+
+ # write all 'external' parents
+ for s in externals.keys() :
+ externals[s] = (nObject, -1)
+ fdia.write(sStartClass % (nObject, x, y, s))
+ positions[s] = (x,y)
+ x += dx
+ fdia.write(sFillColorAttribute % ("#ffff00",))
+ # fixme: any more attributes?
+ fdia.write (sEndObject)
+ nObject += 1
+
+ for klass in klasses :
+ parentName = ""
+ if klass.parent :
+ parentName = klass.parent[1]
+ connectFrom[klass.name] = (nObject, parentName)
+ if positions.has_key (parentName) :
+ x = positions[parentName][0] # same x
+ y = positions[parentName][1] + dy # y below
+ else :
+ x += dx
+ y = dy
+ #fpy.write ('class ' + klass.name + sParent + " :\n")
+ fdia.write(sStartClass % (nObject, x, y, klass.name))
+ positions[klass.name] = (x, y)
+ if len (klass.attrs) > 0 :
+ fdia.write (sStartAttributes)
+ for attr in klass.attrs :
+ fdia.write (sDataAttribute % (attr[0], attr[1]))
+ fdia.write (sEndAttributes)
+# if len (klass.signals) > 0 :
+# fpy.write ('\t\t # Signals\n')
+# for attr in klass.signals :
+# fpy.write ('\t\tself.' + attr[0] + " = None # " + attr[1] + "\n")
+ # the differnence between signals and methods is in the attributes
+ if len (klass.signals) > 0 or len(klass.methods.keys()) > 0 :
+ fdia.write (sStartOperations)
+ for s in klass.methods.keys() :
+ meth = klass.methods[s]
+ fdia.write(sStartOperation % (meth.name, meth.retval))
+ # first parameter is supposed to be 'this' pointer: leave out
+ for par in meth.pars[1:] :
+ fdia.write (sDataParameter % (par[0], par[1]))
+ fdia.write (sEndOperation)
+ if len (klass.signals) > 0 or len(klass.methods.keys()) > 0 :
+ fdia.write (sEndOperations)
+ fdia.write (sEndObject)
+ nObject += 1
+
+ # write all connections
+ for sFrom in connectFrom.keys() :
+ iFrom = connectFrom[sFrom][0]
+ sTo = connectFrom[sFrom][1]
+ if connectFrom.has_key (sTo) :
+ iTo = connectFrom[sTo][0]
+ elif externals.has_key(sTo) :
+ iTo = externals[sTo][0]
+ else :
+ print "sFrom -> sTo?", sFrom, sTo
+ continue # something wrong?
+ nObject += 1
+ #fdia.write ('\n\t<!-- %s : %s -->' % (sFrom, sTo))
+ # just to give it some position (and stop Dia complaining)
+ if positions.has_key (sTo) :
+ x1, y1 = positions[sTo]
+ else :
+ x1, y1 = (dx, dy)
+ if positions.has_key (sFrom) :
+ x2, y2 = positions[sFrom]
+ else :
+ x2, y2 = (dx, dy)
+ fdia.write (sStartConnection % (nObject, x1+dx/2, y1+dy/2,))
+ fdia.write (sOrthPoints % (x1,y1, x1,(y1+y2)/2, x2,(y1+y2)/2, x2,y2 ))
+ # and connect
+ fdia.write ('''
+ <dia:connections>
+ <dia:connection handle="0" to="O%d" connection="6"/>
+ <dia:connection handle="1" to="O%d" connection="1"/>
+ </dia:connections>''' % (iTo, iFrom) )
+ fdia.write (sEndObject)
+
+ fdia.write (sEndDiagram)
+ print len(connectFrom.keys()), " connections"
+
+WritePython (sPkg + "-generated.py")
+WriteDia (sPkg + "-generated.dia")
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]