root/gaphor/tags/gaphor-0.13.0/gaphor/application.py

Revision 2207, 7.0 kB (checked in by arj..@yirdis.nl, 1 year ago)

Fixed bug where items remained in the elementfactory after a shutdown()

Line 
1 """
2 The Application object. One application should be available.
3
4 All important services are present in the application object:
5  - plugin manager
6  - undo manager
7  - main window
8  - UML element factory
9  - action sets
10 """
11
12 import pkg_resources
13 from zope import component
14 from gaphor.interfaces import IService, IEventFilter
15 from gaphor.event import ServiceInitializedEvent, ServiceShutdownEvent
16 import gaphor.UML
17
18
19 class _Application(object):
20     """
21     The Gaphor application is started from the Application instance. It behaves
22     like a singleton in many ways.
23
24     The Application is responsible for loading services and plugins. Services
25     are registered as "utilities" in the application registry.
26
27     Methods are provided that wrap zope.component's handle, adapter and
28     subscription registrations. In addition to registration methods also
29     unregister methods are provided. This way services can be properly
30     unregistered on shutdown for example.
31     """
32
33     # interface.implements(IApplication)
34    
35     def __init__(self):
36         self._uninitialized_services = {}
37         self.init_components()
38         self._event_filter = None
39
40     def init(self, services=None):
41         """
42         Initialize the application.
43         """
44         self.load_services(services)
45         self.init_all_services()
46
47     def init_components(self):
48         """
49         Initialize application level component registry.
50
51         Frequently used query methods are overridden on the zope.component
52         module.
53         """
54         #self._components = component.getGlobalSiteManager()
55         #return
56
57         self._components = component.registry.Components(name='app',
58                                bases=(component.getGlobalSiteManager(),))
59
60         # Make sure component.handle() and query methods works.
61         # TODO: eventually all queries should be done through the Application
62         # instance.
63         component.handle = self.handle
64         component.getMultiAdapter = self._components.getMultiAdapter
65         component.queryMultiAdapter = self._components.queryMultiAdapter
66         component.getAdapter = self._components.getAdapter
67         component.queryAdapter = self._components.queryAdapter
68         component.getAdapters = self._components.getAdapters
69         component.getUtility = self._components.getUtility
70         component.queryUtility = self._components.queryUtility
71         component.getUtilitiesFor = self._components.getUtilitiesFor
72
73     def load_services(self, services=None):
74         """
75         Load services from resources.
76
77         Services are registered as utilities in zope.component.
78         Service should provide an interface gaphor.interfaces.IService.
79         """
80         for ep in pkg_resources.iter_entry_points('gaphor.services'):
81             log.debug('found entry point service.%s' % ep.name)
82             cls = ep.load()
83             if not IService.implementedBy(cls):
84                 raise 'MisConfigurationException', 'Entry point %s doesn''t provide IService' % ep.name
85             if services is None or ep.name in services:
86                 srv = cls()
87                 self._uninitialized_services[ep.name] = srv
88
89     def init_all_services(self):
90         while self._uninitialized_services:
91             self.init_service(self._uninitialized_services.iterkeys().next())
92
93     def init_service(self, name):
94         """
95         Initialize a not yet initialized service.
96
97         Raises ComponentLookupError if the service has nor been found
98         """
99         try:
100             srv = self._uninitialized_services.pop(name)
101         except KeyError:
102             raise component.ComponentLookupError(IService, name)
103         else:
104             log.info('initializing service service.%s' % name)
105             srv.init(self)
106             self._components.registerUtility(srv, IService, name)
107             self.handle(ServiceInitializedEvent(name, srv))
108             return srv
109
110     distribution = property(lambda s: pkg_resources.get_distribution('gaphor'),
111                             doc='Get the PkgResources distribution for Gaphor')
112
113     def get_service(self, name):
114         try:
115             return self._components.getUtility(IService, name)
116         except component.ComponentLookupError:
117             return self.init_service(name)
118
119     def run(self):
120         import gtk
121         gtk.main()
122
123     def shutdown(self):
124         for name, srv in self._components.getUtilitiesFor(IService):
125             srv.shutdown()
126             self.handle(ServiceShutdownEvent(name, srv))
127             self._components.unregisterUtility(srv, IService, name)
128
129         # Re-initialize components registry
130         self.init_components()
131
132     # Wrap zope.component's Components methods
133
134     def register_adapter(self, factory, adapts=None, provides=None, name=''):
135         """
136         Register an adapter (factory) that adapts objects to a specific
137         interface. A name can be used to distinguish between different adapters
138         that adapt to the same interfaces.
139         """
140         self._components.registerAdapter(factory, adapts, provides,
141                               name, event=False)
142
143     def unregister_adapter(self, factory=None,
144                           required=None, provided=None, name=u''):
145         """
146         Unregister a previously registered adapter.
147         """
148         self._components.unregisterAdapter(factory,
149                               required, provided, name)
150
151     def register_subscription_adapter(self, factory, adapts=None, provides=None):
152         """
153         Register a subscription adapter. See registerAdapter().
154         """
155         self._components.registerSubscriptionAdapter(factory, adapts,
156                               provides, event=False)
157
158     def unregister_subscription_adapter(self, factory=None,
159                           required=None, provided=None, name=u''):
160         """
161         Unregister a previously registered subscription adapter.
162         """
163         self._components.unregisterSubscriptionAdapter(factory,
164                               required, provided, name)
165
166     def register_handler(self, factory, adapts=None):
167         """
168         Register a handler. Handlers are triggered (executed) when specific
169         events are emitted through the handle() method.
170         """
171         self._components.registerHandler(factory, adapts, event=False)
172
173     def unregister_handler(self, factory=None, required=None):
174         """
175         Unregister a previously registered handler.
176         """
177         self._components.unregisterHandler(factory, required)
178  
179     def _filter(self, objects):
180         filtered = list(objects)
181         for o in objects:
182             for adapter in self._components.subscribers(objects, IEventFilter):
183                 if adapter.filter():
184                     # event is blocked
185                     filtered.remove(o)
186                     break
187         return filtered
188
189     def handle(self, *events):
190         """
191         Send event notifications to registered handlers.
192         """
193         objects = self._filter(events)
194         if objects:
195             self._components.handle(*events)
196
197
198 # Make sure there is only one!
199 Application = _Application()
200
201 # vim:sw=4:et:ai
Note: See TracBrowser for help on using the browser.