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

Source Code for Module muntjac.ui.abstract_component

   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 the default implementation for the IComponent interface.""" 
  17   
  18  import re 
  19   
  20  from warnings import warn 
  21   
  22  from muntjac.event.method_event_source import IMethodEventSource 
  23  from muntjac.event.event_router import EventRouter 
  24  from muntjac.terminal.terminal import IErrorEvent as ITerminalErrorEvent 
  25  from muntjac.terminal.paintable import RepaintRequestEvent,\ 
  26      IRepaintRequestListener 
  27  from muntjac.util import fullname 
  28   
  29  from muntjac.ui.component import \ 
  30      IComponent, IListener, IFocusable, Event as ComponentEvent 
  31  from muntjac.ui import component 
  32   
  33   
  34  _COMPONENT_EVENT_METHOD = getattr(IListener, 'componentEvent') 
  35   
  36   
37 -class AbstractComponent(IComponent, IMethodEventSource):
38 """An abstract class that defines default implementation for the 39 L{IComponent} interface. Basic UI components that are not derived 40 from an external component can inherit this class to easily qualify 41 as Muntjac components. Most components in Muntjac do just that. 42 43 @author: Vaadin Ltd. 44 @author: Richard Lincoln 45 @version: 1.1.2 46 """ 47 48 SIZE_PATTERN = '^(-?\\d+(\\.\\d+)?)(%|px|em|ex|in|cm|mm|pt|pc)?$' 49
50 - def __init__(self):
51 """Constructs a new IComponent.""" 52 super(AbstractComponent, self).__init__() 53 54 #: Style names. 55 self._styles = None 56 57 #: Caption text. 58 self._caption = None 59 60 #: Application specific data object. The component does not use 61 # or modify this. 62 self._applicationData = None 63 64 #: Icon to be shown together with caption. 65 self._icon = None 66 67 #: Is the component enabled (its normal usage is allowed). 68 self._enabled = True 69 70 #: Is the component visible (it is rendered). 71 self._visible = True 72 73 #: Is the component read-only ? 74 self._readOnly = False 75 76 #: Description of the usage (XML). 77 self._description = None 78 79 #: The container this component resides in. 80 self._parent = None 81 82 #: The EventRouter used for the event model. 83 self._eventRouter = None 84 85 #: A set of event identifiers with registered listeners. 86 self._eventIdentifiers = None 87 88 #: The internal error message of the component. 89 self._componentError = None 90 91 #: Immediate mode: if true, all variable changes are required 92 # to be sent from the terminal immediately. 93 self._immediate = False 94 95 #: Locale of this component. 96 self._locale = None 97 98 #: The component should receive focus (if L{IFocusable}) 99 # when attached. 100 self._delayedFocus = None 101 102 #: List of repaint request listeners or null if not listened at all. 103 self._repaintRequestListeners = list() 104 105 self._repaintRequestCallbacks = dict() 106 107 #: Are all the repaint listeners notified about recent changes ? 108 self._repaintRequestListenersNotified = False 109 110 self._testingId = None 111 112 # Sizeable fields 113 self._width = self.SIZE_UNDEFINED 114 self._height = self.SIZE_UNDEFINED 115 self._widthUnit = self.UNITS_PIXELS 116 self._heightUnit = self.UNITS_PIXELS 117 118 self._sizePattern = re.compile(self.SIZE_PATTERN) 119 120 self.errorHandler = None
121 122 #ComponentSizeValidator.setCreationLocation(self) 123 124
125 - def __getstate__(self):
126 result = self.__dict__.copy() 127 del result['_sizePattern'] 128 return result
129 130
131 - def __setstate__(self, d):
132 self.__dict__ = d 133 self._sizePattern = re.compile(self.SIZE_PATTERN)
134 135
136 - def setDebugId(self, idd):
137 self._testingId = idd
138 139
140 - def getDebugId(self):
141 return self._testingId
142 143
144 - def getStyle(self):
145 """Gets style for component. Multiple styles are joined with spaces. 146 147 @return: the component's styleValue of property style. 148 @deprecated: Use getStyleName() instead; renamed for consistency and 149 to indicate that "style" should not be used to switch 150 client side implementation, only to style the component. 151 """ 152 warn('Use getStyleName() instead', DeprecationWarning) 153 return self.getStyleName()
154 155
156 - def setStyle(self, style):
157 """Sets and replaces all previous style names of the component. This 158 method will trigger a L{RepaintRequestEvent}. 159 160 @param style: 161 the new style of the component. 162 @deprecated: Use setStyleName() instead; renamed for consistency and 163 to indicate that "style" should not be used to switch 164 client side implementation, only to style the component. 165 """ 166 warn('Use setStyleName() instead', DeprecationWarning) 167 self.setStyleName(style)
168 169
170 - def getStyleName(self):
171 # Gets the component's style. 172 s = '' 173 if self._styles is not None: 174 s = ' '.join(self._styles) 175 return s
176 177
178 - def setStyleName(self, style):
179 # Sets the component's style. 180 if style is None or style == '': 181 self._styles = None 182 self.requestRepaint() 183 return 184 185 if self._styles is None: 186 self._styles = list() 187 188 del self._styles[:] 189 190 styleParts = style.split() 191 for part in styleParts: 192 if len(part) > 0: 193 self._styles.append(part) 194 195 self.requestRepaint()
196 197
198 - def addStyleName(self, style):
199 if style is None or style == '': 200 return 201 202 if self._styles is None: 203 self._styles = list() 204 205 for s in style.split(): 206 if s not in self._styles: 207 self._styles.append(s) 208 self.requestRepaint()
209 210
211 - def removeStyleName(self, style):
212 if self._styles is not None: 213 styleParts = style.split() 214 for part in styleParts: 215 if len(part) > 0 and part in self._styles: 216 self._styles.remove(part) 217 self.requestRepaint()
218 219
220 - def getCaption(self):
221 # Get's the component's caption. 222 return self._caption
223 224
225 - def setCaption(self, caption):
226 """Sets the component's caption string. Caption is the 227 visible name of the component. This method will trigger a 228 L{RepaintRequestEvent}. 229 230 @param caption: 231 the new caption string for the component. 232 """ 233 self._caption = caption 234 self.requestRepaint()
235 236
237 - def getLocale(self):
238 if self._locale is not None: 239 return self._locale 240 241 if self._parent is not None: 242 return self._parent.getLocale() 243 244 app = self.getApplication() 245 if app is not None: 246 return app.getLocale() 247 248 return None
249 250
251 - def setLocale(self, locale):
252 """Sets the locale of this component:: 253 254 # IComponent for which the locale is meaningful 255 date = InlineDateField("Datum") 256 257 # German language specified with ISO 639-1 language 258 # code and ISO 3166-1 alpha-2 country code. 259 date.setLocale(Locale("de", "DE")) 260 261 date.setResolution(DateField.RESOLUTION_DAY) 262 layout.addComponent(date) 263 264 @param locale: 265 the locale to become this component's locale. 266 """ 267 self._locale = locale 268 self.requestRepaint()
269 270
271 - def getIcon(self):
272 # Gets the component's icon resource. 273 return self._icon
274 275
276 - def setIcon(self, icon):
277 """Sets the component's icon. This method will trigger a 278 L{RepaintRequestEvent<IPaintable.RepaintRequestEvent>}. 279 280 @param icon: 281 the icon to be shown with the component's caption. 282 """ 283 self._icon = icon 284 self.requestRepaint()
285 286
287 - def isEnabled(self):
288 # Tests if the component is enabled or not. 289 return (self._enabled and ((self._parent is None) 290 or (self._parent.isEnabled())) and self.isVisible())
291 292
293 - def setEnabled(self, enabled):
294 # Enables or disables the component. Don't add a JavaDoc comment 295 # here, we use the default documentation from implemented interface. 296 if self._enabled != enabled: 297 wasEnabled = self._enabled 298 wasEnabledInContext = self.isEnabled() 299 300 self._enabled = enabled 301 302 isEnabled = enabled 303 isEnabledInContext = self.isEnabled() 304 305 # If the actual enabled state (as rendered, in context) has not 306 # changed we do not need to repaint except if the parent is 307 # invisible. 308 # If the parent is invisible we must request a repaint so the 309 # component is repainted with the new enabled state when the 310 # parent is set visible again. This workaround is needed as 311 # isEnabled checks isVisible. 312 needRepaint = ((wasEnabledInContext != isEnabledInContext) 313 or (wasEnabled != isEnabled 314 and (self.getParent() is None) 315 or (not self.getParent().isVisible()))) 316 317 if needRepaint: 318 self.requestRepaint()
319 320
321 - def isImmediate(self):
322 # Tests if the component is in the immediate mode. 323 return self._immediate
324 325
326 - def setImmediate(self, immediate):
327 """Sets the component's immediate mode to the specified status. 328 This method will trigger a L{RepaintRequestEvent}. 329 330 @param immediate: 331 the boolean value specifying if the component should 332 be in the immediate mode after the call. 333 @see: L{IComponent.isImmediate} 334 """ 335 self._immediate = immediate 336 self.requestRepaint()
337 338
339 - def isVisible(self):
340 return (self._visible 341 and (self.getParent() is None 342 or self.getParent().isVisible()))
343 344
345 - def setVisible(self, visible):
346 if self._visible != visible: 347 self._visible = visible 348 # Instead of requesting repaint normally we 349 # fire the event directly to assure that the 350 # event goes through event in the component might 351 # now be invisible 352 self.fireRequestRepaintEvent(None)
353 354
355 - def getDescription(self):
356 """Gets the component's description, used in tooltips and can be 357 displayed directly in certain other components such as forms. The 358 description can be used to briefly describe the state of the 359 component to the user. The description string may contain certain 360 XML tags:: 361 362 <table border=1> 363 <tr> 364 <td width=120><b>Tag</b></td> 365 <td width=120><b>Description</b></td> 366 <td width=120><b>Example</b></td> 367 </tr> 368 <tr> 369 <td>&lt;b></td> 370 <td>bold</td> 371 <td><b>bold text</b></td> 372 </tr> 373 <tr> 374 <td>&lt;i></td> 375 <td>italic</td> 376 <td><i>italic text</i></td> 377 </tr> 378 <tr> 379 <td>&lt;u></td> 380 <td>underlined</td> 381 <td><u>underlined text</u></td> 382 </tr> 383 <tr> 384 <td>&lt;br></td> 385 <td>linebreak</td> 386 <td>N/A</td> 387 </tr> 388 <tr> 389 <td>&lt;ul><br> 390 &lt;li>item1<br> 391 &lt;li>item1<br> 392 &lt;/ul></td> 393 <td>item list</td> 394 <td> 395 <ul> 396 <li>item1 397 <li>item2 398 </ul> 399 </td> 400 </tr> 401 </table> 402 403 These tags may be nested. 404 405 @return: component's description string 406 """ 407 return self._description
408 409
410 - def setDescription(self, description):
411 """Sets the component's description. See L{getDescription} 412 for more information on what the description is. This method will 413 trigger a L{RepaintRequestEvent}. 414 415 The description is displayed as HTML/XHTML in tooltips or directly in 416 certain components so care should be taken to avoid creating the 417 possibility for HTML injection and possibly XSS vulnerabilities. 418 419 @param description: 420 the new description string for the component. 421 """ 422 self._description = description 423 self.requestRepaint()
424 425
426 - def getParent(self):
427 # Gets the component's parent component. 428 return self._parent
429 430
431 - def setParent(self, parent):
432 # Sets the parent component. 433 434 # If the parent is not changed, don't do anything 435 if parent == self._parent: 436 return 437 438 if parent is not None and self._parent is not None: 439 raise ValueError, fullname(self) + ' already has a parent.' 440 441 # Send detach event if the component have been connected to a window 442 if self.getApplication() is not None: 443 self.detach() 444 445 # Connect to new parent 446 self._parent = parent 447 448 # Send attach event if connected to a window 449 if self.getApplication() is not None: 450 self.attach()
451 452
453 - def getErrorMessage(self):
454 """Gets the error message for this component. 455 456 @return: ErrorMessage containing the description of the error state 457 of the component or null, if the component contains no errors. 458 Extending classes should override this method if they support 459 other error message types such as validation errors or 460 buffering errors. The returned error message contains 461 information about all the errors. 462 """ 463 return self._componentError
464 465
466 - def getComponentError(self):
467 """Gets the component's error message. 468 469 @return: the component's error message. 470 """ 471 return self._componentError
472 473
474 - def setComponentError(self, componentError):
475 """Sets the component's error message. The message may contain 476 certain XML tags. 477 478 @param componentError: 479 the new C{ErrorMessage} of the component. 480 """ 481 self._componentError = componentError 482 self.fireComponentErrorEvent() 483 self.requestRepaint()
484 485
486 - def isReadOnly(self):
487 # Tests if the component is in read-only mode. 488 return self._readOnly
489 490
491 - def setReadOnly(self, readOnly):
492 # Sets the component's read-only mode. 493 self._readOnly = readOnly 494 self.requestRepaint()
495 496
497 - def getWindow(self):
498 # Gets the parent window of the component. 499 if self._parent is None: 500 return None 501 else: 502 return self._parent.getWindow()
503 504
505 - def attach(self):
506 # Notify the component that it's attached to a window. 507 self.requestRepaint() 508 if not self._visible: 509 # Bypass the repaint optimization in childRequestedRepaint 510 # method when attaching. When reattaching (possibly moving) 511 # must repaint 512 self.fireRequestRepaintEvent(None) 513 514 if self._delayedFocus: 515 self.focus()
516 517
518 - def detach(self):
519 # Detach the component from application. 520 pass
521 522
523 - def focus(self):
524 """Sets the focus for this component if the component is 525 L{IFocusable}. 526 """ 527 if isinstance(self, IFocusable): 528 app = self.getApplication() 529 if app is not None: 530 self.getWindow().setFocusedComponent(self) 531 self._delayedFocus = False 532 else: 533 self._delayedFocus = True
534 535
536 - def getApplication(self):
537 """Gets the application object to which the component is attached. 538 539 The method will return C{None} if the component is not currently 540 attached to an application. This is often a problem in constructors 541 of regular components and in the initializers of custom composite 542 components. A standard workaround is to move the problematic 543 initialization to L{attach}, as described in the documentation 544 of the method. 545 546 B{This method is not meant to be overridden.} 547 548 @return: the parent application of the component or C{None}. 549 @see: L{attach} 550 """ 551 if self._parent is None: 552 return None 553 else: 554 return self._parent.getApplication()
555 556
557 - def requestRepaintRequests(self):
558 self._repaintRequestListenersNotified = False
559 560
561 - def paint(self, target):
562 """Paints the Paintable into a UIDL stream. This method creates the 563 UIDL sequence describing it and outputs it to the given UIDL stream. 564 565 It is called when the contents of the component should be painted in 566 response to the component first being shown or having been altered so 567 that its visual representation is changed. 568 569 B{Do not override this to paint your component.} Override 570 L{paintContent} instead. 571 572 @param target: 573 the target UIDL stream where the component should paint 574 itself to. 575 @raise PaintException: 576 if the paint operation failed. 577 """ 578 tag = target.getTag(self) 579 if ((not target.startTag(self, tag)) 580 or self._repaintRequestListenersNotified): 581 582 # Paint the contents of the component 583 584 # Only paint content of visible components. 585 if self.isVisible(): 586 from muntjac.terminal.gwt.server.component_size_validator \ 587 import ComponentSizeValidator # FIXME: circular import 588 589 if (self.getHeight() >= 0 590 and (self.getHeightUnits() != self.UNITS_PERCENTAGE 591 or ComponentSizeValidator.parentCanDefineHeight(self))): 592 593 target.addAttribute('height', '' + self.getCSSHeight()) 594 595 if (self.getWidth() >= 0 596 and (self.getWidthUnits() != self.UNITS_PERCENTAGE 597 or ComponentSizeValidator.parentCanDefineWidth(self))): 598 599 target.addAttribute('width', '' + self.getCSSWidth()) 600 601 if self._styles is not None and len(self._styles) > 0: 602 target.addAttribute('style', self.getStyle()) 603 604 if self.isReadOnly(): 605 target.addAttribute('readonly', True) 606 607 if self.isImmediate(): 608 target.addAttribute('immediate', True) 609 610 if not self.isEnabled(): 611 target.addAttribute('disabled', True) 612 613 if self.getCaption() is not None: 614 target.addAttribute('caption', self.getCaption()) 615 616 if self.getIcon() is not None: 617 target.addAttribute('icon', self.getIcon()) 618 619 if (self.getDescription() is not None 620 and len(self.getDescription()) > 0): 621 target.addAttribute('description', self.getDescription()) 622 623 if self._eventIdentifiers is not None: 624 target.addAttribute('eventListeners', 625 list(self._eventIdentifiers)) 626 627 self.paintContent(target) 628 629 error = self.getErrorMessage() 630 if error is not None: 631 error.paint(target) 632 else: 633 target.addAttribute('invisible', True) 634 else: 635 # Contents have not changed, only cached presentation can be used 636 target.addAttribute('cached', True) 637 target.endTag(tag) 638 639 self._repaintRequestListenersNotified = False
640 641
642 - def getCSSHeight(self):
643 """Build CSS compatible string representation of height. 644 645 @return: CSS height 646 """ 647 if self.getHeightUnits() == self.UNITS_PIXELS: 648 return (str( int(self.getHeight()) ) 649 + self.UNIT_SYMBOLS[self.getHeightUnits()]) 650 else: 651 return (str(self.getHeight()) 652 + self.UNIT_SYMBOLS[self.getHeightUnits()])
653 654
655 - def getCSSWidth(self):
656 """Build CSS compatible string representation of width. 657 658 @return: CSS width 659 """ 660 if self.getWidthUnits() == self.UNITS_PIXELS: 661 return (str( int(self.getWidth()) ) 662 + self.UNIT_SYMBOLS[self.getWidthUnits()]) 663 else: 664 return (str(self.getWidth()) 665 + self.UNIT_SYMBOLS[self.getWidthUnits()])
666 667
668 - def paintContent(self, target):
669 """Paints any needed component-specific things to the given UIDL 670 stream. The more general L{paint} method handles 671 all general attributes common to all components, and it calls this 672 method to paint any component-specific attributes to the UIDL stream. 673 674 @param target: 675 the target UIDL stream where the component should paint 676 itself to 677 @raise PaintException: 678 if the paint operation failed. 679 """ 680 pass
681 682
683 - def requestRepaint(self):
684 # The effect of the repaint request is identical to case where 685 # a child requests repaint 686 self.childRequestedRepaint(None)
687 688
689 - def childRequestedRepaint(self, alreadyNotified):
690 # Invisible components (by flag in this particular component) 691 # do not need repaints 692 if not self._visible: 693 return 694 self.fireRequestRepaintEvent(alreadyNotified)
695 696
697 - def fireRequestRepaintEvent(self, alreadyNotified):
698 """Fires the repaint request event. 699 """ 700 # Notify listeners only once 701 if not self._repaintRequestListenersNotified: 702 # Notify the listeners 703 event = RepaintRequestEvent(self) 704 705 for listener in self._repaintRequestListeners: 706 if alreadyNotified is None: 707 alreadyNotified = list() 708 709 if listener not in alreadyNotified: 710 listener.repaintRequested(event) 711 alreadyNotified.append(listener) 712 self._repaintRequestListenersNotified = True 713 714 for callback, args in self._repaintRequestCallbacks.iteritems(): 715 if alreadyNotified is None: 716 alreadyNotified = list() 717 718 if callback not in alreadyNotified: 719 callback(event, *args) 720 alreadyNotified.append(callback) 721 self._repaintRequestListenersNotified = True 722 723 # Notify the parent 724 parent = self.getParent() 725 if parent is not None: 726 parent.childRequestedRepaint(alreadyNotified)
727 728
729 - def addListener(self, listener, iface=None):
730 if (isinstance(listener, IListener) and 731 (iface is None or issubclass(iface, IListener))): 732 self.registerListener(ComponentEvent, listener, 733 _COMPONENT_EVENT_METHOD) 734 735 if (isinstance(listener, IRepaintRequestListener) and 736 (iface is None or issubclass(iface, IRepaintRequestListener))): 737 if listener not in self._repaintRequestListeners: 738 self._repaintRequestListeners.append(listener)
739 740
741 - def addCallback(self, callback, eventType=None, *args):
742 if eventType is None: 743 eventType = callback._eventType 744 745 if issubclass(eventType, ComponentEvent): 746 self.registerCallback(ComponentEvent, callback, None, *args) 747 748 elif issubclass(eventType, RepaintRequestEvent): 749 self._repaintRequestCallbacks[callback] = args 750 751 else: 752 super(AbstractComponent, self).addCallback(callback, 753 eventType, *args)
754 755
756 - def registerListener(self, *args):
757 """Registers a new listener with the specified activation method to 758 listen events generated by this component. If the activation method 759 does not have any arguments the event object will not be passed to 760 it when it's called. 761 762 This method additionally informs the event-api to route events with 763 the given eventIdentifier to the components handleEvent function 764 call. 765 766 For more information on the inheritable event mechanism see the 767 L{muntjac.event package documentation<muntjac.event>}. 768 769 @param args: tuple of the form 770 - (eventIdentifier, eventType, target, method) 771 1. the identifier of the event to listen for 772 2. the type of the listened event. Events of this type or 773 its subclasses activate the listener. 774 3. the object instance who owns the activation method. 775 4. the activation method. 776 - (eventType, target, method) 777 1. the type of the listened event. Events of this type or 778 its subclasses activate the listener. 779 2. the object instance who owns the activation method. 780 3. the activation method or the name of the activation method. 781 """ 782 nargs = len(args) 783 if nargs == 3: 784 eventType, target, method = args 785 786 if self._eventRouter is None: 787 self._eventRouter = EventRouter() 788 789 self._eventRouter.addListener(eventType, target, method) 790 elif nargs == 4: 791 eventIdentifier, eventType, target, method = args 792 793 if self._eventRouter is None: 794 self._eventRouter = EventRouter() 795 796 if self._eventIdentifiers is None: 797 self._eventIdentifiers = set() 798 799 needRepaint = not self._eventRouter.hasListeners(eventType) 800 801 self._eventRouter.addListener(eventType, target, method) 802 803 if needRepaint: 804 self._eventIdentifiers.add(eventIdentifier) 805 self.requestRepaint() 806 else: 807 raise ValueError, 'invalid number of arguments'
808 809
810 - def registerCallback(self, eventType, callback, eventId, *args):
811 812 if hasattr(callback, 'im_self'): 813 target = callback.im_self 814 elif hasattr(callback, 'func_name'): 815 target = None 816 else: 817 raise ValueError('invalid callback: %s' % callback) 818 819 820 if len(args) > 0: 821 arguments = (None,) + args # assume event always passed first 822 eventArgIdx = 0 823 else: 824 arguments = None 825 eventArgIdx = None 826 827 828 if self._eventRouter is None: 829 self._eventRouter = EventRouter() 830 831 if self._eventIdentifiers is None: 832 self._eventIdentifiers = set() 833 834 if eventId is not None: 835 needRepaint = not self._eventRouter.hasListeners(eventType) 836 837 self._eventRouter.addListener(eventType, target, callback, 838 arguments, eventArgIdx) 839 840 if (eventId is not None) and needRepaint: 841 self._eventIdentifiers.add(eventId) 842 self.requestRepaint()
843 844
845 - def removeListener(self, listener, iface=None):
846 if (isinstance(listener, IListener) and 847 (iface is None or issubclass(iface, IListener))): 848 self.withdrawListener(ComponentEvent, listener, 849 _COMPONENT_EVENT_METHOD) 850 851 if (isinstance(listener, IRepaintRequestListener) and 852 (iface is None or issubclass(iface, IRepaintRequestListener))): 853 if listener in self._repaintRequestListeners: 854 self._repaintRequestListeners.remove(listener)
855 856
857 - def removeCallback(self, callback, eventType=None):
858 if eventType is None: 859 eventType = callback._eventType 860 861 if eventType == ComponentEvent: 862 self.withdrawCallback(ComponentEvent, callback) 863 864 elif eventType == RepaintRequestEvent: 865 if callback in self._repaintRequestCallbacks: 866 del self._repaintRequestCallbacks[callback] 867 else: 868 super(AbstractComponent, self).removeCallback(callback, eventType)
869 870
871 - def withdrawListener(self, *args):
872 """Removes all registered listeners matching the given parameters. 873 Since this method receives the event type and the listener object 874 as parameters, it will unregister all C{object}'s methods that are 875 registered to listen to events of type C{eventType} generated by 876 this component. 877 878 This method additionally informs the event-api to stop routing 879 events with the given eventIdentifier to the components handleEvent 880 function call. 881 882 For more information on the inheritable event mechanism see the 883 L{muntjac.event package documentation<muntjac.event>}. 884 885 @param args: tuple of the form 886 - (eventIdentifier, eventType, target) 887 1. the identifier of the event to stop listening for 888 2. the exact event type the C{object} listens to. 889 3. the target object that has registered to listen to events 890 of type C{eventType} with one or more methods. 891 - (eventType, target) 892 1. the exact event type the C{object} listens to. 893 2. the target object that has registered to listen to events 894 of type C{eventType} with one or more methods. 895 - (eventType, target, method) 896 1. the exact event type the C{object} listens to. 897 2. the target object that has registered to listen to events 898 of type C{eventType} with one or more methods. 899 3. the method or the name of the method owned by C{target} 900 that's registered to listen to events of type C{eventType}. 901 """ 902 nargs = len(args) 903 if nargs == 2: 904 eventType, target = args 905 906 if self._eventRouter is not None: 907 self._eventRouter.removeListener(eventType, target) 908 elif nargs == 3: 909 if isinstance(args[0], basestring): 910 eventIdentifier, eventType, target = args 911 912 if self._eventRouter is not None: 913 self._eventRouter.removeListener(eventType, target) 914 if not self._eventRouter.hasListeners(eventType): 915 self._eventIdentifiers.remove(eventIdentifier) 916 self.requestRepaint() 917 else: 918 if isinstance(args[2], basestring): 919 eventType, target, methodName = args 920 921 if self._eventRouter is not None: 922 self._eventRouter.removeListener(eventType, target, 923 methodName) 924 else: 925 eventType, target, method = args 926 927 if self._eventRouter is not None: 928 self._eventRouter.removeListener(eventType, target, 929 method) 930 else: 931 raise ValueError, 'invalid number of arguments'
932 933
934 - def withdrawCallback(self, eventType, callback, eventId=None):
935 if self._eventRouter is not None: 936 937 if hasattr(callback, 'im_self'): # method 938 target = callback.im_self 939 elif hasattr(callback, 'func_name'): # function 940 target = None 941 else: 942 raise ValueError('invalid callback: %s' % callback) 943 944 self._eventRouter.removeListener(eventType, target, callback) 945 946 if (eventId is not None and 947 not self._eventRouter.hasListeners(eventType)): 948 self._eventIdentifiers.remove(eventId) 949 self.requestRepaint()
950 951
952 - def changeVariables(self, source, variables):
953 # Invoked when the value of a variable has changed. 954 pass
955 956
957 - def hasListeners(self, eventType):
958 """Checks if the given L{Event} type is listened for this 959 component. 960 961 @param eventType: 962 the event type to be checked 963 @return: true if a listener is registered for the given event type 964 """ 965 return (self._eventRouter is not None 966 and self._eventRouter.hasListeners(eventType))
967 968
969 - def getListeners(self, eventType):
970 """Returns all listeners that are registered for the given event 971 type or one of its subclasses. 972 973 @param eventType: 974 The type of event to return listeners for. 975 @return: A collection with all registered listeners. Empty if no 976 listeners are found. 977 """ 978 if issubclass(eventType, RepaintRequestEvent): 979 # RepaintRequestListeners are not stored in eventRouter 980 return list(self._repaintRequestListeners) 981 982 if self._eventRouter is None: 983 return list() 984 985 return self._eventRouter.getListeners(eventType)
986 987
988 - def fireEvent(self, event):
989 """Sends the event to all listeners. 990 991 @param event: 992 the Event to be sent to all listeners. 993 """ 994 if self._eventRouter is not None: 995 self._eventRouter.fireEvent(event)
996 997
998 - def fireComponentEvent(self):
999 """Emits the component event. It is transmitted to all registered 1000 listeners interested in such events. 1001 """ 1002 event = ComponentEvent(self) 1003 self.fireEvent(event)
1004 1005
1006 - def fireComponentErrorEvent(self):
1007 """Emits the component error event. It is transmitted to all 1008 registered listeners interested in such events. 1009 """ 1010 event = component.ErrorEvent(self.getComponentError(), self) 1011 self.fireEvent(event)
1012 1013
1014 - def setData(self, data):
1015 """Sets the data object, that can be used for any application 1016 specific data. The component does not use or modify this data. 1017 1018 @param data: 1019 the Application specific data. 1020 """ 1021 self._applicationData = data
1022 1023
1024 - def getData(self):
1025 """Gets the application specific data. See L{setData}. 1026 1027 @return: the Application specific data set with setData function. 1028 """ 1029 return self._applicationData
1030 1031
1032 - def getHeight(self):
1033 return self._height
1034 1035
1036 - def getHeightUnits(self):
1037 return self._heightUnit
1038 1039
1040 - def getWidth(self):
1041 return self._width
1042 1043
1044 - def getWidthUnits(self):
1045 return self._widthUnit
1046 1047
1048 - def setHeight(self, height, unit=None):
1049 if unit is None: 1050 if isinstance(height, float): 1051 self.setHeight(height, self.getHeightUnits()) 1052 else: 1053 p = self.parseStringSize(height) 1054 self.setHeight(p[0], p[1]) 1055 else: 1056 self._height = height 1057 self._heightUnit = unit 1058 self.requestRepaint()
1059 #ComponentSizeValidator.setHeightLocation(this); 1060 1061
1062 - def setHeightUnits(self, unit):
1063 self.setHeight(self.getHeight(), unit)
1064 1065
1066 - def setSizeFull(self):
1067 self.setWidth(100, self.UNITS_PERCENTAGE) 1068 self.setHeight(100, self.UNITS_PERCENTAGE)
1069 1070
1071 - def setSizeUndefined(self):
1072 self.setWidth(-1, self.UNITS_PIXELS) 1073 self.setHeight(-1, self.UNITS_PIXELS)
1074 1075
1076 - def setWidth(self, width, unit=None):
1077 if unit is None: 1078 if isinstance(width, float): 1079 self.setWidth(width, self.getWidthUnits()) 1080 else: 1081 p = self.parseStringSize(width) 1082 self.setWidth(p[0], p[1]) 1083 else: 1084 self._width = width 1085 self._widthUnit = unit 1086 self.requestRepaint()
1087 #ComponentSizeValidator.setWidthLocation(this); 1088 1089
1090 - def setWidthUnits(self, unit):
1091 self.setWidth(self.getWidth(), unit)
1092 1093
1094 - def parseStringSize(self, s):
1095 """Returns array with size in index 0 unit in index 1. Null or empty 1096 string will produce {-1,UNITS_PIXELS}. 1097 """ 1098 values = [-1, self.UNITS_PIXELS] 1099 if s == None: 1100 return values 1101 1102 s = s.strip() 1103 if s == '': 1104 return values 1105 1106 match = self._sizePattern.match(s) 1107 if bool(match) == True: 1108 values[0] = float( match.group(1) ) 1109 if values[0] < 0: 1110 values[0] = -1 1111 else: 1112 unit = match.group(3) 1113 if unit == None: 1114 values[1] = self.UNITS_PIXELS 1115 elif unit == "px": 1116 values[1] = self.UNITS_PIXELS 1117 elif unit == "%": 1118 values[1] = self.UNITS_PERCENTAGE 1119 elif unit == "em": 1120 values[1] = self.UNITS_EM 1121 elif unit == "ex": 1122 values[1] = self.UNITS_EX 1123 elif unit == "in": 1124 values[1] = self.UNITS_INCH 1125 elif unit == "cm": 1126 values[1] = self.UNITS_CM 1127 elif unit == "mm": 1128 values[1] = self.UNITS_MM 1129 elif unit == "pt": 1130 values[1] = self.UNITS_POINTS 1131 elif unit == "pc": 1132 values[1] = self.UNITS_PICAS 1133 else: 1134 raise ValueError, "Invalid size argument: " + s 1135 1136 return values
1137 1138
1139 - def getErrorHandler(self):
1140 """Gets the error handler for the component. 1141 1142 The error handler is dispatched whenever there is an error 1143 processing the data coming from the client. 1144 """ 1145 return self.errorHandler
1146 1147
1148 - def setErrorHandler(self, errorHandler):
1149 """Sets the error handler for the component. 1150 1151 The error handler is dispatched whenever there is an error 1152 processing the data coming from the client. 1153 1154 If the error handler is not set, the application error handler 1155 is used to handle the exception. 1156 1157 @param errorHandler: 1158 AbstractField specific error handler 1159 """ 1160 self.errorHandler = errorHandler
1161 1162
1163 - def handleError(self, error):
1164 """Handle the component error event. 1165 1166 @param error: 1167 Error event to handle 1168 @return: True if the error has been handled False, otherwise. If 1169 the error haven't been handled by this component, it will 1170 be handled in the application error handler. 1171 """ 1172 if self.errorHandler != None: 1173 return self.errorHandler.handleComponentError(error) 1174 1175 return False
1176 1177
1178 -class IComponentErrorHandler(object):
1179 """Handle the component error 1180 """ 1181
1182 - def handleComponentError(self, event):
1183 """@return: True if the error has been handled False, otherwise 1184 """ 1185 pass
1186 1187
1188 -class IComponentErrorEvent(ITerminalErrorEvent):
1189 pass
1190