Package puremvc :: Module core
[hide private]
[frames] | no frames]

Source Code for Module puremvc.core

  1  # -*- coding: utf-8 -*- 
  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
57 - def removeController(cls, key):
58 """ 59 Remove an IController instance 60 61 @param key: of IController instance to remove 62 """ 63 cls.instanceMap.pop(key, None)
64
65 - def __init__(self, key):
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
94 - def initializeController(self):
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
115 - def getInstance(cls, key):
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
126 - def executeCommand(self, note):
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
142 - def registerCommand(self, notificationName, commandClassRef):
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
162 - def hasCommand(self, notificationName):
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
171 - def removeCommand(self, notificationName):
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
212 - def removeModel(cls, key):
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
221 - def getInstance(cls, key):
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
232 - def __init__(self, key):
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
259 - def initializeModel(self):
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
269 - def registerProxy(self, proxy):
270 """ 271 Register an C{IProxy} with the C{Model}. 272 273 @param proxy: an C{IProxy} to be held by the C{Model}. 274 """ 275 proxy.initializeNotifier(self.multitonKey) 276 self.proxyMap[proxy.getProxyName()] = proxy 277 proxy.onRegister()
278
279 - def retrieveProxy(self, proxyName):
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
288 - def hasProxy(self, proxyName):
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
297 - def removeProxy(self, proxyName):
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
344 - def __init__(self, key):
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
374 - def initializeView(self):
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
385 - def getInstance(cls, key):
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
396 - def registerObserver(self, notificationName, observer):
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
408 - def notifyObservers(self, notification):
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 # Get a reference to the observers list for this notification name 419 observerRefs = self.observerMap.get(notification.getName()) 420 421 if observerRefs: 422 # Notify observers from the working copy 423 # Use a list's copy to avoid problems if the list content changes 424 # inside the loop iteration 425 for observer in observerRefs[:]: 426 observer.notifyObserver(notification)
427
428 - def removeObserver(self, notificationName, notifyContext):
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 # Get observer list for the notification under inspection 437 observers = self.observerMap[notificationName] 438 439 # Find the observer for the notifyContext 440 for i, observer in enumerate(observers): 441 if observer.compareNotifyContext(notifyContext): 442 # There can only be one bserver for a given notifyContext 443 # in any given Observer list, so remove it and break 444 del observers[i] 445 break 446 447 # Also, when a Notification's Observer list length falls to 448 # zero, delete the notification key from the observer map 449 if len(observers) == 0: 450 del self.observerMap[notificationName]
451
452 - def registerMediator(self, mediator):
453 """ 454 Register an C{IMediator} instance with the C{View}. 455 456 Registers the C{IMediator} so that it can be retrieved by name, 457 and further interrogates the C{IMediator} for its 458 C{INotification} interests. 459 460 If the C{IMediator} returns any C{INotification} 461 names to be notified about, an C{Observer} is created encapsulating 462 the C{IMediator} instance's C{handleNotification} method 463 and registering it as an C{Observer} for all C{INotifications} the 464 C{IMediator} is interested in. 465 466 @param mediator: a reference to the C{IMediator} instance 467 """ 468 # Do not allow re-registration (you must to removeMediator first) 469 name = mediator.getMediatorName() 470 471 if self.mediatorMap.get(name): 472 return 473 474 mediator.initializeNotifier(self.multitonKey) 475 476 # Register the Mediator for retrieval by name 477 self.mediatorMap[name] = mediator 478 479 # Get notification interests, if any 480 interests = mediator.listNotificationInterests() 481 482 # Register Mediator as an observer for each notification of interests 483 if interests: 484 # Create Observer referencing this mediator's 485 # handleNotification method 486 observer = puremvc.patterns.observer.Observer( 487 mediator.handleNotification, mediator) 488 489 # Register Mediator as Observer for its list interests 490 for interest in interests: 491 self.registerObserver(interest, observer) 492 493 # Alert the Mediator that it has been registered 494 mediator.onRegister()
495
496 - def retrieveMediator(self, mediatorName):
497 """ 498 Retrieve an C{IMediator} from the C{View}. 499 500 @param mediatorName: the name of the C{IMediator} instance to retrieve. 501 @return: the C{IMediator} instance previously registered with the given C{mediatorName}. 502 """ 503 return self.mediatorMap.get(mediatorName)
504
505 - def removeMediator(self, mediatorName):
506 """ 507 Remove an C{IMediator} from the C{View}. 508 509 @param mediatorName: name of the C{IMediator} instance to be removed. 510 @return: the C{IMediator} that was removed from the C{View} 511 """ 512 mediator = self.mediatorMap.get(mediatorName) 513 514 if mediator: 515 # For every notification this mediator is interested in... 516 interests = mediator.listNotificationInterests() 517 518 for interest in interests: 519 # Remove the observer linking the mediator 520 # to the notification interest 521 self.removeObserver(interest, mediator) 522 523 # Remove the mediator from the map 524 del self.mediatorMap[mediatorName] 525 526 # Alert the mediator that it has been removed 527 mediator.onRemove() 528 529 return mediator
530
531 - def hasMediator(self, mediatorName):
532 """ 533 Check if a Mediator is registered or not 534 535 @param mediatorName: the name of the C{IMediator} 536 @return: whether a Mediator is registered with the given C{mediatorName}. 537 """ 538 return self.mediatorMap.get(mediatorName) is not None
539 540 @classmethod
541 - def removeView(cls, key):
542 """ 543 Remove an IView instance 544 545 @param key: of IView instance to remove 546 """ 547 cls.instanceMap.pop(key, None)
548