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

Source Code for Module muntjac.ui.abstract_field

   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  """For implementing buffered property editors.""" 
  17   
  18  from warnings import warn 
  19   
  20  from muntjac.event.shortcut_listener import ShortcutListener 
  21  from muntjac.event.action_manager import ActionManager 
  22   
  23  from muntjac.ui.abstract_component import AbstractComponent 
  24  from muntjac.ui.component import Event as ComponentEvent 
  25   
  26  from muntjac.event import action 
  27  from muntjac.ui import field 
  28  from muntjac.data import property as prop 
  29   
  30  from muntjac.data.validator import EmptyValueException 
  31  from muntjac.data.buffered import SourceException 
  32  from muntjac.data.validator import InvalidValueException 
  33  from muntjac.data.validatable import IValidatable 
  34   
  35  from muntjac.terminal.composite_error_message import CompositeErrorMessage 
  36   
  37   
  38  _VALUE_CHANGE_METHOD = getattr(prop.IValueChangeListener, 'valueChange') 
  39   
  40  _READ_ONLY_STATUS_CHANGE_METHOD = getattr(prop.IReadOnlyStatusChangeListener, 
  41          'readOnlyStatusChange') 
42 43 44 -class AbstractField(AbstractComponent, field.IField, 45 action.IShortcutNotifier, prop.IReadOnlyStatusChangeNotifier, 46 prop.IReadOnlyStatusChangeListener):
47 """Abstract field component for implementing buffered property editors. 48 The field may hold an internal value, or it may be connected to any data 49 source that implements the L{IProperty}interface. C{AbstractField} 50 implements that interface itself, too, so accessing the IProperty value 51 represented by it is straightforward. 52 53 AbstractField also provides the L{IBuffered} interface for buffering the 54 data source value. By default the IField is in write through-mode and 55 L{setWriteThrough}should be called to enable buffering. 56 57 The class also supports L{validators<IValidator>} to 58 make sure the value contained in the field is valid. 59 60 @author: Vaadin Ltd. 61 @author: Richard Lincoln 62 @version: 1.1.2 63 """ 64
65 - def __init__(self):
66 super(AbstractField, self).__init__() 67 68 #: Value of the abstract field. 69 self._value = None 70 71 #: Connected data-source. 72 self._dataSource = None 73 74 #: The list of validators. 75 self._validators = None 76 77 #: Auto commit mode. 78 self._writeThroughMode = True 79 80 #: Reads the value from data-source, when it is not modified. 81 self._readThroughMode = True 82 83 #: Is the field modified but not committed. 84 self._modified = False 85 86 #: Flag to indicate that the field is currently committing its 87 # value to the datasource. 88 self._committingValueToDataSource = False 89 90 #: Current source exception. 91 self._currentBufferedSourceException = None 92 93 #: Are the invalid values allowed in fields ? 94 self._invalidAllowed = True 95 96 #: Are the invalid values committed ? 97 self._invalidCommitted = False 98 99 #: The tab order number of this field. 100 self._tabIndex = 0 101 102 #: Required field. 103 self._required = False 104 105 #: The error message for the exception that is thrown when the field 106 # is required but empty. 107 self._requiredError = '' 108 109 #: Is automatic validation enabled. 110 self._validationVisible = True 111 112 #: Keeps track of the Actions added to this component; the actual 113 # handling/notifying is delegated, usually to the containing window. 114 self._actionManager = None 115 116 self._valueWasModifiedByDataSourceDuringCommit = False
117 118
119 - def paintContent(self, target):
120 121 # The tab ordering number 122 if self.getTabIndex() != 0: 123 target.addAttribute('tabindex', self.getTabIndex()) 124 125 # If the field is modified, but not committed, set modified attribute 126 if self.isModified(): 127 target.addAttribute('modified', True) 128 129 # Adds the required attribute 130 if not self.isReadOnly() and self.isRequired(): 131 target.addAttribute('required', True) 132 133 # Hide the error indicator if needed 134 if self.shouldHideErrors(): 135 target.addAttribute('hideErrors', True)
136 137 138
139 - def shouldHideErrors(self):
140 """Returns true if the error indicator be hidden when painting the 141 component even when there are errors. 142 143 This is a mostly internal method, but can be overridden in subclasses 144 e.g. if the error indicator should also be shown for empty fields in 145 some cases. 146 147 @return: true to hide the error indicator, false to use the normal 148 logic to show it when there are errors 149 """ 150 return (self.isRequired() and self.isEmpty() 151 and self.getComponentError() == None 152 and self.getErrorMessage() != None)
153 154
155 - def getType(self):
156 # Gets the field type 157 raise NotImplementedError
158 159
160 - def isReadOnly(self):
161 """The abstract field is read only also if the data source is in 162 read only mode. 163 """ 164 return (super(AbstractField, self).isReadOnly() 165 or (self._dataSource is not None 166 and self._dataSource.isReadOnly()))
167 168
169 - def setReadOnly(self, readOnly):
170 """Changes the readonly state and throw read-only status change 171 events. 172 173 @see: L{IComponent.setReadOnly} 174 """ 175 super(AbstractField, self).setReadOnly(readOnly) 176 self.fireReadOnlyStatusChange()
177 178
179 - def isInvalidCommitted(self):
180 """Tests if the invalid data is committed to datasource. 181 182 @see: L{BufferedValidatable.isInvalidCommitted} 183 """ 184 return self._invalidCommitted
185 186
187 - def setInvalidCommitted(self, isCommitted):
188 """Sets if the invalid data should be committed to datasource. 189 190 @see: L{BufferedValidatable.setInvalidCommitted} 191 """ 192 self._invalidCommitted = isCommitted
193 194
195 - def commit(self):
196 # Saves the current value to the data source. 197 if (self._dataSource is not None 198 and not self._dataSource.isReadOnly()): 199 200 if self.isInvalidCommitted() or self.isValid(): 201 newValue = self.getValue() 202 # try: 203 204 # Commits the value to datasource. 205 self._valueWasModifiedByDataSourceDuringCommit = False 206 self._committingValueToDataSource = True 207 self._dataSource.setValue(newValue) 208 209 # except Exception, e: 210 # # Sets the buffering state. 211 # exception = SourceException(self, e) 212 # self._currentBufferedSourceException = exception 213 # self.requestRepaint() 214 # 215 # # Throws the source exception. 216 # raise self._currentBufferedSourceException 217 # finally: 218 self._committingValueToDataSource = False 219 220 else: 221 # An invalid value and we don't allow 222 # them, throw the exception 223 self.validate() 224 225 repaintNeeded = False 226 227 # The abstract field is not modified anymore 228 if self._modified: 229 self._modified = False 230 repaintNeeded = True 231 232 # If successful, remove set the buffering state to be ok 233 if self._currentBufferedSourceException is not None: 234 self._currentBufferedSourceException = None 235 repaintNeeded = True 236 237 if self._valueWasModifiedByDataSourceDuringCommit: 238 self._valueWasModifiedByDataSourceDuringCommit = False 239 self.fireValueChange(False) 240 elif repaintNeeded: 241 self.requestRepaint()
242 243
244 - def discard(self):
245 # Updates the value from the data source. 246 if self._dataSource is not None: 247 248 # Gets the correct value from datasource 249 newValue = None 250 try: 251 # Discards buffer by overwriting from datasource 252 if self.getType() == str: 253 newValue = str(self._dataSource) 254 else: 255 newValue = self._dataSource.getValue() 256 257 # If successful, remove set the buffering state to be ok 258 if self._currentBufferedSourceException is not None: 259 self._currentBufferedSourceException = None 260 self.requestRepaint() 261 262 except Exception, e: 263 # Sets the buffering state 264 exception = SourceException(self, e) 265 self._currentBufferedSourceException = exception 266 self.requestRepaint() 267 268 # Throws the source exception 269 raise self._currentBufferedSourceException 270 271 wasModified = self.isModified() 272 self._modified = False 273 274 # If the new value differs from the previous one 275 if ((newValue is None and self._value is not None) 276 or (newValue is not None 277 and (newValue != self._value))): 278 self.setInternalValue(newValue) 279 self.fireValueChange(False) 280 281 elif wasModified: 282 # If the value did not change, but 283 # the modification status did 284 self.requestRepaint()
285 286
287 - def isModified(self):
288 # Has the field been modified since the last commit()? 289 return self._modified
290 291
292 - def isWriteThrough(self):
293 # Tests if the field is in write-through mode. 294 return self._writeThroughMode
295 296
297 - def setWriteThrough(self, writeThrough):
298 # Sets the field's write-through mode to the specified status 299 if self._writeThroughMode == writeThrough: 300 return 301 302 self._writeThroughMode = writeThrough 303 304 if self._writeThroughMode: 305 self.commit()
306 307
308 - def isReadThrough(self):
309 # Tests if the field is in read-through mode. 310 return self._readThroughMode
311 312
313 - def setReadThrough(self, readThrough):
314 # Sets the field's read-through mode to the specified status 315 if self._readThroughMode == readThrough: 316 return 317 318 self._readThroughMode = readThrough 319 320 if (not self.isModified() and self._readThroughMode 321 and (self._dataSource is not None)): 322 if self.getType() == str: 323 self.setInternalValue( str(self._dataSource) ) 324 else: 325 self.setInternalValue(self._dataSource.getValue()) 326 327 self.fireValueChange(False)
328 329
330 - def __str__(self):
331 """Returns the value of the IProperty in human readable textual 332 format. 333 """ 334 value = self.getValue() 335 if value is None: 336 return '' 337 return str( self.getValue() )
338 339
340 - def getValue(self):
341 """Gets the current value of the field. 342 343 This is the visible, modified and possible invalid value the user 344 have entered to the field. In the read-through mode, the abstract 345 buffer is also updated and validation is performed. 346 347 Note that the object returned is compatible with getType(). For 348 example, if the type is String, this returns Strings even when the 349 underlying datasource is of some other type. In order to access the 350 datasources native type, use getPropertyDatasource().getValue() 351 instead. 352 353 Note that when you extend AbstractField, you must reimplement this 354 method if datasource.getValue() is not assignable to class returned 355 by getType() AND getType() is not String. In case of Strings, 356 getValue() calls datasource.toString() instead of 357 datasource.getValue(). 358 359 @return: the current value of the field. 360 """ 361 # Give the value from abstract buffers if the field if possible 362 if (self._dataSource is None or (not self.isReadThrough()) 363 or self.isModified()): 364 return self._value 365 366 if self.getType() == str: 367 newValue = str(self._dataSource) 368 else: 369 newValue = self._dataSource.getValue() 370 371 return newValue
372 373
374 - def setValue(self, newValue, repaintIsNotNeeded=False):
375 """Sets the value of the field. 376 377 @param newValue: 378 the new value of the field. 379 @param repaintIsNotNeeded: 380 True iff caller is sure that repaint is not needed. 381 @raise ReadOnlyException: 382 @raise ConversionException: 383 """ 384 if ((newValue is None and self._value is not None) 385 or (newValue is not None and newValue != self._value)): 386 387 # Read only fields can not be changed 388 if self.isReadOnly(): 389 raise prop.ReadOnlyException() 390 391 # Repaint is needed even when the client thinks that it knows 392 # the new state if validity of the component may change 393 if (repaintIsNotNeeded and (self.isRequired() 394 or (self.getValidators() is not None))): 395 repaintIsNotNeeded = False 396 397 # If invalid values are not allowed, the value must be checked 398 if not self.isInvalidAllowed(): 399 for v in self.getValidators(): 400 v.validate(newValue) 401 402 # Changes the value 403 self.setInternalValue(newValue) 404 self._modified = self._dataSource is not None 405 406 self._valueWasModifiedByDataSourceDuringCommit = False 407 # In write through mode , try to commit 408 if (self.isWriteThrough() and (self._dataSource is not None) 409 and (self.isInvalidCommitted() or self.isValid())): 410 try: 411 412 # Commits the value to datasource 413 self._committingValueToDataSource = True 414 self._dataSource.setValue(newValue) 415 416 # The buffer is now unmodified 417 self._modified = False 418 419 except Exception, e: 420 # Sets the buffering state 421 exception = SourceException(self, e) 422 self._currentBufferedSourceException = exception 423 self.requestRepaint() 424 425 # Throws the source exception 426 raise self._currentBufferedSourceException 427 finally: 428 self._committingValueToDataSource = False 429 430 # If successful, remove set the buffering state to be ok 431 if self._currentBufferedSourceException is not None: 432 self._currentBufferedSourceException = None 433 self.requestRepaint() 434 435 if self._valueWasModifiedByDataSourceDuringCommit: 436 # Value was modified by datasource. Force repaint even if 437 # repaint was not requested. 438 self._valueWasModifiedByDataSourceDuringCommit = \ 439 repaintIsNotNeeded = False 440 441 # Fires the value change 442 self.fireValueChange(repaintIsNotNeeded)
443 444
445 - def getPropertyDataSource(self):
446 """Gets the current data source of the field, if any. 447 448 @return: the current data source as a IProperty, or C{None} 449 if none defined. 450 """ 451 return self._dataSource
452 453
454 - def setPropertyDataSource(self, newDataSource):
455 """Sets the specified IProperty as the data source for the field. 456 All uncommitted changes are replaced with a value from the new data 457 source. 458 459 If the datasource has any validators, the same validators are added 460 to the field. Because the default behavior of the field is to allow 461 invalid values, but not to allow committing them, this only adds 462 visual error messages to fields and do not allow committing them as 463 long as the value is invalid. After the value is valid, the error 464 message is not shown and the commit can be done normally. 465 466 Note: before 6.5 we actually called discard() method in the beginning 467 of the method. This was removed to simplify implementation, avoid 468 excess calls to backing property and to avoid odd value change events 469 that were previously fired (developer expects 0-1 value change events 470 if this method is called). Some complex field implementations might 471 now need to override this method to do housekeeping similar to 472 discard(). 473 474 @param newDataSource: 475 the new data source property. 476 """ 477 # Saves the old value 478 oldValue = self._value 479 480 # Stops listening the old data source changes 481 if (self._dataSource is not None 482 and issubclass(self._dataSource.__class__, 483 prop.IValueChangeNotifier)): 484 485 self._dataSource.removeListener(self, prop.IValueChangeListener) 486 487 488 if (self._dataSource is not None 489 and issubclass(self._dataSource.__class__, 490 prop.IReadOnlyStatusChangeNotifier)): 491 492 self._dataSource.removeListener(self, 493 prop.IReadOnlyStatusChangeListener) 494 495 496 # Sets the new data source 497 self._dataSource = newDataSource 498 499 # Gets the value from source 500 try: 501 if self._dataSource is not None: 502 if self.getType() == str: 503 self.setInternalValue( str(self._dataSource) ) 504 else: 505 self.setInternalValue(self._dataSource.getValue()) 506 self._modified = False 507 except Exception, e: 508 exception = SourceException(self, e) 509 self._currentBufferedSourceException = exception 510 self._modified = True 511 512 # Listens the new data source if possible 513 if isinstance(self._dataSource, prop.IValueChangeNotifier): 514 self._dataSource.addListener(self, prop.IValueChangeListener) 515 516 if isinstance(self._dataSource, 517 prop.IReadOnlyStatusChangeNotifier): 518 self._dataSource.addListener(self, 519 prop.IReadOnlyStatusChangeListener) 520 521 # Copy the validators from the data source 522 if isinstance(self._dataSource, IValidatable): 523 validators = self._dataSource.getValidators() 524 if validators is not None: 525 for v in validators: 526 self.addValidator(v) 527 528 # Fires value change if the value has changed 529 if ((self._value != oldValue) 530 and (self._value is not None and self._value != oldValue) 531 or (self._value is None)): 532 533 self.fireValueChange(False)
534 535
536 - def addValidator(self, validator):
537 """Adds a new validator for the field's value. All validators added 538 to a field are checked each time the its value changes. 539 540 @param validator: 541 the new validator to be added. 542 """ 543 if self._validators is None: 544 self._validators = list() 545 self._validators.append(validator) 546 self.requestRepaint()
547 548
549 - def getValidators(self):
550 """Gets the validators of the field. 551 552 @return: the Unmodifiable collection that holds all validators for 553 the field. 554 """ 555 if self._validators is None or len(self._validators) == 0: 556 return None 557 558 return self._validators
559 560
561 - def removeValidator(self, validator):
562 """Removes the validator from the field. 563 564 @param validator: 565 the validator to remove. 566 """ 567 if self._validators is not None: 568 self._validators.remove(validator) 569 570 self.requestRepaint()
571 572
573 - def isValid(self):
574 """Tests the current value against registered validators if the 575 field is not empty. If the field is empty it is considered valid 576 if it is not required and invalid otherwise. Validators are never 577 checked for empty fields. 578 579 @return: C{True} if all registered validators claim that 580 the current value is valid or if the field is empty and 581 not required, C{False} otherwise. 582 """ 583 if self.isEmpty(): 584 if self.isRequired(): 585 return False 586 else: 587 return True 588 589 if self._validators is None: 590 return True 591 592 value = self.getValue() 593 for v in self._validators: 594 if not v.isValid(value): 595 return False 596 597 return True
598 599
600 - def validate(self):
601 """Checks the validity of the IValidatable by validating the field 602 with all attached validators except when the field is empty. An 603 empty field is invalid if it is required and valid otherwise. 604 605 The "required" validation is a built-in validation feature. If 606 the field is required, but empty, validation will throw an 607 EmptyValueException with the error message set with 608 setRequiredError(). 609 610 @see: L{IValidatable.validate} 611 """ 612 if self.isEmpty(): 613 if self.isRequired(): 614 raise EmptyValueException(self._requiredError) 615 else: 616 return 617 618 # If there is no validator, there can not be any errors 619 if self._validators is None: 620 return 621 622 # Initialize temps 623 firstError = None 624 errors = None 625 value = self.getValue() 626 627 # Gets all the validation errors 628 for v in self._validators: 629 try: 630 v.validate(value) 631 except InvalidValueException, e: 632 if firstError is None: 633 firstError = e 634 else: 635 if errors is None: 636 errors = list() 637 errors.append(firstError) 638 errors.append(e) 639 640 # If there were no error 641 if firstError is None: 642 return 643 644 # If only one error occurred, throw it forwards 645 if errors is None: 646 raise firstError 647 648 # Creates composite validator 649 exceptions = [None] * len(errors) 650 index = 0 651 for e in errors: 652 exceptions[index] = e 653 index += 1 654 655 raise InvalidValueException(None, exceptions)
656 657
658 - def isInvalidAllowed(self):
659 """Fields allow invalid values by default. In most cases this is 660 wanted, because the field otherwise visually forget the user input 661 immediately. 662 663 @return: true iff the invalid values are allowed. 664 @see: L{IValidatable.isInvalidAllowed} 665 """ 666 return self._invalidAllowed
667 668
669 - def setInvalidAllowed(self, invalidAllowed):
670 """Fields allow invalid values by default. In most cases this is 671 wanted, because the field otherwise visually forget the user input 672 immediately. 673 674 In common setting where the user wants to assure the correctness of 675 the datasource, but allow temporarily invalid contents in the field, 676 the user should add the validators to datasource, that should not 677 allow invalid values. The validators are automatically copied to the 678 field when the datasource is set. 679 680 @see: L{IValidatable.setInvalidAllowed} 681 """ 682 self._invalidAllowed = invalidAllowed
683 684
685 - def getErrorMessage(self):
686 """Error messages shown by the fields are composites of the error 687 message thrown by the superclasses (that is the component error 688 message), validation errors and buffered source errors. 689 690 @see: L{AbstractComponent.getErrorMessage} 691 """ 692 # Check validation errors only if automatic validation is enabled. 693 # Empty, required fields will generate a validation error containing 694 # the requiredError string. For these fields the exclamation mark 695 # will be hidden but the error must still be sent to the client. 696 validationError = None 697 if self.isValidationVisible(): 698 try: 699 self.validate() 700 except InvalidValueException, e: 701 if not e.isInvisible(): 702 validationError = e 703 704 # Check if there are any systems errors 705 superError = super(AbstractField, self).getErrorMessage() 706 707 # Return if there are no errors at all 708 if (superError is None and validationError is None 709 and self._currentBufferedSourceException is None): 710 return None 711 712 # Throw combination of the error types 713 return CompositeErrorMessage([superError, validationError, 714 self._currentBufferedSourceException])
715 716
717 - def addListener(self, listener, iface=None):
718 # Adds a value change listener for the field. 719 if (isinstance(listener, prop.IReadOnlyStatusChangeListener) and 720 (iface is None or 721 issubclass(iface, prop.IReadOnlyStatusChangeListener))): 722 self.registerListener(prop.IReadOnlyStatusChangeEvent, 723 listener, _READ_ONLY_STATUS_CHANGE_METHOD) 724 725 if (isinstance(listener, prop.IValueChangeListener) and 726 (iface is None or 727 issubclass(iface, prop.IValueChangeListener))): 728 self.registerListener(field.ValueChangeEvent, 729 listener, _VALUE_CHANGE_METHOD) 730 731 super(AbstractField, self).addListener(listener, iface)
732 733
734 - def addCallback(self, callback, eventType=None, *args):
735 if eventType is None: 736 eventType = callback._eventType 737 738 if issubclass(eventType, prop.IReadOnlyStatusChangeEvent): 739 self.registerCallback(prop.IReadOnlyStatusChangeEvent, callback, 740 None, *args) 741 742 elif issubclass(eventType, prop.ValueChangeEvent): 743 self.registerCallback(prop.ValueChangeEvent, callback, None, *args) 744 745 else: 746 super(AbstractField, self).addCallback(callback, eventType, *args)
747 748
749 - def removeListener(self, listener, iface=None):
750 # Removes a value change listener from the field. 751 if (isinstance(listener, prop.IReadOnlyStatusChangeListener) and 752 (iface is None or 753 issubclass(iface, prop.IReadOnlyStatusChangeListener))): 754 self.withdrawListener(prop.IReadOnlyStatusChangeEvent, listener, 755 _READ_ONLY_STATUS_CHANGE_METHOD) 756 757 if (isinstance(listener, prop.IValueChangeListener) and 758 (iface is None or 759 issubclass(iface, prop.IValueChangeListener))): 760 self.withdrawListener(field.ValueChangeEvent, listener, 761 _VALUE_CHANGE_METHOD) 762 763 super(AbstractField, self).removeListener(listener, iface)
764 765
766 - def removeCallback(self, callback, eventType=None):
767 if eventType is None: 768 eventType = callback._eventType 769 770 if issubclass(eventType, prop.IReadOnlyStatusChangeEvent): 771 self.withdrawCallback(prop.IReadOnlyStatusChangeEvent, callback) 772 773 elif issubclass(eventType, prop.ValueChangeEvent): 774 self.withdrawCallback(prop.ValueChangeEvent, callback) 775 776 else: 777 super(AbstractField, self).removeCallback(callback, eventType)
778 779
780 - def fireValueChange(self, repaintIsNotNeeded):
781 """Emits the value change event. The value contained in the 782 field is validated before the event is created. 783 """ 784 event = field.ValueChangeEvent(self) 785 self.fireEvent(event) 786 787 if not repaintIsNotNeeded: 788 self.requestRepaint()
789 790
791 - def readOnlyStatusChange(self, event):
792 """React to read only status changes of the property by 793 requesting a repaint. 794 795 @see: L{IReadOnlyStatusChangeListener} 796 """ 797 self.requestRepaint()
798 799
800 - def fireReadOnlyStatusChange(self):
801 """Emits the read-only status change event. The value contained 802 in the field is validated before the event is created. 803 """ 804 event = IReadOnlyStatusChangeEvent(self) 805 self.fireEvent(event)
806 807
808 - def valueChange(self, event):
809 """This method listens to data source value changes and passes 810 the changes forwards. 811 812 Changes are not forwarded to the listeners of the field during 813 internal operations of the field to avoid duplicate notifications. 814 815 @param event: 816 the value change event telling the data source 817 contents have changed. 818 """ 819 if self.isReadThrough(): 820 if self._committingValueToDataSource: 821 822 propertyNotifiesOfTheBufferedValue = \ 823 (event.getProperty().getValue() == self._value 824 or (self._value is not None 825 and self._value == event.getProperty().getValue())) 826 827 if not propertyNotifiesOfTheBufferedValue: 828 # Property (or chained property like PropertyFormatter) 829 # now reports different value than the one the field has 830 # just committed to it. In this case we respect the 831 # property value. 832 833 # Still, we don't fire value change yet, but instead 834 # postpone it until "commit" is done. See L{setValue} 835 # and commit(). 836 self.readValueFromProperty(event) 837 self._valueWasModifiedByDataSourceDuringCommit = True 838 839 elif not self.isModified(): 840 self.readValueFromProperty(event) 841 self.fireValueChange(False)
842 843
844 - def readValueFromProperty(self, event):
846 847
848 - def changeVariables(self, source, variables):
849 super(AbstractField, self).changeVariables(source, variables)
850 851
852 - def focus(self):
853 super(AbstractField, self).focus()
854 855 856 @classmethod
857 - def constructField(cls, propertyType):
858 """Creates abstract field by the type of the property. 859 860 This returns most suitable field type for editing property of 861 given type. 862 863 @param propertyType: 864 the Type of the property, that needs to be edited. 865 @deprecated: use e.g. 866 L{DefaultFieldFactory.createFieldByPropertyType} instead 867 """ 868 warn('use createFieldByPropertyType() instead', DeprecationWarning) 869 870 # FIXME: circular import 871 from muntjac.ui.default_field_factory import DefaultFieldFactory 872 873 return DefaultFieldFactory.createFieldByPropertyType(propertyType)
874 875
876 - def getTabIndex(self):
877 return self._tabIndex
878 879
880 - def setTabIndex(self, tabIndex):
881 self._tabIndex = tabIndex 882 self.requestRepaint()
883 884
885 - def setInternalValue(self, newValue):
886 """Sets the internal field value. This is purely used by AbstractField 887 to change the internal IField value. It does not trigger valuechange 888 events. It can be overridden by the inheriting classes to update all 889 dependent variables. 890 891 @param newValue: 892 the new value to be set. 893 """ 894 self._value = newValue 895 if self._validators is not None and len(self._validators) > 0: 896 self.requestRepaint()
897 898
899 - def attach(self):
900 """Notifies the component that it is connected to an application. 901 902 @see: L{IComponent.attach} 903 """ 904 super(AbstractField, self).attach() 905 if self._actionManager is not None: 906 self._actionManager.setViewer(self.getWindow())
907 908
909 - def detach(self):
910 super(AbstractField, self).detach() 911 if self._actionManager is not None: 912 self._actionManager.setViewer(None)
913 914
915 - def isRequired(self):
916 """Is this field required. Required fields must filled by the user. 917 918 If the field is required, it is visually indicated in the user 919 interface. Furthermore, setting field to be required implicitly 920 adds "non-empty" validator and thus isValid() == false or any 921 isEmpty() fields. In those cases validation errors are not painted 922 as it is obvious that the user must fill in the required fields. 923 924 On the other hand, for the non-required fields isValid() == true 925 if the field isEmpty() regardless of any attached validators. 926 927 @return: C{True} if the field is required, otherwise C{False}. 928 """ 929 return self._required
930 931
932 - def setRequired(self, required):
933 """Sets the field required. Required fields must filled by the user. 934 935 If the field is required, it is visually indicated in the user 936 interface. Furthermore, setting field to be required implicitly adds 937 "non-empty" validator and thus isValid() == false or any isEmpty() 938 fields. In those cases validation errors are not painted as it is 939 obvious that the user must fill in the required fields. 940 941 On the other hand, for the non-required fields isValid() == true if 942 the field isEmpty() regardless of any attached validators. 943 944 @param required: 945 Is the field required. 946 """ 947 self._required = required 948 self.requestRepaint()
949 950
951 - def setRequiredError(self, requiredMessage):
952 """Set the error that is show if this field is required, but empty. 953 When setting requiredMessage to be "" or null, no error pop-up or 954 exclamation mark is shown for a empty required field. This faults 955 to "". Even in those cases isValid() returns false for empty 956 required fields. 957 958 @param requiredMessage: 959 Message to be shown when this field is required, but empty. 960 """ 961 self._requiredError = requiredMessage 962 self.requestRepaint()
963 964
965 - def getRequiredError(self):
966 return self._requiredError
967 968
969 - def isEmpty(self):
970 """Is the field empty? 971 972 In general, "empty" state is same as null. As an exception, 973 TextField also treats empty string as "empty". 974 """ 975 return self.getValue() is None
976 977
978 - def isValidationVisible(self):
979 """Is automatic, visible validation enabled? 980 981 If automatic validation is enabled, any validators connected to 982 this component are evaluated while painting the component and 983 potential error messages are sent to client. If the automatic 984 validation is turned off, isValid() and validate() methods still 985 work, but one must show the validation in their own code. 986 987 @return: True, if automatic validation is enabled. 988 """ 989 return self._validationVisible
990 991
992 - def setValidationVisible(self, validateAutomatically):
993 """Enable or disable automatic, visible validation. 994 995 If automatic validation is enabled, any validators connected to 996 this component are evaluated while painting the component and 997 potential error messages are sent to client. If the automatic 998 validation is turned off, isValid() and validate() methods still 999 work, but one must show the validation in their own code. 1000 1001 @param validateAutomatically: 1002 True, if automatic validation is enabled. 1003 """ 1004 if self._validationVisible != validateAutomatically: 1005 self.requestRepaint() 1006 self._validationVisible = validateAutomatically
1007 1008
1009 - def setCurrentBufferedSourceException(self, 1010 currentBufferedSourceException):
1011 """Sets the current buffered source exception. 1012 """ 1013 self._currentBufferedSourceException = currentBufferedSourceException 1014 self.requestRepaint()
1015 1016
1017 - def getActionManager(self):
1018 """Gets the L{ActionManager} used to manage the 1019 L{ShortcutListener}s added to this L{IField}. 1020 1021 @return: the ActionManager in use 1022 """ 1023 if self._actionManager is None: 1024 self._actionManager = ActionManager() 1025 if self.getWindow() is not None: 1026 self._actionManager.setViewer(self.getWindow()) 1027 return self._actionManager
1028 1029
1030 - def addShortcutListener(self, shortcut):
1031 self.getActionManager().addAction(shortcut)
1032 1033
1034 - def removeShortcutListener(self, shortcut):
1035 if self._actionManager is not None: 1036 self._actionManager.removeAction(shortcut)
1037
1038 1039 -class FocusShortcut(ShortcutListener):
1040 """A ready-made L{ShortcutListener} that focuses the given 1041 L{Focusable} (usually a L{IField}) when the keyboard 1042 shortcut is invoked. 1043 """ 1044
1045 - def __init__(self, *args):
1046 """Creates a keyboard shortcut for focusing the given 1047 L{IFocusable} using either the shorthand notation defined in 1048 L{ShortcutAction}, or the given key code. 1049 1050 @param args: tuple of the form 1051 - (focusable, shorthandCaption) 1052 1. to b efocused when the shortcut is invoked 1053 2. caption with keycode and modifiers indicated 1054 - (focusable, keyCode, modifiers) 1055 1. to be focused when the shortcut is invoked 1056 2. keycode that invokes the shortcut 1057 3. modifiers required to invoke the shortcut 1058 - (focusable, keyCode) 1059 1. to focused when the shortcut is invoked 1060 2. keycode that invokes the shortcut 1061 """ 1062 self.focusable = None 1063 1064 nargs = len(args) 1065 if nargs == 2: 1066 if isinstance(args[1], int): 1067 focusable, keyCode = args 1068 FocusShortcut.__init__(self, focusable, keyCode, None) 1069 else: 1070 focusable, shorthandCaption = args 1071 super(FocusShortcut, self).__init__(shorthandCaption) 1072 self.focusable = focusable 1073 else: 1074 focusable, keyCode = args[:2] 1075 modifiers = args[2:] 1076 super(FocusShortcut, self).__init__(None, keyCode, modifiers) 1077 self.focusable = focusable
1078 1079
1080 - def handleAction(self, sender, target):
1081 self.focusable.focus()
1082
1083 1084 -class IReadOnlyStatusChangeEvent(ComponentEvent, prop.IProperty, 1085 prop.IReadOnlyStatusChangeEvent):
1086 """An C{Event} object specifying the IProperty whose 1087 read-only status has changed. 1088 1089 @author: Vaadin Ltd. 1090 @author: Richard Lincoln 1091 @version: 1.1.2 1092 """ 1093
1094 - def __init__(self, source):
1095 """New instance of text change event. 1096 1097 @param source: 1098 the Source of the event. 1099 """ 1100 super(IReadOnlyStatusChangeEvent, self).__init__(source)
1101 1102
1103 - def getProperty(self):
1104 """IProperty where the event occurred. 1105 1106 @return: the Source of the event. 1107 """ 1108 return self.getSource()
1109