root/gaphor/tags/gaphor-0.12.5/gaphor/UML/elementfactory.py

Revision 2101, 5.1 kB (checked in by arj..@yirdis.nl, 1 year ago)
  • send flush event before actual flush.
  • simplified obsolete Element.notify.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 # vim: sw=4
2 """
3 Factory for and registration of model elements.
4 """
5
6 from zope import interface
7 from zope import component
8 from gaphor.misc import uniqueid, odict
9 from gaphor.UML.element import Element
10 from gaphor.UML.diagram import Diagram
11 from gaphor.UML.interfaces import IElementCreateEvent, IElementDeleteEvent, \
12                                   IFlushFactoryEvent, IModelFactoryEvent, \
13                                   IService
14 from gaphor.UML.event import ElementCreateEvent, ElementDeleteEvent, \
15                              FlushFactoryEvent, ModelFactoryEvent
16
17
18 class ElementFactory(object):
19     """
20     The ElementFactory is used to create elements and do lookups to
21     elements.
22
23     Notifications are send with as arguments (name, element, *user_data).
24     The following names are used:
25     create - a new model element is created (element is newly created element)
26     remove - a model element is removed (element is to be removed element)
27     model - a new model has been loaded (element is None)
28     flush - model is flushed: all element are removed from the factory
29             (element is None)
30     """
31     interface.implements(IService)
32
33     def __init__(self):
34         self._elements = odict.odict()
35         self._observers = list()
36
37     def init(self, app):
38         component.provideHandler(self._element_unlinked)
39
40     def shutdown(self):
41         self.flush()
42
43     def create(self, type):
44         """
45         Create a new model element of type type.
46         """
47         obj = self.create_as(type, uniqueid.generate_id())
48         component.handle(ElementCreateEvent(self, obj))
49         return obj
50
51     def create_as(self, type, id):
52         """
53         Create a new model element of type 'type' with 'id' as its ID.
54         This method should only be used when loading models, since it does
55         not emit an ElementCreateEvent event.
56         """
57         assert issubclass(type, Element)
58         obj = type(id, self)
59         self._elements[id] = obj
60         return obj
61
62     def size(self):
63         """
64         Return the amount of elements currently in the factory.
65         """
66         return len(self._elements)
67
68     def lookup(self, id):
69         """
70         Find element with a specific id.
71         """
72         return self._elements.get(id)
73
74     __getitem__ = lookup
75
76     def __contains__(self, element):
77         return self.lookup(element.id) is element
78
79     def select(self, expression=None):
80         """
81         Iterate elements that comply with expression.
82         """
83         if expression is None:
84             for e in self._elements.itervalues():
85                 yield e
86         else:
87             for e in self._elements.itervalues():
88                 if expression(e):
89                     yield e
90
91     def lselect(self, expression=None):
92         """
93         Like select(), but returns a list.
94         """
95         return list(self.select(expression))
96
97     def keys(self):
98         """
99         Return a list with all id's in the factory.
100         """
101         return self._elements.keys()
102
103     def iterkeys(self):
104         """
105         Return a iterator with all id's in the factory.
106         """
107         return self._elements.iterkeys()
108
109     def values(self):
110         """
111         Return a list with all elements in the factory.
112         """
113         return self._elements.values()
114
115     def itervalues(self):
116         """
117         Return a iterator with all elements in the factory.
118         """
119         return self._elements.itervalues()
120
121     def is_empty(self):
122         """
123         Returns True if the factory holds no elements.
124         """
125         if self._elements:
126             return False
127         else:
128             return True
129
130     def flush(self):
131         """
132         Flush all elements (remove them from the factory).
133         """
134         component.handle(FlushFactoryEvent(self))
135
136         # First flush all diagrams:
137         for value in list(self.select(lambda e: isinstance(e, Diagram))):
138             # Make sure no updates happen while destroying the canvas
139             value.canvas.block_updates = True
140             value.unlink()
141
142         for key, value in self._elements.items():
143             #print 'ElementFactory: unlinking', value
144             #print 'references:', gc.get_referrers(value)
145             value.unlink()
146
147         assert len(self._elements) == 0, 'Still items in the factory: %s' % str(self._elements.values())
148
149         # Force Garbage collection, so memory allocated by items is freed.
150         import gc
151         for i in range(4): gc.collect()
152
153
154     def swap_element(self, element, new_class):
155         assert element in self._elements.values()
156         if element.__class__ is not new_class:
157             element.__class__ = new_class
158
159     def notify_model(self):
160         """
161         Send notification that a new model has been loaded by means of the
162         ModelFactoryEvent event from gaphor.UML.event.
163         """
164         component.handle(ModelFactoryEvent(self))
165
166     @component.adapter(ElementDeleteEvent)
167     def _element_unlinked(self, event):
168         """
169         Remove an element from the factory.
170         """
171         element = event.element
172         if self._elements.has_key(element.id):
173             del self._elements[element.id]
174
175
176 # vim:sw=4:et
Note: See TracBrowser for help on using the browser.