Package muntjac :: Module application
[hide private]
[frames] | no frames]

Source Code for Module muntjac.application

   1  # Copyright (C) 2012 Vaadin Ltd.  
   2  # Copyright (C) 2012 Richard Lincoln 
   3  #  
   4  # Licensed under the Apache License, Version 2.0 (the "License");  
   5  # you may not use this file except in compliance with the License.  
   6  # You may obtain a copy of the License at  
   7  #  
   8  #     http://www.apache.org/licenses/LICENSE-2.0  
   9  #  
  10  # Unless required by applicable law or agreed to in writing, software  
  11  # distributed under the License is distributed on an "AS IS" BASIS,  
  12  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
  13  # See the License for the specific language governing permissions and  
  14  # limitations under the License. 
  15   
  16  """Defines a base class required for all Muntjac applications.""" 
  17   
  18  import sys 
  19  import traceback 
  20  import logging 
  21   
  22  from warnings import warn 
  23   
  24  from muntjac.util import EventObject, IEventListener, defaultLocale 
  25  from muntjac.terminal.uri_handler import IUriHandler 
  26  from muntjac.terminal.sys_error import SysError 
  27  from muntjac.terminal.terminal import IErrorListener, ITerminal 
  28  from muntjac.terminal.parameter_handler import IErrorEvent 
  29  from muntjac.terminal.error_message import IErrorMessage 
  30  from muntjac.terminal.variable_owner import IErrorEvent as VariableOwnerErrorEvent 
  31  from muntjac.terminal.uri_handler import IErrorEvent as URIHandlerErrorEvent 
  32  from muntjac.terminal.parameter_handler import IErrorEvent as ParameterHandlerErrorEvent 
  33  from muntjac.terminal.gwt.server.change_variables_error_event import ChangeVariablesErrorEvent 
  34  from muntjac.ui.abstract_component import AbstractComponent 
  35  from muntjac.ui.window import Window 
  36  from muntjac.messages import SystemMessages 
  37   
  38   
  39  logger = logging.getLogger(__name__) 
