OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [javax/] [swing/] [plaf/] [basic/] [BasicComboBoxUI.java] - Blame information for rev 772

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 772 jeremybenn
/* BasicComboBoxUI.java --
2
   Copyright (C) 2004, 2005, 2006,  Free Software Foundation, Inc.
3
 
4
This file is part of GNU Classpath.
5
 
6
GNU Classpath is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
9
any later version.
10
 
11
GNU Classpath is distributed in the hope that it will be useful, but
12
WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GNU Classpath; see the file COPYING.  If not, write to the
18
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
02110-1301 USA.
20
 
21
Linking this library statically or dynamically with other modules is
22
making a combined work based on this library.  Thus, the terms and
23
conditions of the GNU General Public License cover the whole
24
combination.
25
 
26
As a special exception, the copyright holders of this library give you
27
permission to link this library with independent modules to produce an
28
executable, regardless of the license terms of these independent
29
modules, and to copy and distribute the resulting executable under
30
terms of your choice, provided that you also meet, for each linked
31
independent module, the terms and conditions of the license of that
32
module.  An independent module is a module which is not derived from
33
or based on this library.  If you modify this library, you may extend
34
this exception to your version of the library, but you are not
35
obligated to do so.  If you do not wish to do so, delete this
36
exception statement from your version. */
37
 
38
 
39
package javax.swing.plaf.basic;
40
 
41
import java.awt.Color;
42
import java.awt.Component;
43
import java.awt.Container;
44
import java.awt.Dimension;
45
import java.awt.Font;
46
import java.awt.Graphics;
47
import java.awt.Insets;
48
import java.awt.LayoutManager;
49
import java.awt.Rectangle;
50
import java.awt.event.FocusEvent;
51
import java.awt.event.FocusListener;
52
import java.awt.event.ItemEvent;
53
import java.awt.event.ItemListener;
54
import java.awt.event.KeyAdapter;
55
import java.awt.event.KeyEvent;
56
import java.awt.event.KeyListener;
57
import java.awt.event.MouseListener;
58
import java.awt.event.MouseMotionListener;
59
import java.beans.PropertyChangeEvent;
60
import java.beans.PropertyChangeListener;
61
 
62
import javax.accessibility.Accessible;
63
import javax.accessibility.AccessibleContext;
64
import javax.swing.CellRendererPane;
65
import javax.swing.ComboBoxEditor;
66
import javax.swing.ComboBoxModel;
67
import javax.swing.DefaultListCellRenderer;
68
import javax.swing.InputMap;
69
import javax.swing.JButton;
70
import javax.swing.JComboBox;
71
import javax.swing.JComponent;
72
import javax.swing.JList;
73
import javax.swing.ListCellRenderer;
74
import javax.swing.LookAndFeel;
75
import javax.swing.SwingUtilities;
76
import javax.swing.UIManager;
77
import javax.swing.event.ListDataEvent;
78
import javax.swing.event.ListDataListener;
79
import javax.swing.plaf.ComboBoxUI;
80
import javax.swing.plaf.ComponentUI;
81
import javax.swing.plaf.UIResource;
82
 
83
/**
84
 * A UI delegate for the {@link JComboBox} component.
85
 *
86
 * @author Olga Rodimina
87
 * @author Robert Schuster
88
 */
