Subversion Repository Public Repository

litesoft

Diff Revisions 627 vs 628 for /trunk/GWT_Sandbox/FormEngine/src/com/temp/client/foundation/widget/input/InputField.java

Diff revisions: vs.
  @@ -3,428 +3,177 @@
3 3 import com.google.gwt.user.client.ui.*;
4 4 import com.temp.client.foundation.widget.*;
5 5 import com.temp.client.foundation.widget.input.fieldsupport.*;
6 - import com.temp.client.foundation.widget.input.support.*;
7 - import com.temp.client.foundation.widget.HelpWidget;
6 + import com.temp.shared.*;
8 7 import com.temp.shared.externalization.*;
9 8 import com.temp.shared.utils.*;
10 9
11 10 /**
12 - * An Input Field that can be instantiated directly or as a widget in a UI Binding file.
11 + * An interface for an Input Field.
12 + * <p/>
13 + * Implementation should be able to be used directly or as a widget in a UI Binding file.
13 14 * <p/>
14 15 * It operates in two distinct states:
15 16 * <p/>
16 17 * <li>Builder Mode - Where properties of the final widget are specified (and parts of the widget are NOT accessable)</li>
17 - * <li>Run Mode - Whare the parts of the Widget are accessable (and the specification properties are NOT changeable)</li>
18 + * <li>Run Mode - Where the parts of the Widget are accessable (and the specification properties are NOT changeable)</li>
18 19 * <p/>
19 20 * The transition between the states is one way ('Builder' to 'Run') and is a result of the call to 'init'.
21 + * <p/>
22 + * An Input Field has the following:
23 + *
24 + * <ul>
25 + * <li>Name</li>
26 + * <li>Base Value **,</li>
27 + * <li>Current Value **,</li>
28 + * <li>Changed State,</li>
29 + * <li>Errored State,</li>
30 + * <li>Enabled State,</li>
31 + * <li>Visibility State, and</li>
32 + * <li>Following Widgets:</li>
33 + * <ol>
34 + * <li>InputWidget</li>
35 + * <li>LabelLabel</li>
36 + * <li>ExtendedLabel</li>
37 + * <li>ExampleLabel</li>
38 + * <li>ErrorLabel</li>
39 + * <li>HelpWidget</li>
40 + * </ol>
41 + * </ul>
42 + *
43 + * ** - These values are "normalized" in both directions (to & from the underlying Input Widget(s)).
44 + * This means that a value set and then fetched may be different (however a value fetched, then set,
45 + * then fetched should match the original value fetched)! For String based input fields the normalization
46 + * is that leading and trailing whitespace is ignored and empty strings and nulls are substituted based
47 + * on direction ("" -> null when fetching from the underlying input widget, and null -> "" when setting
48 + * into the underlying input widget). For non-String based input fields the normalization could appear
49 + * a bit strange, for example: CheckBox input fields will interpret null as false.
20 50 *
21 51 * @param <T> the data type returned by this InputField
22 52 */
23 - public class InputField<T> extends Composite implements HasName
53 + public interface InputField<T> extends HasName,
54 + Enableable,
55 + Visible
24 56 {
25 - // Required to be set
26 - private String name;
27 -
28 - // Optionally set/changed
29 - private InputType inputType = InputType.String;
30 - private boolean required = false;
31 - private boolean errorLabel = true;
32 - private boolean extendedLabel = false;
33 - private boolean example = false;
34 - private LabelPosition labelPosition = LabelPosition.Left;
35 -
36 - // Optionally set
37 - private Integer maxLength;
38 - private String helpLink;
39 -
40 - // The above must be set/changed BEFORE the widget is attached!
41 -
42 - private HorizontalPanel container = new HorizontalPanel();
43 - private CompleteInputFieldAccessor<T> completeInputFieldAccessor;
44 -
45 - public InputField()
46 - {
47 - container.add( new Label( "!?!" ) );
48 - initWidget( container );
49 - }
50 -
51 - // Configuration Methods
52 -
53 - @Override
54 - public String getName()
55 - {
56 - return name;
57 - }
58 -
59 - @Override
60 - public void setName( String name )
61 - {
62 - assertBuildMode();
63 - this.name = Validate.noEmptyIdentifier( "Name", name );
64 - }
65 -
66 - public InputField<T> name( String name )
67 - {
68 - setName( name );
69 - return this;
70 - }
71 -
72 - public String getType()
57 + interface ChangeListener<T2>
73 58 {
74 - return (inputType != null) ? inputType.name() : null;
59 + void changed( InputField<T2> field );
75 60 }
76 61
77 - public void setType( String type )
78 - {
79 - assertBuildMode();
80 - type = StringUtils.noEmpty( type );
81 - InputType inputType = ObjectUtils.oneOfToStringIgnoreCase( type, InputType.values() );
82 - if ( inputType == null )
83 - {
84 - throw new IllegalArgumentException( "Unacceptable InputType of: " + type );
85 - }
86 - setInputType( inputType );
87 - }
88 -
89 - public InputType getInputType()
90 - {
91 - return inputType;
92 - }
93 -
94 - public void setInputType( InputType inputType )
95 - {
96 - assertBuildMode();
97 - Validate.notNull( "InputType", this.inputType = inputType );
98 - }
99 -
100 - public InputField<T> inputType( InputType inputType )
101 - {
102 - setInputType( inputType );
103 - return this;
104 - }
62 + // Only callable in Builder Mode
105 63
106 - public String getLabel()
107 - {
108 - return labelPosition.name();
109 - }
110 -
111 - public void setLabel( String labelPosition )
112 - {
113 - assertBuildMode();
114 - labelPosition = StringUtils.noEmpty( labelPosition );
115 - LabelPosition position = ObjectUtils.oneOfToStringIgnoreCase( labelPosition, LabelPosition.values() );
116 - if ( position == null )
117 - {
118 - throw new IllegalArgumentException( "Unacceptable LabelPosition of: " + labelPosition );
119 - }
120 - setLabelPosition( position );
121 - }
122 -
123 - public LabelPosition getLabelPosition()
124 - {
125 - return labelPosition;
126 - }
127 -
128 - public void setLabelPosition( LabelPosition labelPosition )
129 - {
130 - assertBuildMode();
131 - Validate.notNull( "LabelPosition", this.labelPosition = labelPosition );
132 - }
64 + // For HasName - The Name MUST be set before the call to init (transition to run mode)
133 65
134 - public InputField<T> labelPosition( LabelPosition labelPosition )
135 - {
136 - setLabelPosition( labelPosition );
137 - return this;
138 - }
66 + InputField<T> name( String name );
139 67
140 - public boolean isRequired()
141 - {
142 - return required;
143 - }
68 + /**
69 + * The 'Builder' to 'Run' state transition method fully constructs/populates the InputField's Widget / container.
70 + * <p/>
71 + * Only callable ONCE and only in Builder Mode!
72 + *
73 + * @return this for method chaining
74 + */
75 + InputField<T> init( E13nResolver resolver );
144 76
145 - public void setRequired( boolean required )
146 - {
147 - assertBuildMode();
148 - this.required = required;
149 - if ( required )
150 - {
151 - setErrorLabel( true );
152 - }
153 - }
77 + // Callable anytime
154 78
155 - public InputField<T> required()
156 - {
157 - setRequired( true );
158 - return this;
159 - }
79 + boolean isRunMode();
160 80
161 - public boolean isErrorLabel()
162 - {
163 - return errorLabel;
164 - }
81 + InputField<T> add( ChangeListener<T> changeListener );
165 82
166 - public void setErrorLabel( boolean pErrorLabel )
167 - {
168 - assertBuildMode();
169 - errorLabel = pErrorLabel;
170 - }
83 + boolean remove( ChangeListener<T> changeListener );
171 84
172 - public InputField<T> errorLabel()
173 - {
174 - setErrorLabel( true );
175 - return this;
176 - }
85 + void removeAllChangeListeners();
177 86
178 - public boolean isExtendedLabel()
179 - {
180 - return extendedLabel;
181 - }
87 + ValueValidator<T>[] getValidators();
182 88
183 - public void setExtendedLabel( boolean pExtendedLabel )
184 - {
185 - assertBuildMode();
186 - extendedLabel = pExtendedLabel;
187 - }
89 + InputField<T> add( ValueValidator<T> validator );
188 90
189 - public InputField<T> extendedLabel()
190 - {
191 - setExtendedLabel( true );
192 - return this;
193 - }
91 + InputField<T> add( ValueValidator<T>... additionalValidators );
194 92
195 - public boolean isExample()
196 - {
197 - return example;
198 - }
93 + // For Enableable
199 94
200 - public void setExample( boolean pExample )
201 - {
202 - assertBuildMode();
203 - example = pExample;
204 - }
95 + InputField<T> enable();
205 96
206 - public InputField<T> example()
207 - {
208 - setExample( true );
209 - return this;
210 - }
97 + InputField<T> disable();
211 98
212 - public Integer getMaxLength()
213 - {
214 - return maxLength;
215 - }
99 + // For Visible
216 100
217 - public void setMaxLength( Integer maxLength )
218 - {
219 - assertBuildMode();
220 - this.maxLength = Validate.optionalLength( "MaxLength", maxLength );
221 - }
101 + InputField<T> visible();
222 102
223 - public InputField<T> maxLength( int maxLength )
224 - {
225 - setMaxLength( maxLength );
226 - return this;
227 - }
103 + InputField<T> cloak();
228 104
229 - public String getHelpLink()
230 - {
231 - return helpLink;
232 - }
105 + InputField<T> invisible();
233 106
234 - public void setHelpLink( String helpLink )
235 - {
236 - assertBuildMode();
237 - this.helpLink = StringUtils.noEmpty( helpLink );
238 - }
107 + // Only callable in Run Mode
239 108
240 - public InputField<T> helpLink( String helpLink )
241 - {
242 - setHelpLink( Validate.noEmpty( "HelpLink", helpLink ) );
243 - return this;
244 - }
109 + /**
110 + * Reset the value as if <code>setCurrentValue( null )</code> has been called.
111 + */
112 + void reset();
245 113
246 114 /**
247 - * The 'Builder' to 'Run' state transition method fully constructs/populates the InputField's Widget / container.
115 + * set the Current value and the "Base" value (the "Base" value is what "change" is determined from).
116 + * <p/>
117 + * Note: The value is "normalized" before giving it to the actual Input Widget
248 118 *
249 - * @return this for method chaining
119 + * @param value null OK
120 + * @return "normalized" round-tripped value (null possible) as if <code>getCurrentValue()</code> was called.
250 121 */
251 - public InputField<T> init( E13nResolver resolver )
252 - {
253 - Validate.notNull( "resolver", resolver );
254 - if ( name == null )
255 - {
256 - throw new IllegalStateException( "Unable to init, Name not set" );
257 - }
258 - assertBuildMode();
259 - completeInputFieldAccessor = buildActualWidget( resolver );
260 - return this;
261 - }
262 -
263 - // Anytime Methods
264 -
265 - public boolean isEnabled()
266 - {
267 - return true; // TODO: XXX
268 - }
269 -
270 - public void setEnabled( boolean enable )
271 - {
272 - // TODO: XXX
273 - }
274 -
275 - public InputField<T> enable()
276 - {
277 - setEnabled( true );
278 - return this;
279 - }
280 -
281 - public InputField<T> disable()
282 - {
283 - setEnabled( false );
284 - return this;
285 - }
286 -
287 - public boolean isHidden()
288 - {
289 - return true; // TODO: XXX
290 - }
291 -
292 - public void setHidden( boolean hidden )
293 - {
294 - // TODO: XXX
295 - }
296 -
297 - public InputField<T> hide()
298 - {
299 - setHidden( true );
300 - return this;
301 - }
302 -
303 - public InputField<T> show()
304 - {
305 - setHidden( false );
306 - return this;
307 - }
308 -
309 - // Widget Accessor Methods
310 -
311 - public T getCurrentValue()
312 - {
313 - return getInput().getValue();
314 - }
315 -
316 - public Widget getInputWidget()
317 - {
318 - return checkRunMode( "getInputWidget" ).getInputWidget();
319 - }
320 -
321 - public InputWidgetChangeFilter<T> getInput()
322 - {
323 - return checkRunMode( "getInput" ).getInput();
324 - }
122 + T setCurrentValue( T value );
325 123
326 - public InputWidgetValidator<T> getValidator()
327 - {
328 - return checkRunMode( "getValidator" ).getValidator();
329 - }
124 + /**
125 + * Returned the "normalized" Current value.
126 + *
127 + * @return null possible
128 + */
129 + T getCurrentValue();
330 130
331 - public TextLabel getLabelLabel()
332 - {
333 - return checkRunMode( "getLabelLabel" ).getLabelLabel();
334 - }
131 + /**
132 + * Returned the "normalized" Base value.
133 + *
134 + * @return null possible
135 + */
136 + T getBaseValue();
335 137
336 - public TextLabel getExtendedLabel()
337 - {
338 - return checkRunMode( "getExtendedLabel" ).getExtendedLabel();
339 - }
138 + /**
139 + * revert to the "Base" value
140 + */
141 + void revert();
340 142
341 - public TextLabel getExampleLabel()
342 - {
343 - return checkRunMode( "getExampleLabel" ).getExampleLabel();
344 - }
143 + /**
144 + * Return if the Current Value is different than the Base Value
145 + */
146 + boolean isChanged();
345 147
346 - public TextLabel getErrorLabel()
347 - {
348 - return checkRunMode( "getErrorLabel" ).getErrorLabel();
349 - }
148 + /**
149 + * Return if the Current Value is rejected by any of the ValueValidator(s)
150 + */
151 + boolean isErrored();
350 152
351 - public HelpWidget getHelpWidget()
352 - {
353 - return checkRunMode( "getHelpWidget" ).getHelpWidget();
354 - }
153 + /**
154 + * Validate the Current Value, and "manage" the Error Label appropriately.
155 + * <p/>
156 + * Error Labels are set to a NBSP & Cloaked when the field is not in Error, and Visible w/ the appropriate E13n data when the field is in Error.
157 + *
158 + * @return true if <code>isErrored() == false</code>.
159 + */
160 + boolean validate();
355 161
356 - // Support Methods...
162 + E13nResolver getE13nResolver();
357 163
358 - protected final void assertBuildMode()
359 - {
360 - if ( completeInputFieldAccessor != null )
361 - {
362 - throw new IllegalStateException( "Unable to Mutate InputField Named '" + name + "', because no longer in Build Mode (init called)" );
363 - }
364 - }
164 + Widget getInputWidget();
365 165
366 - protected final CompleteInputFieldAccessor<T> checkRunMode( String method )
367 - {
368 - if ( completeInputFieldAccessor == null )
369 - {
370 - throw new IllegalStateException( "Unable to access widgets of InputField Named '" + name + "', because not in Run Mode (init NOT called)" );
371 - }
372 - return completeInputFieldAccessor;
373 - }
166 + InputWidgetChangeFilter<T> getInput();
374 167
375 - protected CompleteInputFieldAccessor<T> buildActualWidget( E13nResolver pResolver )
376 - {
377 - InputFieldAccessor<T> accessor = inputType.createAccessor();
378 - TextLabel labelTextLabel = null;
379 - TextLabel extendedTextLabel = null;
380 - if ( !LabelPosition.None.equals( labelPosition ) )
381 - {
382 - labelTextLabel = createWrappingLabel( "labelLabel", true );
383 - extendedTextLabel = createWrappingLabel( "extendedLabel", extendedLabel );
384 - }
385 - TextLabel exampleTextLabel = createWrappingLabel( "exampleLabel", example );
386 - TextLabel errorTextLabel = createClippingLabel( "errorLabel", errorLabel && (accessor.getValidator() != null) );
387 - HelpWidget helpWidget = (helpLink != null) ? new HelpWidget().link( helpLink ) : null;
388 - CompleteInputFieldAccessor<T> completeAccessor = new CompleteInputFieldAccessor<T>( labelTextLabel, //
389 - extendedTextLabel, //
390 - accessor, //
391 - helpWidget, //
392 - exampleTextLabel, //
393 - errorTextLabel );
394 - populate( container, completeAccessor );
395 - return completeAccessor;
396 - }
168 + InputWidgetValidator<T> getValidator();
397 169
398 - protected final TextLabel createNonWrappingLabel( String styleName, boolean create )
399 - {
400 - return create ? new NonWrappingLabel().style( styleName ) : null;
401 - }
170 + Widget getLabelLabel();
402 171
403 - protected final TextLabel createWrappingLabel( String styleName, boolean create )
404 - {
405 - return create ? new WrappingLabel().style( styleName ) : null;
406 - }
172 + Widget getExtendedLabel();
407 173
408 - protected final TextLabel createClippingLabel( String styleName, boolean create )
409 - {
410 - return create ? new ClippingLabel().style( styleName ) : null;
411 - }
174 + Widget getExampleLabel();
412 175
413 - protected void populate( HorizontalPanel container, CompleteInputFieldAccessor<T> completeAccessor )
414 - {
176 + Widget getErrorLabel();
415 177
416 - // completeAccessor.
417 - // boolean required = false;
418 - // boolean errorLabel = true;
419 - // boolean extendedLabel = false;
420 - // boolean example = false;
421 - // LabelPosition labelPosition = LabelPosition.Left;
422 - //
423 - // // Optionally set
424 - // Integer maxLength;
425 - // String helpLink;
426 - //
427 - // E13nResolverAccessor resolverAccessor;
428 - // CompleteInputFieldAccessor<T> completeInputFieldAccessor;
429 - }
178 + Widget getHelpWidget();
430 179 }