1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
84
85 _DEFAULT_SYSTEM_MESSAGES = SystemMessages()
86
87
89
90
91
92 self._nextWindowId = 1
93
94
95 self._context = None
96
97
98 self._user = None
99
100
101 self._windows = dict()
102
103
104 self._mainWindow = None
105
106
107 self._applicationUrl = None
108
109
110 self.theme = None
111
112
113 self._applicationIsRunning = False
114
115
116 self._properties = dict
117
118
119 self._locale = None
120
121
122 self._userChangeListeners = list()
123
124 self._userChangeCallbacks = dict()
125
126
127 self._windowAttachListeners = list()
128
129 self._windowAttachCallbacks = dict()
130
131
132 self._windowDetachListeners = list()
133
134 self._windowDetachCallbacks = dict()
135
136
137 self._resourceKeyMap = dict()
138 self._keyResourceMap = dict()
139 self._lastResourceKeyNumber = 0
140
141
142
143 self._logoutURL = None
144
145
146
147 self._errorHandler = self
148
149
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
203 if not self.isRunning():
204 return None
205
206
207 return self._windows.get(name)
208
209
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
233 if window is None:
234 return
235
236
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
242 name = window.getName()
243
244
245
246 if name is not None and name in self._windows:
247
248
249 if window == self._windows[name]:
250 return
251
252
253 raise ValueError('Window with name \'' + window.getName()
254 + '\' is already present in the application')
255
256
257 if name is None:
258 accepted = False
259 while not accepted:
260
261
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
271 self._windows[name] = window
272 window.setApplication(self)
273
274 self._fireWindowAttachEvent(window)
275
276
277 if self.getMainWindow() is None:
278 self._mainWindow = window
279
280
282 """Send information to all listeners about new Windows associated with
283 this application.
284 """
285
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
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
310 del self._windows[window.getName()]
311
312
313 if self.getMainWindow() == window:
314 self.setMainWindow(None)
315
316
317 if window.getApplication() == self:
318 window.setApplication(None)
319
320 self._fireWindowDetachEvent(window)
321
322
331
332
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
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
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
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
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
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
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
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
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
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
488 self.theme = theme
489
490
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
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
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
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
552 if resource in self._resourceKeyMap:
553 return
554
555
556 self._lastResourceKeyNumber += 1
557 key = str(self._lastResourceKeyNumber)
558
559
560 self._resourceKeyMap[resource] = key
561 self._keyResourceMap[key] = resource
562
563
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
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
597 key = self._resourceKeyMap.get(resource)
598
599
600 if key is None:
601 return None
602
603 return self._context.generateApplicationResourceURL(resource, key)
604
605
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
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
641 return None
642 else:
643 return None
644
645
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
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
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
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
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
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
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
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
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):
820
821 logger.exception('SocketException in CommunicationManager.' \
822 ' Most likely client (browser) closed socket.')
823 return
824
825
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
837 if isinstance(owner, AbstractComponent):
838 if isinstance(t, IErrorMessage):
839 owner.setComponentError(t)
840 else:
841 owner.setComponentError( SysError(t) )
842
843
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
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
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
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
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
920 self._newUser = newUser
921
922
923 self._prevUser = prevUser
924
925
927 """Gets the new user of the application.
928
929 @return: the new user.
930 """
931 return self._newUser
932
933
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
944 """Gets the application where the user change occurred.
945
946 @return: the Application.
947 """
948 return self.getSource()
949
952 """The C{UserChangeListener} interface for listening application
953 user changes.
954
955 @version: 1.1.2
956 """
957
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
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
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
986 """Gets the detached window.
987
988 @return: the detached window.
989 """
990 return self._window
991
992
994 """Gets the application from which the window was detached.
995
996 @return: the application.
997 """
998 return self.getSource()
999
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
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
1019 """Gets the attached window.
1020
1021 @return: the attached window.
1022 """
1023 return self._window
1024
1025
1027 """Gets the application to which the window was attached.
1028
1029 @return: the application.
1030 """
1031 return self.getSource()
1032
1035 """Window attach listener interface."""
1036
1037
1039 """Window attached
1040
1041 @param event:
1042 the window attach event.
1043 """
1044 raise NotImplementedError
1045
1048 """Window detach listener interface."""
1049
1050
1052 """Window detached.
1053
1054 @param event:
1055 the window detach event.
1056 """
1057 raise NotImplementedError
1058
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
1069 self._throwable = throwable
1070
1071
1073 return self._throwable
1074
1077
1078 _singleton = None
1079
1083
1084 @classmethod
1089
1092