1
2 """
3 PureMVC Python Port by Toby de Havilland <toby.de.havilland@puremvc.org>
4 PureMVC Python Port by Daniele Esposti <expo@expobrain.net>
5 PureMVC - Copyright(c) 2006-08 Futurescale, Inc., Some rights reserved.
6 Your reuse is governed by the Creative Commons Attribution 3.0 License
7 """
8
9 from puremvc import MultitonError
10 import puremvc.interfaces
11 import puremvc.patterns.observer
12
13
14 -class Controller(puremvc.interfaces.IController):
15 """
16 A Multiton C{IController} implementation.
17
18 In PureMVC, the C{Controller} class follows the
19 'Command and Controller' strategy, and assumes these
20 responsibilities:
21
22 Remembering which C{ICommand}s
23 are intended to handle which C{INotifications}.
24
25 Registering itself as an C{IObserver} with
26 the C{View} for each C{INotification}
27 that it has an C{ICommand} mapping for.
28
29 Creating a new instance of the proper C{ICommand}
30 to handle a given C{INotification} when notified by the C{View}.
31
32 Calling the C{ICommand}'s C{execute}
33 method, passing in the C{INotification}.
34
35 Your application must register C{ICommands} with the
36 Controller.
37
38 The simplest way is to subclass C{Facade},
39 and use its C{initializeController} method to add your
40 registrations.
41
42 @see: L{View<puremvc.core.view.View>}
43 @see: L{Observer<puremvc.patterns.observer.Observer>}
44 @see: L{Notification<puremvc.patterns.observer.Notification>}
45 @see: L{SimpleCommand<puremvc.patterns.command.SimpleCommand>}
46 @see: L{MacroCommand<puremvc.patterns.command.MacroCommand>}
47 """
48
49 """Singleton instance"""
50 instanceMap = {}
51
52 """Multiton error message"""
53 MULTITON_MSG = ("Controller multiton instance for this key "
54 "is already constructed!")
55
56 @classmethod
58 """
59 Remove an IController instance
60
61 @param key: of IController instance to remove
62 """
63 cls.instanceMap.pop(key, None)
64
66 """
67 Constructor.
68
69 This C{IController} implementation is a Multiton, so you should not
70 call the constructor directly, but instead call the static Factory
71 method, passing the unique key for this instance
72 C{Controller.getInstance( multitonKey )}
73
74 @raise MultitonError: if instance for this Multiton key has already
75 been constructed
76 """
77
78 """Local reference to View"""
79 self.view = None
80
81 """Mapping of Notification names to Command Classes"""
82 self.commandMap = {}
83
84 """The Multiton Key for this Core"""
85 self.multitonKey = key
86
87 if self.instanceMap.get(key) is not None:
88 raise MultitonError(self.MULTITON_MSG)
89
90 self.instanceMap[key] = self
91
92 self.initializeController()
93
95 """
96 Initialize the Multiton C{Controller} instance.
97
98 Called automatically by the constructor.
99
100 Note that if you are using a subclass of C{View} in your application,
101 you should <i>also</i> subclass C{Controller} and override the
102 C{initializeController} method in the following way::
103
104 // ensure that the Controller is talking to my IView implementation
105 public function initializeController( ) : void
106 {
107 view = MyView.getInstance();
108 }
109
110 @return: void
111 """
112 self.view = View.getInstance(self.multitonKey)
113
114 @classmethod
116 """
117 C{Controller} Multiton Factory method.
118
119 @return: the Multiton instance of C{Controller}
120 """
121 if cls.instanceMap.get(key) is None:
122 cls.instanceMap[key] = Controller(key)
123
124 return cls.instanceMap[key]
125
127 """
128 If an C{ICommand} has previously been registered
129 to handle a the given C{INotification}, then it is executed.
130
131 @param note: an C{INotification}
132 """
133 commandClassRef = self.commandMap.get(note.getName())
134 if commandClassRef is None:
135 return
136
137 commandInstance = commandClassRef()
138
139 commandInstance.initializeNotifier(self.multitonKey)
140 commandInstance.execute(note)
141
143 """
144 Register a particular C{ICommand} class as the handler for a particular
145 C{INotification}.
146
147 If an C{ICommand} has already been registered to
148 handle C{INotification}s with this name, it is no longer
149 used, the new C{ICommand} is used instead.
150
151 The Observer for the new ICommand is only created if this the
152 first time an ICommand has been registered for this Notification name.
153
154 @param notificationName: the name of the C{INotification}
155 @param commandClassRef: the C{Class} of the C{ICommand}
156 """
157 if self.commandMap.get(notificationName) is None:
158 self.view.registerObserver(notificationName, puremvc.patterns.observer.Observer(self.executeCommand, self))
159
160 self.commandMap[notificationName] = commandClassRef
161
163 """
164 Check if a Command is registered for a given Notification
165
166 @param notificationName: the name of the C{INotification}
167 @return: whether a Command is currently registered for the given C{notificationName}.
168 """
169 return self.commandMap.get(notificationName) is not None
170
172 """
173 Remove a previously registered C{ICommand} to C{INotification} mapping.
174
175 @param notificationName: the name of the C{INotification} to remove the
176 C{ICommand} mapping for
177 """
178 if self.hasCommand(notificationName):
179 self.view.removeObserver(notificationName, self)
180 del self.commandMap[notificationName]
181
182
183 -class Model(puremvc.interfaces.IModel):
184 """
185 A Multiton C{IModel} implementation.
186
187 In PureMVC, the C{Model} class provides access to model objects (Proxies)
188 by named lookup.
189
190 The C{Model} assumes these responsibilities:
191
192 - Maintain a cache of C{IProxy} instances.
193 - Provide methods for registering, retrieving, and removing C{IProxy}
194 instances.
195
196 Your application must register C{IProxy} instances with the C{Model}.
197 Typically, you use an C{ICommand} to create and register C{IProxy}
198 instances once the C{Facade} has initialized the Core actors.
199
200 @see: L{Proxy<puremvc.patterns.proxy.Proxy>}
201 @see: L{IProxy<puremvc.interfaces.IProxy>}
202 """
203
204 """Singleton instance"""
205 instanceMap = {}
206
207 """Multiton error message"""
208 MULTITON_MSG = ("Model multiton instance for this key "
209 "is already constructed!")
210
211 @classmethod
213 """
214 Remove an IModel instance.
215
216 @param key: of IModel instance to remove
217 """
218 cls.instanceMap.pop(key, None)
219
220 @classmethod
222 """
223 C{Model} Multiton Factory method.
224
225 @return: the instance for this Multiton key
226 """
227 if cls.instanceMap.get(key) is None:
228 cls.instanceMap[key] = Model(key)
229
230 return cls.instanceMap[key]
231
233 """
234 Constructor.
235
236 This C{IModel} implementation is a Multiton, so you should not call the
237 constructor directly, but instead call the static Multiton Factory
238 method C{Model.getInstance( multitonKey )}
239
240 @raise MultitonError: if instance for this Multiton key instance has
241 already been constructed
242 """
243
244 """Mapping of proxyNames to IProxy instances"""
245 self.proxyMap = {}
246
247 """The Multiton Key for this Core"""
248 self.multitonKey = None
249
250 if self.instanceMap.get(key) is not None:
251 raise MultitonError(self.MULTITON_MSG)
252
253 self.multitonKey = key
254 self.instanceMap[key] = self
255 self.proxyMap = {}
256
257 self.initializeModel()
258
260 """
261 Initialize the C{Model} instance.
262
263 Called automatically by the constructor, this is your opportunity to
264 initialize the Singleton instance in your subclass without overriding
265 the constructor.
266 """
267 return
268
278
280 """
281 Retrieve an C{IProxy} from the C{Model}.
282
283 @param proxyName: the name of the C{IProxy}
284 @return: the C{IProxy} instance previously registered with the given C{proxyName}.
285 """
286 return self.proxyMap.get(proxyName)
287
289 """
290 Check if a Proxy is registered
291
292 @param proxyName: the name of the C{IProxy}
293 @return: whether a Proxy is currently registered with the given C{proxyName}.
294 """
295 return self.proxyMap.get(proxyName) is not None
296
298 """
299 Remove an C{IProxy} from the C{Model}.
300
301 @param proxyName: name of the C{IProxy} instance to be removed.
302 @return: the C{IProxy} that was removed from the C{Model}
303 """
304 proxy = self.proxyMap.get(proxyName)
305 if proxy:
306 del self.proxyMap[proxyName]
307 proxy.onRemove()
308 return proxy
309
310
311 -class View(puremvc.interfaces.IView):
312 """
313 A Multiton C{IView} implementation.
314
315 In PureMVC, the C{View} class assumes these responsibilities:
316
317 Maintain a cache of C{IMediator} instances.
318
319 Provide methods for registering, retrieving, and removing C{IMediators}.
320
321 Notifiying C{IMediators} when they are registered or removed.
322
323 Managing the observer lists for each C{INotification} in the application.
324
325 Providing a method for attaching C{IObservers} to an C{INotification}'s observer list.
326
327 Providing a method for broadcasting an C{INotification}.
328
329 Notifying the C{IObservers} of a given C{INotification} when it broadcast.
330
331
332 @see: L{Mediator<puremvc.patterns.mediator.Mediator>}
333 @see: L{Observer<puremvc.patterns.observer.Observer>}
334 @see: L{Notification<puremvc.patterns.observer.Notification>}
335 """
336
337 """Singleton instance"""
338 instanceMap = {}
339
340 """Multiton error message"""
341 MULTITON_MSG = ("View multiton instance for this key "
342 "is already constructed!")
343
345 """
346 Constructor.
347
348 This C{IView} implementation is a Multiton, so you should not call the
349 constructor directly, but instead call the static Multiton Factory
350 method C{View.getInstance( multitonKey )}
351
352 @raise MultitonError: if instance for this Multiton key has already
353 been constructed
354 """
355
356 """Mapping of Mediator names to Mediator instances"""
357 self.mediatorMap = {}
358
359 """Mapping of Notification names to Observer lists"""
360 self.observerMap = {}
361
362 """The Multiton Key for this Core"""
363 self.multitonKey = key
364
365 if self.instanceMap.get(key) is not None:
366 raise MultitonError(self.MULTITON_MSG)
367
368 self.instanceMap[key] = self
369 self.mediatorMap = {}
370 self.observerMap = {}
371
372 self.initializeView()
373
375 """
376 Initialize the Singleton C{View} instance.
377
378 Called automatically by the constructor, this is your opportunity to
379 initialize the Singleton instance in your subclass without overriding
380 the constructor.
381 """
382 pass
383
384 @classmethod
386 """
387 C{View} Singleton Factory method.
388
389 @return: the Singleton instance of C{View}
390 """
391 if cls.instanceMap.get(key) is None:
392 cls.instanceMap[key] = View(key)
393
394 return cls.instanceMap[key]
395
397 """
398 Register an C{IObserver} to be notified
399 of C{INotifications} with a given name.
400
401 @param notificationName: the name of the C{INotifications} to notify this C{IObserver} of
402 @param observer: the C{IObserver} to register
403 """
404 if not notificationName in self.observerMap:
405 self.observerMap[notificationName] = []
406 self.observerMap[notificationName].append(observer)
407
409 """
410 Notify the C{IObservers} for a particular C{INotification}.
411
412 All previously attached C{IObservers} for this C{INotification}'s
413 list are notified and are passed a reference to the C{INotification} in
414 the order in which they were registered.
415
416 @param notification: the C{INotification} to notify C{IObservers} of.
417 """
418
419 observerRefs = self.observerMap.get(notification.getName())
420
421 if observerRefs:
422
423
424
425 for observer in observerRefs[:]:
426 observer.notifyObserver(notification)
427
429 """
430 Remove the observer for a given notifyContext from an observer list for a given Notification name.
431
432 @param notificationName: which observer list to remove from
433 @param notifyContext: remove the observer with this object as its notifyContext
434 """
435 if notificationName in self.observerMap:
436
437 observers = self.observerMap[notificationName]
438
439
440 for i, observer in enumerate(observers):
441 if observer.compareNotifyContext(notifyContext):
442
443
444 del observers[i]
445 break
446
447
448
449 if len(observers) == 0:
450 del self.observerMap[notificationName]
451
495
504
530
539
540 @classmethod
542 """
543 Remove an IView instance
544
545 @param key: of IView instance to remove
546 """
547 cls.instanceMap.pop(key, None)
548