root/gaphor/tags/gaphor-0.12.0/gaphor/UML/element.py

Revision 2101, 4.7 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 #!/usr/bin/env python
2 # vim:sw=4:et
3 """
4 Base class for UML model elements.
5 """
6
7 __all__ = [ 'Element' ]
8
9 import types, mutex
10 from zope import component
11 from event import ElementDeleteEvent
12 from gaphor.misc import uniqueid
13 from properties import umlproperty, association
14
15 class Element(object):
16     """
17     Base class for UML data classes.
18     """
19
20     def __init__(self, id=None, factory=None):
21         self._id = id or uniqueid.generate_id()
22         # The factory this element belongs to.
23         self._factory = factory
24         self._observers = dict()
25         self.__in_unlink = mutex.mutex()
26
27     id = property(lambda self: self._id, doc='Id')
28
29     factory = property(lambda self: self._factory,
30                        doc="The factory that created this element")
31
32     def umlproperties(self):
33         """
34         Iterate over all UML properties
35         """
36         umlprop = umlproperty
37         class_ = type(self)
38         for propname in dir(class_):
39             if not propname.startswith('_'):
40                 prop = getattr(class_, propname)
41                 if isinstance(prop, umlprop):
42                     yield prop
43
44     # TODO: move save/load code to adapters
45     def save(self, save_func):
46         """
47         Save the state by calling save_func(name, value).
48         """
49         for prop in self.umlproperties():
50             prop.save(self, save_func)
51
52     def load(self, name, value):
53         """
54         Loads value in name. Make sure that for every load postload()
55         should be called.
56         """
57         try:
58             prop = getattr(type(self), name)
59         except AttributeError, e:
60             raise AttributeError, "'%s' has no property '%s'" % \
61                                         (type(self).__name__, name)
62         else:
63             prop.load(self, value)
64
65     def postload(self):
66         """
67         Fix up the odds and ends.
68         """
69         for prop in self.umlproperties():
70             prop.postload(self)
71
72     def unlink(self):
73         """
74         Unlink the element. All the elements references are destroyed.
75         """
76         # Uses a mutex to make sure it is not called recursively
77         if self.__in_unlink.testandset():
78             component.handle(ElementDeleteEvent(self._factory, self))
79             try:
80                 for prop in self.umlproperties():
81                     prop.unlink(self)
82                 self.notify('__unlink__')
83             finally:
84                 self.__in_unlink.unlock()
85
86     def connect(self, names, callback, *data):
87         """
88         Attach 'callback' to a list of names. Names may also be a string.
89         A name is the name of a property of the object or '__unlink__'.
90
91         Obsolete. Connect to the appropriate change event (see event.py)
92         """
93         #log.debug('Element.connect(%s, %s, %s)' % (names, callback, data))
94         if type(names) is types.StringType:
95             names = (names,)
96         cb = (callback,) + data
97         for name in names:
98             self._observers.setdefault(name, []).append(cb)
99
100     def disconnect(self, callback, *data):
101         """
102         Detach a callback identified by it's data.
103
104         Obsolete. Connect to the appropriate change event (see event.py)
105         """
106         cb = (callback,) + data
107         for values in self._observers.values():
108             # Remove all occurences of 'cb' from values
109             # (if none is found ValueError is raised).
110             try:
111                 while True:
112                     values.remove(cb)
113             except ValueError:
114                 pass
115
116     def notify(self, name, pspec=None):
117         """
118         Send notification to attached callbacks that a property
119         has changed.
120
121         Obsolete. Connect to the appropriate change event (see event.py)
122         """
123         cb_list = self._observers.get(name, ())
124         #log.debug('Element.notify: %s' % cb_list)
125         if not pspec:
126             try:
127                 pspec = getattr(type(self), name)
128             except AttributeError:
129                 pspec = name
130        
131         # Use a copy of the list to ensure all items are notified
132         for cb_data in list(cb_list):
133             try:
134                 apply(cb_data[0], (self, pspec) + cb_data[1:])
135             except Exception, e:
136                 log.error('failed notification for %s' % cb_data[0], e)
137
138     # OCL methods: (from SMW by Ivan Porres (http://www.abo.fi/~iporres/smw))
139
140     def isKindOf(self, class_):
141         """
142         Returns true if the object is an instance of class_.
143         """
144         return isinstance(self, class_)
145
146     def isTypeOf(self, other):
147         """
148         Returns true if the object is of the same type as other.
149         """
150         return type(self) == type(other)
151
152
153 try:
154     import psyco
155 except ImportError:
156     pass
157 else:
158     psyco.bind(Element)
159
Note: See TracBrowser for help on using the browser.