Package muntjac :: Package ui :: Module window
[hide private]
[frames] | no frames]

Source Code for Module muntjac.ui.window

   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 component that represents an application (browser native) window 
  17  or a sub window.""" 
  18   
  19  from urlparse import urljoin 
  20   
  21  from muntjac.event.shortcut_listener import ShortcutListener 
  22  from muntjac.terminal.uri_handler import IUriHandler 
  23  from muntjac.terminal.gwt.client.ui.v_view import VView 
  24  from muntjac.terminal.parameter_handler import IParameterHandler 
  25  from muntjac.terminal.sizeable import ISizeable 
  26   
  27  from muntjac.ui.client_widget import LoadStyle 
  28  from muntjac.ui.panel import Panel 
  29  from muntjac.ui.component import Event as ComponentEvent 
  30  from muntjac.ui.abstract_component import AbstractComponent 
  31   
  32  from muntjac.event.field_events import \ 
  33      (IFocusNotifier, IBlurNotifier, FocusEvent, BlurEvent, IBlurListener, 
  34      IFocusListener) 
  35   
  36  from muntjac.util import OrderedSet 
  37   
  38   
39 -class ICloseListener(object):
40 """An interface used for listening to Window close events. Add the 41 ICloseListener to a browser level window or a sub window and 42 L{ICloseListener.windowClose} will be called whenever 43 the user closes the window. 44 45 Removing windows using L{removeWindow} does now fire the ICloseListener. 46 """ 47
48 - def windowClose(self, e):
49 """Called when the user closes a window. Use 50 L{CloseEvent.getWindow} to get a reference to the 51 L{Window} that was closed. 52 53 @param e: Event containing 54 """ 55 raise NotImplementedError
56 57 58 _WINDOW_CLOSE_METHOD = getattr(ICloseListener, 'windowClose') 59 60
61 -class IResizeListener(object):
62 """Listener for window resize events. 63 64 @see: L{ResizeEvent} 65 """ 66
67 - def windowResized(self, e):
68 raise NotImplementedError
69 70 71 _WINDOW_RESIZE_METHOD = getattr(IResizeListener, 'windowResized') 72 73
74 -class Window(Panel, IUriHandler, IParameterHandler, IFocusNotifier, 75 IBlurNotifier):
76 """A component that represents an application (browser native) window or 77 a sub window. 78 79 If the window is a application window or a sub window depends on how it 80 is added to the application. Adding a C{Window} to a C{Window} 81 using L{Window.addWindow} makes it a sub window and adding a 82 C{Window} to the C{Application} using 83 L{Application.addWindow} makes it an application window. 84 85 An application window is the base of any view in a Muntjac application. All 86 applications contain a main application window (set using 87 L{ApplicationsetMainWindow} which is what is initially shown 88 to the user. The contents of a window is set using 89 L{setContent}. The contents can in turn contain 90 other components. For multi-tab applications there is one window instance 91 per opened tab. 92 93 A sub window is floating popup style window that can be added to an 94 application window. Like the application window its content is set using 95 L{setContent}. A sub window can be positioned on 96 the screen using absolute coordinates (pixels). The default content of the 97 Window is set to be suitable for application windows. For sub windows it 98 might be necessary to set the size of the content to work as expected. 99 100 Window caption is displayed in the browser title bar for application level 101 windows and in the window header for sub windows. 102 103 Certain methods in this class are only meaningful for sub windows and other 104 parts only for application windows. These are marked using B{Sub window 105 only} and B{Application window only} respectively in the API doc. 106 107 @author: Vaadin Ltd. 108 @author: Richard Lincoln 109 @version: 1.1.2 110 """ 111 112 CLIENT_WIDGET = None #ClientWidget(VWindow, LoadStyle.EAGER) 113 114 #: B{Application window only}. A border style used for opening 115 # resources in a window without a border. 116 BORDER_NONE = 0 117 118 #: B{Application window only}. A border style used for opening 119 # resources in a window with a minimal border. 120 BORDER_MINIMAL = 1 121 122 #: B{Application window only}. A border style that indicates that 123 # the default border style should be used when opening resources. 124 BORDER_DEFAULT = 2 125 126
127 - def __init__(self, caption='', content=None):
128 """Creates a new unnamed window with the given content and title. 129 130 @param caption: 131 the title of the window. 132 @param content: 133 the contents of the window 134 """ 135 136 #: B{Application window only}. The user terminal for this window. 137 self._terminal = None 138 139 #: B{Application window only}. The application this window is 140 # attached to or null. 141 self._application = None 142 143 #: B{Application window only}. List of URI handlers for this 144 # window. 145 self._uriHandlerList = None 146 147 #: B{Application window only}. List of parameter handlers for 148 # this window. 149 self._parameterHandlerList = None 150 151 #: B{Application window only}. List of sub windows in this window. 152 # A sub window cannot have other sub windows. 153 self._subwindows = OrderedSet() 154 155 #: B{Application window only}. Explicitly specified theme of this 156 # window or null if the application theme should be used. 157 self._theme = None 158 159 #: B{Application window only}. Resources to be opened automatically 160 # on next repaint. The list is automatically cleared when it has been 161 # sent to the client. 162 self._openList = list() 163 164 #: B{Application window only}. Unique name of the window used to 165 # identify it. 166 self._name = None 167 168 #: B{Application window only.} Border mode of the Window. 169 self._border = self.BORDER_DEFAULT 170 171 #: B{Sub window only}. Top offset in pixels for the sub window 172 # (relative to the parent application window) or -1 if unspecified. 173 self._positionY = -1 174 175 #: B{Sub window only}. Left offset in pixels for the sub window 176 # (relative to the parent application window) or -1 if unspecified. 177 self._positionX = -1 178 179 #: B{Application window only}. A list of notifications that are 180 # waiting to be sent to the client. Cleared (set to null) when the 181 # notifications have been sent. 182 self._notifications = None 183 184 #: B{Sub window only}. Modality flag for sub window. 185 self._modal = False 186 187 #: B{Sub window only}. Controls if the end user can resize the 188 # window. 189 self._resizable = True 190 191 #: B{Sub window only}. Controls if the end user can move the 192 # window by dragging. 193 self._draggable = True 194 195 #: B{Sub window only}. Flag which is true if the window is 196 # centered on the screen. 197 self._centerRequested = False 198 199 #: Should resize recalculate layouts lazily (as opposed to immediately) 200 self._resizeLazy = False 201 202 #: Component that should be focused after the next repaint. Null if no 203 # focus change should take place. 204 self._pendingFocus = None 205 206 #: B{Application window only}. A list of javascript commands that 207 # are waiting to be sent to the client. Cleared (set to null) when the 208 # commands have been sent. 209 self._jsExecQueue = None 210 211 #: The component that should be scrolled into view after the next 212 # repaint. Null if nothing should be scrolled into view. 213 self._scrollIntoView = None 214 215 super(Window, self).__init__(caption, content) 216 217 self.setScrollable(True) 218 219 self.setSizeUndefined() 220 221 self._bringToFront = None 222 223 # This sequesnce is used to keep the right order of windows if 224 # multiple windows are brought to front in a single changeset. 225 # Incremented and saved by childwindows. If sequence is not used, 226 # the order is quite random (depends on the order getting to dirty 227 # list. e.g. which window got variable changes). 228 self._bringToFrontSequence = 0 229 230 self.closeShortcut = None
231 232
233 - def addComponent(self, c):
234 if isinstance(c, Window): 235 raise ValueError, ('Window cannot be added to another ' 236 'via addComponent. Use addWindow(Window) instead.') 237 super(Window, self).addComponent(c)
238 239
240 - def getTerminal(self):
241 """B{Application window only}. Gets the user terminal. 242 243 @return: the user terminal 244 """ 245 return self._terminal
246 247
248 - def getWindow(self):
249 """Gets the parent window of the component. 250 251 This is always the window itself. 252 253 B{This method is not meant to be overridden.} 254 255 @see: L{IComponent.getWindow} 256 @return: the window itself 257 """ 258 return self
259 260
261 - def getApplication(self):
262 if self.getParent() is None: 263 return self._application 264 265 return self.getParent().getApplication()
266 267
268 - def getParent(self):
269 """Gets the parent component of the window. 270 271 The parent of an application window is always null. The parent of a 272 sub window is the application window the sub window is attached to. 273 274 B{This method is not meant to be overridden.} 275 276 @return: the parent window 277 @see: L{IComponent.getParent} 278 """ 279 return super(Window, self).getParent()
280 281
282 - def addURIHandler(self, handler):
283 """B{Application window only}. Adds a new URI handler to this 284 window. If this is a sub window the URI handler is attached to the 285 parent application window. 286 287 @param handler: 288 the URI handler to add. 289 """ 290 if self.getParent() is not None: 291 # this is subwindow, attach to main level instead 292 # TODO hold internal list also and remove on detach 293 mainWindow = self.getParent() 294 mainWindow.addURIHandler(handler) 295 else: 296 if self._uriHandlerList is None: 297 self._uriHandlerList = list() 298 if handler not in self._uriHandlerList: 299 self._uriHandlerList.append(handler)
300 301
302 - def removeURIHandler(self, handler):
303 """B{Application window only}. Removes the URI handler from this 304 window. If this is a sub window the URI handler is removed from the 305 parent application window. 306 307 @param handler: 308 the URI handler to remove. 309 """ 310 if self.getParent() is not None: 311 # this is subwindow 312 mainWindow = self.getParent() 313 mainWindow.removeURIHandler(handler) 314 else: 315 if handler is None or self._uriHandlerList is None: 316 return 317 self._uriHandlerList.remove(handler) 318 if len(self._uriHandlerList) == 0: 319 self._uriHandlerList = None
320 321
322 - def handleURI(self, context, relativeUri):
323 """B{Application window only}. Handles an URI by passing the URI 324 to all URI handlers defined using L{addURIHandler}. 325 All URI handlers are called for each URI but no more than one handler 326 may return a L{DownloadStream}. If more than one stream is 327 returned a C{RuntimeException} is thrown. 328 329 @param context: 330 The URL of the application 331 @param relativeUri: 332 The URI relative to C{context} 333 @return: A C{DownloadStream} that one of the URI handlers 334 returned, null if no C{DownloadStream} was returned. 335 """ 336 result = None 337 338 if self._uriHandlerList is not None: 339 handlers = list(self._uriHandlerList) 340 341 for handler in handlers: 342 ds = handler.handleURI(context, relativeUri) 343 if ds is not None: 344 if result is not None: 345 raise RuntimeError(('handleURI for ' + context 346 + ' uri: \'' + relativeUri 347 + '\' returns ambigious result.')) 348 result = ds 349 350 return result
351 352
353 - def addParameterHandler(self, handler):
354 """B{Application window only}. Adds a new parameter handler to 355 this window. If this is a sub window the parameter handler is attached 356 to the parent application window. 357 358 @param handler: 359 the parameter handler to add. 360 """ 361 if self.getParent() is not None: 362 # this is subwindow 363 # TODO hold internal list also and remove on detach 364 mainWindow = self.getParent() 365 mainWindow.addParameterHandler(handler) 366 else: 367 if self._parameterHandlerList is None: 368 self._parameterHandlerList = list() 369 if handler not in self._parameterHandlerList: 370 self._parameterHandlerList.append(handler)
371 372
373 - def removeParameterHandler(self, handler):
374 """B{Application window only}. Removes the parameter handler from 375 this window. If this is a sub window the parameter handler is removed 376 from the parent application window. 377 378 @param handler: 379 the parameter handler to remove. 380 """ 381 if self.getParent() is not None: 382 # this is subwindow 383 mainWindow = self.getParent() 384 mainWindow.removeParameterHandler(handler) 385 else: 386 if handler is None or self._parameterHandlerList is None: 387 return 388 self._parameterHandlerList.remove(handler) 389 if len(self._parameterHandlerList) == 0: 390 self._parameterHandlerList = None
391 392
393 - def handleParameters(self, parameters):
394 """B{Application window only}. Handles parameters by passing the 395 parameters to all C{IParameterHandler}s defined using 396 L{addParameterHandler}. All C{IParameterHandler}s are called for 397 each set of parameters. 398 399 @param parameters: 400 a map containing the parameter names and values 401 @see: L{IParameterHandler.handleParameters} 402 """ 403 if self._parameterHandlerList is not None: 404 handlers = list(self._parameterHandlerList) 405 for handler in handlers: 406 handler.handleParameters(parameters)
407 408
409 - def getTheme(self):
410 """B{Application window only}. Gets the theme for this window. 411 412 If the theme for this window is not explicitly set, the application 413 theme name is returned. If the window is not attached to an 414 application, the terminal default theme name is returned. If the theme 415 name cannot be determined, null is returned 416 417 Subwindows do not support themes and return the theme used by the 418 parent window 419 420 @return: the name of the theme used for the window 421 """ 422 if self.getParent() is not None: 423 return self.getParent().getTheme() 424 425 if self._theme is not None: 426 return self._theme 427 428 if self._application is not None \ 429 and self._application.getTheme() is not None: 430 return self._application.getTheme() 431 432 if self._terminal is not None: 433 return self._terminal.getDefaultTheme() 434 435 return None
436 437
438 - def setTheme(self, theme):
439 """B{Application window only}. Sets the name of the theme to 440 use for this window. Changing the theme will cause the page to be 441 reloaded. 442 443 @param theme: 444 the name of the new theme for this window or null to 445 use the application theme. 446 """ 447 if self.getParent() is not None: 448 raise NotImplementedError, \ 449 'Setting theme for sub-windows is not supported.' 450 self._theme = theme 451 self.requestRepaint()
452 453
454 - def paintContent(self, target):
455 # Sets the window name 456 name = self.getName() 457 target.addAttribute('name', '' if name is None else name) 458 459 # Sets the window theme 460 theme = self.getTheme() 461 target.addAttribute('theme', '' if theme is None else theme) 462 463 if self._modal: 464 target.addAttribute('modal', True) 465 466 if self._resizable: 467 target.addAttribute('resizable', True) 468 469 if self._resizeLazy: 470 target.addAttribute(VView.RESIZE_LAZY, self._resizeLazy) 471 472 if not self._draggable: 473 # Inverted to prevent an extra attribute for 474 # almost all sub windows 475 target.addAttribute('fixedposition', True) 476 477 if self._bringToFront is not None: 478 target.addAttribute('bringToFront', int(self._bringToFront)) 479 self._bringToFront = None 480 481 if self._centerRequested: 482 target.addAttribute('center', True) 483 self._centerRequested = False 484 485 if self._scrollIntoView is not None: 486 target.addAttribute('scrollTo', self._scrollIntoView) 487 self._scrollIntoView = None 488 489 # Marks the main window 490 if (self.getApplication() is not None 491 and self == self.getApplication().getMainWindow()): 492 target.addAttribute('main', True) 493 494 if self.getContent() is not None: 495 if (self.getContent().getHeightUnits() 496 == ISizeable.UNITS_PERCENTAGE): 497 target.addAttribute('layoutRelativeHeight', True) 498 499 if (self.getContent().getWidthUnits() 500 == ISizeable.UNITS_PERCENTAGE): 501 target.addAttribute('layoutRelativeWidth', True) 502 503 # Open requested resource 504 if len(self._openList) > 0: 505 for ol in self._openList: 506 ol.paintContent(target) 507 del self._openList[:] 508 509 # Contents of the window panel is painted 510 super(Window, self).paintContent(target) 511 512 # Add executable javascripts if needed 513 if self._jsExecQueue is not None: 514 for script in self._jsExecQueue: 515 target.startTag('execJS') 516 target.addAttribute('script', script) 517 target.endTag('execJS') 518 self._jsExecQueue = None 519 520 # Window position 521 target.addVariable(self, 'positionx', self.getPositionX()) 522 target.addVariable(self, 'positiony', self.getPositionY()) 523 524 # Window closing 525 target.addVariable(self, 'close', False) 526 527 if self.getParent() is None: 528 # Paint subwindows 529 for w in self._subwindows: 530 w.paint(target) 531 else: 532 # mark subwindows 533 target.addAttribute('sub', True) 534 535 # Paint notifications 536 if self._notifications is not None: 537 target.startTag('notifications') 538 for n in self._notifications: 539 target.startTag('notification') 540 if n.getCaption() is not None: 541 target.addAttribute('caption', n.getCaption()) 542 543 if n.getMessage() is not None: 544 target.addAttribute('message', n.getMessage()) 545 546 if n.getIcon() is not None: 547 target.addAttribute('icon', n.getIcon()) 548 549 if not n.isHtmlContentAllowed(): 550 target.addAttribute( 551 VView.NOTIFICATION_HTML_CONTENT_NOT_ALLOWED, True) 552 553 target.addAttribute('position', n.getPosition()) 554 target.addAttribute('delay', n.getDelayMsec()) 555 556 if n.getStyleName() is not None: 557 target.addAttribute('style', n.getStyleName()) 558 559 target.endTag('notification') 560 561 target.endTag('notifications') 562 self._notifications = None 563 564 if self._pendingFocus is not None: 565 # ensure focused component is still attached to this main window 566 if (self._pendingFocus.getWindow() == self 567 or self._pendingFocus.getWindow() is not None 568 and self._pendingFocus.getWindow().getParent() == self): 569 target.addAttribute('focused', self._pendingFocus) 570 571 self._pendingFocus = None
572 573
574 - def scrollIntoView(self, component):
575 """Scrolls any component between the component and window to a 576 suitable position so the component is visible to the user. The given 577 component must be inside this window. 578 579 @param component: 580 the component to be scrolled into view 581 @raise ValueError: 582 if C{component} is not inside this window 583 """ 584 if component.getWindow() != self: 585 raise ValueError, ('The component where to scroll ' 586 'must be inside this window.') 587 self._scrollIntoView = component 588 self.requestRepaint()
589 590
591 - def open(self, resource, windowName=None, width=-1, height=-1, 592 border=None): #@PydevCodeAnalysisIgnore
593 """Opens the given resource in a window with the given size, border and 594 name. 595 596 The supplied C{windowName} is used as the target name in a 597 window.open call in the client. This means that special values such as 598 "_blank", "_self", "_top", "_parent" have special meaning. An empty or 599 C{None} window name is also a special case. 600 601 "", null and "_self" as C{windowName} all causes the resource to 602 be opened in the current window, replacing any old contents. For 603 downloadable content you should avoid "_self" as "_self" causes the 604 client to skip rendering of any other changes as it considers them 605 irrelevant (the page will be replaced by the resource). This can speed 606 up the opening of a resource, but it might also put the client side 607 into an inconsistent state if the window content is not completely 608 replaced e.g., if the resource is downloaded instead of displayed in 609 the browser. 610 611 "_blank" as C{windowName} causes the resource to always be opened 612 in a new window or tab (depends on the browser and browser settings). 613 614 "_top" and "_parent" as C{windowName} works as specified by the 615 HTML standard. 616 617 Any other C{windowName} will open the resource in a window with 618 that name, either by opening a new window/tab in the browser or by 619 replacing the contents of an existing window with that name. 620 621 @param resource: 622 the resource. 623 @param windowName: 624 the name of the window. 625 @param width: 626 the width of the window in pixels 627 @param height: 628 the height of the window in pixels 629 @param border: 630 the border style of the window. See 631 L{Window.BORDER_* constants<BORDER_NONE>} 632 """ 633 if border is None: 634 border = self.BORDER_DEFAULT 635 636 if resource not in self._openList: 637 r = OpenResource(resource, windowName, width, height, border) 638 self._openList.append(r) 639 640 self.requestRepaint()
641 642
643 - def getURL(self):
644 """Gets the full URL of the window. The returned URL is window 645 specific and can be used to directly refer to the window. 646 647 Note! This method can not be used for portlets. 648 649 @return: the URL of the window or null if the window is not attached 650 to an application 651 """ 652 if self._application is None: 653 return None 654 655 try: 656 # FIXME: URL 657 return urljoin(self._application.getURL(), self.getName() + '/') 658 except Exception: 659 raise RuntimeError, \ 660 'Internal problem getting window URL, please report'
661 662
663 - def getName(self):
664 """B{Application window only}. Gets the unique name of the window. 665 The name of the window is used to uniquely identify it. 666 667 The name also determines the URL that can be used for direct access to 668 a window. All windows can be accessed through 669 C{http://host:port/app/win} where C{http://host:port/app} is 670 the application URL (as returned by L{Application.getURL} and 671 C{win} is the window name. 672 673 @return: the name of the Window. 674 """ 675 return self._name
676 677
678 - def getBorder(self):
679 """Returns the border style of the window. 680 681 @see: L{setBorder} 682 @return: the border style for the window 683 """ 684 return self._border
685 686
687 - def setBorder(self, border):
688 """Sets the border style for this window. Valid values are 689 L{Window.BORDER_NONE}, L{Window.BORDER_MINIMAL}, 690 L{Window.BORDER_DEFAULT}. 691 692 B{Note!} Setting this seems to currently have no effect 693 whatsoever on the window. 694 695 @param border: 696 the border style to set 697 """ 698 self._border = border
699 700
701 - def setApplication(self, application):
702 """Sets the application this window is attached to. 703 704 This method is called by the framework and should not be called 705 directly from application code. L{Application.addWindow} 706 should be used to add the window to an application and 707 L{Application.removeWindow} to remove the window from the application. 708 709 This method invokes L{IComponent.attach} and 710 L{IComponent.detach} methods when necessary. 711 712 @param application: 713 the application the window is attached to 714 """ 715 # If the application is not changed, dont do nothing 716 if application == self._application: 717 return 718 719 # Sends detach event if the window is connected to application 720 if self._application is not None: 721 self.detach() 722 723 # Connects to new parent 724 self._application = application 725 726 # Sends the attach event if connected to a window 727 if application is not None: 728 self.attach()
729 730
731 - def setName(self, name):
732 """B{Application window only}. Sets the unique name of the window. 733 The name of the window is used to uniquely identify it inside the 734 application. 735 736 The name also determines the URL that can be used for direct access to 737 a window. All windows can be accessed through 738 C{http://host:port/app/win} where C{http://host:port/app} is 739 the application URL (as returned by L{Application.getURL} and 740 C{win} is the window name. 741 742 This method can only be called before the window is added to an 743 application. 744 745 @param name: 746 the new name for the window or null if the application 747 should automatically assign a name to it 748 @raise ValueError: 749 if the window is attached to an application 750 """ 751 # The name can not be changed in application 752 if self.getApplication() is not None: 753 raise ValueError, ('Window name can not be changed while ' 754 'the window is in application') 755 self._name = name
756 757
758 - def setTerminal(self, typ):
759 """Sets the user terminal. Used by the terminal adapter, should never 760 be called from application code. 761 762 @param typ: 763 the terminal to set. 764 """ 765 self._terminal = typ
766 767
768 - def changeVariables(self, source, variables):
769 770 sizeHasChanged = False 771 # size is handled in super class, but resize events only in windows -> 772 # so detect if size change occurs before super.changeVariables() 773 if ('height' in variables 774 and (self.getHeightUnits() != self.UNITS_PIXELS 775 or variables.get('height') != self.getHeight())): 776 sizeHasChanged = True 777 778 if ('width' in variables 779 and (self.getWidthUnits() != self.UNITS_PIXELS 780 or variables['width'] != self.getWidth())): 781 sizeHasChanged = True 782 783 super(Window, self).changeVariables(source, variables) 784 785 # Positioning 786 positionx = variables.get('positionx') 787 if positionx is not None: 788 x = positionx 789 # This is information from the client so it is already using the 790 # position. No need to repaint. 791 self.setPositionX(-1 if x < 0 else x, False) 792 793 positiony = variables.get('positiony') 794 if positiony is not None: 795 y = positiony 796 # This is information from the client so it is already using the 797 # position. No need to repaint. 798 self.setPositionY(-1 if y < 0 else y, False) 799 800 if self.isClosable(): 801 # Closing 802 close = variables.get('close') 803 if close is not None and bool(close): 804 self.close() 805 806 # fire event if size has really changed 807 if sizeHasChanged: 808 self.fireResize() 809 810 if FocusEvent.EVENT_ID in variables: 811 self.fireEvent( FocusEvent(self) ) 812 813 elif BlurEvent.EVENT_ID in variables: 814 self.fireEvent( BlurEvent(self) )
815 816
817 - def close(self):
818 """Method that handles window closing (from UI). 819 820 By default, sub-windows are removed from their respective parent 821 windows and thus visually closed on browser-side. Browser-level windows 822 also closed on the client-side, but they are not implicitly removed 823 from the application. 824 825 To explicitly close a sub-window, use L{removeWindow}. 826 To react to a window being closed (after it is closed), register a 827 L{ICloseListener}. 828 """ 829 parent = self.getParent() 830 if parent is None: 831 self.fireClose() 832 else: 833 # focus is restored to the parent window 834 parent.focus() 835 836 # subwindow is removed from parent 837 parent.removeWindow(self)
838 839
840 - def getPositionX(self):
841 """Gets the distance of Window left border in pixels from left border 842 of the containing (main window). 843 844 @return: the Distance of Window left border in pixels from left border 845 of the containing (main window). or -1 if unspecified. 846 """ 847 return self._positionX
848 849
850 - def setPositionX(self, positionX, repaintRequired=True):
851 """Sets the distance of Window left border in pixels from left border 852 of the containing (main window). 853 854 @param positionX: 855 the distance of window left border in pixels from 856 left border of the containing (main window). or -1 857 if unspecified. 858 @param repaintRequired: 859 true if the window needs to be repainted, false otherwise 860 """ 861 self._positionX = positionX 862 self._centerRequested = False 863 if repaintRequired: 864 self.requestRepaint()
865 866
867 - def getPositionY(self):
868 """Gets the distance of Window top border in pixels from top border 869 of the containing (main window). 870 871 @return: Distance of Window top border in pixels from top border of 872 the containing (main window). or -1 if unspecified. 873 """ 874 return self._positionY
875 876
877 - def setPositionY(self, positionY, repaintRequired=True):
878 """Sets the distance of Window top border in pixels from top border 879 of the containing (main window). 880 881 @param positionY: 882 the distance of window top border in pixels from top border 883 of the containing (main window). or -1 if unspecified 884 @param repaintRequired: 885 true if the window needs to be repainted, false otherwise 886 """ 887 self._positionY = positionY 888 self._centerRequested = False 889 if repaintRequired: 890 self.requestRepaint()
891 892
893 - def addListener(self, listener, iface=None):
894 """Adds a close/resize/focus/blur listener to the window. 895 896 For a sub window the ICloseListener is fired when the user closes it 897 (clicks on the close button). 898 899 For a browser level window the ICloseListener is fired when the 900 browser level window is closed. Note that closing a browser level 901 window does not mean it will be destroyed. 902 903 Note, that focus/blur listeners in Window class are only supported by 904 sub windows. Also note that Window is not considered focused if its 905 contained component currently has focus. 906 907 @param listener: 908 the listener to add. 909 @see: L{IFocusNotifier.addListener} 910 @see: L{IBlurNotifier.addListener} 911 """ 912 if (isinstance(listener, IBlurListener) and 913 (iface is None or issubclass(iface, IBlurListener))): 914 self.registerListener(BlurEvent.EVENT_ID, 915 BlurEvent, listener, IBlurListener.blurMethod) 916 917 if (isinstance(listener, ICloseListener) and 918 (iface is None or issubclass(iface, ICloseListener))): 919 self.registerListener(CloseEvent, 920 listener, _WINDOW_CLOSE_METHOD) 921 922 if (isinstance(listener, IFocusListener) and 923 (iface is None or issubclass(iface, IFocusListener))): 924 self.registerListener(FocusEvent.EVENT_ID, 925 FocusEvent, listener, IFocusListener.focusMethod) 926 927 if (isinstance(listener, IResizeListener) and 928 (iface is None or issubclass(iface, IResizeListener))): 929 self.registerListener(ResizeEvent, listener, _WINDOW_RESIZE_METHOD) 930 931 super(Window, self).addListener(listener, iface)
932 933
934 - def addCallback(self, callback, eventType=None, *args):
935 if eventType is None: 936 eventType = callback._eventType 937 938 if issubclass(eventType, BlurEvent): 939 self.registerCallback(BlurEvent, callback, 940 BlurEvent.EVENT_ID, *args) 941 942 elif issubclass(eventType, CloseEvent): 943 self.registerCallback(CloseEvent, callback, None, *args) 944 945 elif issubclass(eventType, FocusEvent): 946 self.registerCallback(FocusEvent, callback, 947 FocusEvent.EVENT_ID, *args) 948 949 elif issubclass(eventType, ResizeEvent): 950 self.registerCallback(ResizeEvent, callback, None, *args) 951 952 else: 953 super(Window, self).addCallback(callback, eventType, *args)
954 955
956 - def removeListener(self, listener, iface=None):
957 """Removes the close/resize from the window. 958 959 For more information on CloseListeners see L{ICloseListener}. 960 961 @param listener: 962 the listener to remove. 963 """ 964 if (isinstance(listener, IBlurListener) and 965 (iface is None or issubclass(iface, IBlurListener))): 966 self.withdrawListener(BlurEvent.EVENT_ID, 967 BlurEvent, listener) 968 969 if (isinstance(listener, ICloseListener) and 970 (iface is None or issubclass(iface, ICloseListener))): 971 self.withdrawListener(CloseEvent, listener, 972 _WINDOW_CLOSE_METHOD) 973 974 if (isinstance(listener, IFocusListener) and 975 (iface is None or issubclass(iface, IFocusListener))): 976 self.withdrawListener(FocusEvent.EVENT_ID, 977 FocusEvent, listener) 978 979 if (isinstance(listener, IResizeListener) and 980 (iface is None or issubclass(iface, IResizeListener))): 981 self.withdrawListener(ResizeEvent, listener) 982 983 super(Window, self).removeListener(listener, iface)
984 985
986 - def removeCallback(self, callback, eventType=None):
987 if eventType is None: 988 eventType = callback._eventType 989 990 if issubclass(eventType, BlurEvent): 991 self.withdrawCallback(BlurEvent, callback, BlurEvent.EVENT_ID) 992 993 elif issubclass(eventType, CloseEvent): 994 self.withdrawCallback(CloseEvent, callback) 995 996 elif issubclass(eventType, FocusEvent): 997 self.withdrawCallback(FocusEvent, callback, FocusEvent.EVENT_ID) 998 999 elif issubclass(eventType, ResizeEvent): 1000 self.withdrawCallback(ResizeEvent, callback) 1001 1002 else: 1003 super(Window, self).removeCallback(callback, eventType)
1004 1005
1006 - def fireClose(self):
1007 # Method for the resize event. 1008 self.fireEvent( CloseEvent(self) )
1009 1010
1011 - def fireResize(self):
1012 """Fire the resize event.""" 1013 self.fireEvent( ResizeEvent(self) )
1014 1015
1016 - def attachWindow(self, w):
1017 self._subwindows.add(w) 1018 w.setParent(self) 1019 self.requestRepaint()
1020 1021
1022 - def addWindow(self, window):
1023 """Adds a window inside another window. 1024 1025 Adding windows inside another window creates "subwindows". These 1026 windows should not be added to application directly and are not 1027 accessible directly with any url. Addding windows implicitly sets 1028 their parents. 1029 1030 Only one level of subwindows are supported. Thus you can add windows 1031 inside such windows whose parent is C{None}. 1032 1033 @raise ValueError: 1034 if a window is added inside non-application level window. 1035 """ 1036 if window is None: 1037 raise ValueError, 'Argument must not be null' 1038 1039 if window.getApplication() is not None: 1040 raise ValueError, ('Window was already added to application' 1041 ' - it can not be added to another window also.') 1042 1043 elif self.getParent() is not None: 1044 raise ValueError, ('You can only add windows inside ' 1045 'application-level windows.') 1046 1047 elif len(window._subwindows) > 0: 1048 raise ValueError, 'Only one level of subwindows are supported.' 1049 1050 self.attachWindow(window)
1051 1052
1053 - def removeWindow(self, window):
1054 """Remove the given subwindow from this window. 1055 1056 L{ICloseListener}s are called also when explicitly removing a window 1057 by calling this method. 1058 1059 Returns a boolean indicating if the window was removed or not. 1060 1061 @param window: 1062 Window to be removed. 1063 @return: true if the subwindow was removed, false otherwise 1064 """ 1065 if window not in self._subwindows: 1066 # Window window is not a subwindow of this window. 1067 return False 1068 else: 1069 self._subwindows.remove(window) 1070 1071 window.setParent(None) 1072 window.fireClose() 1073 self.requestRepaint() 1074 1075 return True
1076 1077
1078 - def bringToFront(self):
1079 """If there are currently several sub windows visible, calling this 1080 method makes this window topmost. 1081 1082 This method can only be called if this window is a sub window and 1083 connected a top level window. Else an illegal state exception is 1084 thrown. Also if there are modal windows and this window is not modal, 1085 and illegal state exception is thrown. 1086 1087 B{Note, this API works on sub windows only. Browsers can't 1088 reorder OS windows.} 1089 """ 1090 parent = self.getParent() 1091 if parent is None: 1092 raise ValueError, ('Window must be attached to parent ' 1093 'before calling bringToFront method.') 1094 1095 for w in parent.getChildWindows(): 1096 if w.isModal() and not self.isModal(): 1097 raise ValueError, ('There are modal windows currently ' 1098 'visible, non-modal window cannot be brought to front.') 1099 1100 self._bringToFront = self.getParent().bringToFrontSequence 1101 1102 self.getParent().bringToFrontSequence = \ 1103 self.getParent().bringToFrontSequence + 1 1104 1105 self.requestRepaint()
1106 1107
1108 - def getChildWindows(self):
1109 """Get the set of all child windows. 1110 1111 @return: Set of child windows. 1112 """ 1113 return set(self._subwindows)
1114 1115
1116 - def setModal(self, modality):
1117 """Sets sub-window modal, so that widgets behind it cannot be 1118 accessed. 1119 B{Note:} affects sub-windows only. 1120 1121 @param modality: 1122 true if modality is to be turned on 1123 """ 1124 self._modal = modality 1125 self.center() 1126 self.requestRepaint()
1127 1128
1129 - def isModal(self):
1130 """@return: true if this window is modal.""" 1131 return self._modal
1132 1133
1134 - def setResizable(self, resizable):
1135 """Sets sub-window resizable. B{Note:} affects sub-windows only. 1136 1137 @param resizable: 1138 true if resizability is to be turned on 1139 """ 1140 self._resizable = resizable 1141 self.requestRepaint()
1142 1143
1144 - def isResizable(self):
1145 """@return: true if window is resizable by the end-user, otherwise 1146 false.""" 1147 return self._resizable
1148 1149
1150 - def isResizeLazy(self):
1151 """@return: true if a delay is used before recalculating sizes, 1152 false if sizes are recalculated immediately. 1153 """ 1154 return self._resizeLazy
1155 1156
1157 - def setResizeLazy(self, resizeLazy):
1158 """Should resize operations be lazy, i.e. should there be a delay 1159 before layout sizes are recalculated. Speeds up resize operations 1160 in slow UIs with the penalty of slightly decreased usability. 1161 1162 Note, some browser send false resize events for the browser window 1163 and are therefore always lazy. 1164 1165 @param resizeLazy: 1166 true to use a delay before recalculating sizes, false to 1167 calculate immediately. 1168 """ 1169 self._resizeLazy = resizeLazy 1170 self.requestRepaint()
1171 1172
1173 - def center(self):
1174 """Request to center this window on the screen. B{Note:} affects 1175 sub-windows only. 1176 """ 1177 self._centerRequested = True 1178 self.requestRepaint()
1179 1180
1181 - def showNotification(self, *args):
1182 """Shows a notification message the window. The position and behavior 1183 of the message depends on the type, which is one of the basic types 1184 defined in L{Notification}, for instance 1185 Notification.TYPE_WARNING_MESSAGE, defaults to "humanized". 1186 1187 Care should be taken to to avoid XSS vulnerabilities as the caption is 1188 rendered as html. 1189 1190 @param args: tuple of the form 1191 - (caption) 1192 1. The message 1193 - (caption, type) 1194 1. The message 1195 2. The message type 1196 - (caption, description) 1197 1. The message 1198 2. The message description 1199 - (caption, description, type) 1200 1. The message 1201 2. The message description 1202 3. The message type 1203 - (notification) 1204 1. The notification message to show 1205 - (caption, description, type, htmlContentAllowed) 1206 1. The message 1207 2. The message description 1208 3. The message type 1209 4. Whether html in the caption and description should be 1210 displayed as html or as plain text 1211 """ 1212 args = args 1213 nargs = len(args) 1214 if nargs == 1: 1215 if isinstance(args[0], Notification): 1216 notification, = args 1217 self.addNotification(notification) 1218 else: 1219 caption, = args 1220 self.addNotification( Notification(caption) ) 1221 elif nargs == 2: 1222 if isinstance(args[1], int): 1223 caption, typ = args 1224 self.addNotification( Notification(caption, typ) ) 1225 else: 1226 caption, description = args 1227 self.addNotification( Notification(caption, description) ) 1228 elif nargs == 3: 1229 caption, description, typ = args 1230 self.addNotification( Notification(caption, description, typ) ) 1231 elif nargs == 4: 1232 caption, description, typ, htmlContentAllowed = args 1233 n = Notification(caption, description, typ, htmlContentAllowed) 1234 self.addNotification(n) 1235 else: 1236 raise ValueError, 'invalid number of arguments'
1237 1238
1239 - def addNotification(self, notification):
1240 if self._notifications is None: 1241 self._notifications = list() 1242 1243 self._notifications.append(notification) 1244 self.requestRepaint()
1245 1246
1247 - def setFocusedComponent(self, focusable):
1248 """This method is used by Component.Focusable objects to request focus 1249 to themselves. Focus renders must be handled at window level (instead 1250 of IFocusable) due we want the last focused component to be 1251 focused in client too. Not the one that is rendered last (the case 1252 we'd get if implemented in Focusable only). 1253 1254 To focus component from Muntjac application, use IFocusable.focus(). 1255 See L{IFocusable}. 1256 1257 @param focusable: 1258 to be focused on next paint 1259 """ 1260 if self.getParent() is not None: 1261 # focus is handled by main windows 1262 self.getParent().setFocusedComponent(focusable) 1263 else: 1264 self._pendingFocus = focusable 1265 self.requestRepaint()
1266 1267
1268 - def executeJavaScript(self, script):
1269 """Executes JavaScript in this window. 1270 1271 This method allows one to inject javascript from the server to client. 1272 A client implementation is not required to implement this 1273 functionality, but currently all web-based clients do implement this. 1274 1275 Executing javascript this way often leads to cross-browser 1276 compatibility issues and regressions that are hard to resolve. Use of 1277 this method should be avoided and instead it is recommended to create 1278 new widgets with GWT. 1279 1280 @param script: 1281 JavaScript snippet that will be executed. 1282 """ 1283 if self.getParent() is not None: 1284 raise NotImplementedError, ('Only application level ' 1285 'windows can execute javascript.') 1286 1287 if self._jsExecQueue is None: 1288 self._jsExecQueue = list() 1289 1290 self._jsExecQueue.append(script) 1291 1292 self.requestRepaint()
1293 1294
1295 - def isClosable(self):
1296 """Returns the closable status of the sub window. If a sub window is 1297 closable it typically shows an X in the upper right corner. Clicking 1298 on the X sends a close event to the server. Setting closable to false 1299 will remove the X from the sub window and prevent the user from 1300 closing the window. 1301 1302 Note! For historical reasons readonly controls the closability of the 1303 sub window and therefore readonly and closable affect each other. 1304 Setting readonly to true will set closable to false and vice versa. 1305 1306 Closable only applies to sub windows, not to browser level windows. 1307 1308 @return: true if the sub window can be closed by the user. 1309 """ 1310 return not self.isReadOnly()
1311 1312
1313 - def setClosable(self, closable):
1314 """Sets the closable status for the sub window. If a sub window is 1315 closable it typically shows an X in the upper right corner. Clicking 1316 on the X sends a close event to the server. Setting closable to false 1317 will remove the X from the sub window and prevent the user from 1318 closing the window. 1319 1320 Note! For historical reasons readonly controls the closability of the 1321 sub window and therefore readonly and closable affect each other. 1322 Setting readonly to true will set closable to false and vice versa. 1323 1324 Closable only applies to sub windows, not to browser level windows. 1325 1326 @param closable: 1327 determines if the sub window can be closed by the user. 1328 """ 1329 self.setReadOnly(not closable)
1330 1331
1332 - def isDraggable(self):
1333 """Indicates whether a sub window can be dragged or not. By default 1334 a sub window is draggable. 1335 1336 Draggable only applies to sub windows, not to browser level windows. 1337 """ 1338 return self._draggable
1339 1340
1341 - def setDraggable(self, draggable):
1342 """Enables or disables that a sub window can be dragged (moved) by 1343 the user. By default a sub window is draggable. 1344 1345 Draggable only applies to sub windows, not to browser level windows. 1346 1347 @param draggable: 1348 true if the sub window can be dragged by the user 1349 """ 1350 self._draggable = draggable 1351 self.requestRepaint()
1352 1353
1354 - def setCloseShortcut(self, keyCode, *modifiers):
1355 """Makes is possible to close the window by pressing the given 1356 L{KeyCode} and (optional) L{ModifierKey}s. 1357 1358 Note that this shortcut only reacts while the window has focus, 1359 closing itself - if you want to close a subwindow from a parent 1360 window, use L{addAction} of the parent window instead. 1361 1362 @param keyCode: 1363 the keycode for invoking the shortcut 1364 @param modifiers: 1365 the (optional) modifiers for invoking the shortcut, 1366 null for none 1367 """ 1368 if self.closeShortcut is not None: 1369 self.removeAction(self.closeShortcut) 1370 1371 self.closeShortcut = CloseShortcut(self, keyCode, modifiers) 1372 1373 self.addAction(self.closeShortcut)
1374 1375
1376 - def removeCloseShortcut(self):
1377 """Removes the keyboard shortcut previously set with 1378 L{setCloseShortcut}. 1379 """ 1380 if self.closeShortcut is not None: 1381 self.removeAction(self.closeShortcut) 1382 self.closeShortcut = None
1383 1384
1385 - def focus(self):
1386 """If the window is a sub-window focusing will cause the sub-window 1387 to be brought on top of other sub-windows on gain keyboard focus. 1388 """ 1389 if self.getParent() is not None: 1390 # When focusing a sub-window it basically means it should be 1391 # brought to the front. Instead of just moving the keyboard 1392 # focus we focus the window and bring it top-most. 1393 self._bringToFront() 1394 else: 1395 super(Window, self).focus()
1396 1397
1398 -class OpenResource(object):
1399 """Private class for storing properties related to opening resources.""" 1400
1401 - def __init__(self, resource, name, width, height, border):
1402 """Creates a new open resource. 1403 1404 @param resource: 1405 The resource to open 1406 @param name: 1407 The name of the target window 1408 @param width: 1409 The width of the target window 1410 @param height: 1411 The height of the target window 1412 @param border: 1413 The border style of the target window 1414 """ 1415 self._resource = resource 1416 1417 #: The name of the target window 1418 self._name = name 1419 1420 #: The width of the target window 1421 self._width = width 1422 1423 #: The height of the target window 1424 self._height = height 1425 1426 #: The border style of the target window 1427 self._border = border
1428 1429
1430 - def paintContent(self, target):
1431 """Paints the open request. Should be painted inside the window. 1432 1433 @param target: 1434 the paint target 1435 @raise PaintException: 1436 if the paint operation fails 1437 """ 1438 target.startTag('open') 1439 target.addAttribute('src', self._resource) 1440 if self._name is not None and len(self._name) > 0: 1441 target.addAttribute('name', self._name) 1442 1443 if self._width >= 0: 1444 target.addAttribute('width', self._width) 1445 1446 if self._height >= 0: 1447 target.addAttribute('height', self._height) 1448 1449 if self._border == Window.BORDER_MINIMAL: 1450 target.addAttribute('border', 'minimal') 1451 elif self._border == Window.BORDER_NONE: 1452 target.addAttribute('border', 'none') 1453 1454 target.endTag('open')
1455 1456
1457 -class CloseEvent(ComponentEvent):
1458
1459 - def __init__(self, source):
1460 super(CloseEvent, self).__init__(source)
1461 1462
1463 - def getWindow(self):
1464 """Gets the Window. 1465 1466 @return: the window. 1467 """ 1468 return self.getSource()
1469 1470
1471 -class ResizeEvent(ComponentEvent):
1472 """Resize events are fired whenever the client-side fires a resize-event 1473 (e.g. the browser window is resized). The frequency may vary across 1474 browsers. 1475 """ 1476
1477 - def __init__(self, source):
1478 super(ResizeEvent, self).__init__(source)
1479 1480
1481 - def getWindow(self):
1482 """Get the window form which this event originated 1483 1484 @return: the window 1485 """ 1486 return self.getSource()
1487 1488
1489 -class Notification(object):
1490 """A notification message, used to display temporary messages to the user - 1491 for example "Document saved", or "Save failed". 1492 1493 The notification message can consist of several parts: caption, 1494 description and icon. It is usually used with only caption - one should 1495 be wary of filling the notification with too much information. 1496 1497 The notification message tries to be as unobtrusive as possible, while 1498 still drawing needed attention. There are several basic types of messages 1499 that can be used in different situations: 1500 1501 - TYPE_HUMANIZED_MESSAGE fades away quickly as soon as the user uses 1502 the mouse or types something. It can be used to show fairly unimportant 1503 messages, such as feedback that an operation succeeded ("Document 1504 Saved") - the kind of messages the user ignores once the application 1505 is familiar. 1506 1507 - TYPE_WARNING_MESSAGE is shown for a short while after the user uses 1508 the mouse or types something. It's default style is also more 1509 noticeable than the humanized message. It can be used for messages that 1510 do not contain a lot of important information, but should be noticed by 1511 the user. Despite the name, it does not have to be a warning, but can 1512 be used instead of the humanized message whenever you want to make the 1513 message a little more noticeable. 1514 1515 - TYPE_ERROR_MESSAGE requires to user to click it before disappearing, 1516 and can be used for critical messages. 1517 1518 - TYPE_TRAY_NOTIFICATION is shown for a while in the lower left corner 1519 of the window, and can be used for "convenience notifications" that do 1520 not have to be noticed immediately, and should not interfere with the 1521 current task - for instance to show "You have a new message in your 1522 inbox" while the user is working in some other area of the application. 1523 1524 In addition to the basic pre-configured types, a Notification can also be 1525 configured to show up in a custom position, for a specified time (or 1526 until clicked), and with a custom stylename. An icon can also be added. 1527 """ 1528 1529 TYPE_HUMANIZED_MESSAGE = 1 1530 TYPE_WARNING_MESSAGE = 2 1531 TYPE_ERROR_MESSAGE = 3 1532 TYPE_TRAY_NOTIFICATION = 4 1533 1534 POSITION_CENTERED = 1 1535 POSITION_CENTERED_TOP = 2 1536 POSITION_CENTERED_BOTTOM = 3 1537 POSITION_TOP_LEFT = 4 1538 POSITION_TOP_RIGHT = 5 1539 POSITION_BOTTOM_LEFT = 6 1540 POSITION_BOTTOM_RIGHT = 7 1541 1542 DELAY_FOREVER = -1 1543 DELAY_NONE = 0 1544
1545 - def __init__(self, *args):
1546 """Creates a notification message. 1547 1548 Care should be taken to to avoid XSS vulnerabilities as the caption 1549 and description are by default rendered as html. 1550 1551 @param args: tuple of the form 1552 - (caption) 1553 1. The message to show 1554 - (caption, type) 1555 1. The message to show 1556 2. The type of message 1557 - (caption, description) 1558 1. The message caption 1559 2. The message description 1560 - (caption, description, type) 1561 1. The message caption 1562 2. The message description 1563 3. The type of message 1564 - (caption, description, type, htmlContentAllowed) 1565 1. The message caption 1566 2. The message description 1567 3. The type of message 1568 4. Whether html in the caption and description should be 1569 displayed as html or as plain text 1570 """ 1571 self._caption = None 1572 self._description = None 1573 self._icon = None 1574 self._position = self.POSITION_CENTERED 1575 self._delayMsec = 0 1576 self._styleName = None 1577 self._htmlContentAllowed = True 1578 1579 nargs = len(args) 1580 if nargs == 1: 1581 caption, = args 1582 Notification.__init__(self, caption, None, 1583 self.TYPE_HUMANIZED_MESSAGE) 1584 elif nargs == 2: 1585 if isinstance(args[1], int): 1586 caption, typ = args 1587 Notification.__init__(self, caption, None, typ) 1588 else: 1589 caption, description = args 1590 Notification.__init__(self, caption, description, 1591 self.TYPE_HUMANIZED_MESSAGE) 1592 elif nargs == 3: 1593 caption, description, typ = args 1594 self._caption = caption 1595 self._description = description 1596 self.setType(typ) 1597 elif nargs == 4: 1598 caption, description, typ, htmlContentAllowed = args 1599 self._caption = caption 1600 self._description = description 1601 self._htmlContentAllowed = htmlContentAllowed 1602 self.setType(typ) 1603 else: 1604 raise ValueError, 'invalid number of arguments'
1605 1606
1607 - def setType(self, typ):
1608 if typ == self.TYPE_WARNING_MESSAGE: 1609 self._delayMsec = 1500 1610 self._styleName = 'warning' 1611 elif typ == self.TYPE_ERROR_MESSAGE: 1612 self._delayMsec = -1 1613 self._styleName = 'error' 1614 elif typ == self.TYPE_TRAY_NOTIFICATION: 1615 self._delayMsec = 3000 1616 self._position = self.POSITION_BOTTOM_RIGHT 1617 self._styleName = 'tray' 1618 elif typ == self.TYPE_HUMANIZED_MESSAGE: 1619 pass 1620 else: 1621 pass
1622 1623
1624 - def getCaption(self):
1625 """Gets the caption part of the notification message. 1626 1627 @return: The message caption 1628 """ 1629 return self._caption
1630 1631
1632 - def setCaption(self, caption):
1633 """Sets the caption part of the notification message 1634 1635 @param caption: 1636 The message caption 1637 """ 1638 self._caption = caption
1639 1640
1641 - def getMessage(self):
1642 """@deprecated: Use L{getDescription} instead. 1643 """ 1644 return self._description
1645 1646
1647 - def setMessage(self, description):
1648 """@deprecated: Use L{setDescription} instead. 1649 """ 1650 self._description = description
1651 1652
1653 - def getDescription(self):
1654 """Gets the description part of the notification message. 1655 1656 @return: The message description. 1657 """ 1658 return self._description
1659 1660
1661 - def setDescription(self, description):
1662 """Sets the description part of the notification message. 1663 """ 1664 self._description = description
1665 1666
1667 - def getPosition(self):
1668 """Gets the position of the notification message. 1669 1670 @return: The position 1671 """ 1672 return self._position
1673 1674
1675 - def setPosition(self, position):
1676 """Sets the position of the notification message. 1677 1678 @param position: 1679 The desired notification position 1680 """ 1681 self._position = position
1682 1683
1684 - def getIcon(self):
1685 """Gets the icon part of the notification message. 1686 1687 @return: The message icon 1688 """ 1689 return self._icon
1690 1691
1692 - def setIcon(self, icon):
1693 """Sets the icon part of the notification message. 1694 1695 @param icon: 1696 The desired message icon 1697 """ 1698 self._icon = icon
1699 1700
1701 - def getDelayMsec(self):
1702 """Gets the delay before the notification disappears. 1703 1704 @return: the delay in msec, -1 indicates the message has to be 1705 clicked. 1706 """ 1707 return self._delayMsec
1708 1709
1710 - def setDelayMsec(self, delayMsec):
1711 """Sets the delay before the notification disappears. 1712 1713 @param delayMsec: 1714 the desired delay in msec, -1 to require the user to click 1715 the message 1716 """ 1717 self._delayMsec = delayMsec
1718 1719
1720 - def setStyleName(self, styleName):
1721 """Sets the style name for the notification message. 1722 1723 @param styleName: 1724 The desired style name. 1725 """ 1726 self._styleName = styleName
1727 1728
1729 - def getStyleName(self):
1730 """Gets the style name for the notification message. 1731 """ 1732 return self._styleName
1733 1734
1735 - def setHtmlContentAllowed(self, htmlContentAllowed):
1736 """Sets whether html is allowed in the caption and description. If set 1737 to true, the texts are passed to the browser as html and the 1738 developer is responsible for ensuring no harmful html is used. If set 1739 to false, the texts are passed to the browser as plain text. 1740 1741 @param htmlContentAllowed: 1742 true if the texts are used as html, false if used as plain 1743 text 1744 """ 1745 self._htmlContentAllowed = htmlContentAllowed
1746 1747
1748 - def isHtmlContentAllowed(self):
1749 """Checks whether caption and description are interpreted as html or 1750 plain text. 1751 1752 @return: true if the texts are used as html, false if used as plain 1753 text 1754 @see: L{setHtmlContentAllowed} 1755 """ 1756 return self._htmlContentAllowed
1757 1758
1759 -class CloseShortcut(ShortcutListener):
1760 """A L{ShortcutListener} specifically made to define a keyboard 1761 shortcut that closes the window:: 1762 1763 # within the window using helper 1764 subWindow.setCloseShortcut(KeyCode.ESCAPE, NOne) 1765 1766 # or globally 1767 getWindow().addAction(CloseShortcut(subWindow, KeyCode.ESCAPE)) 1768 """ 1769
1770 - def __init__(self, *args):
1771 """Creates a keyboard shortcut for closing the given window using 1772 the shorthand notation defined in L{ShortcutAction} or the 1773 given L{KeyCode} and L{ModifierKey}s. 1774 1775 @param args: tuple of the form 1776 - (window, shorthandCaption) 1777 1. to be closed when the shortcut is invoked 1778 2. the caption with shortcut keycode and modifiers indicated 1779 - (window, keyCode, modifiers) 1780 1. to be closed when the shortcut is invoked 1781 2. KeyCode to react to 1782 3. optional modifiers for shortcut 1783 - (window, keyCode) 1784 1. to be closed when the shortcut is invoked 1785 2. KeyCode to react to 1786 """ 1787 self.window = None 1788 1789 nargs = len(args) 1790 if nargs == 2: 1791 if isinstance(args[1], int): 1792 window, keyCode = args 1793 CloseShortcut.__init__(self, window, keyCode, None) 1794 else: 1795 window, shorthandCaption = args 1796 super(CloseShortcut, self).__init__(shorthandCaption) 1797 self.window = window 1798 elif nargs == 3: 1799 window, keyCode = args[:2] 1800 modifiers = args[2:] 1801 super(CloseShortcut, self).__init__(None, keyCode, modifiers) 1802 self.window = window 1803 else: 1804 raise ValueError, 'invalid number of arguments'
1805 1806
1807 - def handleAction(self, sender, target):
1808 self.window.close()
1809