diff options
Diffstat (limited to 'projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TimedTextAssociation.java')
| -rw-r--r-- | projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TimedTextAssociation.java | 1430 |
1 files changed, 613 insertions, 817 deletions
diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TimedTextAssociation.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TimedTextAssociation.java index 49879e9..a6e993c 100644 --- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TimedTextAssociation.java +++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TimedTextAssociation.java @@ -48,75 +48,51 @@ import net.wotonomy.ui.EOAssociation; import net.wotonomy.ui.EODisplayGroup; /** -* TimedTextAssociation works like TextAssociation, -* but instead of using a delayed event to update the -* model, it uses a timer so that the model is only -* updated if the user pauses typing for some short interval. -* This is useful when the update and/or re-read of the model -* is a costly operation. -* Bindings are: -* <ul> -* <li>value: a property convertable to/from a string</li> -* <li>editable: a boolean property that determines whether -* the user can edit the text in the field</li> -* <li>enabled: a boolean property that determines whether -* the user can select the text in the field</li> -* <li>label: a boolean property that determines whether -* field should appear as a read-only, selectable label</li> -* <li>icon: a property that returns a Swing icon, for use -* with JLabels and other components with setIcon() methods. -* If bound to a static string, the string will be used to -* load an image resource from the selected object's class.</li> -* </ul> -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 904 $ -*/ -public class TimedTextAssociation extends EOAssociation - implements FocusListener, ActionListener, DocumentListener -{ - //TODO: need to refactor this so that it can subclass text association. - //This implementation is basically a branch from the v1.20 TextAssociation. - - static final NSArray aspects = - new NSArray( new Object[] { - ValueAspect, EnabledAspect, EditableAspect, LabelAspect, IconAspect - } ); - static final NSArray aspectSignatures = - new NSArray( new Object[] { - AttributeToOneAspectSignature, - AttributeToOneAspectSignature, - AttributeToOneAspectSignature, - AttributeToOneAspectSignature - } ); - static final NSArray objectKeysTaken = - new NSArray( new Object[] { - "text", "enabled", "editable" - } ); - - private final static NSSelector getText = - new NSSelector( "getText" ); - private final static NSSelector setText = - new NSSelector( "setText", - new Class[] { String.class } ); - private final static NSSelector getDocument = - new NSSelector( "getDocument" ); - private final static NSSelector setIcon = - new NSSelector( "setIcon", - new Class[] { Icon.class } ); - private final static NSSelector addActionListener = - new NSSelector( "addActionListener", - new Class[] { ActionListener.class } ); - private final static NSSelector removeActionListener = - new NSSelector( "removeActionListener", - new Class[] { ActionListener.class } ); - private final static NSSelector addFocusListener = - new NSSelector( "addFocusListener", - new Class[] { FocusListener.class } ); - private final static NSSelector removeFocusListener = - new NSSelector( "removeFocusListener", - new Class[] { FocusListener.class } ); + * TimedTextAssociation works like TextAssociation, but instead of using a + * delayed event to update the model, it uses a timer so that the model is only + * updated if the user pauses typing for some short interval. This is useful + * when the update and/or re-read of the model is a costly operation. Bindings + * are: + * <ul> + * <li>value: a property convertable to/from a string</li> + * <li>editable: a boolean property that determines whether the user can edit + * the text in the field</li> + * <li>enabled: a boolean property that determines whether the user can select + * the text in the field</li> + * <li>label: a boolean property that determines whether field should appear as + * a read-only, selectable label</li> + * <li>icon: a property that returns a Swing icon, for use with JLabels and + * other components with setIcon() methods. If bound to a static string, the + * string will be used to load an image resource from the selected object's + * class.</li> + * </ul> + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 904 $ + */ +public class TimedTextAssociation extends EOAssociation implements FocusListener, ActionListener, DocumentListener { + // TODO: need to refactor this so that it can subclass text association. + // This implementation is basically a branch from the v1.20 TextAssociation. + + static final NSArray aspects = new NSArray( + new Object[] { ValueAspect, EnabledAspect, EditableAspect, LabelAspect, IconAspect }); + static final NSArray aspectSignatures = new NSArray(new Object[] { AttributeToOneAspectSignature, + AttributeToOneAspectSignature, AttributeToOneAspectSignature, AttributeToOneAspectSignature }); + static final NSArray objectKeysTaken = new NSArray(new Object[] { "text", "enabled", "editable" }); + + private final static NSSelector getText = new NSSelector("getText"); + private final static NSSelector setText = new NSSelector("setText", new Class[] { String.class }); + private final static NSSelector getDocument = new NSSelector("getDocument"); + private final static NSSelector setIcon = new NSSelector("setIcon", new Class[] { Icon.class }); + private final static NSSelector addActionListener = new NSSelector("addActionListener", + new Class[] { ActionListener.class }); + private final static NSSelector removeActionListener = new NSSelector("removeActionListener", + new Class[] { ActionListener.class }); + private final static NSSelector addFocusListener = new NSSelector("addFocusListener", + new Class[] { FocusListener.class }); + private final static NSSelector removeFocusListener = new NSSelector("removeFocusListener", + new Class[] { FocusListener.class }); // null handling protected boolean wasNull; @@ -125,227 +101,186 @@ public class TimedTextAssociation extends EOAssociation // dirty handling protected boolean needsUpdate; protected boolean hasDocument; - protected boolean isListening; + protected boolean isListening; // formatting protected Format format; - // cache the value aspect - private EODisplayGroup valueDisplayGroup; - private String valueKey; - - // coalescing document events - protected boolean autoUpdating; - protected int interval = 400; // adjust as needed - protected Timer keyTimer; - - // NOTE: a new key timer is created for each use and - // is disposed when the timer is stopped. - // Swing's Timer class is kept in a static list of timers - // and each retains a strong reference to their listeners. - // This caused a memory leak as associations typically - // refer to their controlled component which is referred - // to by its parents and so on until no application window - // will ever get garbage collected. yikes. - - /** - * Constructor specifying the object to be controlled by this - * association. Does not establish connection. - */ - public TimedTextAssociation ( Object anObject ) - { - super( anObject ); + // cache the value aspect + private EODisplayGroup valueDisplayGroup; + private String valueKey; + + // coalescing document events + protected boolean autoUpdating; + protected int interval = 400; // adjust as needed + protected Timer keyTimer; + + // NOTE: a new key timer is created for each use and + // is disposed when the timer is stopped. + // Swing's Timer class is kept in a static list of timers + // and each retains a strong reference to their listeners. + // This caused a memory leak as associations typically + // refer to their controlled component which is referred + // to by its parents and so on until no application window + // will ever get garbage collected. yikes. + + /** + * Constructor specifying the object to be controlled by this association. Does + * not establish connection. + */ + public TimedTextAssociation(Object anObject) { + super(anObject); wasNull = false; needsUpdate = false; hasDocument = false; - isListening = true; - valueDisplayGroup = null; - valueKey = null; - - autoUpdating = true; - keyTimer = null; - } - - /** - * Returns a List of aspect signatures whose contents - * correspond with the aspects list. Each element is - * a string whose characters represent a capability of - * the corresponding aspect. <ul> - * <li>"A" attribute: the aspect can be bound to - * an attribute.</li> - * <li>"1" to-one: the aspect can be bound to a - * property that returns a single object.</li> - * <li>"M" to-one: the aspect can be bound to a - * property that returns multiple objects.</li> - * </ul> - * An empty signature "" means that the aspect can - * bind without needing a key. - * This implementation returns "A1M" for each - * element in the aspects array. - */ - public static NSArray aspectSignatures () - { - return aspectSignatures; - } - - /** - * Returns a List that describes the aspects supported - * by this class. Each element in the list is the string - * name of the aspect. This implementation returns an - * empty list. - */ - public static NSArray aspects () - { - return aspects; - } - - /** - * Returns a List of EOAssociation subclasses that, - * for the objects that are usable for this association, - * are less suitable than this association. - */ - public static NSArray associationClassesSuperseded () - { - return new NSArray(); - } - - /** - * Returns whether this class can control the specified - * object. - */ - public static boolean isUsableWithObject ( Object anObject ) - { - return setText.implementedByObject( anObject ); - } - - /** - * Returns a List of properties of the controlled object - * that are controlled by this class. For example, - * "stringValue", or "selected". - */ - public static NSArray objectKeysTaken () - { - return objectKeysTaken; - } - - /** - * Returns the aspect that is considered primary - * or default. This is typically "value" or somesuch. - */ - public static String primaryAspect () - { - return ValueAspect; - } - - /** - * Returns whether this association can bind to the - * specified display group on the specified key for - * the specified aspect. - */ - public boolean canBindAspect ( - String anAspect, EODisplayGroup aDisplayGroup, String aKey) - { - return ( aspects.containsObject( anAspect ) ); - } - - /** - * Binds the specified aspect of this association to the - * specified key on the specified display group. - */ - public void bindAspect ( - String anAspect, EODisplayGroup aDisplayGroup, String aKey ) - { - if ( ValueAspect.equals( anAspect ) ) - { + isListening = true; + valueDisplayGroup = null; + valueKey = null; + + autoUpdating = true; + keyTimer = null; + } + + /** + * Returns a List of aspect signatures whose contents correspond with the + * aspects list. Each element is a string whose characters represent a + * capability of the corresponding aspect. + * <ul> + * <li>"A" attribute: the aspect can be bound to an attribute.</li> + * <li>"1" to-one: the aspect can be bound to a property that returns a single + * object.</li> + * <li>"M" to-one: the aspect can be bound to a property that returns multiple + * objects.</li> + * </ul> + * An empty signature "" means that the aspect can bind without needing a key. + * This implementation returns "A1M" for each element in the aspects array. + */ + public static NSArray aspectSignatures() { + return aspectSignatures; + } + + /** + * Returns a List that describes the aspects supported by this class. Each + * element in the list is the string name of the aspect. This implementation + * returns an empty list. + */ + public static NSArray aspects() { + return aspects; + } + + /** + * Returns a List of EOAssociation subclasses that, for the objects that are + * usable for this association, are less suitable than this association. + */ + public static NSArray associationClassesSuperseded() { + return new NSArray(); + } + + /** + * Returns whether this class can control the specified object. + */ + public static boolean isUsableWithObject(Object anObject) { + return setText.implementedByObject(anObject); + } + + /** + * Returns a List of properties of the controlled object that are controlled by + * this class. For example, "stringValue", or "selected". + */ + public static NSArray objectKeysTaken() { + return objectKeysTaken; + } + + /** + * Returns the aspect that is considered primary or default. This is typically + * "value" or somesuch. + */ + public static String primaryAspect() { + return ValueAspect; + } + + /** + * Returns whether this association can bind to the specified display group on + * the specified key for the specified aspect. + */ + public boolean canBindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) { + return (aspects.containsObject(anAspect)); + } + + /** + * Binds the specified aspect of this association to the specified key on the + * specified display group. + */ + public void bindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) { + if (ValueAspect.equals(anAspect)) { valueDisplayGroup = aDisplayGroup; valueKey = aKey; } - super.bindAspect( anAspect, aDisplayGroup, aKey ); + super.bindAspect(anAspect, aDisplayGroup, aKey); } - /** - * Establishes a connection between this association - * and the controlled object. This implementation - * attempts to add this class as an ActionListener - * and as a FocusListener to the specified object. - */ - public void establishConnection () - { + /** + * Establishes a connection between this association and the controlled object. + * This implementation attempts to add this class as an ActionListener and as a + * FocusListener to the specified object. + */ + public void establishConnection() { Object component = object(); - try - { - if ( addActionListener.implementedByObject( component ) ) - { - addActionListener.invoke( component, this ); + try { + if (addActionListener.implementedByObject(component)) { + addActionListener.invoke(component, this); } - if ( addFocusListener.implementedByObject( component ) ) - { - addFocusListener.invoke( component, this ); + if (addFocusListener.implementedByObject(component)) { + addFocusListener.invoke(component, this); } - hasDocument = false; - if ( getDocument.implementedByObject( component ) ) - { - Object document = getDocument.invoke( component ); - if ( document instanceof Document ) - { - ((Document)document).addDocumentListener( this ); - hasDocument = true; - } + hasDocument = false; + if (getDocument.implementedByObject(component)) { + Object document = getDocument.invoke(component); + if (document instanceof Document) { + ((Document) document).addDocumentListener(this); + hasDocument = true; + } } - } - catch ( Exception exc ) - { - throw new WotonomyException( - "Error while establishing connection", exc ); + } catch (Exception exc) { + throw new WotonomyException("Error while establishing connection", exc); } - super.establishConnection(); + super.establishConnection(); // forces update from bindings subjectChanged(); - } - - /** - * Breaks the connection between this association and - * its object. Override to stop listening for events - * from the object. - */ - public void breakConnection () - { + } + + /** + * Breaks the connection between this association and its object. Override to + * stop listening for events from the object. + */ + public void breakConnection() { Object component = object(); - try - { - if ( removeActionListener.implementedByObject( component ) ) - { - removeActionListener.invoke( component, this ); + try { + if (removeActionListener.implementedByObject(component)) { + removeActionListener.invoke(component, this); } - if ( removeFocusListener.implementedByObject( component ) ) - { - removeFocusListener.invoke( component, this ); + if (removeFocusListener.implementedByObject(component)) { + removeFocusListener.invoke(component, this); } - if ( getDocument.implementedByObject( component ) ) - { - Object document = getDocument.invoke( component ); - if ( document instanceof Document ) - { - ((Document)document).removeDocumentListener( this ); - } + if (getDocument.implementedByObject(component)) { + Object document = getDocument.invoke(component); + if (document instanceof Document) { + ((Document) document).removeDocumentListener(this); + } } + } catch (Exception exc) { + throw new WotonomyException("Error while breaking connection", exc); } - catch ( Exception exc ) - { - throw new WotonomyException( - "Error while breaking connection", exc ); - } - super.breakConnection(); - } - - /** - * Called when either the selection or the contents - * of an associated display group have changed. - */ - public void subjectChanged () - { + super.breakConnection(); + } + + /** + * Called when either the selection or the contents of an associated display + * group have changed. + */ + public void subjectChanged() { Object component = object(); EODisplayGroup displayGroup; String key; @@ -353,677 +288,538 @@ public class TimedTextAssociation extends EOAssociation // value aspect displayGroup = valueDisplayGroup; - if ( displayGroup != null ) - { - if ( component instanceof Component ) - { - ((Component)component).setEnabled( - displayGroup.enabledToSetSelectedObjectValueForKey( valueKey ) ); - } - + if (displayGroup != null) { + if (component instanceof Component) { + ((Component) component).setEnabled(displayGroup.enabledToSetSelectedObjectValueForKey(valueKey)); + } + key = valueKey; - if ( displayGroup.selectedObjects().size() > 1 ) - { - // if there're more than one object selected, set - // the value to blank for all of them. - Object previousValue; - - Iterator indexIterator = displayGroup.selectionIndexes(). - iterator(); - - // get value for the first selected object. - int initialIndex = ( (Integer)indexIterator.next() ).intValue(); - previousValue = displayGroup.valueForObjectAtIndex( - initialIndex, key ); - value = null; - - // go through the rest of the selected objects, compare each - // value with the previous one. continue comparing if two - // values are equal, break the while loop if they're different. - // the final value will be the common value of all selected objects - // if there is one, or be blank if there is not. - while ( indexIterator.hasNext() ) - { - int index = ( (Integer)indexIterator.next() ).intValue(); - Object currentValue = displayGroup.valueForObjectAtIndex( - index, key ); - if ( currentValue != null && !currentValue.equals( previousValue ) ) - { - value = null; - break; - } - else - { - // currentValue is the same as the previous one - value = currentValue; - } - - } // end while - - } else { - - // if there's only one object selected. - value = displayGroup.selectedObjectValueForKey( key ); - } // end checking the size of selected objects in displayGroup - - // convert value to string - if ( value == null ) - { - wasNull = true; - value = EMPTY_STRING; - } - else - { - wasNull = false; - if ( format() != null ) - { - try - { - value = format().format( value ); - } - catch ( IllegalArgumentException exc ) - { - value = value.toString(); - } - } - } - - - try - { - if ( ! value.toString().equals( getText.invoke( component ) ) ) - { - // No need to listen for any events that might get fired - // while setting the text since we are the one setting it. - boolean wasListening = isListening; - isListening = false; - - // setText is an expensive operation - setText.invoke( component, value.toString() ); - - isListening = wasListening; - needsUpdate = false; - } + if (displayGroup.selectedObjects().size() > 1) { + // if there're more than one object selected, set + // the value to blank for all of them. + Object previousValue; + + Iterator indexIterator = displayGroup.selectionIndexes().iterator(); + + // get value for the first selected object. + int initialIndex = ((Integer) indexIterator.next()).intValue(); + previousValue = displayGroup.valueForObjectAtIndex(initialIndex, key); + value = null; + + // go through the rest of the selected objects, compare each + // value with the previous one. continue comparing if two + // values are equal, break the while loop if they're different. + // the final value will be the common value of all selected objects + // if there is one, or be blank if there is not. + while (indexIterator.hasNext()) { + int index = ((Integer) indexIterator.next()).intValue(); + Object currentValue = displayGroup.valueForObjectAtIndex(index, key); + if (currentValue != null && !currentValue.equals(previousValue)) { + value = null; + break; + } else { + // currentValue is the same as the previous one + value = currentValue; + } + + } // end while + + } else { + + // if there's only one object selected. + value = displayGroup.selectedObjectValueForKey(key); + } // end checking the size of selected objects in displayGroup + + // convert value to string + if (value == null) { + wasNull = true; + value = EMPTY_STRING; + } else { + wasNull = false; + if (format() != null) { + try { + value = format().format(value); + } catch (IllegalArgumentException exc) { + value = value.toString(); + } + } } - catch ( Exception exc ) - { - throw new WotonomyException( - "Error while updating component connection", exc ); + + try { + if (!value.toString().equals(getText.invoke(component))) { + // No need to listen for any events that might get fired + // while setting the text since we are the one setting it. + boolean wasListening = isListening; + isListening = false; + + // setText is an expensive operation + setText.invoke(component, value.toString()); + + isListening = wasListening; + needsUpdate = false; + } + } catch (Exception exc) { + throw new WotonomyException("Error while updating component connection", exc); } } // icon aspect - displayGroup = displayGroupForAspect( IconAspect ); - key = displayGroupKeyForAspect( IconAspect ); - if ( key != null ) - { - if ( displayGroup != null ) - { - value = - displayGroup.selectedObjectValueForKey( key ); - } - else - { - // treat bound key without display group - // as a resource to be loaded from the selected class. - value = null; - Object o = displayGroup.selectedObject(); - if ( o != null ) - { - URL url = o.getClass().getResource( key ); - if ( url != null ) - { - value = new ImageIcon( url ); - } - } + displayGroup = displayGroupForAspect(IconAspect); + key = displayGroupKeyForAspect(IconAspect); + if (key != null) { + if (displayGroup != null) { + value = displayGroup.selectedObjectValueForKey(key); + } else { + // treat bound key without display group + // as a resource to be loaded from the selected class. + value = null; + Object o = displayGroup.selectedObject(); + if (o != null) { + URL url = o.getClass().getResource(key); + if (url != null) { + value = new ImageIcon(url); + } + } } - try - { - setIcon.invoke( component, value ); - } - catch ( Exception exc ) - { - throw new WotonomyException( - "Error while updating component connection", exc ); + try { + setIcon.invoke(component, value); + } catch (Exception exc) { + throw new WotonomyException("Error while updating component connection", exc); } } // enabled aspect - displayGroup = displayGroupForAspect( EnabledAspect ); - key = displayGroupKeyForAspect( EnabledAspect ); - if ( ( key != null ) - && ( component instanceof Component ) ) - { - if ( displayGroup != null ) - { - value = - displayGroup.selectedObjectValueForKey( key ); - } - else - { + displayGroup = displayGroupForAspect(EnabledAspect); + key = displayGroupKeyForAspect(EnabledAspect); + if ((key != null) && (component instanceof Component)) { + if (displayGroup != null) { + value = displayGroup.selectedObjectValueForKey(key); + } else { // treat bound key without display group as a value value = key; } - Boolean converted = null; - if ( value != null ) - { - converted = (Boolean) - ValueConverter.convertObjectToClass( - value, Boolean.class ); - } - if ( converted == null ) converted = Boolean.FALSE; - if ( ((Component)component).isEnabled() != converted.booleanValue() ) - { - ((Component)component).setEnabled( converted.booleanValue() ); - } + Boolean converted = null; + if (value != null) { + converted = (Boolean) ValueConverter.convertObjectToClass(value, Boolean.class); + } + if (converted == null) + converted = Boolean.FALSE; + if (((Component) component).isEnabled() != converted.booleanValue()) { + ((Component) component).setEnabled(converted.booleanValue()); + } } // editable aspect - displayGroup = displayGroupForAspect( EditableAspect ); - key = displayGroupKeyForAspect( EditableAspect ); - if ( ( key != null ) - && ( component instanceof JTextComponent ) ) - { - if ( displayGroup != null ) - { - value = - displayGroup.selectedObjectValueForKey( key ); - } - else - { + displayGroup = displayGroupForAspect(EditableAspect); + key = displayGroupKeyForAspect(EditableAspect); + if ((key != null) && (component instanceof JTextComponent)) { + if (displayGroup != null) { + value = displayGroup.selectedObjectValueForKey(key); + } else { // treat bound key without display group as a value value = key; } - Boolean converted = (Boolean) - ValueConverter.convertObjectToClass( - value, Boolean.class ); - - if ( converted != null ) - { - if ( converted.booleanValue() != ((JTextComponent)component).isEditable() ) - { - ((JTextComponent)component).setEditable( converted.booleanValue() ); + Boolean converted = (Boolean) ValueConverter.convertObjectToClass(value, Boolean.class); + + if (converted != null) { + if (converted.booleanValue() != ((JTextComponent) component).isEditable()) { + ((JTextComponent) component).setEditable(converted.booleanValue()); } } } // label aspect - displayGroup = displayGroupForAspect( LabelAspect ); - key = displayGroupKeyForAspect( LabelAspect ); - - if ( ( key != null ) - && ( component instanceof JTextComponent ) ) - { - if ( displayGroup != null ) - { - value = - displayGroup.selectedObjectValueForKey( key ); - } - else - { + displayGroup = displayGroupForAspect(LabelAspect); + key = displayGroupKeyForAspect(LabelAspect); + + if ((key != null) && (component instanceof JTextComponent)) { + if (displayGroup != null) { + value = displayGroup.selectedObjectValueForKey(key); + } else { // treat bound key without display group as a value value = key; } - Boolean converted = (Boolean) - ValueConverter.convertObjectToClass( - value, Boolean.class ); - - if ( converted != null ) - { - if ( converted.booleanValue() ) - { - if ( component instanceof JTextComponent ) - { - if ( component instanceof JTextArea ) - { - areaToLabel( (JTextArea) component ); - } - else - { - fieldToLabel( (JTextComponent) component ); - } - } + Boolean converted = (Boolean) ValueConverter.convertObjectToClass(value, Boolean.class); + + if (converted != null) { + if (converted.booleanValue()) { + if (component instanceof JTextComponent) { + if (component instanceof JTextArea) { + areaToLabel((JTextArea) component); + } else { + fieldToLabel((JTextComponent) component); + } + } + } else { + if (component instanceof JTextComponent) { + if (component instanceof JTextArea) { + labelToArea((JTextArea) component); + } else { + labelToField((JTextComponent) component); + } + } } - else - { - if ( component instanceof JTextComponent ) - { - if ( component instanceof JTextArea ) - { - labelToArea( (JTextArea) component ); - } - else - { - labelToField( (JTextComponent ) component ); - } - } - } } } - } + } - private void fieldToLabel( JTextComponent aTextField ) - { - // turn on wrapping and disable editing and highlighting + private void fieldToLabel(JTextComponent aTextField) { + // turn on wrapping and disable editing and highlighting - aTextField.setEditable(false); - aTextField.setOpaque(false); + aTextField.setEditable(false); + aTextField.setOpaque(false); - // Set the border, colors and font to that of a label + // Set the border, colors and font to that of a label - LookAndFeel.installBorder(aTextField, "Label.border"); + LookAndFeel.installBorder(aTextField, "Label.border"); - LookAndFeel.installColorsAndFont(aTextField, - "Label.background", - "Label.foreground", - "Label.font"); - } + LookAndFeel.installColorsAndFont(aTextField, "Label.background", "Label.foreground", "Label.font"); + } - private void labelToField( JTextComponent aTextField ) - { - // turn on wrapping and disable editing and highlighting + private void labelToField(JTextComponent aTextField) { + // turn on wrapping and disable editing and highlighting - aTextField.setEditable(true); - aTextField.setOpaque(true); + aTextField.setEditable(true); + aTextField.setOpaque(true); - // Set the border, colors and font to that of a label + // Set the border, colors and font to that of a label - LookAndFeel.installBorder(aTextField, "TextField.border"); + LookAndFeel.installBorder(aTextField, "TextField.border"); - LookAndFeel.installColorsAndFont(aTextField, - "TextField.background", - "TextField.foreground", - "TextField.font"); - } + LookAndFeel.installColorsAndFont(aTextField, "TextField.background", "TextField.foreground", "TextField.font"); + } - private void areaToLabel( JTextArea aTextArea ) - { - // turn on wrapping and disable editing and highlighting + private void areaToLabel(JTextArea aTextArea) { + // turn on wrapping and disable editing and highlighting - aTextArea.setLineWrap(true); - aTextArea.setWrapStyleWord(true); - aTextArea.setEditable(false); + aTextArea.setLineWrap(true); + aTextArea.setWrapStyleWord(true); + aTextArea.setEditable(false); - // Set the text area's border, colors and font to - // that of a label + // Set the text area's border, colors and font to + // that of a label - LookAndFeel.installBorder(aTextArea, "Label.border"); + LookAndFeel.installBorder(aTextArea, "Label.border"); - LookAndFeel.installColorsAndFont(aTextArea, - "Label.background", - "Label.foreground", - "Label.font"); + LookAndFeel.installColorsAndFont(aTextArea, "Label.background", "Label.foreground", "Label.font"); } - private void labelToArea( JTextArea aTextArea ) - { - // turn on wrapping and disable editing and highlighting + private void labelToArea(JTextArea aTextArea) { + // turn on wrapping and disable editing and highlighting - aTextArea.setEditable(true); + aTextArea.setEditable(true); - // Set the border, colors and font to that of a label + // Set the border, colors and font to that of a label - LookAndFeel.installBorder(aTextArea, "TextArea.border"); + LookAndFeel.installBorder(aTextArea, "TextArea.border"); - LookAndFeel.installColorsAndFont(aTextArea, - "TextArea.background", - "TextArea.foreground", - "TextArea.font"); + LookAndFeel.installColorsAndFont(aTextArea, "TextArea.background", "TextArea.foreground", "TextArea.font"); } - - /** - * Forces this association to cause the object to - * stop editing and validate the user's input. - * @return false if there were problems validating, - * or true to continue. - */ - public boolean endEditing () - { - if ( keyTimer != null ) - { - keyTimer.stop(); - keyTimer.removeActionListener( this ); - keyTimer = null; - } + /** + * Forces this association to cause the object to stop editing and validate the + * user's input. + * + * @return false if there were problems validating, or true to continue. + */ + public boolean endEditing() { + if (keyTimer != null) { + keyTimer.stop(); + keyTimer.removeActionListener(this); + keyTimer = null; + } return writeValueToDisplayGroup(); - } + } /** - * Writes the value currently in the component - * to the selected object in the display group - * bound to the value aspect. - * @return false if there were problems validating, - * or true to continue. - */ - protected boolean writeValueToDisplayGroup() - { - boolean returnValue = true; - if ( hasDocument && !needsUpdate ) return true; - - EODisplayGroup displayGroup = valueDisplayGroup; - if ( displayGroup != null ) - { - String key = valueKey; - Object component = object(); - Object value = null; - try - { - //if ( getText.implementedByObject( component ) ) - //{ - value = getText.invoke( component ); - //} - } - catch ( Exception exc ) - { - throw new WotonomyException( - "Error updating display group", exc ); - } - - if ( ( wasNull ) && ( EMPTY_STRING.equals( value ) ) ) - { - value = null; - } - else - if ( format() != null ) - { - try - { - value = format().parseObject( value.toString() ); - } - catch ( ParseException exc ) - { - String message = exc.getMessage(); - //"That format was not recognized."; - if ( displayGroup.associationFailedToValidateValue( - this, value.toString(), key, exc, message ) ) - { - boolean wasListening = isListening; - isListening = false; - JOptionPane.showMessageDialog( - (Component)component, message ); - isListening = wasListening; - } - needsUpdate = false; - return false; - } - } - - needsUpdate = false; - - // only update if the value is different from the one in the display group - Object existingValue = displayGroup.selectedObjectValueForKey( key ); - if ( displayGroup.selectedObjects().size() == 1 ) - { - if ( existingValue == value ) return true; - if ( ( existingValue != null ) && ( existingValue.equals( value ) ) ) return true; - if ( ( value != null ) && ( value.equals( existingValue ) ) ) return true; - } - - // we might lose focus if display group displays a validation message - boolean wasListening = isListening; - isListening = false; - - Iterator selectedIterator = displayGroup.selectionIndexes().iterator(); - while ( selectedIterator.hasNext() ) - { - int index = ( (Integer)selectedIterator.next() ).intValue(); - - if ( displayGroup.setValueForObjectAtIndex( value, index, key ) ) - { - isListening = wasListening; - needsUpdate = false; - } - else - { - isListening = wasListening; - needsUpdate = false; - returnValue = false; - } - } - - } - return returnValue; + * Writes the value currently in the component to the selected object in the + * display group bound to the value aspect. + * + * @return false if there were problems validating, or true to continue. + */ + protected boolean writeValueToDisplayGroup() { + boolean returnValue = true; + if (hasDocument && !needsUpdate) + return true; + + EODisplayGroup displayGroup = valueDisplayGroup; + if (displayGroup != null) { + String key = valueKey; + Object component = object(); + Object value = null; + try { + // if ( getText.implementedByObject( component ) ) + // { + value = getText.invoke(component); + // } + } catch (Exception exc) { + throw new WotonomyException("Error updating display group", exc); + } + + if ((wasNull) && (EMPTY_STRING.equals(value))) { + value = null; + } else if (format() != null) { + try { + value = format().parseObject(value.toString()); + } catch (ParseException exc) { + String message = exc.getMessage(); + // "That format was not recognized."; + if (displayGroup.associationFailedToValidateValue(this, value.toString(), key, exc, message)) { + boolean wasListening = isListening; + isListening = false; + JOptionPane.showMessageDialog((Component) component, message); + isListening = wasListening; + } + needsUpdate = false; + return false; + } + } + + needsUpdate = false; + + // only update if the value is different from the one in the display group + Object existingValue = displayGroup.selectedObjectValueForKey(key); + if (displayGroup.selectedObjects().size() == 1) { + if (existingValue == value) + return true; + if ((existingValue != null) && (existingValue.equals(value))) + return true; + if ((value != null) && (value.equals(existingValue))) + return true; + } + + // we might lose focus if display group displays a validation message + boolean wasListening = isListening; + isListening = false; + + Iterator selectedIterator = displayGroup.selectionIndexes().iterator(); + while (selectedIterator.hasNext()) { + int index = ((Integer) selectedIterator.next()).intValue(); + + if (displayGroup.setValueForObjectAtIndex(value, index, key)) { + isListening = wasListening; + needsUpdate = false; + } else { + isListening = wasListening; + needsUpdate = false; + returnValue = false; + } + } + + } + return returnValue; } /** - * Sets the Format that is used to convert values from the display - * group to and from text that is displayed in the component. - * Having a formatter disables auto-updating. - */ - public void setFormat( Format aFormat ) - { + * Sets the Format that is used to convert values from the display group to and + * from text that is displayed in the component. Having a formatter disables + * auto-updating. + */ + public void setFormat(Format aFormat) { format = aFormat; } /** - * Gets the Format that is used to convert values from the display - * group to and from text that is displayed in the component. - */ - public Format format() - { + * Gets the Format that is used to convert values from the display group to and + * from text that is displayed in the component. + */ + public Format format() { return format; } - // interface ActionListener + // interface ActionListener /** - * Updates object on action performed. - */ - public void actionPerformed( ActionEvent evt ) - { - if ( keyTimer != null ) - { - keyTimer.stop(); - keyTimer.removeActionListener( this ); - keyTimer = null; - } - if ( ! isListening ) return; - if ( needsUpdate ) - { - writeValueToDisplayGroup(); - } + * Updates object on action performed. + */ + public void actionPerformed(ActionEvent evt) { + if (keyTimer != null) { + keyTimer.stop(); + keyTimer.removeActionListener(this); + keyTimer = null; + } + if (!isListening) + return; + if (needsUpdate) { + writeValueToDisplayGroup(); + } } - // interface FocusListener + // interface FocusListener /** - * Notifies of beginning of edit. - */ - public void focusGained(FocusEvent evt) - { - if ( ! isListening ) return; + * Notifies of beginning of edit. + */ + public void focusGained(FocusEvent evt) { + if (!isListening) + return; Object o; EODisplayGroup displayGroup; - Enumeration e = aspects().objectEnumerator(); - while ( e.hasMoreElements() ) - { - displayGroup = - displayGroupForAspect( e.nextElement().toString() ); - if ( displayGroup != null ) - { - displayGroup.associationDidBeginEditing( this ); + Enumeration e = aspects().objectEnumerator(); + while (e.hasMoreElements()) { + displayGroup = displayGroupForAspect(e.nextElement().toString()); + if (displayGroup != null) { + displayGroup.associationDidBeginEditing(this); } } - } + } /** - * Updates object on focus lost and notifies of end of edit. - */ - public void focusLost(FocusEvent evt) - { - if ( ! isListening ) return; - if ( endEditing() ) - { + * Updates object on focus lost and notifies of end of edit. + */ + public void focusLost(FocusEvent evt) { + if (!isListening) + return; + if (endEditing()) { Object o; EODisplayGroup displayGroup; Enumeration e = aspects().objectEnumerator(); - while ( e.hasMoreElements() ) - { - displayGroup = - displayGroupForAspect( e.nextElement().toString() ); - if ( displayGroup != null ) - { - displayGroup.associationDidEndEditing( this ); + while (e.hasMoreElements()) { + displayGroup = displayGroupForAspect(e.nextElement().toString()); + if (displayGroup != null) { + displayGroup.associationDidEndEditing(this); } } - } - else - { + } else { // probably should notify of a validation error here, } - } - - /** - * Returns whether the data model is updated for every change - * in the controlled component. If false, the data is only - * updated on focus lost or the enter key. Default is true. - */ - public boolean isAutoUpdating() - { - if ( format() != null ) return false; - return autoUpdating; - } - - /** - * Sets whether the data model is updated for every change - * in the controlled component. - */ - public void setAutoUpdating( boolean isAutoUpdating ) - { - autoUpdating = isAutoUpdating; - } - - /** - * Triggers the key timer to start. - */ - protected void queueUpdate() - { - if ( isAutoUpdating() ) - { - if ( keyTimer == null ) - { - keyTimer = new Timer( interval, this ); - } - keyTimer.restart(); - } - } - - // interface DocumentListener - - public void insertUpdate(DocumentEvent e) - { - if ( ! isListening ) return; - needsUpdate = true; - queueUpdate(); - } - - public void removeUpdate(DocumentEvent e) - { - if ( ! isListening ) return; - needsUpdate = true; - queueUpdate(); - } - - public void changedUpdate(DocumentEvent e) - { - if ( ! isListening ) return; - needsUpdate = true; - queueUpdate(); - } + } + + /** + * Returns whether the data model is updated for every change in the controlled + * component. If false, the data is only updated on focus lost or the enter key. + * Default is true. + */ + public boolean isAutoUpdating() { + if (format() != null) + return false; + return autoUpdating; + } + + /** + * Sets whether the data model is updated for every change in the controlled + * component. + */ + public void setAutoUpdating(boolean isAutoUpdating) { + autoUpdating = isAutoUpdating; + } + + /** + * Triggers the key timer to start. + */ + protected void queueUpdate() { + if (isAutoUpdating()) { + if (keyTimer == null) { + keyTimer = new Timer(interval, this); + } + keyTimer.restart(); + } + } + + // interface DocumentListener + + public void insertUpdate(DocumentEvent e) { + if (!isListening) + return; + needsUpdate = true; + queueUpdate(); + } + + public void removeUpdate(DocumentEvent e) { + if (!isListening) + return; + needsUpdate = true; + queueUpdate(); + } + + public void changedUpdate(DocumentEvent e) { + if (!isListening) + return; + needsUpdate = true; + queueUpdate(); + } } /* - * $Log$ - * Revision 1.2 2006/02/18 23:19:05 cgruber - * Update imports and maven dependencies. + * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven + * dependencies. * - * Revision 1.1 2006/02/16 13:22:22 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.3 2004/01/28 18:34:57 mpowers - * Better handling for enabling. - * Now respecting enabledToSetSelectedObjectValueForKey from display group. + * Revision 1.3 2004/01/28 18:34:57 mpowers Better handling for enabling. Now + * respecting enabledToSetSelectedObjectValueForKey from display group. * - * Revision 1.2 2003/08/06 23:07:52 chochos - * general code cleanup (mostly, removing unused imports) + * Revision 1.2 2003/08/06 23:07:52 chochos general code cleanup (mostly, + * removing unused imports) * - * Revision 1.1 2001/12/20 18:57:24 mpowers - * (Re-)Contributing TimedTextAssociation. Just like TA, except uses timers. + * Revision 1.1 2001/12/20 18:57:24 mpowers (Re-)Contributing + * TimedTextAssociation. Just like TA, except uses timers. * - * Revision 1.20 2001/10/26 19:58:06 mpowers - * Better handling for non-string types. We were testing with equals with the - * new value against the existing value in the component. Now we convert - * the new value to a string before comparing. Fixes case for properties - * of non-String types, like StringBuffer. + * Revision 1.20 2001/10/26 19:58:06 mpowers Better handling for non-string + * types. We were testing with equals with the new value against the existing + * value in the component. Now we convert the new value to a string before + * comparing. Fixes case for properties of non-String types, like StringBuffer. * - * Revision 1.19 2001/09/30 21:57:14 mpowers - * Timers were not getting cleaned up if breakConnection was called - * before the timer got a chance to fire. + * Revision 1.19 2001/09/30 21:57:14 mpowers Timers were not getting cleaned up + * if breakConnection was called before the timer got a chance to fire. * - * Revision 1.18 2001/08/22 15:42:26 mpowers - * Added support for JTextComponent label-izing. + * Revision 1.18 2001/08/22 15:42:26 mpowers Added support for JTextComponent + * label-izing. * - * Revision 1.17 2001/07/30 16:32:55 mpowers - * Implemented support for bulk-editing. Detail associations will now - * apply changes to all selected objects. + * Revision 1.17 2001/07/30 16:32:55 mpowers Implemented support for + * bulk-editing. Detail associations will now apply changes to all selected + * objects. * - * Revision 1.16 2001/07/17 19:53:37 mpowers - * Made some private fields protected for benefit of subclassers. + * Revision 1.16 2001/07/17 19:53:37 mpowers Made some private fields protected + * for benefit of subclassers. * - * Revision 1.15 2001/06/30 14:59:36 mpowers - * LabelAspect now sets the text field's opaque setting. + * Revision 1.15 2001/06/30 14:59:36 mpowers LabelAspect now sets the text + * field's opaque setting. * - * Revision 1.14 2001/06/29 14:54:08 mpowers - * Another fix for timers - timers were definitely causing a memory leak. + * Revision 1.14 2001/06/29 14:54:08 mpowers Another fix for timers - timers + * were definitely causing a memory leak. * - * Revision 1.13 2001/06/26 21:37:19 mpowers - * Fixed a null pointer in the new key timer scheme. + * Revision 1.13 2001/06/26 21:37:19 mpowers Fixed a null pointer in the new key + * timer scheme. * - * Revision 1.12 2001/06/25 14:46:03 mpowers - * Fixed a memory leak involving the use of timers. + * Revision 1.12 2001/06/25 14:46:03 mpowers Fixed a memory leak involving the + * use of timers. * - * Revision 1.11 2001/06/01 19:14:59 mpowers - * Text association's enabled aspect is now more discriminating. + * Revision 1.11 2001/06/01 19:14:59 mpowers Text association's enabled aspect + * is now more discriminating. * - * Revision 1.10 2001/05/18 21:07:24 mpowers - * Changed the way we handle failure to update object value. + * Revision 1.10 2001/05/18 21:07:24 mpowers Changed the way we handle failure + * to update object value. * - * Revision 1.9 2001/03/13 21:39:58 mpowers - * Improved validation handling. + * Revision 1.9 2001/03/13 21:39:58 mpowers Improved validation handling. * - * Revision 1.8 2001/03/12 12:49:10 mpowers - * Improved validation handling. - * Having a formatter disables auto-updating. + * Revision 1.8 2001/03/12 12:49:10 mpowers Improved validation handling. Having + * a formatter disables auto-updating. * - * Revision 1.7 2001/03/09 22:08:13 mpowers - * Now handling any objects that have a valid Document. - * No longer checking enabled before updating the enabled state. + * Revision 1.7 2001/03/09 22:08:13 mpowers Now handling any objects that have a + * valid Document. No longer checking enabled before updating the enabled state. * - * Revision 1.6 2001/03/07 19:57:32 mpowers - * Fixed paste error in IconAspect. + * Revision 1.6 2001/03/07 19:57:32 mpowers Fixed paste error in IconAspect. * - * Revision 1.4 2001/02/17 16:52:05 mpowers - * Changes in imports to support building with jdk1.1 collections. + * Revision 1.4 2001/02/17 16:52:05 mpowers Changes in imports to support + * building with jdk1.1 collections. * - * Revision 1.3 2001/01/31 19:12:33 mpowers - * Implemented auto-updating in TextComponent. + * Revision 1.3 2001/01/31 19:12:33 mpowers Implemented auto-updating in + * TextComponent. * - * Revision 1.2 2001/01/10 15:53:58 mpowers - * Preventing a null pointer exception if getText were to return null, - * which doesn't happen for JTextFields but might happen for other objects. + * Revision 1.2 2001/01/10 15:53:58 mpowers Preventing a null pointer exception + * if getText were to return null, which doesn't happen for JTextFields but + * might happen for other objects. * - * Revision 1.1.1.1 2000/12/21 15:49:08 mpowers - * Contributing wotonomy. + * Revision 1.1.1.1 2000/12/21 15:49:08 mpowers Contributing wotonomy. * - * Revision 1.13 2000/12/20 16:25:41 michael - * Added log to all files. + * Revision 1.13 2000/12/20 16:25:41 michael Added log to all files. * * */ - |
