Coverage Report - net.wotonomy.ui.swing.SliderAssociation
 
Classes in this File Line Coverage Branch Coverage Complexity
SliderAssociation
0% 
0% 
2.267
 
 1  
 /*
 2  
 Wotonomy: OpenStep design patterns for pure Java applications.
 3  
 Copyright (C) 2000 Intersect Software Corporation
 4  
 
 5  
 This library is free software; you can redistribute it and/or
 6  
 modify it under the terms of the GNU Lesser General Public
 7  
 License as published by the Free Software Foundation; either
 8  
 version 2.1 of the License, or (at your option) any later version.
 9  
 
 10  
 This library is distributed in the hope that it will be useful,
 11  
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13  
 Lesser General Public License for more details.
 14  
 
 15  
 You should have received a copy of the GNU Lesser General Public
 16  
 License along with this library; if not, see http://www.gnu.org
 17  
 */
 18  
 
 19  
 package net.wotonomy.ui.swing;
 20  
 
 21  
 import java.util.Iterator;
 22  
 
 23  
 import javax.swing.JSlider;
 24  
 import javax.swing.event.ChangeEvent;
 25  
 import javax.swing.event.ChangeListener;
 26  
 
 27  
 import net.wotonomy.foundation.NSArray;
 28  
 import net.wotonomy.foundation.internal.ValueConverter;
 29  
 import net.wotonomy.ui.EOAssociation;
 30  
 import net.wotonomy.ui.EODisplayGroup;
 31  
 
 32  
 /**
 33  
 * SliderAssociation binds a JSlider component to
 34  
 * a display group.  Bindings are: 
 35  
 * <ul>
 36  
 * <li>value: a property convertable to/from a string</li> 
 37  
 * <li>enabled: a boolean property that determines whether
 38  
 * the user can select the text in the field</li> 
 39  
 * </ul>
 40  
 *
 41  
 * @author michael@mpowers.net
 42  
 * @author $Author: cgruber $
 43  
 * @version $Revision: 904 $
 44  
 */
 45  0
 public class SliderAssociation extends EOAssociation
 46  
         implements ChangeListener
 47  
 {
 48  0
     static final NSArray aspects = 
 49  0
         new NSArray( new Object[] {
 50  0
             ValueAspect, EnabledAspect, VisibleAspect
 51  
         } );
 52  0
     static final NSArray aspectSignatures = 
 53  0
         new NSArray( new Object[] {
 54  0
             AttributeToOneAspectSignature, 
 55  0
                         AttributeToOneAspectSignature, 
 56  
         } );
 57  0
     static final NSArray objectKeysTaken = 
 58  0
         new NSArray( new Object[] {
 59  0
             "value" 
 60  
         } );
 61  
                 
 62  
     /**
 63  
     * Constructor specifying the object to be controlled by this
 64  
     * association.  Does not establish connection.
 65  
     */
 66  
     public SliderAssociation ( Object anObject )
 67  
     {
 68  0
         super( anObject );
 69  0
     }
 70  
     
 71  
     /**
 72  
     * Returns a List of aspect signatures whose contents
 73  
     * correspond with the aspects list.  Each element is 
 74  
     * a string whose characters represent a capability of
 75  
     * the corresponding aspect. <ul>
 76  
     * <li>"A" attribute: the aspect can be bound to
 77  
     * an attribute.</li>
 78  
     * <li>"1" to-one: the aspect can be bound to a
 79  
     * property that returns a single object.</li>
 80  
     * <li>"M" to-one: the aspect can be bound to a
 81  
     * property that returns multiple objects.</li>
 82  
     * </ul> 
 83  
     * An empty signature "" means that the aspect can
 84  
     * bind without needing a key.
 85  
     * This implementation returns "A1M" for each
 86  
     * element in the aspects array.
 87  
     */
 88  
     public static NSArray aspectSignatures ()
 89  
     {
 90  0
         return aspectSignatures;
 91  
     }
 92  
     
 93  
     /**
 94  
     * Returns a List that describes the aspects supported
 95  
     * by this class.  Each element in the list is the string
 96  
     * name of the aspect.  This implementation returns an
 97  
     * empty list.
 98  
     */
 99  
     public static NSArray aspects ()
 100  
     {
 101  0
         return aspects;
 102  
     }
 103  
     
 104  
     /**
 105  
     * Returns a List of EOAssociation subclasses that,
 106  
     * for the objects that are usable for this association,
 107  
     * are less suitable than this association.
 108  
     */
 109  
     public static NSArray associationClassesSuperseded ()
 110  
     {
 111  0
         return new NSArray();
 112  
     }
 113  
     
 114  
     /**
 115  
     * Returns whether this class can control the specified 
 116  
     * object. 
 117  
     */
 118  
     public static boolean isUsableWithObject ( Object anObject )
 119  
     {
 120  0
         return ( anObject instanceof JSlider );
 121  
     }
 122  
     
 123  
     /**
 124  
     * Returns a List of properties of the controlled object
 125  
     * that are controlled by this class.  For example,
 126  
     * "stringValue", or "selected".
 127  
     */
 128  
     public static NSArray objectKeysTaken ()
 129  
     {
 130  0
         return objectKeysTaken;
 131  
     }
 132  
     
 133  
     /**
 134  
     * Returns the aspect that is considered primary
 135  
     * or default.  This is typically "value" or somesuch.
 136  
     */
 137  
     public static String primaryAspect ()
 138  
     {
 139  0
         return ValueAspect;
 140  
     }
 141  
         
 142  
     /**
 143  
     * Returns whether this association can bind to the
 144  
     * specified display group on the specified key for
 145  
     * the specified aspect.  
 146  
     */
 147  
     public boolean canBindAspect ( 
 148  
         String anAspect, EODisplayGroup aDisplayGroup, String aKey)
 149  
     {
 150  0
         return ( aspects.containsObject( anAspect ) );
 151  
     }
 152  
     
 153  
     /**
 154  
     * Establishes a connection between this association
 155  
     * and the controlled object.  This implementation 
 156  
         * attempts to add this class as an ActionListener
 157  
         * and as a FocusListener to the specified object.
 158  
     */
 159  
     public void establishConnection ()
 160  
     {
 161  0
                 component().addChangeListener( this );
 162  0
         super.establishConnection();
 163  
                 
 164  
                 // forces update from bindings
 165  0
                 subjectChanged();
 166  0
     }
 167  
         
 168  
     /**
 169  
     * Breaks the connection between this association and 
 170  
     * its object.  Override to stop listening for events
 171  
     * from the object.
 172  
     */
 173  
     public void breakConnection ()
 174  
     {
 175  0
                 component().removeChangeListener( this );
 176  0
         super.breakConnection();
 177  0
     }
 178  
 
 179  
     /**
 180  
     * Called when either the selection or the contents 
 181  
     * of an associated display group have changed.
 182  
     */
 183  
     public void subjectChanged ()
 184  
     {
 185  0
                 JSlider component = component();
 186  
                 EODisplayGroup displayGroup;
 187  
                 String key;
 188  
                 Object value;
 189  
         
 190  
                 // value aspect
 191  0
                 displayGroup = displayGroupForAspect( ValueAspect );
 192  0
                 if ( displayGroup != null )
 193  
                 {
 194  0
                         key = displayGroupKeyForAspect( ValueAspect );
 195  0
             component.setEnabled( 
 196  0
                     displayGroup.enabledToSetSelectedObjectValueForKey( key ) );
 197  
                     
 198  0
                     if ( displayGroup.selectedObjects().size() > 1 )
 199  
                     {
 200  
                         // if there're more than one object selected, set
 201  
                         // the value to blank for all of them.
 202  
                         Object previousValue;
 203  
 
 204  0
                         Iterator indexIterator = displayGroup.selectionIndexes().
 205  0
                                                   iterator();
 206  
 
 207  
                         // get value for the first selected object.
 208  0
                         int initialIndex = ( (Integer)indexIterator.next() ).intValue();
 209  0
                         previousValue = displayGroup.valueForObjectAtIndex(
 210  0
                                                   initialIndex, key );
 211  0
                         value = null;
 212  
 
 213  
                         // go through the rest of the selected objects, compare each
 214  
                         // value with the previous one. continue comparing if two
 215  
                         // values are equal, break the while loop if they're different.
 216  
                         // the final value will be the common value of all selected objects
 217  
                         // if there is one, or be blank if there is not.
 218  0
                         while ( indexIterator.hasNext() )
 219  
                         {
 220  0
                             int index = ( (Integer)indexIterator.next() ).intValue();
 221  0
                             Object currentValue = displayGroup.valueForObjectAtIndex(
 222  0
                                                   index, key );
 223  0
                             if ( currentValue != null && !currentValue.equals( previousValue ) )
 224  
                             {
 225  0
                                 value = null;
 226  0
                                 break;
 227  
                             }
 228  
                             else
 229  
                             {
 230  
                                 // currentValue is the same as the previous one
 231  0
                                 value = currentValue;
 232  
                             }
 233  
 
 234  0
                         } // end while
 235  
 
 236  0
                     } else {
 237  
 
 238  0
                         value = displayGroup.selectedObjectValueForKey( key );
 239  
                     } // end checking size of displayGroup
 240  
 
 241  
                         // convert value to int
 242  0
                         value = ValueConverter.convertObjectToClass( value, Integer.class );
 243  
 
 244  
                         int intValue;
 245  0
                         if ( value == null ) 
 246  
                         {
 247  0
                                 intValue = 0;
 248  0
                         }
 249  
                         else
 250  
                         {
 251  0
                                 intValue = ((Integer)value).intValue();
 252  
                         }
 253  
                         
 254  0
                         if ( component.getValue() != intValue )
 255  
                         {
 256  0
                 component().removeChangeListener( this );
 257  0
                                 component.setValue( intValue );
 258  0
                 component().addChangeListener( this );
 259  
                         }
 260  
                 }
 261  
 
 262  
                 // enabled aspect
 263  0
                 displayGroup = displayGroupForAspect( EnabledAspect );
 264  0
                 key = displayGroupKeyForAspect( EnabledAspect );
 265  0
                 if ( ( displayGroup != null ) || ( key != null ) )
 266  
                 {
 267  0
                         if ( displayGroup != null )
 268  
                         {
 269  0
                                 value =
 270  0
                                         displayGroup.selectedObjectValueForKey( key );
 271  0
                         }
 272  
                         else
 273  
                         {
 274  
                                 // treat bound key without display group as a value
 275  0
                                 value = key;        
 276  
                         }
 277  0
             Boolean converted = null;
 278  0
             if ( value != null ) 
 279  
             {
 280  0
                 converted = (Boolean)
 281  0
                     ValueConverter.convertObjectToClass(
 282  0
                         value, Boolean.class );
 283  
             }
 284  0
             if ( converted == null ) converted = Boolean.FALSE;
 285  0
             if ( converted.booleanValue() != component.isEnabled() )
 286  
             {
 287  0
                 component.setEnabled( converted.booleanValue() );        
 288  
             }
 289  
                 }
 290  
 
 291  
                 // visible aspect
 292  0
                 displayGroup = displayGroupForAspect( VisibleAspect );
 293  0
                 key = displayGroupKeyForAspect( VisibleAspect );
 294  0
                 if ( ( displayGroup != null ) || ( key != null ) )
 295  
                 {
 296  0
                         if ( displayGroup != null )
 297  
                         {
 298  0
                                 value =
 299  0
                                         displayGroup.selectedObjectValueForKey( key );
 300  0
                         }
 301  
                         else
 302  
                         {
 303  
                                 // treat bound key without display group as a value
 304  0
                                 value = key;        
 305  
                         }
 306  0
                         Boolean converted = (Boolean)
 307  0
                                 ValueConverter.convertObjectToClass( 
 308  0
                                         value, Boolean.class );
 309  
                                         
 310  0
                         if ( converted != null )
 311  
                         {
 312  0
                                 if ( converted.booleanValue() != component.isVisible() )
 313  
                                 {
 314  0
                                         component.setVisible( converted.booleanValue() );        
 315  
                                 }
 316  
                         }                        
 317  
                 }
 318  
 
 319  0
     }
 320  
         
 321  
     /**
 322  
     * Forces this association to cause the object to 
 323  
     * stop editing and validate the user's input.
 324  
     * @return false if there were problems validating,
 325  
     * or true to continue.
 326  
     */
 327  
     public boolean endEditing ()
 328  
     {
 329  0
                 return writeValueToDisplayGroup();
 330  
     }
 331  
         
 332  
         /**
 333  
         * Writes the value currently in the component
 334  
         * to the selected object in the display group
 335  
         * bound to the value aspect.
 336  
     * @return false if there were problems validating,
 337  
     * or true to continue.
 338  
         */
 339  
         protected boolean writeValueToDisplayGroup()
 340  
         {
 341  0
                 EODisplayGroup displayGroup = 
 342  0
                         displayGroupForAspect( ValueAspect );
 343  0
                 if ( displayGroup != null )
 344  
                 {
 345  0
                         String key = displayGroupKeyForAspect( ValueAspect );
 346  0
                         Object value = new Integer( component().getValue() );
 347  
 
 348  0
             boolean returnValue = true;
 349  0
             Iterator selectedIterator = displayGroup.selectionIndexes().iterator();
 350  0
             while ( selectedIterator.hasNext() )
 351  
             {
 352  0
                 int index = ( (Integer)selectedIterator.next() ).intValue();
 353  
 
 354  0
                 if ( !displayGroup.setValueForObjectAtIndex( value, index, key ) )
 355  
                 {
 356  0
                     returnValue = false;
 357  
                 }
 358  0
             }
 359  0
             return returnValue;
 360  
                 }
 361  0
                 return false;
 362  
         }
 363  
 
 364  
     // interface ChangeListener
 365  
         
 366  
         /**
 367  
         * Updates object on change.
 368  
         */
 369  
         public void stateChanged(ChangeEvent e)  
 370  
         {
 371  0
                 writeValueToDisplayGroup();
 372  0
         }
 373  
     
 374  
         private JSlider component()
 375  
         {
 376  0
                 return (JSlider) object();        
 377  
         }
 378  
 }
 379  
 
 380  
 /*
 381  
  * $Log$
 382  
  * Revision 1.2  2006/02/18 23:19:05  cgruber
 383  
  * Update imports and maven dependencies.
 384  
  *
 385  
  * Revision 1.1  2006/02/16 13:22:22  cgruber
 386  
  * Check in all sources in eclipse-friendly maven-enabled packages.
 387  
  *
 388  
  * Revision 1.8  2004/01/28 18:34:57  mpowers
 389  
  * Better handling for enabling.
 390  
  * Now respecting enabledToSetSelectedObjectValueForKey from display group.
 391  
  *
 392  
  * Revision 1.7  2003/08/06 23:07:52  chochos
 393  
  * general code cleanup (mostly, removing unused imports)
 394  
  *
 395  
  * Revision 1.6  2002/10/11 20:12:58  mpowers
 396  
  * Updated aspect signature.
 397  
  *
 398  
  * Revision 1.5  2002/10/11 20:08:14  mpowers
 399  
  * Added visible aspect to slider association.
 400  
  *
 401  
  * Revision 1.4  2001/11/01 15:54:37  mpowers
 402  
  * Minor update to aspect signature.
 403  
  *
 404  
  * Revision 1.3  2001/07/30 16:32:55  mpowers
 405  
  * Implemented support for bulk-editing.  Detail associations will now
 406  
  * apply changes to all selected objects.
 407  
  *
 408  
  * Revision 1.2  2001/02/16 15:03:34  mpowers
 409  
  * Fixed: slider sets value in display group after selection changed.
 410  
  *
 411  
  * Revision 1.1.1.1  2000/12/21 15:48:55  mpowers
 412  
  * Contributing wotonomy.
 413  
  *
 414  
  * Revision 1.2  2000/12/20 16:25:41  michael
 415  
  * Added log to all files.
 416  
  *
 417  
  *
 418  
  */
 419