View Javadoc

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.Adjustable;
22  import java.awt.Component;
23  import java.awt.event.AdjustmentEvent;
24  import java.awt.event.AdjustmentListener;
25  
26  import net.wotonomy.foundation.NSArray;
27  import net.wotonomy.foundation.internal.ValueConverter;
28  import net.wotonomy.ui.EOAssociation;
29  import net.wotonomy.ui.EODisplayGroup;
30  
31  /***
32  * AdjustableAssociation binds any Adjustable component to
33  * a display group.  Components implementing the adjustable
34  * interface include: ScrollBar and JScrollBar.
35  * Bindings are: 
36  * <ul>
37  * <li>value: a property convertable to/from a string</li> 
38  * <li>enabled: a boolean property that determines whether
39  * the user can select the text in the field</li> 
40  * </ul>
41  *
42  * @author michael@mpowers.net
43  * @author $Author: cgruber $
44  * @version $Revision: 904 $
45  */
46  public class AdjustableAssociation extends EOAssociation
47  	implements AdjustmentListener
48  {
49      static final NSArray aspects = 
50          new NSArray( new Object[] {
51              ValueAspect, EnabledAspect
52          } );
53      static final NSArray aspectSignatures = 
54          new NSArray( new Object[] {
55              AttributeToOneAspectSignature, 
56  			AttributeToOneAspectSignature, 
57  			AttributeToOneAspectSignature,
58  			AttributeToOneAspectSignature 
59          } );
60      static final NSArray objectKeysTaken = 
61          new NSArray( new Object[] {
62              "value" 
63          } );
64  		
65      /***
66      * Constructor specifying the object to be controlled by this
67      * association.  Does not establish connection.
68      */
69      public AdjustableAssociation ( Object anObject )
70      {
71          super( anObject );
72      }
73      
74      /***
75      * Returns a List of aspect signatures whose contents
76      * correspond with the aspects list.  Each element is 
77      * a string whose characters represent a capability of
78      * the corresponding aspect. <ul>
79      * <li>"A" attribute: the aspect can be bound to
80      * an attribute.</li>
81      * <li>"1" to-one: the aspect can be bound to a
82      * property that returns a single object.</li>
83      * <li>"M" to-one: the aspect can be bound to a
84      * property that returns multiple objects.</li>
85      * </ul> 
86      * An empty signature "" means that the aspect can
87      * bind without needing a key.
88      * This implementation returns "A1M" for each
89      * element in the aspects array.
90      */
91      public static NSArray aspectSignatures ()
92      {
93          return aspectSignatures;
94      }
95      
96      /***
97      * Returns a List that describes the aspects supported
98      * by this class.  Each element in the list is the string
99      * name of the aspect.  This implementation returns an
100     * empty list.
101     */
102     public static NSArray aspects ()
103     {
104         return aspects;
105     }
106     
107     /***
108     * Returns a List of EOAssociation subclasses that,
109     * for the objects that are usable for this association,
110     * are less suitable than this association.
111     */
112     public static NSArray associationClassesSuperseded ()
113     {
114         return new NSArray();
115     }
116     
117     /***
118     * Returns whether this class can control the specified 
119     * object. 
120     */
121     public static boolean isUsableWithObject ( Object anObject )
122     {
123         return ( anObject instanceof Adjustable );
124     }
125     
126     /***
127     * Returns a List of properties of the controlled object
128     * that are controlled by this class.  For example,
129     * "stringValue", or "selected".
130     */
131     public static NSArray objectKeysTaken ()
132     {
133         return objectKeysTaken;
134     }
135     
136     /***
137     * Returns the aspect that is considered primary
138     * or default.  This is typically "value" or somesuch.
139     */
140     public static String primaryAspect ()
141     {
142         return ValueAspect;
143     }
144         
145     /***
146     * Returns whether this association can bind to the
147     * specified display group on the specified key for
148     * the specified aspect.  
149     */
150     public boolean canBindAspect ( 
151         String anAspect, EODisplayGroup aDisplayGroup, String aKey)
152     {
153         return ( aspects.containsObject( anAspect ) );
154     }
155     
156     /***
157     * Establishes a connection between this association
158     * and the controlled object.  This implementation 
159 	* attempts to add this class as an ActionListener
160 	* and as a FocusListener to the specified object.
161     */
162     public void establishConnection ()
163     {
164 		component().addAdjustmentListener( this );
165         super.establishConnection();
166 		
167 		// forces update from bindings
168 		subjectChanged();
169     }
170 	
171     /***
172     * Breaks the connection between this association and 
173     * its object.  Override to stop listening for events
174     * from the object.
175     */
176     public void breakConnection ()
177     {
178 		component().removeAdjustmentListener( this );
179         super.breakConnection();
180     }
181 
182     /***
183     * Called when either the selection or the contents 
184     * of an associated display group have changed.
185     */
186     public void subjectChanged ()
187     {
188 		Adjustable component = component();
189 		EODisplayGroup displayGroup;
190 		String key;
191 		Object value;
192 	
193 		// value aspect
194 		displayGroup = displayGroupForAspect( ValueAspect );
195 		if ( displayGroup != null )
196 		{
197 			key = displayGroupKeyForAspect( ValueAspect );
198             if ( component instanceof Component )
199             {
200                 ((Component)component).setEnabled( 
201                         displayGroup.enabledToSetSelectedObjectValueForKey( key ) );
202             }
203 			value = displayGroup.selectedObjectValueForKey( key );
204 			
205 			// convert value to int
206 			value = ValueConverter.convertObjectToClass( 
207 				value, Integer.class );
208 
209 			int intValue;
210 			if ( value == null ) 
211 			{
212 				intValue = 0;
213 			}
214 			else
215 			{
216 				intValue = ((Integer)value).intValue();
217 			}
218 			
219 			if ( component.getValue() != intValue )
220 			{
221 				component.setValue( intValue );
222 			}
223 		}
224 
225 		// enabled aspect
226 		displayGroup = displayGroupForAspect( EnabledAspect );
227 		key = displayGroupKeyForAspect( EnabledAspect );
228 		if ( ( ( displayGroup != null ) || ( key != null ) )
229 		&& ( component instanceof Component ) )
230 		{
231 			if ( displayGroup != null )
232 			{
233 				value =
234 					displayGroup.selectedObjectValueForKey( key );
235 			}
236 			else
237 			{
238 				// treat bound key without display group as a value
239 				value = key;	
240 			}
241             Boolean converted = null;
242             if ( value != null ) 
243             {
244                 converted = (Boolean)
245                     ValueConverter.convertObjectToClass(
246                         value, Boolean.class );
247             }
248             if ( converted == null ) converted = Boolean.FALSE;
249             if ( converted.booleanValue() != ((Component)component).isEnabled() )
250             {
251                 ((Component)component).setEnabled( converted.booleanValue() );	
252             }
253 		}
254 
255     }
256 	
257     /***
258     * Forces this association to cause the object to 
259     * stop editing and validate the user's input.
260     * @return false if there were problems validating,
261     * or true to continue.
262     */
263     public boolean endEditing ()
264     {
265 		return writeValueToDisplayGroup();
266     }
267 	
268 	/***
269 	* Writes the value currently in the component
270 	* to the selected object in the display group
271 	* bound to the value aspect.
272     * @return false if there were problems validating,
273     * or true to continue.
274 	*/
275 	protected boolean writeValueToDisplayGroup()
276 	{
277 		EODisplayGroup displayGroup = 
278 			displayGroupForAspect( ValueAspect );
279 		if ( displayGroup != null )
280 		{
281 			String key = displayGroupKeyForAspect( ValueAspect );
282 			Object value = new Integer( component().getValue() );
283 			return displayGroup.setSelectedObjectValue( value, key );
284 		}
285 		return false;
286 	}
287 
288     // interface AdjustmentListener
289 	
290 	/***
291 	* Updates object on action performed.
292 	*/
293 	public void adjustmentValueChanged(AdjustmentEvent e) 
294 	{
295 		writeValueToDisplayGroup();
296 	}
297     
298 	private Adjustable component()
299 	{
300 		return (Adjustable) object();	
301 	}
302 }
303 
304 /*
305  * $Log$
306  * Revision 1.2  2006/02/18 23:19:05  cgruber
307  * Update imports and maven dependencies.
308  *
309  * Revision 1.1  2006/02/16 13:22:23  cgruber
310  * Check in all sources in eclipse-friendly maven-enabled packages.
311  *
312  * Revision 1.3  2004/01/28 18:34:57  mpowers
313  * Better handling for enabling.
314  * Now respecting enabledToSetSelectedObjectValueForKey from display group.
315  *
316  * Revision 1.2  2003/08/06 23:07:52  chochos
317  * general code cleanup (mostly, removing unused imports)
318  *
319  * Revision 1.1.1.1  2000/12/21 15:48:35  mpowers
320  * Contributing wotonomy.
321  *
322  * Revision 1.2  2000/12/20 16:25:40  michael
323  * Added log to all files.
324  *
325  *
326  */
327