89
public class BasicComboBoxUI extends ComboBoxUI
90
{
91
  /**
92
   * The arrow button that is displayed in the right side of JComboBox. This
93
   * button is used to hide and show combo box's list of items.
94
   */
95
  protected JButton arrowButton;
96
 
97
  /**
98
   * The combo box represented by this UI delegate.
99
   */
100
  protected JComboBox comboBox;
101
 
102
  /**
103
   * The component that is responsible for displaying/editing the selected
104
   * item of the combo box.
105
   *
106
   * @see BasicComboBoxEditor#getEditorComponent()
107
   */
108
  protected Component editor;
109
 
110
  /**
111
   * A listener listening to focus events occurring in the {@link JComboBox}.
112
   */
113
  protected FocusListener focusListener;
114
 
115
  /**
116
   * A flag indicating whether JComboBox currently has the focus.
117
   */
118
  protected boolean hasFocus;
119
 
120
  /**
121
   * A listener listening to item events fired by the {@link JComboBox}.
122
   */
123
  protected ItemListener itemListener;
124
 
125
  /**
126
   * A listener listening to key events that occur while {@link JComboBox} has
127
   * the focus.
128
   */
129
  protected KeyListener keyListener;
130
 
131
  /**
132
   * List used when rendering selected item of the combo box. The selection
133
   * and foreground colors for combo box renderer are configured from this
134
   * list.
135
   */
136
  protected JList listBox;
137
 
138
  /**
139
   * ListDataListener listening to JComboBox model
140
   */
141
  protected ListDataListener listDataListener;
142
 
143
  /**
144
   * Popup list containing the combo box's menu items.
145
   */
146
  protected ComboPopup popup;
147
 
148
  protected KeyListener popupKeyListener;
149
 
150
  protected MouseListener popupMouseListener;
151
 
152
  protected MouseMotionListener popupMouseMotionListener;
153
 
154
  /**
155
   * Listener listening to changes in the bound properties of JComboBox
156
   */
157
  protected PropertyChangeListener propertyChangeListener;
158
 
159
  /* Size of the largest item in the comboBox
160
   * This is package-private to avoid an accessor method.
161
   */
162
  Dimension displaySize = new Dimension();
163
 
164
  /**
165
   * Used to render the combo box values.
166
   */
167
  protected CellRendererPane currentValuePane;
168
 
169
  /**
170
   * The current minimum size if isMinimumSizeDirty is false.
171
   * Setup by getMinimumSize() and invalidated by the various listeners.
172
   */
173
  protected Dimension cachedMinimumSize;
174
 
175
  /**
176
   * Indicates whether or not the cachedMinimumSize field is valid or not.
177
   */
178
  protected boolean isMinimumSizeDirty = true;
179
 
180
  /**
181
   * Creates a new <code>BasicComboBoxUI</code> object.
182
   */
183
  public BasicComboBoxUI()
184
  {
185
    currentValuePane = new CellRendererPane();
186
    cachedMinimumSize = new Dimension();
187
  }
188
 
189
  /**
190
   * A factory method to create a UI delegate for the given
191
   * {@link JComponent}, which should be a {@link JComboBox}.
192
   *
193
   * @param c The {@link JComponent} a UI is being created for.
194
   *
195
   * @return A UI delegate for the {@link JComponent}.
196
   */
197
  public static ComponentUI createUI(JComponent c)
198
  {
199
    return new BasicComboBoxUI();
200
  }
201
 
202
  /**
203
   * Installs the UI for the given {@link JComponent}.
204
   *
205
   * @param c  the JComponent to install a UI for.
206
   *
207
   * @see #uninstallUI(JComponent)
208
   */
209
  public void installUI(JComponent c)
210
  {
211
    super.installUI(c);
212
 
213
    if (c instanceof JComboBox)
214
      {
215
        isMinimumSizeDirty = true;
216
        comboBox = (JComboBox) c;
217
        installDefaults();
218
        popup = createPopup();
219
        listBox = popup.getList();
220
 
221
        // Set editor and renderer for the combo box. Editor is used
222
        // only if combo box becomes editable, otherwise renderer is used
223
        // to paint the selected item; combobox is not editable by default.
224
        ListCellRenderer renderer = comboBox.getRenderer();
225
        if (renderer == null || renderer instanceof UIResource)
226
          comboBox.setRenderer(createRenderer());
227
 
228
        ComboBoxEditor currentEditor = comboBox.getEditor();
229
        if (currentEditor == null || currentEditor instanceof UIResource)
230
          {
231
            currentEditor = createEditor();
232
            comboBox.setEditor(currentEditor);
233
          }
234
 
235
        installComponents();
236
        installListeners();
237
        comboBox.setLayout(createLayoutManager());
238
        comboBox.setFocusable(true);
239
        installKeyboardActions();
240
        comboBox.putClientProperty(BasicLookAndFeel.DONT_CANCEL_POPUP,
241
                                   Boolean.TRUE);
242
      }
243
  }
244
 
245
  /**
246
   * Uninstalls the UI for the given {@link JComponent}.
247
   *
248
   * @param c The JComponent that is having this UI removed.
249
   *
250
   * @see #installUI(JComponent)
251
   */
252
  public void uninstallUI(JComponent c)
253
  {
254
    setPopupVisible(comboBox, false);
255
    popup.uninstallingUI();
256
    uninstallKeyboardActions();
257
    comboBox.setLayout(null);
258
    uninstallComponents();
259
    uninstallListeners();
260
    uninstallDefaults();
261
    comboBox = null;
262
  }
263
 
264
  /**
265
   * Installs the defaults that are defined in the {@link BasicLookAndFeel}
266
   * for this {@link JComboBox}.
267
   *
268
   * @see #uninstallDefaults()
269
   */
270
  protected void installDefaults()
271
  {
272
    LookAndFeel.installColorsAndFont(comboBox, "ComboBox.background",
273
                                     "ComboBox.foreground", "ComboBox.font");
274
    LookAndFeel.installBorder(comboBox, "ComboBox.border");
275
  }
276
 
277
  /**
278
   * Creates and installs the listeners for this UI.
279
   *
280
   * @see #uninstallListeners()
281
   */
282
  protected void installListeners()
283
  {
284
    // install combo box's listeners
285
    propertyChangeListener = createPropertyChangeListener();
286
    comboBox.addPropertyChangeListener(propertyChangeListener);
287
 
288
    focusListener = createFocusListener();
289
    comboBox.addFocusListener(focusListener);
290
 
291
    itemListener = createItemListener();
292
    comboBox.addItemListener(itemListener);
293
 
294
    keyListener = createKeyListener();
295
    comboBox.addKeyListener(keyListener);
296
 
297
    // install listeners that listen to combo box model
298
    listDataListener = createListDataListener();
299
    comboBox.getModel().addListDataListener(listDataListener);
300
 
301
    // Install mouse and key listeners from the popup.
302
    popupMouseListener = popup.getMouseListener();
303
    comboBox.addMouseListener(popupMouseListener);
304
 
305
    popupMouseMotionListener = popup.getMouseMotionListener();
306
    comboBox.addMouseMotionListener(popupMouseMotionListener);
307
 
308
    popupKeyListener = popup.getKeyListener();
309
    comboBox.addKeyListener(popupKeyListener);
310
  }
311
 
312
  /**
313
   * Uninstalls the defaults and sets any objects created during
314
   * install to <code>null</code>.
315
   *
316
   * @see #installDefaults()
317
   */
318
  protected void uninstallDefaults()
319
  {
320
    if (comboBox.getFont() instanceof UIResource)
321
      comboBox.setFont(null);
322
 
323
    if (comboBox.getForeground() instanceof UIResource)
324
      comboBox.setForeground(null);
325
 
326
    if (comboBox.getBackground() instanceof UIResource)
327
      comboBox.setBackground(null);
328
 
329
    LookAndFeel.uninstallBorder(comboBox);
330
  }
331
 
332
  /**
333
   * Detaches all the listeners we attached in {@link #installListeners}.
334
   *
335
   * @see #installListeners()
336
   */
337
  protected void uninstallListeners()
338
  {
339
    comboBox.removePropertyChangeListener(propertyChangeListener);
340
    propertyChangeListener = null;
341
 
342
    comboBox.removeFocusListener(focusListener);
343
    listBox.removeFocusListener(focusListener);
344
    focusListener = null;
345
 
346
    comboBox.removeItemListener(itemListener);
347
    itemListener = null;
348
 
349
    comboBox.removeKeyListener(keyListener);
350
    keyListener = null;
351
 
352
    comboBox.getModel().removeListDataListener(listDataListener);
353
    listDataListener = null;
354
 
355
    if (popupMouseListener != null)
356
      comboBox.removeMouseListener(popupMouseListener);
357
    popupMouseListener = null;
358
 
359
    if (popupMouseMotionListener != null)
360
      comboBox.removeMouseMotionListener(popupMouseMotionListener);
361
    popupMouseMotionListener = null;
362
 
363
    if (popupKeyListener != null)
364
      comboBox.removeKeyListener(popupKeyListener);
365
    popupKeyListener = null;
366
  }
367
 
368
  /**
369
   * Creates the popup that will contain list of combo box's items.
370
   *
371
   * @return popup containing list of combo box's items
372
   */
373
  protected ComboPopup createPopup()
374
  {
375
    return new BasicComboPopup(comboBox);
376
  }
377
 
378
  /**
379
   * Creates a {@link KeyListener} to listen to key events.
380
   *
381
   * @return KeyListener that listens to key events.
382
   */
383
  protected KeyListener createKeyListener()
384
  {
385
    return new KeyHandler();
386
  }
387
 
388
  /**
389
   * Creates the {@link FocusListener} that will listen to changes in this
390
   * JComboBox's focus.
391
   *
392
   * @return the FocusListener.
393
   */
394
  protected FocusListener createFocusListener()
395
  {
396
    return new FocusHandler();
397
  }
398
 
399
  /**
400
   * Creates a {@link ListDataListener} to listen to the combo box's data model.
401
   *
402
   * @return The new listener.
403
   */
404
  protected ListDataListener createListDataListener()
405
  {
406
    return new ListDataHandler();
407
  }
408
 
409
  /**
410
   * Creates an {@link ItemListener} that will listen to the changes in
411
   * the JComboBox's selection.
412
   *
413
   * @return The ItemListener
414
   */
415
  protected ItemListener createItemListener()
416
  {
417
    return new ItemHandler();
418
  }
419
 
420
  /**
421
   * Creates a {@link PropertyChangeListener} to listen to the changes in
422
   * the JComboBox's bound properties.
423
   *
424
   * @return The PropertyChangeListener
425
   */
426
  protected PropertyChangeListener createPropertyChangeListener()
427
  {
428
    return new PropertyChangeHandler();
429
  }
430
 
431
  /**
432
   * Creates and returns a layout manager for the combo box.  Subclasses can
433
   * override this method to provide a different layout.
434
   *
435
   * @return a layout manager for the combo box.
436
   */
437
  protected LayoutManager createLayoutManager()
438
  {
439
    return new ComboBoxLayoutManager();
440
  }
441
 
442
  /**
443
   * Creates a component that will be responsible for rendering the
444
   * selected component in the combo box.
445
   *
446
   * @return A renderer for the combo box.
447
   */
448
  protected ListCellRenderer createRenderer()
449
  {
450
    return new BasicComboBoxRenderer.UIResource();
451
  }
452
 
453
  /**
454
   * Creates the component that will be responsible for displaying/editing
455
   * the selected item in the combo box. This editor is used only when combo
456
   * box is editable.
457
   *
458
   * @return A new component that will be responsible for displaying/editing
459
   *         the selected item in the combo box.
460
   */
461
  protected ComboBoxEditor createEditor()
462
  {
463
    return new BasicComboBoxEditor.UIResource();
464
  }
465
 
466
  /**
467
   * Installs the components for this JComboBox. ArrowButton, main
468
   * part of combo box (upper part) and popup list of items are created and
469
   * configured here.
470
   */
471
  protected void installComponents()
472
  {
473
    // create and install arrow button
474
    arrowButton = createArrowButton();
475
    comboBox.add(arrowButton);
476
    if (arrowButton != null)
477
      configureArrowButton();
478
 
479
    if (comboBox.isEditable())
480
      addEditor();
481
 
482
    comboBox.add(currentValuePane);
483
  }
484
 
485
  /**
486
   * Uninstalls components from this {@link JComboBox}.
487
   *
488
   * @see #installComponents()
489
   */
490
  protected void uninstallComponents()
491
  {
492
    // Unconfigure arrow button.
493
    if (arrowButton != null)
494
      {
495
        unconfigureArrowButton();
496
      }
497
 
498
    // Unconfigure editor.
499
    if (editor != null)
500
      {
501
        unconfigureEditor();
502
      }
503
 
504
    comboBox.removeAll();
505
    arrowButton = null;
506
  }
507
 
508
  /**
509
   * Adds the current editor to the combo box.
510
   */
511
  public void addEditor()
512
  {
513
    removeEditor();
514
    editor = comboBox.getEditor().getEditorComponent();
515
    if (editor != null)
516
      {
517
        configureEditor();
518
        comboBox.add(editor);
519
      }
520
  }
521
 
522
  /**
523
   * Removes the current editor from the combo box.
524
   */
525
  public void removeEditor()
526
  {
527
    if (editor != null)
528
      {
529
        unconfigureEditor();
530
        comboBox.remove(editor);
531
      }
532
  }
533
 
534
  /**
535
   * Configures the editor for this combo box.
536
   */
537
  protected void configureEditor()
538
  {
539
    editor.setFont(comboBox.getFont());
540
    if (popupKeyListener != null)
541
      editor.addKeyListener(popupKeyListener);
542
    if (keyListener != null)
543
      editor.addKeyListener(keyListener);
544
    comboBox.configureEditor(comboBox.getEditor(),
545
                             comboBox.getSelectedItem());
546
  }
547
 
548
  /**
549
   * Unconfigures the editor for this combo box.
550
   */
551
  protected void unconfigureEditor()
552
  {
553
    if (popupKeyListener != null)
554
      editor.removeKeyListener(popupKeyListener);
555
    if (keyListener != null)
556
      editor.removeKeyListener(keyListener);
557
  }
558
 
559
  /**
560
   * Configures the arrow button.
561
   *
562
   * @see #configureArrowButton()
563
   */
564
  public void configureArrowButton()
565
  {
566
    if (arrowButton != null)
567
      {
568
        arrowButton.setEnabled(comboBox.isEnabled());
569
        arrowButton.setFocusable(false);
570
        arrowButton.addMouseListener(popup.getMouseListener());
571
        arrowButton.addMouseMotionListener(popup.getMouseMotionListener());
572
 
573
        // Mark the button as not closing the popup, we handle this ourselves.
574
        arrowButton.putClientProperty(BasicLookAndFeel.DONT_CANCEL_POPUP,
575
                                      Boolean.TRUE);
576
      }
577
  }
578
 
579
  /**
580
   * Unconfigures the arrow button.
581
   *
582
   * @see #configureArrowButton()
583
   *
584
   * @specnote The specification says this method is implementation specific
585
   *           and should not be used or overridden.
586
   */
587
  public void unconfigureArrowButton()
588
  {
589
    if (arrowButton != null)
590
      {
591
        if (popupMouseListener != null)
592
          arrowButton.removeMouseListener(popupMouseListener);
593
        if (popupMouseMotionListener != null)
594
          arrowButton.removeMouseMotionListener(popupMouseMotionListener);
595
      }
596
  }
597
 
598
  /**
599
   * Creates an arrow button for this {@link JComboBox}.  The arrow button is
600
   * displayed at the right end of the combo box and is used to display/hide
601
   * the drop down list of items.
602
   *
603
   * @return A new button.
604
   */
605
  protected JButton createArrowButton()
606
  {
607
    return new BasicArrowButton(BasicArrowButton.SOUTH);
608
  }
609
 
610
  /**
611
   * Returns <code>true</code> if the popup is visible, and <code>false</code>
612
   * otherwise.
613
   *
614
   * @param c The JComboBox to check
615
   *
616
   * @return <code>true</code> if popup part of the JComboBox is visible and
617
   *         <code>false</code> otherwise.
618
   */
619
  public boolean isPopupVisible(JComboBox c)
620
  {
621
    return popup.isVisible();
622
  }
623
 
624
  /**
625
   * Displays/hides the {@link JComboBox}'s list of items on the screen.
626
   *
627
   * @param c The combo box, for which list of items should be
628
   *        displayed/hidden
629
   * @param v true if show popup part of the jcomboBox and false to hide.
630
   */
631
  public void setPopupVisible(JComboBox c, boolean v)
632
  {
633
    if (v)
634
      popup.show();
635
    else
636
      popup.hide();
637
  }
638
 
639
  /**
640
   * JComboBox is focus traversable if it is editable and not otherwise.
641
   *
642
   * @param c combo box for which to check whether it is focus traversable
643
   *
644
   * @return true if focus tranversable and false otherwise
645
   */
646
  public boolean isFocusTraversable(JComboBox c)
647
  {
648
    if (!comboBox.isEditable())
649
      return true;
650
 
651
    return false;
652
  }
653
 
654
  /**
655
   * Paints given menu item using specified graphics context
656
   *
657
   * @param g The graphics context used to paint this combo box
658
   * @param c comboBox which needs to be painted.
659
   */
660
  public void paint(Graphics g, JComponent c)
661
  {
662
    hasFocus = comboBox.hasFocus();
663
    if (! comboBox.isEditable())
664
      {
665
        Rectangle rect = rectangleForCurrentValue();
666
        paintCurrentValueBackground(g, rect, hasFocus);
667
        paintCurrentValue(g, rect, hasFocus);
668
      }
669
  }
670
 
671
  /**
672
   * Returns preferred size for the combo box.
673
   *
674
   * @param c comboBox for which to get preferred size
675
   *
676
   * @return The preferred size for the given combo box
677
   */
678
  public Dimension getPreferredSize(JComponent c)
679
  {
680
    return getMinimumSize(c);
681
  }
682
 
683
  /**
684
   * Returns the minimum size for this {@link JComboBox} for this
685
   * look and feel. Also makes sure cachedMinimimSize is setup correctly.
686
   *
687
   * @param c The {@link JComponent} to find the minimum size for.
688
   *
689
   * @return The dimensions of the minimum size.
690
   */
691
  public Dimension getMinimumSize(JComponent c)
692
  {
693
    if (isMinimumSizeDirty)
694
      {
695
        Insets i = getInsets();
696
        Dimension d = getDisplaySize();
697
        d.width += i.left + i.right + d.height;
698
        cachedMinimumSize = new Dimension(d.width, d.height + i.top + i.bottom);
699
        isMinimumSizeDirty = false;
700
      }
701
    return new Dimension(cachedMinimumSize);
702
  }
703
 
704
  /**
705
   * Returns the maximum size for this {@link JComboBox} for this
706
   * look and feel.
707
   *
708
   * @param c The {@link JComponent} to find the maximum size for
709
   *
710
   * @return The maximum size (<code>Dimension(32767, 32767)</code>).
711
   */
712
  public Dimension getMaximumSize(JComponent c)
713
  {
714
    return new Dimension(32767, 32767);
715
  }
716
 
717
  /**
718
   * Returns the number of accessible children of the combobox.
719
   *
720
   * @param c the component (combobox) to check, ignored
721
   *
722
   * @return the number of accessible children of the combobox
723
   */
724
  public int getAccessibleChildrenCount(JComponent c)
725
  {
726
    int count = 1;
727
    if (comboBox.isEditable())
728
      count = 2;
729
    return count;
730
  }
731
 
732
  /**
733
   * Returns the accessible child with the specified index.
734
   *
735
   * @param c the component, this is ignored
736
   * @param i the index of the accessible child to return
737
   */
738
  public Accessible getAccessibleChild(JComponent c, int i)
739
  {
740
    Accessible child = null;
741
    switch (i)
742
    {
743
      case 0: // The popup.
744
        if (popup instanceof Accessible)
745
          {
746
            AccessibleContext ctx = ((Accessible) popup).getAccessibleContext();
747
            ctx.setAccessibleParent(comboBox);
748
            child = (Accessible) popup;
749
          }
750
        break;
751
      case 1: // The editor, if any.
752
        if (comboBox.isEditable() && editor instanceof Accessible)
753
          {
754
            AccessibleContext ctx =
755
              ((Accessible) editor).getAccessibleContext();
756
            ctx.setAccessibleParent(comboBox);
757
            child = (Accessible) editor;
758
          }
759
        break;
760
    }
761
    return child;
762
  }
763
 
764
  /**
765
   * Returns true if the specified key is a navigation key and false otherwise
766
   *
767
   * @param keyCode a key for which to check whether it is navigation key or
768
   *        not.
769
   *
770
   * @return true if the specified key is a navigation key and false otherwis
771
   */
772
  protected boolean isNavigationKey(int keyCode)
773
  {
774
    return keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_DOWN
775
           || keyCode == KeyEvent.VK_LEFT || keyCode == KeyEvent.VK_RIGHT
776
           || keyCode == KeyEvent.VK_ENTER || keyCode == KeyEvent.VK_ESCAPE
777
           || keyCode == KeyEvent.VK_TAB;
778
  }
779
 
780
  /**
781
   * Selects next possible item relative to the current selection
782
   * to be next selected item in the combo box.
783
   */
784
  protected void selectNextPossibleValue()
785
  {
786
    int index = comboBox.getSelectedIndex();
787
    if (index != comboBox.getItemCount() - 1)
788
      comboBox.setSelectedIndex(index + 1);
789
  }
790
 
791
  /**
792
   * Selects previous item relative to current selection to be
793
   * next selected item.
794
   */
795
  protected void selectPreviousPossibleValue()
796
  {
797
    int index = comboBox.getSelectedIndex();
798
    if (index > 0)
799
      comboBox.setSelectedIndex(index - 1);
800
  }
801
 
802
  /**
803
   * Displays combo box popup if the popup is not currently shown
804
   * on the screen and hides it if it is currently shown
805
   */
806
  protected void toggleOpenClose()
807
  {
808
    setPopupVisible(comboBox, ! isPopupVisible(comboBox));
809
  }
810
 
811
  /**
812
   * Returns the bounds in which comboBox's selected item will be
813
   * displayed.
814
   *
815
   * @return rectangle bounds in which comboBox's selected Item will be
816
   *         displayed
817
   */
818
  protected Rectangle rectangleForCurrentValue()
819
  {
820
    int w = comboBox.getWidth();
821
    int h = comboBox.getHeight();
822
    Insets i = comboBox.getInsets();
823
    int arrowSize = h - (i.top + i.bottom);
824
    if (arrowButton != null)
825
      arrowSize = arrowButton.getWidth();
826
    return new Rectangle(i.left, i.top, w - (i.left + i.right + arrowSize),
827
                         h - (i.top + i.left));
828
  }
829
 
830
  /**
831
   * Returns the insets of the current border.
832
   *
833
   * @return Insets representing space between combo box and its border
834
   */
835
  protected Insets getInsets()
836
  {
837
    return comboBox.getInsets();
838
  }
839
 
840
  /**
841
   * Paints currently selected value in the main part of the combo
842
   * box (part without popup).
843
   *
844
   * @param g graphics context
845
   * @param bounds Rectangle representing the size of the area in which
846
   *        selected item should be drawn
847
   * @param hasFocus true if combo box has focus and false otherwise
848
   */
849
  public void paintCurrentValue(Graphics g, Rectangle bounds, boolean hasFocus)
850
  {
851
    /* Gets the component to be drawn for the current value.
852
     * If there is currently no selected item we will take an empty
853
     * String as replacement.
854
     */
855
    ListCellRenderer renderer = comboBox.getRenderer();
856
    if (comboBox.getSelectedIndex() != -1)
857
      {
858
        Component comp;
859
        if (hasFocus && ! isPopupVisible(comboBox))
860
          {
861
            comp = renderer.getListCellRendererComponent(listBox,
862
                comboBox.getSelectedItem(), -1, true, false);
863
          }
864
        else
865
          {
866
            comp = renderer.getListCellRendererComponent(listBox,
867
                comboBox.getSelectedItem(), -1, false, false);
868
            Color bg = UIManager.getColor("ComboBox.disabledForeground");
869
            comp.setBackground(bg);
870
          }
871
        comp.setFont(comboBox.getFont());
872
        if (hasFocus && ! isPopupVisible(comboBox))
873
          {
874
            comp.setForeground(listBox.getSelectionForeground());
875
            comp.setBackground(listBox.getSelectionBackground());
876
          }
877
        else if (comboBox.isEnabled())
878
          {
879
            comp.setForeground(comboBox.getForeground());
880
            comp.setBackground(comboBox.getBackground());
881
          }
882
        else
883
          {
884
            Color fg = UIManager.getColor("ComboBox.disabledForeground");
885
            comp.setForeground(fg);
886
            Color bg = UIManager.getColor("ComboBox.disabledBackground");
887
            comp.setBackground(bg);
888
          }
889
        currentValuePane.paintComponent(g, comp, comboBox, bounds.x, bounds.y,
890
                                        bounds.width, bounds.height);
891
      }
892
  }
893
 
894
  /**
895
   * Paints the background of part of the combo box, where currently
896
   * selected value is displayed. If the combo box has focus this method
897
   * should also paint focus rectangle around the combo box.
898
   *
899
   * @param g graphics context
900
   * @param bounds Rectangle representing the size of the largest item  in the
901
   *        comboBox
902
   * @param hasFocus true if combo box has fox and false otherwise
903
   */
904
  public void paintCurrentValueBackground(Graphics g, Rectangle bounds,
905
                                          boolean hasFocus)
906
  {
907
    Color saved = g.getColor();
908
    if (comboBox.isEnabled())
909
      g.setColor(UIManager.getColor("UIManager.background"));
910
    else
911
      g.setColor(UIManager.getColor("UIManager.disabledBackground"));
912
    g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
913
    g.setColor(saved);
914
  }
915
 
916
  private static final ListCellRenderer DEFAULT_RENDERER
917
    = new DefaultListCellRenderer();
918
 
919
  /**
920
   * Returns the default size for the display area of a combo box that does
921
   * not contain any elements.  This method returns the width and height of
922
   * a single space in the current font, plus a margin of 1 pixel.
923
   *
924
   * @return The default display size.
925
   *
926
   * @see #getDisplaySize()
927
   */
928
  protected Dimension getDefaultSize()
929
  {
930
    Component comp = DEFAULT_RENDERER.getListCellRendererComponent(listBox,
931
        " ", -1, false, false);
932
    currentValuePane.add(comp);
933
    comp.setFont(comboBox.getFont());
934
    Dimension d = comp.getPreferredSize();
935
    currentValuePane.remove(comp);
936
    return d;
937
  }
938
 
939
  /**
940
   * Returns the size of the display area for the combo box. This size will be
941
   * the size of the combo box, not including the arrowButton.
942
   *
943
   * @return The size of the display area for the combo box.
944
   */
945
  protected Dimension getDisplaySize()
946
  {
947
    Dimension dim = new Dimension();
948
    ListCellRenderer renderer = comboBox.getRenderer();
949
    if (renderer == null)
950
      {
951
        renderer = DEFAULT_RENDERER;
952
      }
953
 
954
    Object prototype = comboBox.getPrototypeDisplayValue();
955
    if (prototype != null)
956
      {
957
        Component comp = renderer.getListCellRendererComponent(listBox,
958
            prototype, -1, false, false);
959
        currentValuePane.add(comp);
960
        comp.setFont(comboBox.getFont());
961
        Dimension renderSize = comp.getPreferredSize();
962
        currentValuePane.remove(comp);
963
        dim.height = renderSize.height;
964
        dim.width = renderSize.width;
965
      }
966
    else
967
      {
968
        ComboBoxModel model = comboBox.getModel();
969
        int size = model.getSize();
970
        if (size > 0)
971
          {
972
            for (int i = 0; i < size; ++i)
973
              {
974
                Component comp = renderer.getListCellRendererComponent(listBox,
975
                    model.getElementAt(i), -1, false, false);
976
                currentValuePane.add(comp);
977
                comp.setFont(comboBox.getFont());
978
                Dimension renderSize = comp.getPreferredSize();
979
                currentValuePane.remove(comp);
980
                dim.width = Math.max(dim.width, renderSize.width);
981
                dim.height = Math.max(dim.height, renderSize.height);
982
              }
983
          }
984
        else
985
          {
986
            dim = getDefaultSize();
987
            if (comboBox.isEditable())
988
              dim.width = 100;
989
          }
990
      }
991
    if (comboBox.isEditable())
992
      {
993
        Dimension editSize = editor.getPreferredSize();
994
        dim.width = Math.max(dim.width, editSize.width);
995
        dim.height = Math.max(dim.height, editSize.height);
996
      }
997
    displaySize.setSize(dim.width, dim.height);
998
    return dim;
999
  }
1000
 
1001
  /**
1002
   * Installs the keyboard actions for the {@link JComboBox} as specified
1003
   * by the look and feel.
1004
   */
1005
  protected void installKeyboardActions()
1006
  {
1007
    SwingUtilities.replaceUIInputMap(comboBox,
1008
        JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
1009
        (InputMap) UIManager.get("ComboBox.ancestorInputMap"));
1010
    // Install any action maps here.
1011
  }
1012
 
1013
  /**
1014
   * Uninstalls the keyboard actions for the {@link JComboBox} there were
1015
   * installed by in {@link #installListeners}.
1016
   */
1017
  protected void uninstallKeyboardActions()
1018
  {
1019
    SwingUtilities.replaceUIInputMap(comboBox,
1020
        JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
1021
    // Uninstall any action maps here.
1022
  }
1023
 
1024
  /**
1025
   * A {@link LayoutManager} used to position the sub-components of the
1026
   * {@link JComboBox}.
1027
   *
1028
   * @see BasicComboBoxUI#createLayoutManager()
1029
   */
1030
  public class ComboBoxLayoutManager implements LayoutManager
1031
  {
1032
    /**
1033
     * Creates a new ComboBoxLayoutManager object.
1034
     */
1035
    public ComboBoxLayoutManager()
1036
    {
1037
      // Nothing to do here.
1038
    }
1039
 
1040
    /**
1041
     * Adds a component to the layout.  This method does nothing, since the
1042
     * layout manager doesn't need to track the components.
1043
     *
1044
     * @param name  the name to associate the component with (ignored).
1045
     * @param comp  the component (ignored).
1046
     */
1047
    public void addLayoutComponent(String name, Component comp)
1048
    {
1049
      // Do nothing
1050
    }
1051
 
1052
    /**
1053
     * Removes a component from the layout.  This method does nothing, since
1054
     * the layout manager doesn't need to track the components.
1055
     *
1056
     * @param comp  the component.
1057
     */
1058
    public void removeLayoutComponent(Component comp)
1059
    {
1060
      // Do nothing
1061
    }
1062
 
1063
    /**
1064
     * Returns preferred layout size of the JComboBox.
1065
     *
1066
     * @param parent  the Container for which the preferred size should be
1067
     *                calculated.
1068
     *
1069
     * @return The preferred size for the given container
1070
     */
1071
    public Dimension preferredLayoutSize(Container parent)
1072
    {
1073
      return parent.getPreferredSize();
1074
    }
1075
 
1076
    /**
1077
     * Returns the minimum layout size.
1078
     *
1079
     * @param parent  the container.
1080
     *
1081
     * @return The minimum size.
1082
     */
1083
    public Dimension minimumLayoutSize(Container parent)
1084
    {
1085
      return parent.getMinimumSize();
1086
    }
1087
 
1088
    /**
1089
     * Arranges the components in the container.  It puts arrow
1090
     * button right end part of the comboBox. If the comboBox is editable
1091
     * then editor is placed to the left of arrow  button, starting from the
1092
     * beginning.
1093
     *
1094
     * @param parent Container that should be layed out.
1095
     */
1096
    public void layoutContainer(Container parent)
1097
    {
1098
      // Position editor component to the left of arrow button if combo box is
1099
      // editable
1100
      Insets i = getInsets();
1101
      int arrowSize = comboBox.getHeight() - (i.top + i.bottom);
1102
 
1103
      if (arrowButton != null)
1104
        arrowButton.setBounds(comboBox.getWidth() - (i.right + arrowSize),
1105
                              i.top, arrowSize, arrowSize);
1106
      if (editor != null)
1107
        editor.setBounds(rectangleForCurrentValue());
1108
    }
1109
  }
1110
 
1111
  /**
1112
   * Handles focus changes occuring in the combo box. This class is
1113
   * responsible for repainting combo box whenever focus is gained or lost
1114
   * and also for hiding popup list of items whenever combo box loses its
1115
   * focus.
1116
   */
1117
  public class FocusHandler extends Object implements FocusListener
1118
  {
1119
    /**
1120
     * Creates a new FocusHandler object.
1121
     */
1122
    public FocusHandler()
1123
    {
1124
      // Nothing to do here.
1125
    }
1126
 
1127
    /**
1128
     * Invoked when combo box gains focus. It repaints main
1129
     * part of combo box accordingly.
1130
     *
1131
     * @param e the FocusEvent
1132
     */
1133
    public void focusGained(FocusEvent e)
1134
    {
1135
      hasFocus = true;
1136
      comboBox.repaint();
1137
    }
1138
 
1139
    /**
1140
     * Invoked when the combo box loses focus.  It repaints the main part
1141
     * of the combo box accordingly and hides the popup list of items.
1142
     *
1143
     * @param e the FocusEvent
1144
     */
1145
    public void focusLost(FocusEvent e)
1146
    {
1147
      hasFocus = false;
1148
      if (! e.isTemporary() && comboBox.isLightWeightPopupEnabled())
1149
        setPopupVisible(comboBox, false);
1150
      comboBox.repaint();
1151
    }
1152
  }
1153
 
1154
  /**
1155
   * Handles {@link ItemEvent}s fired by the {@link JComboBox} when its
1156
   * selected item changes.
1157
   */
1158
  public class ItemHandler extends Object implements ItemListener
1159
  {
1160
    /**
1161
     * Creates a new ItemHandler object.
1162
     */
1163
    public ItemHandler()
1164
    {
1165
      // Nothing to do here.
1166
    }
1167
 
1168
    /**
1169
     * Invoked when selected item becomes deselected or when
1170
     * new item becomes selected.
1171
     *
1172
     * @param e the ItemEvent representing item's state change.
1173
     */
1174
    public void itemStateChanged(ItemEvent e)
1175
    {
1176
      ComboBoxModel model = comboBox.getModel();
1177
      Object v = model.getSelectedItem();
1178
      if (editor != null)
1179
        comboBox.configureEditor(comboBox.getEditor(), v);
1180
      comboBox.repaint();
1181
    }
1182
  }
1183
 
1184
  /**
1185
   * KeyHandler handles key events occuring while JComboBox has focus.
1186
   */
1187
  public class KeyHandler extends KeyAdapter
1188
  {
1189
    public KeyHandler()
1190
    {
1191
      // Nothing to do here.
1192
    }
1193
 
1194
    /**
1195
     * Invoked whenever key is pressed while JComboBox is in focus.
1196
     */
1197
    public void keyPressed(KeyEvent e)
1198
    {
1199
      if (comboBox.getModel().getSize() != 0 && comboBox.isEnabled())
1200
        {
1201
          if (! isNavigationKey(e.getKeyCode()))
1202
            {
1203
              if (! comboBox.isEditable())
1204
                if (comboBox.selectWithKeyChar(e.getKeyChar()))
1205
                  e.consume();
1206
            }
1207
          else
1208
            {
1209
              if (e.getKeyCode() == KeyEvent.VK_UP && comboBox.isPopupVisible())
1210
                selectPreviousPossibleValue();
1211
              else if (e.getKeyCode() == KeyEvent.VK_DOWN)
1212
                {
1213
                  if (comboBox.isPopupVisible())
1214
                    selectNextPossibleValue();
1215
                  else
1216
                    comboBox.showPopup();
1217
                }
1218
              else if (e.getKeyCode() == KeyEvent.VK_ENTER
1219
                       || e.getKeyCode() == KeyEvent.VK_ESCAPE)
1220
                popup.hide();
1221
            }
1222
        }
1223
    }
1224
  }
1225
 
1226
  /**
1227
   * Handles the changes occurring in the JComboBox's data model.
1228
   */
1229
  public class ListDataHandler extends Object implements ListDataListener
1230
  {
1231
    /**
1232
     * Creates a new ListDataHandler object.
1233
     */
1234
    public ListDataHandler()
1235
    {
1236
      // Nothing to do here.
1237
    }
1238
 
1239
    /**
1240
     * Invoked if the content's of JComboBox's data model are changed.
1241
     *
1242
     * @param e ListDataEvent describing the change.
1243
     */
1244
    public void contentsChanged(ListDataEvent e)
1245
    {
1246
      if (e.getIndex0() != -1 || e.getIndex1() != -1)
1247
        {
1248
          isMinimumSizeDirty = true;
1249
          comboBox.revalidate();
1250
        }
1251
      if (editor != null)
1252
        comboBox.configureEditor(comboBox.getEditor(),
1253
            comboBox.getSelectedItem());
1254
      comboBox.repaint();
1255
    }
1256
 
1257
    /**
1258
     * Invoked when items are added to the JComboBox's data model.
1259
     *
1260
     * @param e ListDataEvent describing the change.
1261
     */
1262
    public void intervalAdded(ListDataEvent e)
1263
    {
1264
      int start = e.getIndex0();
1265
      int end = e.getIndex1();
1266
      if (start == 0 && comboBox.getItemCount() - (end - start + 1) == 0)
1267
        contentsChanged(e);
1268
      else if (start != -1  || end != -1)
1269
        {
1270
          ListCellRenderer renderer = comboBox.getRenderer();
1271
          ComboBoxModel model = comboBox.getModel();
1272
          int w = displaySize.width;
1273
          int h = displaySize.height;
1274
          // TODO: Optimize using prototype here.
1275
          for (int i = start; i <= end; ++i)
1276
            {
1277
              Component comp = renderer.getListCellRendererComponent(listBox,
1278
                  model.getElementAt(i), -1, false, false);
1279
              currentValuePane.add(comp);
1280
              comp.setFont(comboBox.getFont());
1281
              Dimension dim = comp.getPreferredSize();
1282
              w = Math.max(w, dim.width);
1283
              h = Math.max(h, dim.height);
1284
              currentValuePane.remove(comp);
1285
            }
1286
          if (displaySize.width < w || displaySize.height < h)
1287
            {
1288
              if (displaySize.width < w)
1289
                displaySize.width = w;
1290
              if (displaySize.height < h)
1291
                displaySize.height = h;
1292
              comboBox.revalidate();
1293
              if (editor != null)
1294
                {
1295
                  comboBox.configureEditor(comboBox.getEditor(),
1296
                                           comboBox.getSelectedItem());
1297
                }
1298
            }
1299
        }
1300
 
1301
    }
1302
 
1303
    /**
1304
     * Invoked when items are removed from the JComboBox's
1305
     * data model.
1306
     *
1307
     * @param e ListDataEvent describing the change.
1308
     */
1309
    public void intervalRemoved(ListDataEvent e)
1310
    {
1311
      contentsChanged(e);
1312
    }
1313
  }
1314
 
1315
  /**
1316
   * Handles {@link PropertyChangeEvent}s fired by the {@link JComboBox}.
1317
   */
1318
  public class PropertyChangeHandler extends Object
1319
    implements PropertyChangeListener
1320
  {
1321
    /**
1322
     * Creates a new instance.
1323
     */
1324
    public PropertyChangeHandler()
1325
    {
1326
      // Nothing to do here.
1327
    }
1328
 
1329
    /**
1330
     * Invoked whenever bound property of JComboBox changes.
1331
     *
1332
     * @param e  the event.
1333
     */
1334
    public void propertyChange(PropertyChangeEvent e)
1335
    {
1336
      // Lets assume every change invalidates the minimumsize.
1337
      String propName = e.getPropertyName();
1338
      if (propName.equals("enabled"))
1339
        {
1340
          boolean enabled = comboBox.isEnabled();
1341
          if (editor != null)
1342
            editor.setEnabled(enabled);
1343
          if (arrowButton != null)
1344
            arrowButton.setEnabled(enabled);
1345
 
1346
          comboBox.repaint();
1347
        }
1348
      else if (propName.equals("editor") && comboBox.isEditable())
1349
        {
1350
          addEditor();
1351
          comboBox.revalidate();
1352
        }
1353
      else if (e.getPropertyName().equals("editable"))
1354
        {
1355
          if (comboBox.isEditable())
1356
            {
1357
              addEditor();
1358
            }
1359
          else
1360
            {
1361
              removeEditor();
1362
            }
1363
 
1364
          comboBox.revalidate();
1365
        }
1366
      else if (propName.equals("model"))
1367
        {
1368
          // remove ListDataListener from old model and add it to new model
1369
          ComboBoxModel oldModel = (ComboBoxModel) e.getOldValue();
1370
          if (oldModel != null && listDataListener != null)
1371
            oldModel.removeListDataListener(listDataListener);
1372
 
1373
          ComboBoxModel newModel = (ComboBoxModel) e.getNewValue();
1374
          if (newModel != null && listDataListener != null)
1375
            comboBox.getModel().addListDataListener(listDataListener);
1376
 
1377
          if (editor != null)
1378
            {
1379
              comboBox.configureEditor(comboBox.getEditor(),
1380
                                       comboBox.getSelectedItem());
1381
            }
1382
          isMinimumSizeDirty = true;
1383
          comboBox.revalidate();
1384
          comboBox.repaint();
1385
        }
1386
      else if (propName.equals("font"))
1387
        {
1388
          Font font = (Font) e.getNewValue();
1389
          if (editor != null)
1390
            {
1391
              editor.setFont(font);
1392
            }
1393
          listBox.setFont(font);
1394
          isMinimumSizeDirty = true;
1395
          comboBox.revalidate();
1396
        }
1397
      else if (propName.equals("prototypeDisplayValue"))
1398
        {
1399
          isMinimumSizeDirty = true;
1400
          comboBox.revalidate();
1401
        }
1402
      else if (propName.equals("renderer"))
1403
        {
1404
          isMinimumSizeDirty = true;
1405
          comboBox.revalidate();
1406
        }
1407
      // FIXME: Need to handle changes in other bound properties.
1408
    }
1409
  }
1410
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.