Source code: com/flexstor/common/awt/field/FlexChoice.java
1 /*
2 * FlexChoice.java
3 *
4 * Copyright $Date: 2003/08/11 02:22:44 $ FLEXSTOR.net Inc.
5 *
6 * This work is licensed for use and distribution under license terms found at
7 * http://www.flexstor.org/license.html
8 *
9 */
10
11 package com.flexstor.common.awt.field;
12
13 import java.awt.Choice;
14 import java.awt.Color;
15 import java.awt.Component;
16 import java.awt.Dimension;
17 import java.awt.FontMetrics;
18 import java.awt.Frame;
19 import java.awt.event.ItemEvent;
20 import java.awt.event.ItemListener;
21 import java.util.ArrayList;
22 import java.util.Iterator;
23 import java.util.Vector;
24
25 import com.flexstor.common.awt.dialogs.MessageBox;
26 import com.flexstor.common.awt.event.FlexTextEvent;
27 import com.flexstor.common.awt.event.FlexTextListener;
28 import com.flexstor.common.disguise.LookupListItem;
29 import com.flexstor.common.parsers.ValidatorI;
30
31 /**
32 * FlexChoice extends choice by providing for:
33 * 1. The ability to add a list of items at one time with the construstor.
34 * 2. The setItems() method which clears the choice and adds a list of items.
35 * 3. Auto padding automatically handled. This means that the first item in the choice is
36 * always a space. This option must be selected in the constructor.
37 * 4. Keeping an associated id to each item value in the list of choices.
38 */
39 public class FlexChoice
40 extends Choice
41 implements ItemListener, ComponentI
42 {
43 /** The preferred length of the items in this choice. */
44 private int nMaxLength;
45
46 /** If set to false, then this choice does not support tabbing. */
47 private boolean bTabbable;
48
49 /** A string with a single space is added as the first item to the choice when true. */
50 private boolean bPadChoice;
51
52 /** Text Listeners -- used for filtering of text events. */
53 private Vector textListeners;
54
55 private boolean bRequired;
56
57 /** The currently valid selected item. May differ from actual selected value when between textValueChangeBegin()
58 and textValueChangeEnd() processing. */
59 private String sLastValue = "";
60 private long nLastValueId = -1;;
61
62 /** The list of lookup items (value,id pairs) for this choice. */
63 private ArrayList alItems = null;
64
65 private static FontMetrics metrics = null;
66
67 /**
68 * Creates an empty FlexChoice.
69 */
70 public FlexChoice()
71 {
72 this( "", new ArrayList(), false );
73 }
74
75 /**
76 * Creates a new FlexChoice containing the items saItems.
77 * @param alItems the items values and ids to add to the choice.
78 */
79 public FlexChoice( ArrayList alItems )
80 {
81 this( "", alItems, false );
82 }
83
84 /**
85 * Creates a new FlexChoice containing the items saItems.
86 * @param saItems the items values to add to the choice. The values ids will be set to -1.
87 */
88 public FlexChoice( String[] saItems )
89 {
90 this( "", saItems, false );
91 }
92
93 /**
94 * Creates a new FlexChoice with the name sName and containing the items saItems.
95 * @param bPadChoice Padding automatically handled if true.
96 */
97 public FlexChoice( boolean bPadChoice )
98 {
99 this( "", new ArrayList(), bPadChoice );
100 }
101
102 /**
103 * Creates a new FlexChoice with the name sName and containing the items saItems.
104 * @param sName the name of this choice.
105 * @param saItems the items values to add to the choice. The values ids will be set to -1.
106 * @param bPadChoice Padding automatically handled if true.
107 */
108 public FlexChoice( String sName, String[] saItems, boolean bPadChoice )
109 {
110 super();
111
112 setName( sName );
113 setForeground( Color.black );
114 setBackground( Color.white );
115
116 textListeners = new Vector( 1, 1 );
117 addItemListener( this );
118
119 this.alItems = new ArrayList();
120 this.bPadChoice = bPadChoice;
121
122 setItems( saItems );
123
124 setFocusTraversable( true );
125 }
126
127 /**
128 * Creates a new FlexChoice with the name sName and containing the items saItems.
129 * @param sName the name of this choice.
130 * @param alItems the lookup items values and ids to add to the choice.
131 * @param bPadChoice Padding automatically handled if true.
132 */
133 public FlexChoice( String sName, ArrayList alItems, boolean bPadChoice )
134 {
135 super();
136
137 setName( sName );
138 setForeground( Color.black );
139 setBackground( Color.white );
140
141 textListeners = new Vector( 1, 1 );
142 addItemListener( this );
143
144 this.alItems = new ArrayList();
145 this.bPadChoice = bPadChoice;
146
147 setItems( alItems );
148
149 setFocusTraversable( true );
150 }
151
152 /**
153 * Configures the validator field.
154 * @param bEditable will this field be editable.
155 * @param bRequired will the user be required to enter data in this field.
156 * @param sLabel the name that is used in error messages for vaildation.
157 */
158 public void configure( boolean bEditable, boolean bRequired, String sLabel, String[] saItems )
159 {
160 ArrayList alItems = new ArrayList();
161 if ( saItems != null )
162 {
163 for ( int i = 0; i < saItems.length; i++ )
164 alItems.add( new LookupListItem( saItems[i], -1 ) );
165 }
166
167 configure( bEditable, bRequired, sLabel, alItems );
168 }
169
170 /**
171 * Configures the validator field.
172 * @param bEditable will this field be editable.
173 * @param bRequired will the user be required to enter data in this field.
174 * @param sLabel the name that is used in error messages for vaildation.
175 */
176 public void configure( boolean bEditable, boolean bRequired, String sLabel, ArrayList alItems )
177 {
178 setEnabled( bEditable );
179 setRequired( bRequired );
180 setName( sLabel );
181
182 setItems( alItems );
183
184 clear( false );
185 }
186
187 /**
188 *
189 */
190 public void addItem( String sItem )
191 {
192 addItem( new LookupListItem( sItem, -1 ) );
193 }
194
195 /**
196 *
197 */
198 public void addItem( LookupListItem item )
199 {
200 if ( item != null && item.getValue() != null )
201 {
202 alItems.add( item );
203 super.addItem( item.getValue() );
204
205 if ( metrics != null )
206 nMaxLength = Math.max( metrics.stringWidth( item.getValue() ), nMaxLength );
207 }
208 }
209
210 /**
211 * Adds an array of items to the choice.
212 * @param saItems The array of items to add.
213 */
214 public void setItems( String[] saItems )
215 {
216 ArrayList alItems = new ArrayList();
217 if ( saItems != null )
218 {
219 for ( int i = 0; i < saItems.length; i++ )
220 alItems.add( new LookupListItem( saItems[i], -1 ) );
221 }
222
223 setItems( alItems );
224 }
225
226 /**
227 * Adds an array of items to the choice.
228 * @param alItems the items ( values and ids ) to be added to the choices list.
229 */
230 public void setItems( ArrayList alItems )
231 {
232 removeAll();
233
234 if ( bPadChoice )
235 addItem( " " );
236
237 if ( alItems != null && alItems.size() > 0 )
238 {
239 Iterator itItems = alItems.iterator();
240 while ( itItems.hasNext() )
241 addItem( (LookupListItem)itItems.next() );
242 }
243
244 if ( this.alItems.size() > 0 )
245 {
246 sLastValue = ( (LookupListItem)this.alItems.get( 0 ) ).getValue();
247 nLastValueId = ( (LookupListItem)this.alItems.get( 0 ) ).getLookupRecordId();
248 }
249 else
250 {
251 sLastValue = "";
252 nLastValueId = -1;
253 }
254 }
255
256 /**
257 *
258 */
259 public void removeAll()
260 {
261 nMaxLength = 0;
262
263 super.removeAll();
264 alItems.clear();
265 }
266
267 /**
268 *
269 */
270 public void insert( String sItem, int index )
271 {
272 alItems.add( index, new LookupListItem( sItem, -1 ) );
273 super.insert( sItem, index );
274
275 if ( metrics != null )
276 nMaxLength = Math.max ( metrics.stringWidth( sItem ), nMaxLength );
277 }
278
279 /**
280 *
281 */
282 public void insert( LookupListItem item, int index )
283 {
284 alItems.add( index, item );
285 super.insert( item.getValue(), index );
286
287 if ( metrics != null )
288 nMaxLength = Math.max ( metrics.stringWidth( item.getValue() ), nMaxLength );
289 }
290
291 /**
292 * Selects the first item in the choice.
293 * @param bNotify Sends an edit ActionEvent to all listeners if true.
294 */
295 public void clear( boolean bNotify )
296 {
297 select( 0 );
298
299 if ( bNotify )
300 itemStateChanged( null );
301 }
302
303 /**
304 *
305 */
306 public void cleanup()
307 {
308 removeAll();
309
310 textListeners.removeAllElements();
311 textListeners = null;
312
313 metrics = null;
314 }
315
316 /**
317 *
318 */
319 public void addNotify()
320 {
321 super.addNotify();
322
323 metrics = getFontMetrics( getFont() );
324 for ( int i = 0; i < getItemCount(); i++ )
325 nMaxLength = Math.max( metrics.stringWidth( getItem( i ) ), nMaxLength );
326 }
327
328 /**
329 * Sets the focusTraversable function.
330 * @param bState this choice supports tabbing if true.
331 */
332 public void setFocusTraversable( boolean bState )
333 {
334 bTabbable = bState;
335 }
336
337 /**
338 * Overides isFocusTraversable in java.awt.Component.
339 * This choice supports tabbing only if it is enabled, showing on the
340 * screen, and setFocusTraversable(false) was not called.
341 */
342 public boolean isFocusTraversable()
343 {
344 return isEnabled() && isShowing() && bTabbable;
345 }
346
347 /**
348 *
349 */
350 public void itemStateChanged ( ItemEvent ie )
351 {
352 synchronized ( textListeners )
353 {
354 FlexTextEvent e = new FlexTextEvent( this, 0, 0, "" );
355 for ( int i = 0; i < textListeners.size(); i++ )
356 ( (FlexTextListener)textListeners.elementAt( i ) ).textValueChangeBegin( e );
357
358 // Check if the change was aborted...
359 if ( !e.getAllowChange() )
360 {
361 setText( sLastValue );
362 return;
363 }
364
365 sLastValue = getText();
366
367 e = new FlexTextEvent( this, 0, 0, "" );
368 for ( int i = 0; i < textListeners.size(); i++ )
369 ( (FlexTextListener)textListeners.elementAt( i ) ).textValueChangeEnd( e );
370 }
371 }
372
373 /**
374 * Returns true if this choice is enabled.
375 * @return true if this choice is enabled.
376 */
377 public boolean getEnabled()
378 {
379 return isEnabled();
380 }
381
382 /**
383 * Sets the contents of the upper part of the choice. Automatically handles padding.
384 * @sText the new value.
385 */
386 public void setText( String sText )
387 {
388 if ( bPadChoice && sText.trim().equals( "" ) )
389 sText = " ";
390
391 select( sText );
392 }
393
394 /**
395 * Returns the contents of the upper part of the choice. Automatically handles padding.
396 * @return the contents of the choice.
397 */
398 public String getText()
399 {
400 if ( bPadChoice && getSelectedIndex() == 0 )
401 return "";
402 else
403 return getSelectedItem();
404 }
405
406 /**
407 *
408 */
409 public void setId( long nId )
410 {
411 int i = -1;
412 Iterator itItems = alItems.iterator();
413 for ( i = 0; itItems.hasNext(); i++ )
414 {
415 if ( ( (LookupListItem)itItems.next() ).getLookupRecordId() == nId )
416 break;
417 }
418
419 select( i );
420 }
421
422 /**
423 *
424 */
425 public long getId()
426 {
427 return ( (LookupListItem)alItems.get( getSelectedIndex() ) ).getLookupRecordId();
428 }
429
430 /**
431 *
432 */
433 public synchronized void select( int pos )
434 {
435 sLastValue = getItem( pos );
436 nLastValueId = ( (LookupListItem)alItems.get( pos ) ).getLookupRecordId();
437
438 super.select( pos );
439 }
440
441 /**
442 *
443 */
444 public synchronized void select( String str )
445 {
446 sLastValue = str;
447
448 LookupListItem item = null;
449 Iterator itItems = alItems.iterator();
450 while ( itItems.hasNext() )
451 {
452 item = (LookupListItem)itItems.next();
453 if ( item.getValue().equals( str ) )
454 {
455 nLastValueId = item.getLookupRecordId();
456 break;
457 }
458 }
459
460 super.select( str );
461 }
462
463 /**
464 *
465 */
466 public boolean verify( boolean bCheckRequired )
467 {
468 // Check required.
469 if ( bCheckRequired && isBlank() && bRequired )
470 {
471 MessageBox.showMessageDialog ( getParentFrame(), 5792, MessageBox.OK, getName() );
472 requestFocus();
473 return false;
474 }
475
476 return true;
477 }
478
479 /**
480 *
481 */
482 private Frame getParentFrame()
483 {
484 Component c = this;
485
486 do
487 {
488 c = c.getParent();
489 }
490 while ( c != null && !(c instanceof Frame) );
491
492 return (Frame)c;
493 }
494
495 /** Not implemented until this choice supports editing. */
496 public void formatCase ( )
497 {
498 }
499
500 /** Not implemented until this choice supports editing. */
501 public void setCustomValidator ( ValidatorI validator )
502 {
503 }
504
505 /**
506 *
507 */
508 public boolean quietVerify()
509 {
510 return !(isBlank() && bRequired);
511 }
512
513 /**
514 *
515 */
516 public boolean isBlank()
517 {
518 if ( bPadChoice )
519 return ( getSelectedIndex() == 0 );
520 else
521 return false;
522 }
523
524 /**
525 *
526 */
527 public boolean isRequired ( )
528 {
529 return bRequired;
530 }
531
532 /**
533 *
534 */
535 public void setRequired ( boolean bRequired )
536 {
537 this.bRequired = bRequired;
538 }
539
540 /**
541 *
542 */
543 public Dimension getMinimumSize ( )
544 {
545 return getPreferredSize();
546 }
547
548 /**
549 *
550 */
551 public Dimension getPreferredSize ( )
552 {
553 return new Dimension ( nMaxLength + 40, ComponentI.COMPONENT_HEIGHT );
554 }
555
556 /**
557 *
558 */
559 public synchronized void addTextListener ( FlexTextListener l )
560 {
561 textListeners.addElement ( l );
562 }
563
564 /**
565 *
566 */
567 public synchronized void removeTextListener ( FlexTextListener l )
568 {
569 if ( textListeners.contains ( l ) )
570 textListeners.removeElement ( l );
571 }
572
573 }