dia r3940 - in trunk: . app lib objects/UML samples



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]