Coverage Report - net.wotonomy.ui.swing.ActionAssociation
 
Classes in this File Line Coverage Branch Coverage Complexity
ActionAssociation
0% 
0% 
2.333
 
 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.Component;
 22  
 import java.awt.event.ActionEvent;
 23  
 import java.awt.event.ActionListener;
 24  
 import java.util.Enumeration;
 25  
 
 26  
 import net.wotonomy.foundation.NSArray;
 27  
 import net.wotonomy.foundation.NSSelector;
 28  
 import net.wotonomy.foundation.internal.ValueConverter;
 29  
 import net.wotonomy.foundation.internal.WotonomyException;
 30  
 import net.wotonomy.ui.EOAssociation;
 31  
 import net.wotonomy.ui.EODisplayGroup;
 32  
 
 33  
 /**
 34  
 * ActionAssociation binds any ActionEvent broadcaster 
 35  
 * (typically Buttons and the like) to a display group.  
 36  
 * Actions are invoked on all selected objects in the 
 37  
 * display group bound to the action aspect.
 38  
 * Bindings are: 
 39  
 * <ul>
 40  
 * <li>action: a method to be invoked on selected objects.
 41  
 * If the argument aspect is bound, the method must take 
 42  
 * one argument.  Otherwise, the method must take no arguments.</li> 
 43  
 * <li>argument: the attribute of the selected object(s) (possibly 
 44  
 * from a different display group) that will be used as an argument 
 45  
 * to the action method</li> 
 46  
 * <li>enabled: a boolean property that determines whether
 47  
 * the controlled component is enabled</li> 
 48  
 * <li>visible: a boolean property that determines whether
 49  
 * the controlled component is visible</li> 
 50  
 * </ul>
 51  
 *
 52  
 * @author michael@mpowers.net
 53  
 * @author $Author: cgruber $
 54  
 * @version $Revision: 904 $
 55  
 */
 56  0
 public class ActionAssociation extends EOAssociation
 57  
         implements ActionListener
 58  
 {
 59  0
     static final NSArray aspects = 
 60  0
         new NSArray( new Object[] {
 61  0
             ActionAspect, ArgumentAspect, EnabledAspect, VisibleAspect
 62  
         } );
 63  0
     static final NSArray aspectSignatures = 
 64  0
         new NSArray( new Object[] {
 65  0
             AttributeToOneAspectSignature, 
 66  0
                         AttributeToOneAspectSignature, 
 67  0
                         AttributeToOneAspectSignature, 
 68  0
                         AttributeToOneAspectSignature 
 69  
         } );
 70  0
     static final NSArray objectKeysTaken = 
 71  0
         new NSArray( new Object[] {
 72  0
             "target" 
 73  
         } );
 74  
                 
 75  0
         static NSSelector addActionListener =
 76  0
                 new NSSelector( "addActionListener", 
 77  0
                 new Class[] { ActionListener.class } );
 78  0
         static NSSelector removeActionListener =
 79  0
                 new NSSelector( "removeActionListener", 
 80  0
                 new Class[] { ActionListener.class } );
 81  
 
 82  
     /**
 83  
     * Constructor specifying the object to be controlled by this
 84  
     * association.  Does not establish connection.
 85  
     */
 86  
     public ActionAssociation ( Object anObject )
 87  
     {
 88  0
         super( anObject );
 89  0
     }
 90  
     
 91  
     /**
 92  
     * Returns a List of aspect signatures whose contents
 93  
     * correspond with the aspects list.  Each element is 
 94  
     * a string whose characters represent a capability of
 95  
     * the corresponding aspect. <ul>
 96  
     * <li>"A" attribute: the aspect can be bound to
 97  
     * an attribute.</li>
 98  
     * <li>"1" to-one: the aspect can be bound to a
 99  
     * property that returns a single object.</li>
 100  
     * <li>"M" to-one: the aspect can be bound to a
 101  
     * property that returns multiple objects.</li>
 102  
     * </ul> 
 103  
     * An empty signature "" means that the aspect can
 104  
     * bind without needing a key.
 105  
     * This implementation returns "A1M" for each
 106  
     * element in the aspects array.
 107  
     */
 108  
     public static NSArray aspectSignatures ()
 109  
     {
 110  0
         return aspectSignatures;
 111  
     }
 112  
     
 113  
     /**
 114  
     * Returns a List that describes the aspects supported
 115  
     * by this class.  Each element in the list is the string
 116  
     * name of the aspect.  This implementation returns an
 117  
     * empty list.
 118  
     */
 119  
     public static NSArray aspects ()
 120  
     {
 121  0
         return aspects;
 122  
     }
 123  
     
 124  
     /**
 125  
     * Returns a List of EOAssociation subclasses that,
 126  
     * for the objects that are usable for this association,
 127  
     * are less suitable than this association.
 128  
     */
 129  
     public static NSArray associationClassesSuperseded ()
 130  
     {
 131  0
         return new NSArray();
 132  
     }
 133  
     
 134  
     /**
 135  
     * Returns whether this class can control the specified 
 136  
     * object. 
 137  
     */
 138  
     public static boolean isUsableWithObject ( Object anObject )
 139  
     {
 140  0
         return 
 141  0
                    ( addActionListener.implementedByObject( anObject ) )
 142  0
                 && ( removeActionListener.implementedByObject( anObject ) );
 143  
     }
 144  
     
 145  
     /**
 146  
     * Returns a List of properties of the controlled object
 147  
     * that are controlled by this class.  For example,
 148  
     * "stringValue", or "selected".
 149  
     */
 150  
     public static NSArray objectKeysTaken ()
 151  
     {
 152  0
         return objectKeysTaken;
 153  
     }
 154  
     
 155  
     /**
 156  
     * Returns the aspect that is considered primary
 157  
     * or default.  
 158  
     */
 159  
     public static String primaryAspect ()
 160  
     {
 161  0
         return ActionAspect;
 162  
     }
 163  
         
 164  
     /**
 165  
     * Returns whether this association can bind to the
 166  
     * specified display group on the specified key for
 167  
     * the specified aspect.  
 168  
     */
 169  
     public boolean canBindAspect ( 
 170  
         String anAspect, EODisplayGroup aDisplayGroup, String aKey)
 171  
     {
 172  0
         return ( aspects.containsObject( anAspect ) );
 173  
     }
 174  
     
 175  
     /**
 176  
     * Establishes a connection between this association
 177  
     * and the controlled object.  Subclasses should begin
 178  
     * listening for events from their controlled object here.
 179  
     */
 180  
     public void establishConnection ()
 181  
     {
 182  
                 try
 183  
                 {
 184  0
                         addActionListener.invoke( object(), this );
 185  
                 }
 186  0
                 catch ( Exception exc )
 187  
                 {
 188  0
                         throw new WotonomyException( "EOActionAssociation: " +
 189  0
                                 "could not add action listener to object:" + object() );
 190  0
                 }
 191  0
         super.establishConnection();
 192  0
     }
 193  
     
 194  
     /**
 195  
     * Breaks the connection between this association and 
 196  
     * its object.  Override to stop listening for events
 197  
     * from the object.
 198  
     */
 199  
     public void breakConnection ()
 200  
     {
 201  
                 try
 202  
                 {
 203  0
                         removeActionListener.invoke( object(), this );
 204  
                 }
 205  0
                 catch ( Exception exc )
 206  
                 {
 207  0
                         throw new WotonomyException( "EOActionAssociation: " +
 208  0
                                 "could not add action listener to object:" + object() );
 209  0
                 }
 210  0
         super.breakConnection();
 211  0
     }
 212  
     
 213  
     /**
 214  
     * Called when either the selection or the contents 
 215  
     * of an associated display group have changed.
 216  
     * This implementation does nothing.
 217  
     */
 218  
     public void subjectChanged ()
 219  
     {
 220  0
                 Object component = object();
 221  
                 EODisplayGroup displayGroup;
 222  
                 String key;
 223  
         
 224  0
                 if ( component instanceof Component ) 
 225  
                 {
 226  
                         // enabled aspect
 227  0
                         displayGroup = displayGroupForAspect( EnabledAspect );
 228  0
                         if ( displayGroup != null )
 229  
                         {
 230  0
                                 key = displayGroupKeyForAspect( EnabledAspect );
 231  0
                 ((Component)component).setEnabled( 
 232  0
                         displayGroup.enabledToSetSelectedObjectValueForKey( key ) );
 233  0
                                 Object value = 
 234  0
                                         displayGroup.selectedObjectValueForKey( key );
 235  0
                 Boolean converted = null;
 236  0
                 if ( value != null ) 
 237  
                 {
 238  0
                     converted = (Boolean)
 239  0
                         ValueConverter.convertObjectToClass(
 240  0
                             value, Boolean.class );
 241  
                 }
 242  0
                 if ( converted == null ) converted = Boolean.FALSE;
 243  0
                 if ( converted.booleanValue() != 
 244  0
                     ((Component)component).isEnabled() )
 245  
                 {
 246  0
                     ((Component)component).setEnabled( 
 247  0
                         converted.booleanValue() );        
 248  
                 }
 249  
                         }
 250  
         
 251  
                         // visible aspect
 252  0
                         displayGroup = displayGroupForAspect( VisibleAspect );
 253  0
                         if ( displayGroup != null )
 254  
                         {
 255  0
                                 key = displayGroupKeyForAspect( VisibleAspect );
 256  0
                                 Object value = 
 257  0
                                         displayGroup.selectedObjectValueForKey( key );
 258  0
                                 Boolean converted = (Boolean)
 259  0
                                         ValueConverter.convertObjectToClass( 
 260  0
                                                 value, Boolean.class );
 261  0
                                 if ( converted != null )
 262  
                                 {
 263  0
                                         if ( converted.booleanValue() != 
 264  0
                                                 ((Component)component).isVisible() )
 265  
                                         {
 266  0
                                                 ((Component)component).setVisible( 
 267  0
                                                         converted.booleanValue() );        
 268  
                                         }
 269  
                                 }                        
 270  
                         }
 271  
                 }
 272  0
     }
 273  
             
 274  
     // interface ActionListener
 275  
     
 276  
     public void actionPerformed( ActionEvent evt )
 277  
     {
 278  0
                 EODisplayGroup actionDisplayGroup = null;
 279  0
                 String actionKey = null;
 280  
                 
 281  
                 // action aspect
 282  0
                 actionDisplayGroup = displayGroupForAspect( ActionAspect );
 283  0
                 if ( actionDisplayGroup != null )
 284  
                 {
 285  0
                         actionKey = displayGroupKeyForAspect( ActionAspect );
 286  
 
 287  
                         //TODO: argument aspect not implemented
 288  
 
 289  
                         try
 290  
                         {
 291  
                         
 292  0
                                 NSSelector selector = new NSSelector( actionKey );                
 293  0
                                 Enumeration e = 
 294  0
                                         actionDisplayGroup.selectedObjects().objectEnumerator();
 295  0
                                 while ( e.hasMoreElements() )
 296  
                                 {
 297  0
                                         selector.invoke( e.nextElement() );
 298  0
                                 }
 299  
                         }
 300  0
                         catch ( Exception exc )
 301  
                         {
 302  0
                                 throw new WotonomyException( 
 303  0
                                         "ActionAssociation: error invoking action: " + actionKey, exc );
 304  0
                         }
 305  
                 }
 306  0
         }        
 307  
 }
 308  
 
 309  
 /*
 310  
  * $Log$
 311  
  * Revision 1.2  2006/02/18 23:19:05  cgruber
 312  
  * Update imports and maven dependencies.
 313  
  *
 314  
  * Revision 1.1  2006/02/16 13:22:22  cgruber
 315  
  * Check in all sources in eclipse-friendly maven-enabled packages.
 316  
  *
 317  
  * Revision 1.4  2004/01/28 18:34:57  mpowers
 318  
  * Better handling for enabling.
 319  
  * Now respecting enabledToSetSelectedObjectValueForKey from display group.
 320  
  *
 321  
  * Revision 1.3  2003/08/06 23:07:52  chochos
 322  
  * general code cleanup (mostly, removing unused imports)
 323  
  *
 324  
  * Revision 1.2  2001/02/17 16:52:05  mpowers
 325  
  * Changes in imports to support building with jdk1.1 collections.
 326  
  *
 327  
  * Revision 1.1.1.1  2000/12/21 15:48:28  mpowers
 328  
  * Contributing wotonomy.
 329  
  *
 330  
  * Revision 1.5  2000/12/20 16:25:40  michael
 331  
  * Added log to all files.
 332  
  *
 333  
  *
 334  
  */
 335