1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
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
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
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
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
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
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
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327