1:
37:
38:
39: package ;
40:
41: import ;
42:
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53: import ;
54: import ;
55: import ;
56: import ;
57: import ;
58: import ;
59: import ;
60: import ;
61: import ;
62: import ;
63:
64: import ;
65: import ;
66: import ;
67: import ;
68: import ;
69: import ;
70: import ;
71: import ;
72: import ;
73: import ;
74: import ;
75: import ;
76: import ;
77: import ;
78: import ;
79: import ;
80: import ;
81: import ;
82: import ;
83:
84:
90: public class BasicComboBoxUI extends ComboBoxUI
91: {
92:
96: protected JButton arrowButton;
97:
98:
101: protected JComboBox comboBox;
102:
103:
109: protected Component editor;
110:
111:
114: protected FocusListener focusListener;
115:
116:
119: protected boolean hasFocus;
120:
121:
124: protected ItemListener itemListener;
125:
126:
130: protected KeyListener keyListener;
131:
132:
137: protected JList listBox;
138:
139:
142: protected ListDataListener listDataListener;
143:
144:
147: protected ComboPopup popup;
148:
149: protected KeyListener popupKeyListener;
150:
151: protected MouseListener popupMouseListener;
152:
153: protected MouseMotionListener popupMouseMotionListener;
154:
155:
158: protected PropertyChangeListener propertyChangeListener;
159:
160:
163: Dimension displaySize = new Dimension();
164:
165:
168: protected CellRendererPane currentValuePane;
169:
170:
174: protected Dimension cachedMinimumSize;
175:
176:
179: protected boolean isMinimumSizeDirty = true;
180:
181:
184: public BasicComboBoxUI()
185: {
186: currentValuePane = new CellRendererPane();
187: cachedMinimumSize = new Dimension();
188: }
189:
190:
198: public static ComponentUI createUI(JComponent c)
199: {
200: return new BasicComboBoxUI();
201: }
202:
203:
210: public void installUI(JComponent c)
211: {
212: super.installUI(c);
213:
214: if (c instanceof JComboBox)
215: {
216: isMinimumSizeDirty = true;
217: comboBox = (JComboBox) c;
218: installDefaults();
219:
220:
221:
222:
223: ListCellRenderer renderer = comboBox.getRenderer();
224: if (renderer == null || renderer instanceof UIResource)
225: comboBox.setRenderer(createRenderer());
226:
227: ComboBoxEditor currentEditor = comboBox.getEditor();
228: if (currentEditor == null || currentEditor instanceof UIResource)
229: {
230: currentEditor = createEditor();
231: comboBox.setEditor(currentEditor);
232: }
233: editor = currentEditor.getEditorComponent();
234:
235: installComponents();
236: installListeners();
237: if (arrowButton != null)
238: configureArrowButton();
239: if (editor != null)
240: configureEditor();
241: comboBox.setLayout(createLayoutManager());
242: comboBox.setFocusable(true);
243: installKeyboardActions();
244: }
245: }
246:
247:
254: public void uninstallUI(JComponent c)
255: {
256: setPopupVisible(comboBox, false);
257: popup.uninstallingUI();
258: uninstallKeyboardActions();
259: comboBox.setLayout(null);
260: uninstallComponents();
261: uninstallListeners();
262: uninstallDefaults();
263: comboBox = null;
264: }
265:
266:
272: protected void installDefaults()
273: {
274: LookAndFeel.installColorsAndFont(comboBox, "ComboBox.background",
275: "ComboBox.foreground", "ComboBox.font");
276: LookAndFeel.installBorder(comboBox, "ComboBox.border");
277: }
278:
279:
284: protected void installListeners()
285: {
286:
287: propertyChangeListener = createPropertyChangeListener();
288: comboBox.addPropertyChangeListener(propertyChangeListener);
289:
290: focusListener = createFocusListener();
291: editor.addFocusListener(focusListener);
292:
293: itemListener = createItemListener();
294: comboBox.addItemListener(itemListener);
295:
296: keyListener = createKeyListener();
297: comboBox.addKeyListener(keyListener);
298:
299:
300: listDataListener = createListDataListener();
301: comboBox.getModel().addListDataListener(listDataListener);
302:
303:
304: popupMouseListener = popup.getMouseListener();
305: comboBox.addMouseListener(popupMouseListener);
306:
307: popupMouseMotionListener = popup.getMouseMotionListener();
308: comboBox.addMouseMotionListener(popupMouseMotionListener);
309:
310: popupKeyListener = popup.getKeyListener();
311: comboBox.addKeyListener(popupKeyListener);
312: }
313:
314:
320: protected void uninstallDefaults()
321: {
322: if (comboBox.getFont() instanceof UIResource)
323: comboBox.setFont(null);
324:
325: if (comboBox.getForeground() instanceof UIResource)
326: comboBox.setForeground(null);
327:
328: if (comboBox.getBackground() instanceof UIResource)
329: comboBox.setBackground(null);
330:
331: LookAndFeel.uninstallBorder(comboBox);
332: }
333:
334:
339: protected void uninstallListeners()
340: {
341: comboBox.removePropertyChangeListener(propertyChangeListener);
342: propertyChangeListener = null;
343:
344: comboBox.removeFocusListener(focusListener);
345: listBox.removeFocusListener(focusListener);
346: focusListener = null;
347:
348: comboBox.removeItemListener(itemListener);
349: itemListener = null;
350:
351: comboBox.removeKeyListener(keyListener);
352: keyListener = null;
353:
354: comboBox.getModel().removeListDataListener(listDataListener);
355: listDataListener = null;
356:
357: if (popupMouseListener != null)
358: comboBox.removeMouseListener(popupMouseListener);
359: popupMouseListener = null;
360:
361: if (popupMouseMotionListener != null)
362: comboBox.removeMouseMotionListener(popupMouseMotionListener);
363: popupMouseMotionListener = null;
364:
365: if (popupKeyListener != null)
366: comboBox.removeKeyListener(popupKeyListener);
367: popupKeyListener = null;
368: }
369:
370:
375: protected ComboPopup createPopup()
376: {
377: return new BasicComboPopup(comboBox);
378: }
379:
380:
385: protected KeyListener createKeyListener()
386: {
387: return new KeyHandler();
388: }
389:
390:
396: protected FocusListener createFocusListener()
397: {
398: return new FocusHandler();
399: }
400:
401:
406: protected ListDataListener createListDataListener()
407: {
408: return new ListDataHandler();
409: }
410:
411:
417: protected ItemListener createItemListener()
418: {
419: return new ItemHandler();
420: }
421:
422:
428: protected PropertyChangeListener createPropertyChangeListener()
429: {
430: return new PropertyChangeHandler();
431: }
432:
433:
439: protected LayoutManager createLayoutManager()
440: {
441: return new ComboBoxLayoutManager();
442: }
443:
444:
450: protected ListCellRenderer createRenderer()
451: {
452: return new BasicComboBoxRenderer.UIResource();
453: }
454:
455:
463: protected ComboBoxEditor createEditor()
464: {
465: return new BasicComboBoxEditor.UIResource();
466: }
467:
468:
473: protected void installComponents()
474: {
475:
476: popup = createPopup();
477: listBox = popup.getList();
478:
479:
480: arrowButton = createArrowButton();
481: comboBox.add(arrowButton);
482:
483: if (comboBox.isEditable())
484: addEditor();
485:
486: comboBox.add(currentValuePane);
487: }
488:
489:
494: protected void uninstallComponents()
495: {
496:
497: unconfigureArrowButton();
498: comboBox.remove(arrowButton);
499: arrowButton = null;
500:
501: popup = null;
502:
503: if (comboBox.getRenderer() instanceof UIResource)
504: comboBox.setRenderer(null);
505:
506:
507:
508: ComboBoxEditor currentEditor = comboBox.getEditor();
509: if (currentEditor instanceof UIResource)
510: {
511: comboBox.setEditor(null);
512: editor = null;
513: }
514: }
515:
516:
519: public void addEditor()
520: {
521: removeEditor();
522: editor = comboBox.getEditor().getEditorComponent();
523: comboBox.add(editor);
524: }
525:
526:
529: public void removeEditor()
530: {
531: if (editor != null)
532: {
533: unconfigureEditor();
534: comboBox.remove(editor);
535: }
536: }
537:
538:
541: protected void configureEditor()
542: {
543: editor.setFont(comboBox.getFont());
544: if (popupKeyListener != null)
545: editor.addKeyListener(popupKeyListener);
546: comboBox.configureEditor(comboBox.getEditor(),
547: comboBox.getSelectedItem());
548: }
549:
550:
553: protected void unconfigureEditor()
554: {
555: if (popupKeyListener != null)
556: editor.removeKeyListener(popupKeyListener);
557: }
558:
559:
564: public void configureArrowButton()
565: {
566: if (arrowButton != null)
567: {
568: arrowButton.setEnabled(comboBox.isEnabled());
569: arrowButton.setFocusable(false);
570: if (popupMouseListener != null)
571: arrowButton.addMouseListener(popupMouseListener);
572: if (popupMouseMotionListener != null)
573: arrowButton.addMouseMotionListener(popupMouseMotionListener);
574: }
575: }
576:
577:
585: public void unconfigureArrowButton()
586: {
587: if (arrowButton != null)
588: {
589: if (popupMouseListener != null)
590: arrowButton.removeMouseListener(popupMouseListener);
591: if (popupMouseMotionListener != null)
592: arrowButton.removeMouseMotionListener(popupMouseMotionListener);
593: }
594: }
595:
596:
603: protected JButton createArrowButton()
604: {
605: return new BasicArrowButton(BasicArrowButton.SOUTH);
606: }
607:
608:
617: public boolean isPopupVisible(JComboBox c)
618: {
619: return popup.isVisible();
620: }
621:
622:
629: public void setPopupVisible(JComboBox c, boolean v)
630: {
631: if (v)
632: popup.show();
633: else
634: popup.hide();
635: }
636:
637:
644: public boolean isFocusTraversable(JComboBox c)
645: {
646: if (!comboBox.isEditable())
647: return true;
648:
649: return false;
650: }
651:
652:
658: public void paint(Graphics g, JComponent c)
659: {
660: hasFocus = comboBox.hasFocus();
661: if (! comboBox.isEditable())
662: {
663: Rectangle rect = rectangleForCurrentValue();
664: paintCurrentValueBackground(g, rect, hasFocus);
665: paintCurrentValue(g, rect, hasFocus);
666: }
667: }
668:
669:
676: public Dimension getPreferredSize(JComponent c)
677: {
678: return getMinimumSize(c);
679: }
680:
681:
689: public Dimension getMinimumSize(JComponent c)
690: {
691: if (isMinimumSizeDirty)
692: {
693: Insets i = getInsets();
694: Dimension d = getDisplaySize();
695: d.width += i.left + i.right + d.height;
696: cachedMinimumSize = new Dimension(d.width, d.height + i.top + i.bottom);
697: isMinimumSizeDirty = false;
698: }
699: return new Dimension(cachedMinimumSize);
700: }
701:
702:
710: public Dimension getMaximumSize(JComponent c)
711: {
712: return new Dimension(32767, 32767);
713: }
714:
715: public int getAccessibleChildrenCount(JComponent c)
716: throws NotImplementedException
717: {
718:
719: return 0;
720: }
721:
722: public Accessible getAccessibleChild(JComponent c, int i)
723: throws NotImplementedException
724: {
725:
726: return null;
727: }
728:
729:
737: protected boolean isNavigationKey(int keyCode)
738: throws NotImplementedException
739: {
740:
741: return false;
742: }
743:
744:
748: protected void selectNextPossibleValue()
749: {
750: int index = comboBox.getSelectedIndex();
751: if (index != comboBox.getItemCount() - 1)
752: comboBox.setSelectedIndex(index + 1);
753: }
754:
755:
759: protected void selectPreviousPossibleValue()
760: {
761: int index = comboBox.getSelectedIndex();
762: if (index != 0)
763: comboBox.setSelectedIndex(index - 1);
764: }
765:
766:
770: protected void toggleOpenClose()
771: {
772: setPopupVisible(comboBox, ! isPopupVisible(comboBox));
773: }
774:
775:
782: protected Rectangle rectangleForCurrentValue()
783: {
784: int w = comboBox.getWidth();
785: int h = comboBox.getHeight();
786: Insets i = comboBox.getInsets();
787: int arrowSize = h - (i.top + i.bottom);
788: if (arrowButton != null)
789: arrowSize = arrowButton.getWidth();
790: return new Rectangle(i.left, i.top, w - (i.left + i.right + arrowSize),
791: h - (i.top + i.left));
792: }
793:
794:
799: protected Insets getInsets()
800: {
801: return comboBox.getInsets();
802: }
803:
804:
813: public void paintCurrentValue(Graphics g, Rectangle bounds, boolean hasFocus)
814: {
815: Object currentValue = comboBox.getSelectedItem();
816: boolean isPressed = arrowButton.getModel().isPressed();
817:
818:
822: ListCellRenderer renderer = comboBox.getRenderer();
823: if (comboBox.getSelectedIndex() != -1)
824: {
825: Component comp;
826: if (hasFocus && ! isPopupVisible(comboBox))
827: {
828: comp = renderer.getListCellRendererComponent(listBox,
829: comboBox.getSelectedItem(), -1, true, false);
830: }
831: else
832: {
833: comp = renderer.getListCellRendererComponent(listBox,
834: comboBox.getSelectedItem(), -1, false, false);
835: Color bg = UIManager.getColor("ComboBox.disabledForeground");
836: comp.setBackground(bg);
837: }
838: comp.setFont(comboBox.getFont());
839: if (hasFocus && ! isPopupVisible(comboBox))
840: {
841: comp.setForeground(listBox.getSelectionForeground());
842: comp.setBackground(listBox.getSelectionBackground());
843: }
844: else if (comboBox.isEnabled())
845: {
846: comp.setForeground(comboBox.getForeground());
847: comp.setBackground(comboBox.getBackground());
848: }
849: else
850: {
851: Color fg = UIManager.getColor("ComboBox.disabledForeground");
852: comp.setForeground(fg);
853: Color bg = UIManager.getColor("ComboBox.disabledBackground");
854: comp.setBackground(bg);
855: }
856: currentValuePane.paintComponent(g, comp, comboBox, bounds.x, bounds.y,
857: bounds.width, bounds.height);
858: }
859: }
860:
861:
871: public void paintCurrentValueBackground(Graphics g, Rectangle bounds,
872: boolean hasFocus)
873: {
874: Color saved = g.getColor();
875: if (comboBox.isEnabled())
876: g.setColor(UIManager.getColor("UIManager.background"));
877: else
878: g.setColor(UIManager.getColor("UIManager.disabledBackground"));
879: g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
880: g.setColor(saved);
881: }
882:
883: private static final ListCellRenderer DEFAULT_RENDERER
884: = new DefaultListCellRenderer();
885:
886:
895: protected Dimension getDefaultSize()
896: {
897: Component comp = DEFAULT_RENDERER.getListCellRendererComponent(listBox,
898: " ", -1, false, false);
899: currentValuePane.add(comp);
900: comp.setFont(comboBox.getFont());
901: Dimension d = comp.getPreferredSize();
902: currentValuePane.remove(comp);
903: return d;
904: }
905:
906:
912: protected Dimension getDisplaySize()
913: {
914: Dimension dim = new Dimension();
915: ListCellRenderer renderer = comboBox.getRenderer();
916: if (renderer == null)
917: {
918: renderer = DEFAULT_RENDERER;
919: }
920:
921: Object prototype = comboBox.getPrototypeDisplayValue();
922: if (prototype != null)
923: {
924: Component comp = renderer.getListCellRendererComponent(listBox,
925: prototype, -1, false, false);
926: currentValuePane.add(comp);
927: comp.setFont(comboBox.getFont());
928: Dimension renderSize = comp.getPreferredSize();
929: currentValuePane.remove(comp);
930: dim.height = renderSize.height;
931: dim.width = renderSize.width;
932: }
933: else
934: {
935: ComboBoxModel model = comboBox.getModel();
936: int size = model.getSize();
937: if (size > 0)
938: {
939: for (int i = 0; i < size; ++i)
940: {
941: Component comp = renderer.getListCellRendererComponent(listBox,
942: model.getElementAt(i), -1, false, false);
943: currentValuePane.add(comp);
944: comp.setFont(comboBox.getFont());
945: Dimension renderSize = comp.getPreferredSize();
946: currentValuePane.remove(comp);
947: dim.width = Math.max(dim.width, renderSize.width);
948: dim.height = Math.max(dim.height, renderSize.height);
949: }
950: }
951: else
952: {
953: dim = getDefaultSize();
954: if (comboBox.isEditable())
955: dim.width = 100;
956: }
957: }
958: if (comboBox.isEditable())
959: {
960: Dimension editSize = editor.getPreferredSize();
961: dim.width = Math.max(dim.width, editSize.width);
962: dim.height = Math.max(dim.height, editSize.height);
963: }
964: displaySize.setSize(dim.width, dim.height);
965: return dim;
966: }
967:
968:
972: protected void installKeyboardActions()
973: {
974: SwingUtilities.replaceUIInputMap(comboBox,
975: JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
976: (InputMap) UIManager.get("ComboBox.ancestorInputMap"));
977:
978: }
979:
980:
984: protected void uninstallKeyboardActions()
985: {
986: SwingUtilities.replaceUIInputMap(comboBox,
987: JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
988:
989: }
990:
991:
997: public class ComboBoxLayoutManager implements LayoutManager
998: {
999:
1002: public ComboBoxLayoutManager()
1003: {
1004:
1005: }
1006:
1007:
1014: public void addLayoutComponent(String name, Component comp)
1015: {
1016:
1017: }
1018:
1019:
1025: public void removeLayoutComponent(Component comp)
1026: {
1027:
1028: }
1029:
1030:
1038: public Dimension preferredLayoutSize(Container parent)
1039: {
1040: return parent.getPreferredSize();
1041: }
1042:
1043:
1050: public Dimension minimumLayoutSize(Container parent)
1051: {
1052: return parent.getMinimumSize();
1053: }
1054:
1055:
1063: public void layoutContainer(Container parent)
1064: {
1065:
1066:
1067: Insets i = getInsets();
1068: int arrowSize = comboBox.getHeight() - (i.top + i.bottom);
1069: int editorWidth = comboBox.getBounds().width - arrowSize;
1070:
1071: if (arrowButton != null)
1072: arrowButton.setBounds(comboBox.getWidth() - (i.right + arrowSize),
1073: i.top, arrowSize, arrowSize);
1074: if (editor != null)
1075: editor.setBounds(rectangleForCurrentValue());
1076: }
1077: }
1078:
1079:
1085: public class FocusHandler extends Object implements FocusListener
1086: {
1087:
1090: public FocusHandler()
1091: {
1092:
1093: }
1094:
1095:
1101: public void focusGained(FocusEvent e)
1102: {
1103: hasFocus = true;
1104: comboBox.repaint();
1105: }
1106:
1107:
1113: public void focusLost(FocusEvent e)
1114: {
1115: hasFocus = false;
1116: if (! e.isTemporary() && comboBox.isLightWeightPopupEnabled())
1117: setPopupVisible(comboBox, false);
1118: comboBox.repaint();
1119: }
1120: }
1121:
1122:
1126: public class ItemHandler extends Object implements ItemListener
1127: {
1128:
1131: public ItemHandler()
1132: {
1133:
1134: }
1135:
1136:
1142: public void itemStateChanged(ItemEvent e)
1143: {
1144: ComboBoxModel model = comboBox.getModel();
1145: Object v = model.getSelectedItem();
1146: if (editor != null)
1147: comboBox.configureEditor(comboBox.getEditor(), v);
1148: comboBox.repaint();
1149: }
1150: }
1151:
1152:
1155: public class KeyHandler extends KeyAdapter
1156: {
1157: public KeyHandler()
1158: {
1159:
1160: }
1161:
1162:
1165: public void keyPressed(KeyEvent e)
1166: throws NotImplementedException
1167: {
1168:
1169:
1170: }
1171: }
1172:
1173:
1176: public class ListDataHandler extends Object implements ListDataListener
1177: {
1178:
1181: public ListDataHandler()
1182: {
1183:
1184: }
1185:
1186:
1191: public void contentsChanged(ListDataEvent e)
1192: {
1193: if (e.getIndex0() != -1 || e.getIndex1() != -1)
1194: {
1195: isMinimumSizeDirty = true;
1196: comboBox.revalidate();
1197: }
1198: if (editor != null)
1199: comboBox.configureEditor(comboBox.getEditor(),
1200: comboBox.getSelectedItem());
1201: comboBox.repaint();
1202: }
1203:
1204:
1209: public void intervalAdded(ListDataEvent e)
1210: {
1211: int start = e.getIndex0();
1212: int end = e.getIndex1();
1213: if (start == 0 && comboBox.getItemCount() - (end - start + 1) == 0)
1214: contentsChanged(e);
1215: else if (start != -1 || end != -1)
1216: {
1217: ListCellRenderer renderer = comboBox.getRenderer();
1218: ComboBoxModel model = comboBox.getModel();
1219: int w = displaySize.width;
1220: int h = displaySize.height;
1221:
1222: for (int i = start; i <= end; ++i)
1223: {
1224: Component comp = renderer.getListCellRendererComponent(listBox,
1225: model.getElementAt(i), -1, false, false);
1226: currentValuePane.add(comp);
1227: comp.setFont(comboBox.getFont());
1228: Dimension dim = comp.getPreferredSize();
1229: w = Math.max(w, dim.width);
1230: h = Math.max(h, dim.height);
1231: currentValuePane.remove(comp);
1232: }
1233: if (displaySize.width < w || displaySize.height < h)
1234: {
1235: if (displaySize.width < w)
1236: displaySize.width = w;
1237: if (displaySize.height < h)
1238: displaySize.height = h;
1239: comboBox.revalidate();
1240: if (editor != null)
1241: {
1242: comboBox.configureEditor(comboBox.getEditor(),
1243: comboBox.getSelectedItem());
1244: }
1245: }
1246: }
1247:
1248: }
1249:
1250:
1256: public void intervalRemoved(ListDataEvent e)
1257: {
1258: contentsChanged(e);
1259: }
1260: }
1261:
1262:
1265: public class PropertyChangeHandler extends Object
1266: implements PropertyChangeListener
1267: {
1268:
1271: public PropertyChangeHandler()
1272: {
1273:
1274: }
1275:
1276:
1281: public void propertyChange(PropertyChangeEvent e)
1282: {
1283:
1284: isMinimumSizeDirty = true;
1285:
1286: if (e.getPropertyName().equals("enabled"))
1287: {
1288: arrowButton.setEnabled(comboBox.isEnabled());
1289:
1290: if (comboBox.isEditable())
1291: comboBox.getEditor().getEditorComponent().setEnabled(
1292: comboBox.isEnabled());
1293: }
1294: else if (e.getPropertyName().equals("editable"))
1295: {
1296: if (comboBox.isEditable())
1297: {
1298: configureEditor();
1299: addEditor();
1300: }
1301: else
1302: {
1303: unconfigureEditor();
1304: removeEditor();
1305: }
1306:
1307: comboBox.revalidate();
1308: comboBox.repaint();
1309: }
1310: else if (e.getPropertyName().equals("dataModel"))
1311: {
1312:
1313: ComboBoxModel oldModel = (ComboBoxModel) e.getOldValue();
1314: if (oldModel != null)
1315: oldModel.removeListDataListener(listDataListener);
1316:
1317: if ((ComboBoxModel) e.getNewValue() != null)
1318: comboBox.getModel().addListDataListener(listDataListener);
1319: }
1320: else if (e.getPropertyName().equals("font"))
1321: {
1322: Font font = (Font) e.getNewValue();
1323: editor.setFont(font);
1324: listBox.setFont(font);
1325: arrowButton.setFont(font);
1326: comboBox.revalidate();
1327: comboBox.repaint();
1328: }
1329:
1330:
1331: }
1332: }
1333:
1334: }