root/gaphor/tags/gaphor-0.3.0/gaphor/storage.py

Revision 251, 9.7 kB (checked in by arjanmol, 5 years ago)

*** empty log message ***

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 # vim: sw=4:et
2 """Load and save Gaphor models to Gaphors own XML format.
3
4 Three functions are exported:
5 load(filename)
6     load a model from a file
7 save(filename)
8     store the current model in a file
9 verify(filename)
10     check the validity of the file (this does not tell us
11     we have a valid model, just a valid file).
12 """
13
14 from cStringIO import StringIO
15 from xml.sax.saxutils import escape
16 import types
17 import os.path
18 import gc
19 import UML
20 import parser
21 import diagram
22 import diacanvas
23 import gaphor
24 from gaphor.i18n import _
25
26 __all__ = [ 'load', 'save' ]
27
28 FILE_FORMAT_VERSION = '3.0'
29
30 def save(filename=None, factory=None):
31     """Save the current model to @filename. If no filename is given,
32     standard out is used.
33     """
34
35     def save_reference(name, value):
36         """Save a value as a reference to another element in the model.
37         This applies to both UML as well as canvas items.
38         """
39         # Save a reference to the object:
40         if value.id:
41             buffer.write('<%s><ref refid="%s"/></%s>\n' % (name, value.id, name))
42
43     def save_collection(name, value):
44         """Save a list of references.
45         """
46         if len(value) > 0:
47             buffer.write('<%s><reflist>' % name)
48             for v in value:
49                 #save_reference(name, v)
50                 if v.id:
51                     buffer.write('<ref refid="%s"/>' % v.id)
52             buffer.write('</reflist></%s>' % name)
53
54     def save_value(name, value):
55         """Save a value (attribute).
56         If the value is a string, it is saves as a CDATA block.
57         """
58         if value is not None:
59             buffer.write('<%s><val>' % name)
60             if isinstance(value, types.StringTypes):
61                 buffer.write('<![CDATA[%s]]>' % value.replace(']]>', '] ]>'))
62             else:
63                 buffer.write(escape(str(value)))
64             buffer.write('</val></%s>\n' % name)
65
66     def save_element(name, value):
67         """Save attributes and references from items in the gaphor.UML module.
68         A value may be a primitive (string, int), a gaphor.UML.collection
69         (which contains a list of references to other UML elements) or a
70         diacanvas.Canvas (which contains canvas items).
71         """
72         if isinstance (value, (UML.Element, diacanvas.CanvasItem)):
73             save_reference(name, value)
74         elif isinstance(value, UML.collection):
75             save_collection(name, value)
76         elif isinstance(value, diacanvas.Canvas):
77             buffer.write('<canvas>')
78             value.save(save_canvasitem)
79             buffer.write('</canvas>')
80         else:
81             save_value(name, value)
82
83     def save_canvasitem(name, value, reference=False):
84         """Save attributes and references in a gaphor.diagram.* object.
85         The extra attribute reference can be used to force UML
86         """
87         #log.debug('saving canvasitem: %s|%s %s' % (name, value, type(value)))
88         if reference or isinstance(value, UML.Element):
89             save_reference(name, value)
90         elif isinstance(value, UML.collection):
91             save_collection(name, value)
92         elif isinstance(value, diacanvas.CanvasItem):
93             buffer.write('<item id="%s" type="%s">' % (value.id, value.__class__.__name__))
94             value.save(save_canvasitem)
95             buffer.write('</item>')
96         else:
97             save_value(name, value)
98
99     if not factory:
100         factory = gaphor.resource(UML.ElementFactory)
101
102     buffer = StringIO()
103     buffer.write('<?xml version="1.0"?>\n')
104     buffer.write('<gaphor version="%s" gaphor_version="%s">' % (FILE_FORMAT_VERSION, gaphor.resource('Version')))
105
106     for e in factory.values():
107         clazz = e.__class__.__name__
108         buffer.write('<%s id="%s">' % (clazz, str(e.id)))
109         e.save(save_element)
110         buffer.write('</%s>' % clazz)
111
112     buffer.write('</gaphor>')
113
114     buffer.reset()
115
116     if not filename:
117         print str(buffer.read())
118     else:
119         file = open (filename, 'w')
120         if not file:
121             raise IOError, 'Could not open file `%s\'' % (filename)
122         try:
123             file.write(buffer.read())
124         finally:
125             file.close()
126
127 def _load(elements, factory):
128     """Load a file and create a model if possible.
129     Exceptions: IOError, ValueError.
130     """
131
132     log.debug(_('Loading %d elements...') % len(elements.keys()))
133
134     log.info('0%')
135
136     # First create elements and canvas items in the factory
137     # The elements are stored as attribute 'element' on the parser objects:
138     for id, elem in elements.items():
139         if isinstance(elem, parser.element):
140             try:
141                 cls = getattr(UML, elem.type)
142                 #log.debug('Creating UML element for %s' % elem)
143                 elem.element = factory.create_as(cls, id)
144             except:
145                 raise
146         elif isinstance(elem, parser.canvasitem):
147             cls = getattr(diagram, elem.type)
148             #log.debug('Creating canvas item for %s' % elem)
149             elem.element = diagram.create_as(cls, id)
150         else:
151             raise ValueError, 'Item with id "%s" and type %s can not be instantiated' % (id, type(elem))
152
153     log.info('0% ... 33%')
154
155     # load attributes and create references:
156     for id, elem in elements.items():
157         # Ensure that all elements have their element instance ready...
158         assert hasattr(elem, 'element')
159
160         # establish parent/child relations on canvas items:
161         if isinstance(elem, parser.element) and elem.canvas:
162             for item in elem.canvas.canvasitems:
163                 assert item in elements.values(), 'Item %s (%s) is a canvas item, but it is not in the parsed objects table' % (item, item.id)
164                 item.element.set_property('parent', elem.element.canvas.root)
165         if isinstance(elem, parser.canvasitem):
166             for item in elem.canvasitems:
167                 assert item in elements.values(), 'Item %s (%s) is a canvas item, but it is not in the parsed objects table' % (item, item.id)
168                 item.element.set_property('parent', elem.element)
169
170         # load attributes and references:
171         for name, value in elem.values.items():
172             try:
173                 elem.element.load(name, value)
174             except:
175                 log.error('Loading value %s (%s) for element %s failed.' % (name, value, elem.element))
176                 raise
177
178         for name, refids in elem.references.items():
179             if type(refids) == type([]):
180                 for refid in refids:
181                     try:
182                         ref = elements[refid]
183                     except:
184                         raise ValueError, 'Invalid ID for reference (%s) for element %s.%s' % (refid, elem.type, name)
185                     else:
186                         try:
187                             elem.element.load(name, ref.element)
188                         except:
189                             log.error('Loading %s.%s with value %s failed' % (type(elem.element).__name__, name, ref.element.id))
190                             raise
191             else:
192                 try:
193                     ref = elements[refids]
194                 except:
195                     raise ValueError, 'Invalid ID for reference (%s)' % refids
196                 else:
197                     try:
198                         elem.element.load(name, ref.element)
199                     except:
200                         log.error('Loading %s.%s with value %s failed' % (type(elem.element).__name__, name, ref.element.id))
201                         raise
202                
203     log.info('0% ... 33% ... 66%')
204
205     # do a postload:
206     for id, elem in elements.items():
207         elem.element.postload()
208
209     log.info('0% ... 33% ... 66% ... 100%')
210
211     factory.notify_model()
212
213 def load(filename, factory=None):
214     '''Load a file and create a model if possible.
215     Exceptions: GaphorError.'''
216     log.info('Loading file %s' % os.path.basename(filename))
217     try:
218         elements = parser.parse(filename) #dom.parse (filename)
219     except Exception, e:
220         print e
221         log.error('File could no be parsed')
222         raise
223         #raise GaphorError, 'File %s is probably no valid XML.' % filename
224
225     try:
226             # For some reason, loading the model in a temp. factory will
227         # cause DiaCanvas2 to keep a idle handler around... This should
228         # be fixed in DiaCanvas2 ASAP.
229         #factory = UML.ElementFactory()
230         #_load(doc, factory)
231         #gc.collect()
232         #factory.flush()
233         #del factory
234         #gc.collect()
235         #print '===================================== pre load succeeded =='
236         if not factory:
237             factory = gaphor.resource(UML.ElementFactory)
238         factory.flush()
239         gc.collect()
240         _load(elements, factory)
241         # DEBUG code:
242 #        print ''
243 #        print ''
244 #        print ''
245 #        for d in factory.select(lambda e: e.isKindOf(UML.Diagram)):
246 #            for i in d.canvas.root.children:
247 #                print i, i.__dict__
248         gc.collect()
249 #        for d in factory.select(lambda e: e.isKindOf(UML.Diagram)):
250 #            for i in d.canvas.root.children:
251 #                print i, i.__dict__
252 #                print '   ', i.get_property('id')
253
254     except Exception, e:
255         log.info('file %s could not be loaded' % filename)
256         import traceback
257         traceback.print_exc()
258         raise #GaphorError, 'Could not load file %s (%s)' % (filename, e)
259
260 def verify (filename):
261     """Try to load the file. If loading succeeded, this file is
262     probably a valid Gaphor file.
263     """
264     try:
265         doc = dom.parse (filename)
266     except Exception, e:
267         log.info('File %s is probably no valid XML.' % filename)
268         return False
269
270     factory = UML.ElementFactory()
271     try:
272         _load(doc, factory)
273     except Exception, e:
274         log.info('File %s could not be loaded' % filename)
275         return False
276
277     return True
Note: See TracBrowser for help on using the browser.