1 /*
2 J-Bird net/sourceforge/jbird/awt/ListChooser.java
3
4 Copyright 2001, 2002, 2003 Dick Repasky
5 */
6 package net.sourceforge.jbird.awt;
7
8 import java.awt.Color;
9 import java.awt.GridBagConstraints;
10 import java.awt.GridBagLayout;
11 import java.awt.Insets;
12 import java.awt.Label;
13 import java.awt.List;
14 import java.awt.Panel;
15 import java.awt.TextField;
16 import java.awt.Toolkit;
17 import java.awt.event.ActionEvent;
18 import java.awt.event.ActionListener;
19 import java.awt.event.ItemEvent;
20 import java.awt.event.ItemListener;
21 import java.awt.event.KeyAdapter;
22 import java.awt.event.KeyEvent;
23 import java.awt.event.KeyListener;
24 import java.awt.event.TextEvent;
25 import java.awt.event.TextListener;
26 import java.text.Collator;
27 import java.text.NumberFormat;
28 import java.util.Iterator;
29 import java.util.ResourceBundle;
30 import javax.swing.SwingUtilities;
31
32 import net.sourceforge.jbird.iface.IntarrayListener;
33 import net.sourceforge.jbird.iface.IntarrayListenerList;
34 import net.sourceforge.jbird.iface.NullListener;
35 import net.sourceforge.jbird.iface.TextFocus;
36 import net.sourceforge.jbird.util.CollationKeyArray;
37 import net.sourceforge.jbird.util.MyStringArray;
38
39 /**
40 * A component that provides two ways to select among choices:
41 * a TextField and a List. If an item is selected in the List
42 * its name appears in the TextField, or if the name of an item
43 * is typed into the TextField, the corresponding item is selected
44 * in the List. Titles are available for the TextField and List
45 * as well as for the entire component. An indicator appears for the
46 * whole component. If no item is selected it is yellow and indicates
47 * that nothing has been selected. Whan an item has been selected
48 * its name appears in green.
49 * <p>
50 * ListChooser beeps when name completion is enabled and the
51 * user types in text that matches no entry in the list. Developers
52 * can override with whatever action they choose by using the
53 * setBeeper method to provide an object that implmenets NullListener
54 * to do the job.
55 */
56
57 public class ListChooser extends Panel implements TextFocus {
58 // STATE VARIABLES
59 public int[] selecteditems = null;
60 public String[] selectednames = null;
61 public boolean canchoose;
62 public String names[]; // array to be displayed
63 public String lasttextentry = "";
64 private CollationKeyArray keylist;
65 public Collator collator = null;
66 NumberFormat nformatter = NumberFormat.getInstance();
67 private int fieldcompletion = 3; // modify constructor if you
68 // change this default to 1
69 private CompletionListener completionlistener = null;
70
71 // COMPONENTS
72 protected Label title = new Label();
73 public Label selectedname = new Label("none selected",
74 Label.LEFT);
75 protected Color unselectedcolor = Color.yellow;
76 protected Color selectedcolor = Color.green;
77
78 public Label typetitle = new Label("Enter from keyboard");
79 public Label picktitle = new Label("Pick");
80 public TextField typefield = new TextField();
81 public List picklist;
82 // WORK HERE - get rid of these
83 // once all sublcasses have been
84 // weened of insets.
85 public Insets inset = new Insets(0,0,0,0);
86 public ListAction listlistener;
87 public ClickOnList itemlistener;
88 private IntarrayListenerList arraylistener = new IntarrayListenerList();
89
90 // widths of other fields should be 3 x title
91
92 protected boolean skiptext = false;
93 protected boolean skiplist = false;
94
95 // used to hold value of text field for delayed
96 // setting of typefield values
97 protected String newtextvalue;
98
99 /** When not null, the receiveNull method of this
100 interface will be called when the ListChooser
101 wishes to scold the user. Otherwise, it
102 beeps. Implemented in method beep. Configured
103 using method setBeeper. @since J-Bird 0.1.2 */
104 protected NullListener beeper;
105
106 /** A KeyAdapter that listens for return character
107 in typefield. Not instantiated until
108 setNextFocus is called. @since J-Bird 0.1.2 */
109 protected KeyAdapter return_listener;
110 protected TextFocus next_text_focus;
111
112 /**
113 * 6 visible choices. Single-selection mode.
114 *
115 */
116
117 public ListChooser() {
118 this(6);
119 }
120
121 /**
122 * <code>nrows</code> visible choices. Single-selection mode.
123 *
124 */
125
126 public ListChooser(int rows) {
127 this(rows, false);
128 }
129
130 /**
131 * <code>nrows</code> visible choices. <code>multmode</code>
132 * sets multiple-selection mode of List.
133 *
134 */
135
136 public ListChooser(int rows, boolean multmode) {
137 this(rows, multmode, getHorizontalConstraints());
138 }
139
140 /**
141 * A constructor that provides control over the position
142 * of the components using GrigBagConstraints.
143 * <p>
144 * The array of GridBagConstraints should be length 6 and
145 * describe the postions of (in order):
146 * <ol>
147 * <li>chooser title</li>
148 * <li>selected value</li>
149 * <li>header for keyboard input area</li>
150 * <li>keyboard input field</li>
151 * <li>header for pick list</li>
152 * <li>pick list</li>
153 * </ol>
154 * Titles for the chooser, keyboard input field and the picker can be
155 * omitted by setting those elements of the array to null values.
156 */
157
158 public ListChooser(int rows, boolean multmode, GridBagConstraints[] gbc) {
159 picklist = new List(rows, multmode);
160 setLayout(new GridBagLayout());
161 if (gbc[0] != null) {
162 add(title,gbc[0]);
163 }
164 add(selectedname, gbc[1]);
165 if (gbc[2] != null) {
166 add(typetitle, gbc[2]);
167 }
168 add(typefield, gbc[3]);
169 if (gbc[4] != null) {
170 add(picktitle, gbc[4]);
171 }
172 add(picklist, gbc[5]);
173 common();
174 }
175
176 /**
177 * Tasks that are common to all constructors.
178 *
179 */
180
181 protected void common() {
182 title.setAlignment(Label.LEFT);
183 selectedname.setForeground(unselectedcolor);
184 listlistener = new ListAction();
185 picklist.addActionListener(listlistener);
186 setEnabledChoices(false);
187 itemlistener = new ClickOnList();
188 picklist.addItemListener(itemlistener);
189 TextWrangler textwrangler = new TextWrangler();
190 typefield.addTextListener(textwrangler);
191 }
192
193 /**
194 * Returns boolean indicator of whether multiple selections
195 * are allowed.
196 *
197 */
198
199 public boolean isMultipleMode() {
200 return picklist.isMultipleMode();
201 }
202
203 /**
204 * Set multiple selection mode according to <code>multmode</code>.
205 *
206 */
207
208 public void setMultipleMode(boolean multmode) {
209 if (multmode == picklist.isMultipleMode()) { // no change
210 return;
211 }
212 // arbitrarily reduce selected items if going false
213 while (!multmode && selecteditems.length > 1) { // will this work?
214 int take = selecteditems.length - 1;
215 deselectItem(take);
216 }
217 picklist.setMultipleMode(multmode);
218 }
219
220 /**
221 * Provide a NullListener that will perform suitable acts
222 * when the ListChooser wishes to beep. By default
223 * the ListChooser beeps. Provide a null value to restore
224 * default behavior.
225 * @since J-Bird 0.1.2
226 *
227 */
228
229 public final void setBeeper(NullListener beeper) {
230 this.beeper = beeper;
231 }
232
233 /**
234 * Enable or disble ListChoice for use by users.
235 *
236 */
237
238 public void setEnabledChoices(boolean b) {
239 typefield.setEnabled(b);
240 picklist.setEnabled(b);
241 canchoose = b;
242 }
243
244 /**
245 * Return boolean indication of whether ListChoice is enabled.
246 * @since J-Bird 0.1.1
247 *
248 */
249
250 public boolean isEnabledChoices() {
251 return canchoose;
252 }
253
254 public final void buildList (String[] itemnames) {
255 buildList(itemnames, Collator.getInstance(), false);
256 }
257
258 public final void buildList (String[] itemnames, Collator coll,
259 boolean presorted) {
260 collator = (Collator) coll.clone();
261 clearList();
262 //System.out.println("buildList: cloning names");
263 names = (String[])itemnames.clone();
264 //System.out.println("buildList: names cloned");
265 //System.out.println("buildList: adding names to picklist");
266 int i;
267 for (i=0; i < itemnames.length; i++) {
268 picklist.add(names[i]);
269 }
270 //System.out.println("buildList: added names to picklist");
271 picklist.makeVisible(0);
272 //System.out.println("buildList: building collationkeyarray");
273 keylist = new CollationKeyArray(itemnames, collator);
274 //System.out.println("buildList: built collationkeyarray");
275 if (! presorted) {
276 //System.out.println("buildList: sorting keys");
277 keylist.sortArray();
278 //System.out.println("buildList: finished sorting");
279 }
280 setEnabledChoices(true);
281 }
282
283 /**
284 * Use this method when itemnames is already sorted and
285 * you've already built a sorted CollationKeyArray
286 */
287
288 public final void buildList(String[] itemnames,
289 CollationKeyArray cka) {
290 collator = cka.collator;
291 clearList();
292 names = (String[])itemnames.clone();
293 int i;
294 for (i=0; i < itemnames.length; i++) {
295 picklist.add(names[i]);
296 }
297 picklist.makeVisible(0);
298 keylist = cka;
299 setEnabledChoices(true);
300 }
301
302 private final void clearList() {
303 setEnabledChoices(true); // WORK HERE - is this wrong?
304 if (picklist.getItemCount() > 0) {
305 picklist.deselect(picklist.getSelectedIndex());
306 picklist.removeAll();
307 }
308 }
309
310 /**
311 * Select item by row number in List.
312 *
313 */
314
315 public void selectItem (int index) {
316 if (index < 0) {
317 return;
318 }
319 if (picklist.isIndexSelected(index)) {
320 return;
321 }
322 skiplist = true;
323 picklist.select(index);
324 updateSelectedItemInfo();
325 }
326
327 /**
328 * Reset the label and notify listeners based on state of
329 * ListChooser.
330 *
331 */
332
333 public void updateSelectedItemInfo() {
334 selecteditems = picklist.getSelectedIndexes();
335 selectednames = picklist.getSelectedItems();
336 if (selecteditems.length == 0) {
337 selectedname.setText("none selected");
338 selectedname.setForeground(unselectedcolor);
339 } else if (selecteditems.length == 1) {
340 selectedname.setForeground(selectedcolor);
341 int selecteditem = selecteditems[0];
342 selectedname.setText(names[selecteditem]);
343 lasttextentry = names[selecteditem];// decoy text listeners
344 setTypefieldTextNoNotice(lasttextentry);
345 } else {
346 selectedname.setForeground(selectedcolor);
347 selectedname.setText(nformatter.format(selecteditems.length) +
348 " items selected");
349 }
350 //if (selecteditems.length > 0) {
351 //int i;
352 //System.out.println("seletcted items in list");
353 //for (i=0; i < selecteditems.length; i++ ) {
354 //System.out.println("\t" + names[selecteditems[i]]);
355 //}
356 //}
357 //System.out.println("updateSelectedIteminfo - notifying Array listeners");
358 notifyArrayListeners(selecteditems);
359 }
360
361 /**
362 * Unselect item based on row number in List.
363 *
364 */
365
366 public void deselectItem (int item) {
367 if (item == -1) {
368 return;
369 }
370 if (! picklist.isIndexSelected(item)) {
371 return;
372 }
373 picklist.deselect(item);
374 updateSelectedItemInfo();
375 }
376
377 // deselect items only in non-multiple mode
378 public void narrowPossibilities(String value) {
379 narrowPossibilities(value, fieldcompletion);
380 }
381
382 public void narrowPossibilities(String value, int completion) {
383 //System.out.println("narrow possibilities on " + value + "X");
384 if (names.length <= 0) {
385 lasttextentry = "";
386 return;
387 }
388 boolean issinglemode = ! picklist.isMultipleMode();
389 if (value.length() == 0) { // value empty
390 picklist.makeVisible(0);
391 if (issinglemode && selecteditems != null &&
392 selecteditems.length == 1) {
393 deselectItem(selecteditems[0]);
394 }
395 lasttextentry = "";
396 return;
397 }
398 int sortedat = keylist.searchFor(value);
399 int realat = keylist.originalIndex(sortedat);
400
401 if (realat >= 0) { // Exact match
402 picklist.makeVisible(realat);
403 selectItem(realat);
404 return;
405 }
406 // if a match existed, it is no more
407 if (issinglemode && selecteditems != null && selecteditems.length == 1){
408 deselectItem(selecteditems[0]);
409 }
410 // quit if no name completion
411 if (completion < 2 ) {
412 lasttextentry = value;
413 return;
414 }
415 // quit if backspace
416 if ((lasttextentry.length() - value.length() >= 1)) { // is shorter
417 if (lasttextentry.startsWith(value)) { // is the same
418 lasttextentry = value;
419 return;
420 }
421 }
422 // Convert negative indices
423 sortedat = - ( sortedat + 1 );
424 realat = - ( realat + 1 );
425
426 if (realat == names.length) {
427 picklist.makeVisible(names.length-1);
428 beep();
429 lasttextentry = value;
430 return;
431 }
432 picklist.makeVisible(realat);
433 // count the number of elements that
434 // begin with the value
435 int matchcount = countBeginners(value, sortedat);
436 if (matchcount == 0) {
437 if ( (lasttextentry.length() - value.length()) != 1) {
438 beep();
439 }
440 lasttextentry = value;
441 return;
442 }
443
444 if (matchcount == 1) { // only one match - a winner
445 selectItem(realat);
446 return;
447 }
448
449 if ( completion < 3) {
450 return;
451 }
452 // no exact match - may be common chars
453 String[] commonbegin = new String[matchcount];
454 int i;
455 int sortedati = sortedat;
456 for (i = 0; i < matchcount; i++) {
457 commonbegin[i] = names[keylist.originalIndex(sortedati)];
458 sortedati ++;
459 }
460
461 int commoncount = MyStringArray.commonChars(commonbegin,value.length(),
462 collator);
463 commonbegin = null;
464
465 if (commoncount > 0) {
466 commoncount += value.length();
467 if (commoncount == names[realat].length()) {
468 selectItem(realat);
469 return;
470 }
471 lasttextentry = names[realat].substring(0, commoncount);//decoy
472 setTypefieldTextNoNotice(lasttextentry);
473 return;
474 }
475
476 lasttextentry = value;
477 return;
478 }
479
480 class TextWrangler implements TextListener {
481 public void textValueChanged (TextEvent e) {
482 if (skiptext) {
483 skiptext = false;
484 return;
485 }
486 String newvalue = typefield.getText();
487 if (! newvalue.equals(lasttextentry)) {
488 narrowPossibilities(newvalue);
489 //lasttextentry = newvalue; //done in narrowPossibilites
490 }
491 }
492 }
493
494 class ListAction implements ActionListener {
495 public void actionPerformed (ActionEvent e) {
496 // System.out.println("ListChooser detects ListAction");
497 if (skiplist) {
498 skiplist = false;
499 } else {
500 updateSelectedItemInfo();
501 }
502 }
503 }
504
505 class ClickOnList implements ItemListener {
506 public void itemStateChanged (ItemEvent e) {
507 //System.out.println("ListChooser - ClickOnList");
508 updateSelectedItemInfo();
509 }
510 }
511
512 public void addArrayActionListener (IntarrayListener item) {
513 arraylistener.addListener(item);
514 }
515
516 public void removeArrayActionListener(IntarrayListener item) {
517 arraylistener.removeListener(item);
518 }
519
520 private void notifyArrayListeners(int[] values) {
521 arraylistener.alertListeners(values);
522 }
523
524 public void setTypefieldTextNoNotice (String value) {
525 lasttextentry = value;
526 skiptext = true;
527 setTypefieldText(value);
528 }
529
530 public void setTypefieldText (String value) {
531 newtextvalue = value;
532 Runnable setnew = new Runnable() {
533 public void run () {
534 typefield.setText(newtextvalue);
535 if (typefield.isDisplayable()) {
536 typefield.setCaretPosition(newtextvalue.length());
537 }
538 }
539 };
540 SwingUtilities.invokeLater(setnew);
541 }
542
543 private int countBeginners(String value, int beginat) {
544 int realat;
545 int answer = 0;
546 int i = beginat;
547 while (i < names.length) {
548 realat = keylist.originalIndex(i);
549 // if (names[realat].startsWith(value)) // need collator
550 if (stringBStartsWithA(value, names[realat])) {
551 answer ++;
552 i++;
553 } else {
554 return answer;
555 }
556 }
557 return answer;
558 }
559
560 private boolean stringBStartsWithA(String a, String b) {
561
562 int lengtha = a.length();
563 int lengthb = b.length();
564
565 if (lengthb < lengtha) {
566 return false;
567 }
568
569 String bsub = b.substring(0, lengtha);
570 return collator.equals(bsub, a);
571 }
572
573 public void setNameCompletion (int value) {
574 if (value != fieldcompletion && value >= 0 && value < 4) {
575 if (fieldcompletion == 1) {
576 dismantleKeyListener();
577 }
578 if (value == 1) {
579 setupKeyListener();
580 }
581 fieldcompletion = value;
582 }
583 }
584
585 private void setupKeyListener () {
586 if (completionlistener != null) {
587 return;
588 }
589 completionlistener = new CompletionListener();
590 typefield.addKeyListener(completionlistener);
591 }
592
593 private void dismantleKeyListener() {
594 if (completionlistener == null) {
595 return;
596 }
597 typefield.removeKeyListener(completionlistener);
598 completionlistener = null;
599 }
600
601
602 public int getNameCompletion (int value) {
603 return fieldcompletion;
604 }
605
606 class CompletionListener extends KeyAdapter {
607 public void keyPressed(KeyEvent e) {
608 if (e.getKeyCode() == KeyEvent.VK_END) {
609 String newvalue = typefield.getText();
610 if (! newvalue.equals("")) {
611 narrowPossibilities(newvalue, 3);
612 }
613 }
614 }
615 }
616
617 public void localize (ResourceBundle bund) {
618 typetitle.setText((String)bund.getObject("Enter_f_keyboard"));
619 picktitle.setText((String)bund.getObject("Pick"));
620 }
621
622 public void localize (String kbdtxt, String picktxt) {
623 typetitle.setText(kbdtxt);
624 picktitle.setText(picktxt);
625 }
626
627 /**
628 * @since J-Bird 0.1.2
629 *
630 */
631
632 public final void setTitle(String text) {
633 title.setText(text);
634 }
635
636 /**
637 * Return a string array of the selected items
638 *
639 * This method returns information exactly as does the
640 * getSelectedItems method of objects of type List
641 *
642 */
643
644 public String[] getSelectedNames() {
645 return picklist.getSelectedItems();
646 }
647
648 /**
649 * Set color of selected value.
650 * @since J-Bird 0.1.2
651 *
652 */
653
654 public final void setSelectedColor(Color color) {
655 selectedcolor = color;
656 if (picklist.getSelectedIndex() >= 0) {
657 selectedname.setForeground(selectedcolor);
658 }
659 }
660
661 /**
662 * Return color of selected value.
663 * @since J-Bird 0.1.2
664 *
665 */
666
667 public final Color getSelectedColor() {
668 return selectedcolor;
669 }
670
671 /**
672 * Set color of non-selected message.
673 * @since J-Bird 0.1.2
674 *
675 */
676
677 public final void setUnselectedColor(Color color) {
678 unselectedcolor = color;
679 if (picklist.getSelectedIndex() < 0) {
680 selectedname.setForeground(unselectedcolor);
681 }
682 }
683
684 /**
685 * Return color of non-selected message.
686 * @since J-Bird 0.1.2
687 *
688 */
689
690 public final Color getUnselectedColor() {
691 return unselectedcolor;
692 }
693
694 /**
695 * Return an array of GridBagConstraints that lays out
696 * a ListChooser with keyboard input on the left and
697 * picker on the right.
698 * <p>
699 * The picker should always be much taller than the keyboard
700 * input field. Empty space in the lower left
701 * quadrant is useful placing buttons and other
702 * components that might be used in subclasses of
703 * ListChooser.
704 *
705 */
706
707 public static GridBagConstraints[] getHorizontalConstraints() {
708
709 GridBagConstraints[] gbc = new GridBagConstraints[6];
710
711 // title
712 gbc[0] = new GridBagConstraints(0, // gridx
713 0, // gridy
714 1, // gridwidth
715 1, // gridheight
716 0, // weightx,
717 0, // weighty,
718 GridBagConstraints.CENTER,
719 // anchor
720 GridBagConstraints.NONE,
721 // fill
722 new Insets(5,0,2,0), // insets
723 //new Insets(5,5,2,5), // insets
724 0, // ipadx
725 0); // ipady
726
727 // selected value
728 gbc[1] = new GridBagConstraints(1, // gridx
729 0, // gridy
730 6, // gridwidth
731 1, // gridheight
732 0, // weightx,
733 0, // weighty,
734 GridBagConstraints.WEST,
735 // anchor
736 GridBagConstraints.HORIZONTAL,
737 // fill
738 new Insets(5,0,2,0), // insets
739 0, // ipadx
740 0); // ipady
741
742 // type title
743 gbc[2] = new GridBagConstraints(1, // gridx
744 2, // gridy
745 3, // gridwidth
746 1, // gridheight
747 0, // weightx,
748 0, // weighty,
749 GridBagConstraints.CENTER,
750 // anchor
751 GridBagConstraints.NONE,
752 // fill
753 new Insets(5,0,0,0), // insets
754 0, // ipadx
755 0); // ipady
756
757 // picker title
758 gbc[4] = new GridBagConstraints(4, // gridx
759 2, // gridy
760 3, // gridwidth
761 1, // gridheight
762 0, // weightx,
763 0, // weighty,
764 GridBagConstraints.CENTER,
765 // anchor
766 GridBagConstraints.NONE,
767 // fill
768 new Insets(5,0,0,0), // insets
769 0, // ipadx
770 0); // ipady
771
772 // keyboard input field
773 gbc[3] = new GridBagConstraints(1, // gridx
774 3, // gridy
775 3, // gridwidth
776 1, // gridheight
777 0, // weightx,
778 0, // weighty,
779 GridBagConstraints.CENTER,
780 // anchor
781 GridBagConstraints.NONE,
782 // fill
783 new Insets(1,0,5,0), // insets
784 0, // ipadx
785 0); // ipady
786
787 // picker
788 gbc[5] = new GridBagConstraints(4, // gridx
789 3, // gridy
790 3, // gridwidth
791 6, // gridheight
792 1.0, // weightx,
793 1.0, // weighty,
794 GridBagConstraints.CENTER,
795 // anchor
796 GridBagConstraints.BOTH,
797 // fill
798 new Insets(1,3,5,5), // insets
799 0, // ipadx
800 0); // ipady
801 return gbc;
802 }
803
804 /**
805 * Return an array of GridBagConstraints that will layout
806 * members of a ListChooser vertically, with keyboard chooser
807 * over picker.
808 *
809 */
810
811 public static GridBagConstraints[] getVerticalConstraints() {
812
813 GridBagConstraints[] gbc = new GridBagConstraints[6];
814
815 // title
816 gbc[0] = new GridBagConstraints(0, // gridx
817 0, // gridy
818 1, // gridwidth
819 1, // gridheight
820 0, // weightx,
821 0, // weighty,
822 GridBagConstraints.CENTER,
823 // anchor
824 GridBagConstraints.NONE,
825 // fill
826 new Insets(5,0,2,0), // insets
827 //new Insets(5,5,2,5), // insets
828 0, // ipadx
829 0); // ipady
830
831 // selected value
832 gbc[1] = new GridBagConstraints(1, // gridx
833 0, // gridy
834 3, // gridwidth
835 1, // gridheight
836 0, // weightx,
837 0, // weighty,
838 GridBagConstraints.WEST,
839 // anchor
840 GridBagConstraints.HORIZONTAL,
841 // fill
842 new Insets(5,0,2,5), // insets
843 0, // ipadx
844 0); // ipady
845
846 // type title
847 gbc[2] = new GridBagConstraints(1, // gridx
848 2, // gridy
849 3, // gridwidth
850 1, // gridheight
851 0, // weightx,
852 0, // weighty,
853 GridBagConstraints.CENTER,
854 // anchor
855 GridBagConstraints.NONE,
856 // fill
857 new Insets(5,5,0,5), // insets
858 0, // ipadx
859 0); // ipady
860
861 // picker title
862 gbc[4] = new GridBagConstraints(1, // gridx orig 4
863 4, // gridy orig 2
864 3, // gridwidth
865 1, // gridheight
866 0, // weightx,
867 0, // weighty,
868 GridBagConstraints.CENTER,
869 // anchor
870 GridBagConstraints.NONE,
871 // fill
872 new Insets(5,5,0,5), // insets
873 0, // ipadx
874 0); // ipady
875
876 // keyboard input field
877 gbc[3] = new GridBagConstraints(1, // gridx
878 3, // gridy
879 3, // gridwidth
880 1, // gridheight
881 0, // weightx,
882 0, // weighty,
883 GridBagConstraints.CENTER,
884 // anchor
885 GridBagConstraints.HORIZONTAL,
886 // fill
887 new Insets(1,0,5,5), // insets
888 0, // ipadx
889 0); // ipady
890
891 // picker
892 gbc[5] = new GridBagConstraints(1, // gridx orig 4
893 5, // gridy orig 3
894 3, // gridwidth
895 6, // gridheight
896 0, // weightx,
897 0, // weighty,
898 GridBagConstraints.CENTER,
899 // anchor
900 GridBagConstraints.HORIZONTAL,
901 // fill
902 new Insets(1,0,5,5), // insets
903 0, // ipadx
904 0); // ipady
905 return gbc;
906 }
907
908 /////////////////////// methods implementing Text Focus ///////////////
909
910 /**
911 * Calls requestFocus method of the text field.
912 * <p>
913 * Implements TextFocus.
914 * @since J-Bird 0.1.2
915 *
916 */
917
918 public final void requestTextFocus() {
919 typefield.requestFocus();
920 }
921
922 /**
923 * Set the component that will receive focus when
924 * the user presses return in the typefield of
925 * this component.
926 * <p>
927 * Implements TextFocus.
928 * @since J-Bird 0.1.2
929 */
930
931 public void setNextFocus(TextFocus component) {
932 if (return_listener == null && component != null) {
933 return_listener = new KeyAdapter() {
934 public void keyTyped(KeyEvent ke) {
935 char kt = ke.getKeyChar();
936 if (kt == '\n' && next_text_focus != null) {
937 next_text_focus.requestTextFocus();
938 }
939 }
940 };
941 typefield.addKeyListener(return_listener);
942 }
943 next_text_focus = component;
944 }
945
946 /////////////////////// protected methods below //////////////////////
947
948 /**
949 * Use this method to scold users. Calls the receiveNull
950 * method of beeper if beeper is not null. Otherwise, it
951 * just beeps. Use setBeeper to control behavior.
952 * @since J-Bird 0.1.2
953 *
954 */
955
956 protected final void beep() {
957 if (beeper != null) {
958 beeper.receiveNull();
959 } else {
960 Toolkit.getDefaultToolkit().beep();
961 }
962 }
963
964 ////////////////////// private methods below ////////////////////////
965
966 }