Coverage Report - net.wotonomy.ui.swing.RadioPanelAssociation
 
Classes in this File Line Coverage Branch Coverage Complexity
RadioPanelAssociation
0% 
0% 
2.211
 
 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.awt.event.ActionEvent;
 22  
 import java.awt.event.ActionListener;
 23  
 
 24  
 import net.wotonomy.foundation.NSArray;
 25  
 import net.wotonomy.foundation.internal.ValueConverter;
 26  
 import net.wotonomy.ui.EOAssociation;
 27  
 import net.wotonomy.ui.EODisplayGroup;
 28  
 import net.wotonomy.ui.swing.components.RadioButtonPanel;
 29  
 
 30  
 /**
 31  
 * RadioPanelAssociation binds RadioButtonPanels to
 32  
 * display groups.  It works exactly like a 
 33  
 * ComboBoxAssociation.  Bindings are: 
 34  
 * <ul>
 35  
 *
 36  
 * <li>value: a property of the selected object in the 
 37  
 * display group that will be bind to the item the user
 38  
 * selects or the text that the user enters in the field.</li> 
 39  
 *
 40  
 * <li>titles: a property of the objects in the bound 
 41  
 * display group that will appear in the list.  If the
 42  
 * objects aspect is not bound, this property is also
 43  
 * used to populate the value binding.</li> 
 44  
 *
 45  
 * <li>objects: optional - if specified, when the user 
 46  
 * selects an title in the list, the property of the
 47  
 * object at the corresponding index of the bound display
 48  
 * group will be used to populate the value binding.</li> 
 49  
 *
 50  
 * <li>enabled: a boolean property of the selected object in the 
 51  
 * display group that determines whether
 52  
 * the user can edit the field.</li> 
 53  
 * 
 54  
 * </ul>
 55  
 *
 56  
 * @author michael@mpowers.net
 57  
 * @author $Author: cgruber $
 58  
 * @version $Revision: 904 $
 59  
 */
 60  0
 public class RadioPanelAssociation extends EOAssociation
 61  
         implements ActionListener
 62  
 {
 63  0
     static final NSArray aspects = 
 64  0
         new NSArray( new Object[] {
 65  0
             TitlesAspect, ValueAspect,
 66  0
                         ObjectsAspect, EnabledAspect
 67  
         } );
 68  0
     static final NSArray aspectSignatures = 
 69  0
         new NSArray( new Object[] {
 70  0
             AttributeToOneAspectSignature, 
 71  0
             AttributeToOneAspectSignature, 
 72  0
                         AttributeToOneAspectSignature, 
 73  0
                         AttributeToOneAspectSignature 
 74  
         } );
 75  0
     static final NSArray objectKeysTaken = 
 76  0
         new NSArray( new Object[] {
 77  0
             "text" 
 78  
         } );
 79  
                 
 80  
    /**
 81  
     * Constructor specifying the object to be controlled by this
 82  
     * association.  Does not establish connection.
 83  
     */
 84  
     public RadioPanelAssociation ( Object anObject )
 85  
     {
 86  0
         super( anObject );
 87  0
     }
 88  
     
 89  
     /**
 90  
     * Returns a List of aspect signatures whose contents
 91  
     * correspond with the aspects list.  Each element is 
 92  
     * a string whose characters represent a capability of
 93  
     * the corresponding aspect. <ul>
 94  
     * <li>"A" attribute: the aspect can be bound to
 95  
     * an attribute.</li>
 96  
     * <li>"1" to-one: the aspect can be bound to a
 97  
     * property that returns a single object.</li>
 98  
     * <li>"M" to-one: the aspect can be bound to a
 99  
     * property that returns multiple objects.</li>
 100  
     * </ul> 
 101  
     * An empty signature "" means that the aspect can
 102  
     * bind without needing a key.
 103  
     * This implementation returns "A1M" for each
 104  
     * element in the aspects array.
 105  
     */
 106  
     public static NSArray aspectSignatures ()
 107  
     {
 108  0
         return aspectSignatures;
 109  
     }
 110  
     
 111  
     /**
 112  
     * Returns a List that describes the aspects supported
 113  
     * by this class.  Each element in the list is the string
 114  
     * name of the aspect.  This implementation returns an
 115  
     * empty list.
 116  
     */
 117  
     public static NSArray aspects ()
 118  
     {
 119  0
         return aspects;
 120  
     }
 121  
     
 122  
     /**
 123  
     * Returns a List of EOAssociation subclasses that,
 124  
     * for the objects that are usable for this association,
 125  
     * are less suitable than this association.
 126  
     */
 127  
     public static NSArray associationClassesSuperseded ()
 128  
     {
 129  0
         return new NSArray();
 130  
     }
 131  
     
 132  
     /**
 133  
     * Returns whether this class can control the specified 
 134  
     * object. 
 135  
     */
 136  
     public static boolean isUsableWithObject ( Object anObject )
 137  
     {
 138  0
         return ( anObject instanceof RadioButtonPanel );
 139  
     }
 140  
     
 141  
     /**
 142  
     * Returns a List of properties of the controlled object
 143  
     * that are controlled by this class.  For example,
 144  
     * "stringValue", or "selected".
 145  
     */
 146  
     public static NSArray objectKeysTaken ()
 147  
     {
 148  0
         return objectKeysTaken;
 149  
     }
 150  
     
 151  
     /**
 152  
     * Returns the aspect that is considered primary
 153  
     * or default.  This is typically "value" or somesuch.
 154  
     */
 155  
     public static String primaryAspect ()
 156  
     {
 157  0
         return ValueAspect;
 158  
     }
 159  
         
 160  
     /**
 161  
     * Returns whether this association can bind to the
 162  
     * specified display group on the specified key for
 163  
     * the specified aspect.  
 164  
     */
 165  
     public boolean canBindAspect ( 
 166  
         String anAspect, EODisplayGroup aDisplayGroup, String aKey)
 167  
     {
 168  0
         return ( aspects.containsObject( anAspect ) );
 169  
     }
 170  
     
 171  
     /**
 172  
     * Establishes a connection between this association
 173  
     * and the controlled object.  Subclasses should begin
 174  
     * listening for events from their controlled object here.
 175  
     */
 176  
     public void establishConnection ()
 177  
     {
 178  0
                 super.establishConnection();
 179  
 
 180  
                 // prepopulate titles
 181  0
                 EODisplayGroup displayGroup = 
 182  0
                         displayGroupForAspect( TitlesAspect );
 183  0
                 if ( displayGroup != null )
 184  
                 {
 185  0
                         String key = displayGroupKeyForAspect( TitlesAspect );
 186  0
                         populateTitles( displayGroup, key );
 187  
                 }
 188  0
         populateValue();
 189  0
         addAsListener();
 190  0
     }
 191  
         
 192  
         protected void addAsListener()
 193  
         {
 194  0
                 component().addActionListener( this );
 195  0
         }
 196  
     
 197  
     /**
 198  
     * Breaks the connection between this association and 
 199  
     * its object.  Override to stop listening for events
 200  
     * from the object.
 201  
     */
 202  
     public void breakConnection ()
 203  
     {
 204  0
                 removeAsListener();
 205  0
         super.breakConnection();
 206  0
     }
 207  
 
 208  
         protected void removeAsListener()
 209  
         {
 210  0
                 component().removeActionListener( this );
 211  0
         }
 212  
         
 213  
     /**
 214  
     * Called when either the selection or the contents 
 215  
     * of an associated display group have changed.
 216  
     */
 217  
     public void subjectChanged ()
 218  
     {
 219  0
                 removeAsListener();
 220  
                 
 221  0
                 RadioButtonPanel component = component();
 222  
                 EODisplayGroup displayGroup;
 223  
                 String key;
 224  
         
 225  
                 // titles aspect
 226  0
                 displayGroup = displayGroupForAspect( TitlesAspect );
 227  0
                 if ( displayGroup != null )
 228  
                 {
 229  
                         // if backing group has changed
 230  0
                         if ( displayGroup.contentsChanged() ) 
 231  
                         {
 232  0
                                 key = displayGroupKeyForAspect( TitlesAspect );
 233  0
                                 populateTitles( displayGroup, key );
 234  
                         }
 235  
                 }
 236  
 
 237  
         // value aspect
 238  0
         populateValue();
 239  
         
 240  
                 // enabled aspect
 241  0
                 displayGroup = displayGroupForAspect( EnabledAspect );
 242  0
                 if ( displayGroup != null )
 243  
                 {
 244  0
                         key = displayGroupKeyForAspect( EnabledAspect );
 245  0
                         Object value = 
 246  0
                                 displayGroup.selectedObjectValueForKey( key );
 247  0
             Boolean converted = null;
 248  0
             if ( value != null ) 
 249  
             {
 250  0
                 converted = (Boolean)
 251  0
                     ValueConverter.convertObjectToClass(
 252  0
                         value, Boolean.class );
 253  
             }
 254  0
             if ( converted == null ) converted = Boolean.FALSE;
 255  0
             if ( converted.booleanValue() != component.isEnabled() )
 256  
             {
 257  0
                 component.setEnabled( converted.booleanValue() );        
 258  
             }
 259  
                 }
 260  
                 
 261  0
                 addAsListener();
 262  0
     }
 263  
                 
 264  
         /**
 265  
         * Called to repopulate the title list from the
 266  
         * specified display group.
 267  
         */
 268  
         protected void populateTitles( 
 269  
                 EODisplayGroup displayGroup, String key )
 270  
         {
 271  
                 Object value;
 272  0
                 int count = displayGroup.displayedObjects().count();
 273  0
                 String[] titles = new String[ count ];
 274  0
                 for ( int i = 0; i < count; i++ )
 275  
                 {
 276  0
                         value = displayGroup.valueForObjectAtIndex( i, key );
 277  0
                         if ( value != null )
 278  
                         {
 279  0
                                 titles[i] = value.toString();
 280  0
                         }
 281  
                         else
 282  
                         {
 283  0
                                 titles[i] = "";        
 284  
                         }
 285  
                 }
 286  0
                 component().setLabels( titles );
 287  0
         }
 288  
     
 289  
         /**
 290  
         * Called to populate the value from the display group.
 291  
         */
 292  
         protected void populateValue()
 293  
         {
 294  0
                 RadioButtonPanel component = component();
 295  
                 EODisplayGroup displayGroup;
 296  
                 String key;
 297  
 
 298  
                 // value aspect
 299  0
                 displayGroup = displayGroupForAspect( ValueAspect );
 300  0
                 if ( displayGroup != null )
 301  
                 {
 302  0
                         key = displayGroupKeyForAspect( ValueAspect );
 303  0
             component.setEnabled( 
 304  0
                     displayGroup.enabledToSetSelectedObjectValueForKey( key ) );
 305  
                     
 306  0
                         Object value = displayGroup.selectedObjectValueForKey( key );
 307  
 
 308  
                         // objects aspect
 309  0
                         EODisplayGroup objectsDisplayGroup = 
 310  0
                                 displayGroupForAspect( ObjectsAspect );
 311  0
                         if ( ( objectsDisplayGroup != null ) && ( value != null ) )
 312  
                         {
 313  0
                                 String objectKey = displayGroupKeyForAspect( ObjectsAspect );
 314  
                                 Object match;
 315  0
                                 int index = NSArray.NotFound;
 316  0
                                 int count = objectsDisplayGroup.displayedObjects().count();
 317  0
                                 for ( int i = 0; i < count; i++ )
 318  
                                 {
 319  0
                                         match = objectsDisplayGroup.valueForObjectAtIndex( i, objectKey );
 320  0
                                         if ( value.equals( match ) )
 321  
                                         {
 322  0
                                                 index = i;
 323  
                                         }
 324  
                                 }
 325  0
                                 if ( index == NSArray.NotFound )
 326  
                                 {
 327  0
                                         if ( component.getValue() != null )
 328  
                                         {        
 329  0
                                                 component.setValue( null );
 330  0
                                         }
 331  
                                 }
 332  
                                 else
 333  
                                 {
 334  0
                                         String[] titles = component().getLabels();
 335  0
                                         component.setValue( titles[ index ] );
 336  
                                 }
 337  0
                         }
 338  
                         else
 339  
                         {
 340  0
                                 if ( value != null ) value = value.toString();
 341  0
                                 component.setValue( (String) value );
 342  
                         }
 343  
                 }
 344  0
         }
 345  
     
 346  
     /**
 347  
     * Forces this association to cause the object to 
 348  
     * stop editing and validate the user's input.
 349  
     * @return false if there were problems validating,
 350  
     * or true to continue.
 351  
     */
 352  
     public boolean endEditing ()
 353  
     {
 354  0
                 return writeValueToDisplayGroup();
 355  
     }
 356  
         
 357  
         /**
 358  
         * Writes the value currently in the component
 359  
         * to the selected object in the display group
 360  
         * bound to the value aspect.
 361  
     * @return false if there were problems validating,
 362  
     * or true to continue.
 363  
         */
 364  
         protected boolean writeValueToDisplayGroup()
 365  
         {
 366  0
                 RadioButtonPanel component = component();
 367  
                 EODisplayGroup displayGroup;
 368  
                 String key;
 369  
                 
 370  
                 // selected title aspect
 371  0
                 displayGroup = displayGroupForAspect( ValueAspect );
 372  0
                 if ( displayGroup != null )
 373  
                 {
 374  0
                         key = displayGroupKeyForAspect( ValueAspect );
 375  0
                         Object value = null;
 376  
 
 377  
                         // selected object aspect, if any
 378  0
                         EODisplayGroup objectsGroup = 
 379  0
                                 displayGroupForAspect( ObjectsAspect );
 380  0
                         if ( objectsGroup != null )
 381  
                         {
 382  0
                                 String objectKey = displayGroupKeyForAspect( ObjectsAspect );
 383  0
                                 String selectedValue = component.getValue();                                
 384  0
                                 if ( selectedValue != null )
 385  
                                 {
 386  0
                                         String[] titles = component.getLabels();
 387  0
                                         int index = -1;
 388  0
                                         for ( int i = 0; i < titles.length; i++ )
 389  
                                         {
 390  0
                                                 if ( selectedValue.equals( titles[i] ) )
 391  
                                                 {
 392  0
                                                         index = i;        
 393  
                                                 }
 394  
                                         }
 395  0
                                         if ( index != -1 )
 396  
                                         {
 397  0
                                                 value = objectsGroup
 398  0
                                                         .valueForObjectAtIndex( index, objectKey );                                
 399  
                                         }
 400  
                                 }
 401  0
                         }
 402  
                         else // just use the selected item
 403  
                         {
 404  0
                                 value = component.getValue();        
 405  
                         }
 406  
 
 407  0
                         return displayGroup.setSelectedObjectValue( value, key );
 408  
                 }
 409  
                 
 410  0
                 return false;
 411  
         }
 412  
         
 413  
     // interface ActionListener
 414  
         
 415  
         /**
 416  
         * Updates object on action performed.
 417  
         */
 418  
         public void actionPerformed( ActionEvent evt )
 419  
         {
 420  0
                 writeValueToDisplayGroup();
 421  0
         }
 422  
             
 423  
         // convenience
 424  
 
 425  
         private RadioButtonPanel component() 
 426  
         {
 427  0
                 return (RadioButtonPanel) object();
 428  
         }
 429  
 }
 430  
 
 431  
 /*
 432  
  * $Log$
 433  
  * Revision 1.2  2006/02/18 23:19:05  cgruber
 434  
  * Update imports and maven dependencies.
 435  
  *
 436  
  * Revision 1.1  2006/02/16 13:22:22  cgruber
 437  
  * Check in all sources in eclipse-friendly maven-enabled packages.
 438  
  *
 439  
  * Revision 1.4  2004/01/28 18:34:57  mpowers
 440  
  * Better handling for enabling.
 441  
  * Now respecting enabledToSetSelectedObjectValueForKey from display group.
 442  
  *
 443  
  * Revision 1.3  2003/08/06 23:07:52  chochos
 444  
  * general code cleanup (mostly, removing unused imports)
 445  
  *
 446  
  * Revision 1.2  2001/02/16 17:48:07  mpowers
 447  
  * Populating titles or data not longer marks target object as changed.
 448  
  *
 449  
  * Revision 1.1.1.1  2000/12/21 15:48:52  mpowers
 450  
  * Contributing wotonomy.
 451  
  *
 452  
  * Revision 1.3  2000/12/20 16:25:41  michael
 453  
  * Added log to all files.
 454  
  *
 455  
  *
 456  
  */
 457