40 41 42 -class Application(IUriHandler, ITerminal, IErrorListener):
43 """Base class required for all Muntjac applications. This class provides 44 all the basic services required by Muntjac. These services allow external 45 discovery and manipulation of the user, L{com.vaadin.ui.Window windows} and 46 themes, and starting and stopping the application. 47 48 As mentioned, all Muntjac applications must inherit this class. However, 49 this is almost all of what one needs to do to create a fully functional 50 application. The only thing a class inheriting the C{Application} 51 needs to do is implement the C{init} method where it creates the 52 windows it needs to perform its function. Note that all applications must 53 have at least one window: the main window. The first unnamed window 54 constructed by an application automatically becomes the main window which 55 behaves just like other windows with one exception: when accessing windows 56 using URLs the main window corresponds to the application URL whereas other 57 windows correspond to a URL gotten by catenating the window's name to the 58 application URL. 59 60 See the class C{muntjac.demo.HelloWorld} for a simple example of 61 a fully working application. 62 63 B{Window access.} C{Application} provides methods to 64 list, add and remove the windows it contains. 65 66 B{Execution control.} This class includes method to start and finish the 67 execution of the application. Being finished means basically that no 68 windows will be available from the application anymore. 69 70 B{Theme selection.} The theme selection process allows a theme to be 71 specified at three different levels. When a window's theme needs to be 72 found out, the window itself is queried for a preferred theme. If the 73 window does not prefer a specific theme, the application containing the 74 window is queried. If neither the application prefers a theme, the default 75 theme for the L{terminal<muntjac.terminal.terminal.ITerminal>} is used. The 76 terminal always defines a default theme. 77 78 @author: Vaadin Ltd. 79 @author: Richard Lincoln 80 @version: 1.1.2 81 """ 82 83 #: The default SystemMessages (read-only). Change by overriding 84 # getSystemMessages() and returning CustomizedSystemMessages 85 _DEFAULT_SYSTEM_MESSAGES = SystemMessages() 86 87
88 - def __init__(self):
89 90 #: Id use for the next window that is opened. Access to this must be 91 # synchronized. 92 self._nextWindowId = 1 93 94 #: Application context the application is running in. 95 self._context = None 96 97 #: The current user or C{None} if no user has logged in. 98 self._user = None 99 100 #: Mapping from window name to window instance. 101 self._windows = dict() 102 103 #: Main window of the application. 104 self._mainWindow = None 105 106 #: The application's URL. 107 self._applicationUrl = None 108 109 #: Name of the theme currently used by the application. 110 self.theme = None 111 112 #: Application status. 113 self._applicationIsRunning = False 114 115 #: Application properties. 116 self._properties = dict 117 118 #: Default locale of the application. 119 self._locale = None 120 121 #: List of listeners listening user changes. 122 self._userChangeListeners = list() 123 124 self._userChangeCallbacks = dict() 125 126 #: Window attach listeners. 127 self._windowAttachListeners = list() 128 129 self._windowAttachCallbacks = dict() 130 131 #: Window detach listeners. 132 self._windowDetachListeners = list() 133 134 self._windowDetachCallbacks = dict() 135 136 #: Application resource mapping: key <-> resource. 137 self._resourceKeyMap = dict() 138 self._keyResourceMap = dict() 139 self._lastResourceKeyNumber = 0 140 141 #: URL where the user is redirected to on application close, or null if 142 # application is just closed without redirection. 143 self._logoutURL = None 144 145 #: Application wide error handler which is used by default if an error 146 # is left unhandled. 147 self._errorHandler = self
148 149
150 - def getWindow(self, name):
151 """Gets a window by name. Returns C{None} if the application is 152 not running or it does not contain a window corresponding to the name. 153 154 All windows can be referenced by their names in url 155 C{http://host:port/foo/bar/} where 156 C{http://host:port/foo/} is the application url as returned by 157 getURL() and C{bar} is the name of the window. 158 159 One should note that this method can, as a side effect create new 160 windows if needed by the application. This can be achieved by 161 overriding the default implementation. 162 163 If for some reason user opens another window with same url that is 164 already open, name is modified by adding "_12345678" postfix to the 165 name, where 12345678 is a random number. One can decide to create 166 another window-object for those windows (recommended) or to discard 167 the postfix. If the user has two browser windows pointing to the same 168 window-object on server, synchronization errors are likely to occur. 169 170 If no browser-level windowing is used, all defaults are fine and this 171 method can be left as is. In case browser-level windows are needed, it 172 is recommended to create new window-objects on this method from their 173 names if the super.getWindow() does not find existing windows. See 174 below for implementation example:: 175 176 # If we already have the requested window, use it 177 w = super(Application, self).getWindow(name) 178 if w == None: 179 # If no window found, create it 180 w = Window(name) 181 # set windows name to the one requested 182 w.setName(name) 183 # add it to this application 184 addWindow(w) 185 # ensure use of window specific url 186 w.open( ExternalResource(w.getURL()) ) 187 # add some content 188 w.addComponent( Label("Test window") ) 189 190 return w 191 192 B{Note} that all returned Window objects must be added to 193 this application instance. 194 195 The method should return null if the window does not exists (and is not 196 created as a side-effect) or if the application is not running anymore. 197 198 @param name: 199 the name of the window. 200 @return: the window associated with the given URI or C{None} 201 """ 202 # For closed app, do not give any windows 203 if not self.isRunning(): 204 return None 205 206 # Gets the window by name 207 return self._windows.get(name)
208 209
210 - def addWindow(self, window):
211 """Adds a new window to the application. 212 213 This implicitly invokes the L{Window.setApplication} method. 214 215 Note that all application-level windows can be accessed by their names 216 in url C{http://host:port/foo/bar/} where C{http://host:port/foo/} is 217 the application url as returned by getURL() and C{bar} is the name of 218 the window. Also note that not all windows should be added to 219 application - one can also add windows inside other windows - these 220 windows show as smaller windows inside those windows. 221 222 @param window: 223 the new C{Window} to add. If the name of the window 224 is C{None}, an unique name is automatically given 225 for the window. 226 @raise ValueError: 227 if a window with the same name as the new window already 228 exists in the application. 229 @raise ValueError: 230 if the given C{Window} is C{None}. 231 """ 232 # Nulls can not be added to application 233 if window is None: 234 return 235 236 # Check that one is not adding a sub-window to application 237 if window.getParent() is not None: 238 raise ValueError('Window was already added inside another window' 239 + ' - it can not be added to application also.') 240 241 # Gets the naming proposal from window 242 name = window.getName() 243 244 # Checks that the application does not already contain 245 # window having the same name 246 if name is not None and name in self._windows: 247 248 # If the window is already added 249 if window == self._windows[name]: 250 return 251 252 # Otherwise complain 253 raise ValueError('Window with name \'' + window.getName() 254 + '\' is already present in the application') 255 256 # If the name of the window is null, the window is automatically named 257 if name is None: 258 accepted = False 259 while not accepted: 260 261 # Try another name 262 name = str(self._nextWindowId) 263 self._nextWindowId += 1 264 265 if not (name in self._windows): 266 accepted = True 267 268 window.setName(name) 269 270 # Adds the window to application 271 self._windows[name] = window 272 window.setApplication(self) 273 274 self._fireWindowAttachEvent(window) 275 276 # If no main window is set, declare the window to be main window 277 if self.getMainWindow() is None: 278 self._mainWindow = window
279 280
281 - def _fireWindowAttachEvent(self, window):
282 """Send information to all listeners about new Windows associated with 283 this application. 284 """ 285 # Fires the window attach event 286 event = WindowAttachEvent(window) 287 for l in self._windowAttachListeners: 288 l.windowAttached(event) 289 290 for callback, args in self._windowAttachCallbacks: 291 callback(event, *args)
292 293
294 - def removeWindow(self, window):
295 """Removes the specified window from the application. 296 297 Removing the main window of the Application also sets the main window 298 to null. One must another window to be the main window after this with 299 L{setMainWindow}. 300 301 Note that removing window from the application does not close the 302 browser window - the window is only removed from the server-side. 303 304 @param window: 305 the window to be removed. 306 """ 307 if window is not None and window in self._windows.values(): 308 309 # Removes the window from application 310 del self._windows[window.getName()] 311 312 # If the window was main window, clear it 313 if self.getMainWindow() == window: 314 self.setMainWindow(None) 315 316 # Removes the application from window 317 if window.getApplication() == self: 318 window.setApplication(None) 319 320 self._fireWindowDetachEvent(window)
321 322
323 - def _fireWindowDetachEvent(self, window):
324 # Fires the window detach event 325 event = WindowDetachEvent(window) 326 for l in self._windowDetachListeners: 327 l.windowDetached(event) 328 329 for callback, args in self._windowDetachCallbacks: 330 callback(event, *args)
331 332
333 - def getUser(self):
334 """Gets the user of the application. 335 336 Muntjac doesn't define of use user object in any way - it only provides 337 this getter and setter methods for convenience. The user is any object 338 that has been stored to the application with L{setUser}. 339 340 @return: the user of the application. 341 """ 342 return self._user
343 344
345 - def setUser(self, user):
346 """Sets the user of the application instance. An application instance 347 may have a user associated to it. This can be set in login procedure or 348 application initialization. 349 350 A component performing the user login procedure can assign the user 351 property of the application and make the user object available to other 352 components of the application. 353 354 Muntjac doesn't define of use user object in any way - it only provides 355 getter and setter methods for convenience. The user reference stored to 356 the application can be read with L{getUser}. 357 358 @param user: 359 the new user. 360 """ 361 prevUser = self._user 362 if (user == prevUser) or (user is not None and user == prevUser): 363 return 364 365 self._user = user 366 367 event = UserChangeEvent(self, user, prevUser) 368 for l in self._userChangeListeners: 369 l.applicationUserChanged(event) 370 371 for callback, args in self._userChangeCallbacks: 372 callback(event, *args)
373 374
375 - def getURL(self):
376 """Gets the URL of the application. 377 378 This is the URL what can be entered to a browser window to start the 379 application. Navigating to the application URL shows the main window ( 380 L{getMainWindow}) of the application. Note that the main window 381 can also be shown by navigating to the window url (L{Window.getURL}). 382 383 @return: the application's URL. 384 """ 385 return self._applicationUrl
386 387
388 - def close(self):
389 """Ends the Application. 390 391 In effect this will cause the application stop returning any windows 392 when asked. When the application is closed, its state is removed from 393 the session and the browser window is redirected to the application 394 logout url set with L{setLogoutURL}. If the logout url has not 395 been set, the browser window is reloaded and the application is 396 restarted. 397 """ 398 self._applicationIsRunning = False
399 400
401 - def start(self, applicationUrl, applicationProperties, context):
402 """Starts the application on the given URL. 403 404 This method is called by Muntjac framework when a user navigates to the 405 application. After this call the application corresponds to the given 406 URL and it will return windows when asked for them. There is no need to 407 call this method directly. 408 409 Application properties are defined by servlet configuration. 410 411 @param applicationUrl: 412 the URL the application should respond to. 413 @param applicationProperties: 414 the Application properties as specified by the servlet 415 configuration. 416 @param context: 417 the context application will be running in. 418 """ 419 self._applicationUrl = applicationUrl 420 self._properties = applicationProperties 421 self._context = context 422 self.init() 423 self._applicationIsRunning = True
424 425
426 - def isRunning(self):
427 """Tests if the application is running or if it has been finished. 428 429 Application starts running when its L{start} method has been 430 called and stops when the L{close} is called. 431 432 @return: C{True} if the application is running, C{False} if not. 433 """ 434 return self._applicationIsRunning
435 436
437 - def getWindows(self):
438 """Gets the set of windows contained by the application. 439 440 Note that the returned set of windows can not be modified. 441 442 @return: the collection of windows. 443 """ 444 return self._windows.values()
445 446
447 - def init(self):
448 """Main initializer of the application. The C{init} method is 449 called by the framework when the application is started, and it should 450 perform whatever initialization operations the application needs, such 451 as creating windows and adding components to them. 452 """ 453 raise NotImplementedError
454 455
456 - def getTheme(self):
457 """Gets the application's theme. The application's theme is the default 458 theme used by all the windows in it that do not explicitly specify a 459 theme. If the application theme is not explicitly set, the C{None} is 460 returned. 461 462 @return: the name of the application's theme. 463 """ 464 return self.theme
465 466
467 - def setTheme(self, theme):
468 """Sets the application's theme. 469 470 Note that this theme can be overridden in the the application level 471 windows with L{Window.setTheme}. Setting theme 472 to be C{None} selects the default theme. For the available 473 theme names, see the contents of the VAADIN/themes directory. 474 475 @param theme: 476 the new theme for this application. 477 """ 478 # Collect list of windows not having the current or future theme 479 toBeUpdated = list() 480 oldAppTheme = self.getTheme() 481 482 for w in self.getWindows(): 483 windowTheme = w.getTheme() 484 if ((windowTheme is None) or (not (windowTheme == theme) and windowTheme == oldAppTheme)): 485 toBeUpdated.append(w) 486 487 # Updates the theme 488 self.theme = theme 489 490 # Ask windows to update themselves 491 for w in toBeUpdated: 492 w.requestRepaint()
493 494
495 - def getMainWindow(self):
496 """Gets the mainWindow of the application. 497 498 The main window is the window attached to the application URL 499 (L{getURL}) and thus which is show by default to the user. 500 501 Note that each application must have at least one main window. 502 503 @return: the main window. 504 """ 505 return self._mainWindow
506 507
508 - def setMainWindow(self, mainWindow):
509 """Sets the mainWindow. If the main window is not explicitly set, the 510 main window defaults to first created window. Setting window as a main 511 window of this application also adds the window to this application. 512 513 @param mainWindow: 514 the mainWindow to set. 515 """ 516 self.addWindow(mainWindow) 517 self._mainWindow = mainWindow
518 519
520 - def getPropertyNames(self):
521 """Returns an enumeration of all the names in this application. 522 523 See L{start} how properties are defined. 524 525 @return: an enumeration of all the keys in this property list, 526 including the keys in the default property list. 527 """ 528 return self._properties.keys()
529 530
531 - def getProperty(self, name):
532 """Searches for the property with the specified name in this 533 application. This method returns C{None} if the property is not found. 534 535 See L{start} how properties are defined. 536 537 @param name: 538 the name of the property. 539 @return: the value in this property list with the specified key value. 540 """ 541 return self._properties[name]
542 543
544 - def addResource(self, resource):
545 """Adds new resource to the application. The resource can be accessed 546 by the user of the application. 547 548 @param resource: 549 the resource to add. 550 """ 551 # Check if the resource is already mapped 552 if resource in self._resourceKeyMap: 553 return 554 555 # Generate key 556 self._lastResourceKeyNumber += 1 557 key = str(self._lastResourceKeyNumber) 558 559 # Add the resource to mappings 560 self._resourceKeyMap[resource] = key 561 self._keyResourceMap[key] = resource
562 563
564 - def removeResource(self, resource):
565 """Removes the resource from the application. 566 567 @param resource: 568 the resource to remove. 569 """ 570 key = self._resourceKeyMap.get(resource) 571 if key is not None: 572 del self._resourceKeyMap[resource] 573 if key in self._keyResourceMap: 574 del self._keyResourceMap[key]
575 576
577 - def getRelativeLocation(self, resource):
578 """Gets the relative uri of the resource. This method is intended to be 579 called only be the terminal implementation. 580 581 This method can only be called from within the processing of a UIDL 582 request, not from a background thread. 583 584 @param resource: 585 the resource to get relative location. 586 @return: the relative uri of the resource or null if called in a 587 background thread 588 589 @deprecated: this method is intended to be used by the terminal only. 590 It may be removed or moved in the future. 591 """ 592 warn(("this method is intended to be used by the " 593 "terminal only. It may be removed or moved in the future."), 594 DeprecationWarning) 595 596 # Gets the key 597 key = self._resourceKeyMap.get(resource) 598 599 # If the resource is not registered, return null 600 if key is None: 601 return None 602 603 return self._context.generateApplicationResourceURL(resource, key)
604 605
606 - def handleURI(self, context, relativeUri):
607 """Application URI handling hub. 608 609 This method gets called by terminal. It has lots of duties like to pass 610 uri handler to proper uri handlers registered to windows etc. 611 612 In most situations developers should NOT OVERRIDE this method. Instead 613 developers should implement and register uri handlers to windows. 614 615 @deprecated: this method is called be the terminal implementation only 616 and might be removed or moved in the future. Instead of 617 overriding this method, add your L{IUriHandler} to a top 618 level L{Window} (eg. 619 getMainWindow().addUriHanler(handler) instead. 620 """ 621 warn(("this method is called be the terminal " 622 "implementation only and might be removed or moved in the future. " 623 "Instead of overriding this method, add your L{IUriHandler} to " 624 "a top level L{Window} (eg. getMainWindow().addUriHanler(handler) " 625 "instead."), DeprecationWarning) 626 627 if self._context.isApplicationResourceURL(context, relativeUri): 628 629 # Handles the resource request 630 key = self._context.getURLKey(context, relativeUri) 631 resource = self._keyResourceMap.get(key) 632 if resource is not None: 633 stream = resource.getStream() 634 if stream is not None: 635 stream.setCacheTime(resource.getCacheTime()) 636 return stream 637 else: 638 return None 639 else: 640 # Resource requests override uri handling 641 return None 642 else: 643 return None
644 645
646 - def getLocale(self):
647 """Gets the default locale for this application. 648 649 By default this is the preferred locale of the user using the 650 application. In most cases it is read from the browser defaults. 651 652 @return: the locale of this application. 653 """ 654 if self._locale is not None: 655 return self._locale 656 657 return defaultLocale()
658 659
660 - def setLocale(self, locale):
661 """Sets the default locale for this application. 662 663 By default this is the preferred locale of the user using the 664 application. In most cases it is read from the browser defaults. 665 666 @param locale: 667 the Locale object. 668 """ 669 self._locale = locale
670 671
672 - def addListener(self, listener, iface=None):
673 """Adds the user change/window attach/window detach listener. 674 675 The user change listener allows one to get notification each time 676 L{setUser} is called. The window attach listener is used to get 677 notifications each time a window is attached to the application 678 with L{addWindow}. The window detach listener is used to get 679 notifications each time a window is remove from the application 680 with L{removeWindow}. 681 """ 682 if (isinstance(listener, IUserChangeListener) and 683 (iface is None or issubclass(iface, IUserChangeListener))): 684 self._userChangeListeners.append(listener) 685 686 if (isinstance(listener, IWindowAttachListener) and 687 (iface is None or issubclass(iface, IWindowAttachListener))): 688 self._windowAttachListeners.append(listener) 689 690 if (isinstance(listener, IWindowDetachListener) and 691 (iface is None or issubclass(iface, IWindowDetachListener))): 692 self._windowDetachListeners.append(listener) 693 694 super(Application, self).addListener(listener, iface)
695 696
697 - def addCallback(self, callback, eventType=None, *args):
698 if eventType is None: 699 eventType = callback._eventType 700 701 if issubclass(eventType, UserChangeEvent): 702 self._userChangeCallbacks[callback] = args 703 704 elif issubclass(eventType, WindowAttachEvent): 705 self._windowAttachCallbacks[callback] = args 706 707 elif issubclass(eventType, WindowDetachEvent): 708 self._windowDetachCallbacks[callback] = args 709 710 else: 711 super(Application, self).addCallback(callback, eventType, *args)
712 713
714 - def removeListener(self, listener, iface=None):
715 """Removes the user change/window attach/window detach listener. 716 717 @param listener: 718 the listener to remove 719 """ 720 if (isinstance(listener, IUserChangeListener) and 721 (iface is None or iface == IUserChangeListener)): 722 if listener in self._userChangeListeners: 723 self._userChangeListeners.remove(listener) 724 725 if (isinstance(listener, IWindowAttachListener) and 726 (iface is None or issubclass(iface, IWindowAttachListener))): 727 if listener in self._windowAttachListeners: 728 self._windowAttachListeners.remove(listener) 729 730 if (isinstance(listener, IWindowDetachListener) and 731 (iface is None or issubclass(iface, IWindowDetachListener))): 732 if listener in self._windowDetachListeners: 733 self._windowDetachListeners.remove(listener) 734 735 super(Application, self).addListener(listener, iface)
736 737
738 - def removeCallback(self, callback, eventType=None):
739 if eventType is None: 740 eventType = callback._eventType 741 742 if issubclass(eventType, UserChangeEvent): 743 if callback in self._userChangeCallbacks: 744 del self._userChangeCallbacks[callback] 745 746 elif issubclass(eventType, WindowAttachEvent): 747 if callback in self._windowAttachCallbacks: 748 del self._windowAttachCallbacks[callback] 749 750 elif issubclass(eventType, WindowDetachEvent): 751 if callback in self._windowDetachCallbacks: 752 del self._windowDetachCallbacks[callback] 753 754 else: 755 super(Application, self).removeCallback(callback, eventType)
756 757
758 - def getLogoutURL(self):
759 """Returns the URL user is redirected to on application close. If the 760 URL is C{None}, the application is closed normally as defined by the 761 application running environment. 762 763 Desktop application just closes the application window and 764 web-application redirects the browser to application main URL. 765 766 @return: the URL. 767 """ 768 return self._logoutURL
769 770
771 - def setLogoutURL(self, logoutURL):
772 """Sets the URL user is redirected to on application close. If the URL 773 is C{None}, the application is closed normally as defined by the 774 application running environment: Desktop application just closes the 775 application window and web-application redirects the browser to 776 application main URL. 777 778 @param logoutURL: 779 the logoutURL to set. 780 """ 781 self._logoutURL = logoutURL
782 783 784 @classmethod
785 - def getSystemMessages(cls):
786 """Gets the SystemMessages for this application. SystemMessages are 787 used to notify the user of various critical situations that can occur, 788 such as session expiration, client/server out of sync, and internal 789 server error. 790 791 You can customize the messages by "overriding" this method and 792 returning L{CustomizedSystemMessages}. To "override" this method, 793 re-implement this method in your application (the class that extends 794 L{Application}). Even though overriding class methods is not 795 possible in Python, Muntjac selects to call the static method from the 796 subclass instead of the original L{getSystemMessages} if such a 797 method exists. 798 799 @return: the SystemMessages for this application 800 """ 801 return cls._DEFAULT_SYSTEM_MESSAGES
802 803
804 - def terminalError(self, event):
805 """Invoked by the terminal on any exception that occurs in application 806 and is thrown by the C{setVariable} to the terminal. The default 807 implementation sets the exceptions as C{ComponentErrors} to the 808 component that initiated the exception and prints stack trace to standard 809 error stream. 810 811 You can safely override this method in your application in order to 812 direct the errors to some other destination (for example log). 813 814 @param event: 815 the change event. 816 @see: L{IErrorListener.terminalError} 817 """ 818 t = event.getThrowable() 819 if isinstance(t, IOError): #SocketException 820 # Most likely client browser closed socket 821 logger.exception('SocketException in CommunicationManager.' \ 822 ' Most likely client (browser) closed socket.') 823 return 824 825 # Finds the original source of the error/exception 826 owner = None 827 if isinstance(event, VariableOwnerErrorEvent): 828 owner = event.getVariableOwner() 829 elif isinstance(event, URIHandlerErrorEvent): 830 owner = event.getURIHandler() 831 elif isinstance(event, ParameterHandlerErrorEvent): 832 owner = event.getParameterHandler() 833 elif isinstance(event, ChangeVariablesErrorEvent): 834 owner = event.getComponent() 835 836 # Shows the error in AbstractComponent 837 if isinstance(owner, AbstractComponent): 838 if isinstance(t, IErrorMessage): 839 owner.setComponentError(t) 840 else: 841 owner.setComponentError( SysError(t) ) 842 843 # also print the error on console 844 logger.exception('ITerminal error: ' + str(t)) 845 846 exc_type, _, exc_traceback = sys.exc_info() 847 traceback.print_exception(exc_type, t, 848 exc_traceback, file=sys.stdout)
849 850
851 - def getContext(self):
852 """Gets the application context. 853 854 The application context is the environment where the application is 855 running in. The actual implementation class of may contains quite a lot 856 more functionality than defined in the L{ApplicationContext} 857 interface. 858 859 By default, when you are deploying your application to a servlet 860 container, the implementation class is L{WebApplicationContext} - 861 you can safely cast to this class and use the methods from there. 862 863 @return: the application context. 864 """ 865 return self._context
866 867
868 - def getVersion(self):
869 """Override this method to return correct version number of your 870 Application. Version information is delivered for example to Testing 871 Tools test results. By default this returns a string "NONVERSIONED". 872 873 @return: version string 874 """ 875 return 'NONVERSIONED'
876 877
878 - def getErrorHandler(self):
879 """Gets the application error handler. 880 881 The default error handler is the application itself. 882 883 @return: Application error handler 884 """ 885 return self._errorHandler
886 887
888 - def setErrorHandler(self, errorHandler):
889 """Sets the application error handler. 890 891 The default error handler is the application itself. By overriding 892 this, you can redirect the error messages to your selected target 893 (log for example). 894 """ 895 self._errorHandler = errorHandler
896
897 898 -class UserChangeEvent(EventObject):
899 """An event that characterizes a change in the current selection. 900 901 Application user change event sent when the setUser is called to change 902 the current user of the application. 903 904 @version: 1.1.2 905 """ 906
907 - def __init__(self, source, newUser, prevUser):
908 """Constructor for user change event. 909 910 @param source: 911 the application source. 912 @param newUser: 913 the new user. 914 @param prevUser: 915 the previous user. 916 """ 917 super(UserChangeEvent, self).__init__(source) 918 919 #: New user of the application. 920 self._newUser = newUser 921 922 #: Previous user of the application. 923 self._prevUser = prevUser
924 925
926 - def getNewUser(self):
927 """Gets the new user of the application. 928 929 @return: the new user. 930 """ 931 return self._newUser
932 933
934 - def getPreviousUser(self):
935 """Gets the previous user of the application. 936 937 @return: the previous Muntjac user, if user has not changed ever on 938 application it returns C{None} 939 """ 940 return self._prevUser
941 942
943 - def getApplication(self):
944 """Gets the application where the user change occurred. 945 946 @return: the Application. 947 """ 948 return self.getSource()
949
950 951 -class IUserChangeListener(IEventListener):
952 """The C{UserChangeListener} interface for listening application 953 user changes. 954 955 @version: 1.1.2 956 """ 957
958 - def applicationUserChanged(self, event):
959 """The C{applicationUserChanged} method Invoked when the 960 application user has changed. 961 962 @param event: 963 the change event. 964 """ 965 raise NotImplementedError
966
967 968 -class WindowDetachEvent(EventObject):
969 """Window detach event. 970 971 This event is sent each time a window is removed from the application 972 with L{Application.removeWindow}. 973 """ 974
975 - def __init__(self, window):
976 """Creates a event. 977 978 @param window: 979 the detached window. 980 """ 981 super(WindowDetachEvent, self).__init__(self) 982 self._window = window
983 984
985 - def getWindow(self):
986 """Gets the detached window. 987 988 @return: the detached window. 989 """ 990 return self._window
991 992
993 - def getApplication(self):
994 """Gets the application from which the window was detached. 995 996 @return: the application. 997 """ 998 return self.getSource()
999
1000 1001 -class WindowAttachEvent(EventObject):
1002 """Window attach event. 1003 1004 This event is sent each time a window is attached to the application with 1005 L{Application.addWindow}. 1006 """ 1007
1008 - def __init__(self, window):
1009 """Creates a event. 1010 1011 @param window: 1012 the attached window. 1013 """ 1014 super(WindowAttachEvent, self).__init__(self) 1015 self._window = window
1016 1017
1018 - def getWindow(self):
1019 """Gets the attached window. 1020 1021 @return: the attached window. 1022 """ 1023 return self._window
1024 1025
1026 - def getApplication(self):
1027 """Gets the application to which the window was attached. 1028 1029 @return: the application. 1030 """ 1031 return self.getSource()
1032
1033 1034 -class IWindowAttachListener(object):
1035 """Window attach listener interface.""" 1036 1037
1038 - def windowAttached(self, event):
1039 """Window attached 1040 1041 @param event: 1042 the window attach event. 1043 """ 1044 raise NotImplementedError
1045
1046 1047 -class IWindowDetachListener(object):
1048 """Window detach listener interface.""" 1049 1050
1051 - def windowDetached(self, event):
1052 """Window detached. 1053 1054 @param event: 1055 the window detach event. 1056 """ 1057 raise NotImplementedError
1058
1059 1060 -class ApplicationError(IErrorEvent):
1061 """Application error is an error message defined on the application level. 1062 1063 When an error occurs on the application level, this error message type 1064 should be used. This indicates that the problem is caused by the 1065 application - not by the user. 1066 """ 1067
1068 - def __init__(self, throwable):
1069 self._throwable = throwable
1070 1071
1072 - def getThrowable(self):
1073 return self._throwable
1074
1075 1076 -class SingletonApplication(Application):
1077 1078 _singleton = None 1079
1080 - def __init__(self):
1081 super(SingletonApplication, self).__init__() 1082 self.setMainWindow(Window())
1083 1084 @classmethod
1085 - def get(cls):
1086 if cls._singleton is None: 1087 cls._singleton = SingletonApplication() 1088 return cls._singleton
1089
1090 - def init(self):
1091 pass
1092