54 * appropriate for short term storage or RMI between applications running
55 * the same version of Swing. As of 1.4, support for long term storage
56 * of all JavaBeans™
57 * has been added to the <code>java.beans</code> package.
58 * Please see {@link java.beans.XMLEncoder}.
59 *
60 * @author Tom Santos
61 * @author Mark Davidson
62 */
63 @SuppressWarnings("serial") // Same-version serialization only
64 public class BasicComboPopup extends JPopupMenu implements ComboPopup {
65 // An empty ListMode, this is used when the UI changes to allow
66 // the JList to be gc'ed.
67 private static class EmptyListModelClass implements ListModel<Object>, Serializable {
68 public int getSize() { return 0; }
69 public Object getElementAt(int index) { return null; }
70 public void addListDataListener(ListDataListener l) {}
71 public void removeListDataListener(ListDataListener l) {}
72 };
73
74 static final ListModel EmptyListModel = new EmptyListModelClass();
75
76 private static Border LIST_BORDER = new LineBorder(Color.BLACK, 1);
77
78 protected JComboBox comboBox;
79 /**
80 * This protected field is implementation specific. Do not access directly
81 * or override. Use the accessor methods instead.
82 *
83 * @see #getList
84 * @see #createList
85 */
86 protected JList list;
87 /**
88 * This protected field is implementation specific. Do not access directly
89 * or override. Use the create method instead
90 *
91 * @see #createScroller
92 */
93 protected JScrollPane scroller;
94
95 /**
96 * As of Java 2 platform v1.4 this previously undocumented field is no
97 * longer used.
98 */
99 protected boolean valueIsAdjusting = false;
100
101 // Listeners that are required by the ComboPopup interface
102
103 /**
104 * Implementation of all the listener classes.
105 */
106 private Handler handler;
212 /**
213 * Implementation of ComboPopup.hide().
214 */
215 public void hide() {
216 MenuSelectionManager manager = MenuSelectionManager.defaultManager();
217 MenuElement [] selection = manager.getSelectedPath();
218 for ( int i = 0 ; i < selection.length ; i++ ) {
219 if ( selection[i] == this ) {
220 manager.clearSelectedPath();
221 break;
222 }
223 }
224 if (selection.length > 0) {
225 comboBox.repaint();
226 }
227 }
228
229 /**
230 * Implementation of ComboPopup.getList().
231 */
232 public JList getList() {
233 return list;
234 }
235
236 /**
237 * Implementation of ComboPopup.getMouseListener().
238 *
239 * @return a <code>MouseListener</code> or null
240 * @see ComboPopup#getMouseListener
241 */
242 public MouseListener getMouseListener() {
243 if (mouseListener == null) {
244 mouseListener = createMouseListener();
245 }
246 return mouseListener;
247 }
248
249 /**
250 * Implementation of ComboPopup.getMouseMotionListener().
251 *
252 * @return a <code>MouseMotionListener</code> or null
286 }
287 uninstallComboBoxModelListeners(comboBox.getModel());
288 uninstallKeyboardActions();
289 uninstallListListeners();
290 // We do this, otherwise the listener the ui installs on
291 // the model (the combobox model in this case) will keep a
292 // reference to the list, causing the list (and us) to never get gced.
293 list.setModel(EmptyListModel);
294 }
295
296 //
297 // end ComboPopup method implementations
298 //======================================
299
300 /**
301 * Removes the listeners from the combo box model
302 *
303 * @param model The combo box model to install listeners
304 * @see #installComboBoxModelListeners
305 */
306 protected void uninstallComboBoxModelListeners( ComboBoxModel model ) {
307 if (model != null && listDataListener != null) {
308 model.removeListDataListener(listDataListener);
309 }
310 }
311
312 protected void uninstallKeyboardActions() {
313 // XXX - shouldn't call this method
314 // comboBox.unregisterKeyboardAction( KeyStroke.getKeyStroke( KeyEvent.VK_ENTER, 0 ) );
315 }
316
317
318
319 //===================================================================
320 // begin Initialization routines
321 //
322 public BasicComboPopup( JComboBox combo ) {
323 super();
324 setName("ComboPopup.popup");
325 comboBox = combo;
326
327 setLightWeightPopupEnabled( comboBox.isLightWeightPopupEnabled() );
328
329 // UI construction of the popup.
330 list = createList();
331 list.setName("ComboBox.list");
332 configureList();
333 scroller = createScroller();
334 scroller.setName("ComboBox.scrollPane");
335 configureScroller();
336 configurePopup();
337
338 installComboBoxListeners();
339 installKeyboardActions();
340 }
341
342 // Overriden PopupMenuListener notification methods to inform combo box
464 * @return an instance of an <code>ItemListener</code> or null
465 */
466 protected ItemListener createItemListener() {
467 return getHandler();
468 }
469
470 private Handler getHandler() {
471 if (handler == null) {
472 handler = new Handler();
473 }
474 return handler;
475 }
476
477 /**
478 * Creates the JList used in the popup to display
479 * the items in the combo box model. This method is called when the UI class
480 * is created.
481 *
482 * @return a <code>JList</code> used to display the combo box items
483 */
484 protected JList createList() {
485 return new JList( comboBox.getModel() ) {
486 public void processMouseEvent(MouseEvent e) {
487 if (BasicGraphicsUtils.isMenuShortcutKeyDown(e)) {
488 // Fix for 4234053. Filter out the Control Key from the list.
489 // ie., don't allow CTRL key deselection.
490 Toolkit toolkit = Toolkit.getDefaultToolkit();
491 e = new MouseEvent((Component)e.getSource(), e.getID(), e.getWhen(),
492 e.getModifiers() ^ toolkit.getMenuShortcutKeyMask(),
493 e.getX(), e.getY(),
494 e.getXOnScreen(), e.getYOnScreen(),
495 e.getClickCount(),
496 e.isPopupTrigger(),
497 MouseEvent.NOBUTTON);
498 }
499 super.processMouseEvent(e);
500 }
501 };
502 }
503
504 /**
505 * Configures the list which is used to hold the combo box items in the
593 * This method adds the necessary listeners to the JComboBox.
594 */
595 protected void installComboBoxListeners() {
596 if ((propertyChangeListener = createPropertyChangeListener()) != null) {
597 comboBox.addPropertyChangeListener(propertyChangeListener);
598 }
599 if ((itemListener = createItemListener()) != null) {
600 comboBox.addItemListener(itemListener);
601 }
602 installComboBoxModelListeners(comboBox.getModel());
603 }
604
605 /**
606 * Installs the listeners on the combo box model. Any listeners installed
607 * on the combo box model should be removed in
608 * <code>uninstallComboBoxModelListeners</code>.
609 *
610 * @param model The combo box model to install listeners
611 * @see #uninstallComboBoxModelListeners
612 */
613 protected void installComboBoxModelListeners( ComboBoxModel model ) {
614 if (model != null && (listDataListener = createListDataListener()) != null) {
615 model.addListDataListener(listDataListener);
616 }
617 }
618
619 protected void installKeyboardActions() {
620
621 /* XXX - shouldn't call this method. take it out for testing.
622 ActionListener action = new ActionListener() {
623 public void actionPerformed(ActionEvent e){
624 }
625 };
626
627 comboBox.registerKeyboardAction( action,
628 KeyStroke.getKeyStroke( KeyEvent.VK_ENTER, 0 ),
629 JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT ); */
630
631 }
632
633 //
911 startAutoScrolling( directionToScroll );
912 }
913 else if ( !isAutoScrolling ) {
914 startAutoScrolling( directionToScroll );
915 }
916 }
917 else {
918 if ( e.getPoint().y < 0 ) {
919 hasEntered = true;
920 startAutoScrolling( SCROLL_UP );
921 }
922 }
923 }
924 }
925 }
926
927 //
928 // PropertyChangeListener
929 //
930 public void propertyChange(PropertyChangeEvent e) {
931 JComboBox comboBox = (JComboBox)e.getSource();
932 String propertyName = e.getPropertyName();
933
934 if ( propertyName == "model" ) {
935 ComboBoxModel oldModel = (ComboBoxModel)e.getOldValue();
936 ComboBoxModel newModel = (ComboBoxModel)e.getNewValue();
937 uninstallComboBoxModelListeners(oldModel);
938 installComboBoxModelListeners(newModel);
939
940 list.setModel(newModel);
941
942 if ( isVisible() ) {
943 hide();
944 }
945 }
946 else if ( propertyName == "renderer" ) {
947 list.setCellRenderer( comboBox.getRenderer() );
948 if ( isVisible() ) {
949 hide();
950 }
951 }
952 else if (propertyName == "componentOrientation") {
953 // Pass along the new component orientation
954 // to the list and the scroller
955
956 ComponentOrientation o =(ComponentOrientation)e.getNewValue();
957
958 JList list = getList();
959 if (list!=null && list.getComponentOrientation()!=o) {
960 list.setComponentOrientation(o);
961 }
962
963 if (scroller!=null && scroller.getComponentOrientation()!=o) {
964 scroller.setComponentOrientation(o);
965 }
966
967 if (o!=getComponentOrientation()) {
968 setComponentOrientation(o);
969 }
970 }
971 else if (propertyName == "lightWeightPopupEnabled") {
972 setLightWeightPopupEnabled(comboBox.isLightWeightPopupEnabled());
973 }
974 }
975
976 //
977 // ItemListener
978 //
979 public void itemStateChanged( ItemEvent e ) {
980 if (e.getStateChange() == ItemEvent.SELECTED) {
981 JComboBox comboBox = (JComboBox)e.getSource();
982 setListSelection(comboBox.getSelectedIndex());
983 }
984 }
985 }
986
987 //
988 // end Event Listeners
989 //=================================================================
990
991
992 /**
993 * Overridden to unconditionally return false.
994 */
995 public boolean isFocusTraversable() {
996 return false;
997 }
998
999 //===================================================================
1000 // begin Autoscroll methods
1001 //
1155 e.getModifiers(),
1156 convertedPoint.x,
1157 convertedPoint.y,
1158 e.getXOnScreen(),
1159 e.getYOnScreen(),
1160 e.getClickCount(),
1161 e.isPopupTrigger(),
1162 MouseEvent.NOBUTTON );
1163 return newEvent;
1164 }
1165
1166
1167 /**
1168 * Retrieves the height of the popup based on the current
1169 * ListCellRenderer and the maximum row count.
1170 */
1171 protected int getPopupHeightForRowCount(int maxRowCount) {
1172 // Set the cached value of the minimum row count
1173 int minRowCount = Math.min( maxRowCount, comboBox.getItemCount() );
1174 int height = 0;
1175 ListCellRenderer renderer = list.getCellRenderer();
1176 Object value = null;
1177
1178 for ( int i = 0; i < minRowCount; ++i ) {
1179 value = list.getModel().getElementAt( i );
1180 Component c = renderer.getListCellRendererComponent( list, value, i, false, false );
1181 height += c.getPreferredSize().height;
1182 }
1183
1184 if (height == 0) {
1185 height = comboBox.getHeight();
1186 }
1187
1188 Border border = scroller.getViewportBorder();
1189 if (border != null) {
1190 Insets insets = border.getBorderInsets(null);
1191 height += insets.top + insets.bottom;
1192 }
1193
1194 border = scroller.getBorder();
1195 if (border != null) {
|
54 * appropriate for short term storage or RMI between applications running
55 * the same version of Swing. As of 1.4, support for long term storage
56 * of all JavaBeans™
57 * has been added to the <code>java.beans</code> package.
58 * Please see {@link java.beans.XMLEncoder}.
59 *
60 * @author Tom Santos
61 * @author Mark Davidson
62 */
63 @SuppressWarnings("serial") // Same-version serialization only
64 public class BasicComboPopup extends JPopupMenu implements ComboPopup {
65 // An empty ListMode, this is used when the UI changes to allow
66 // the JList to be gc'ed.
67 private static class EmptyListModelClass implements ListModel<Object>, Serializable {
68 public int getSize() { return 0; }
69 public Object getElementAt(int index) { return null; }
70 public void addListDataListener(ListDataListener l) {}
71 public void removeListDataListener(ListDataListener l) {}
72 };
73
74 static final ListModel<Object> EmptyListModel = new EmptyListModelClass();
75
76 private static Border LIST_BORDER = new LineBorder(Color.BLACK, 1);
77
78 protected JComboBox<Object> comboBox;
79 /**
80 * This protected field is implementation specific. Do not access directly
81 * or override. Use the accessor methods instead.
82 *
83 * @see #getList
84 * @see #createList
85 */
86 protected JList<Object> list;
87 /**
88 * This protected field is implementation specific. Do not access directly
89 * or override. Use the create method instead
90 *
91 * @see #createScroller
92 */
93 protected JScrollPane scroller;
94
95 /**
96 * As of Java 2 platform v1.4 this previously undocumented field is no
97 * longer used.
98 */
99 protected boolean valueIsAdjusting = false;
100
101 // Listeners that are required by the ComboPopup interface
102
103 /**
104 * Implementation of all the listener classes.
105 */
106 private Handler handler;
212 /**
213 * Implementation of ComboPopup.hide().
214 */
215 public void hide() {
216 MenuSelectionManager manager = MenuSelectionManager.defaultManager();
217 MenuElement [] selection = manager.getSelectedPath();
218 for ( int i = 0 ; i < selection.length ; i++ ) {
219 if ( selection[i] == this ) {
220 manager.clearSelectedPath();
221 break;
222 }
223 }
224 if (selection.length > 0) {
225 comboBox.repaint();
226 }
227 }
228
229 /**
230 * Implementation of ComboPopup.getList().
231 */
232 public JList<Object> getList() {
233 return list;
234 }
235
236 /**
237 * Implementation of ComboPopup.getMouseListener().
238 *
239 * @return a <code>MouseListener</code> or null
240 * @see ComboPopup#getMouseListener
241 */
242 public MouseListener getMouseListener() {
243 if (mouseListener == null) {
244 mouseListener = createMouseListener();
245 }
246 return mouseListener;
247 }
248
249 /**
250 * Implementation of ComboPopup.getMouseMotionListener().
251 *
252 * @return a <code>MouseMotionListener</code> or null
286 }
287 uninstallComboBoxModelListeners(comboBox.getModel());
288 uninstallKeyboardActions();
289 uninstallListListeners();
290 // We do this, otherwise the listener the ui installs on
291 // the model (the combobox model in this case) will keep a
292 // reference to the list, causing the list (and us) to never get gced.
293 list.setModel(EmptyListModel);
294 }
295
296 //
297 // end ComboPopup method implementations
298 //======================================
299
300 /**
301 * Removes the listeners from the combo box model
302 *
303 * @param model The combo box model to install listeners
304 * @see #installComboBoxModelListeners
305 */
306 protected void uninstallComboBoxModelListeners( ComboBoxModel<?> model ) {
307 if (model != null && listDataListener != null) {
308 model.removeListDataListener(listDataListener);
309 }
310 }
311
312 protected void uninstallKeyboardActions() {
313 // XXX - shouldn't call this method
314 // comboBox.unregisterKeyboardAction( KeyStroke.getKeyStroke( KeyEvent.VK_ENTER, 0 ) );
315 }
316
317
318
319 //===================================================================
320 // begin Initialization routines
321 //
322 public BasicComboPopup( JComboBox<Object> combo ) {
323 super();
324 setName("ComboPopup.popup");
325 comboBox = combo;
326
327 setLightWeightPopupEnabled( comboBox.isLightWeightPopupEnabled() );
328
329 // UI construction of the popup.
330 list = createList();
331 list.setName("ComboBox.list");
332 configureList();
333 scroller = createScroller();
334 scroller.setName("ComboBox.scrollPane");
335 configureScroller();
336 configurePopup();
337
338 installComboBoxListeners();
339 installKeyboardActions();
340 }
341
342 // Overriden PopupMenuListener notification methods to inform combo box
464 * @return an instance of an <code>ItemListener</code> or null
465 */
466 protected ItemListener createItemListener() {
467 return getHandler();
468 }
469
470 private Handler getHandler() {
471 if (handler == null) {
472 handler = new Handler();
473 }
474 return handler;
475 }
476
477 /**
478 * Creates the JList used in the popup to display
479 * the items in the combo box model. This method is called when the UI class
480 * is created.
481 *
482 * @return a <code>JList</code> used to display the combo box items
483 */
484 protected JList<Object> createList() {
485 return new JList<Object>( comboBox.getModel() ) {
486 public void processMouseEvent(MouseEvent e) {
487 if (BasicGraphicsUtils.isMenuShortcutKeyDown(e)) {
488 // Fix for 4234053. Filter out the Control Key from the list.
489 // ie., don't allow CTRL key deselection.
490 Toolkit toolkit = Toolkit.getDefaultToolkit();
491 e = new MouseEvent((Component)e.getSource(), e.getID(), e.getWhen(),
492 e.getModifiers() ^ toolkit.getMenuShortcutKeyMask(),
493 e.getX(), e.getY(),
494 e.getXOnScreen(), e.getYOnScreen(),
495 e.getClickCount(),
496 e.isPopupTrigger(),
497 MouseEvent.NOBUTTON);
498 }
499 super.processMouseEvent(e);
500 }
501 };
502 }
503
504 /**
505 * Configures the list which is used to hold the combo box items in the
593 * This method adds the necessary listeners to the JComboBox.
594 */
595 protected void installComboBoxListeners() {
596 if ((propertyChangeListener = createPropertyChangeListener()) != null) {
597 comboBox.addPropertyChangeListener(propertyChangeListener);
598 }
599 if ((itemListener = createItemListener()) != null) {
600 comboBox.addItemListener(itemListener);
601 }
602 installComboBoxModelListeners(comboBox.getModel());
603 }
604
605 /**
606 * Installs the listeners on the combo box model. Any listeners installed
607 * on the combo box model should be removed in
608 * <code>uninstallComboBoxModelListeners</code>.
609 *
610 * @param model The combo box model to install listeners
611 * @see #uninstallComboBoxModelListeners
612 */
613 protected void installComboBoxModelListeners( ComboBoxModel<?> model ) {
614 if (model != null && (listDataListener = createListDataListener()) != null) {
615 model.addListDataListener(listDataListener);
616 }
617 }
618
619 protected void installKeyboardActions() {
620
621 /* XXX - shouldn't call this method. take it out for testing.
622 ActionListener action = new ActionListener() {
623 public void actionPerformed(ActionEvent e){
624 }
625 };
626
627 comboBox.registerKeyboardAction( action,
628 KeyStroke.getKeyStroke( KeyEvent.VK_ENTER, 0 ),
629 JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT ); */
630
631 }
632
633 //
911 startAutoScrolling( directionToScroll );
912 }
913 else if ( !isAutoScrolling ) {
914 startAutoScrolling( directionToScroll );
915 }
916 }
917 else {
918 if ( e.getPoint().y < 0 ) {
919 hasEntered = true;
920 startAutoScrolling( SCROLL_UP );
921 }
922 }
923 }
924 }
925 }
926
927 //
928 // PropertyChangeListener
929 //
930 public void propertyChange(PropertyChangeEvent e) {
931 @SuppressWarnings("unchecked")
932 JComboBox<Object> comboBox = (JComboBox)e.getSource();
933 String propertyName = e.getPropertyName();
934
935 if ( propertyName == "model" ) {
936 @SuppressWarnings("unchecked")
937 ComboBoxModel<Object> oldModel = (ComboBoxModel)e.getOldValue();
938 @SuppressWarnings("unchecked")
939 ComboBoxModel<Object> newModel = (ComboBoxModel)e.getNewValue();
940 uninstallComboBoxModelListeners(oldModel);
941 installComboBoxModelListeners(newModel);
942
943 list.setModel(newModel);
944
945 if ( isVisible() ) {
946 hide();
947 }
948 }
949 else if ( propertyName == "renderer" ) {
950 list.setCellRenderer( comboBox.getRenderer() );
951 if ( isVisible() ) {
952 hide();
953 }
954 }
955 else if (propertyName == "componentOrientation") {
956 // Pass along the new component orientation
957 // to the list and the scroller
958
959 ComponentOrientation o =(ComponentOrientation)e.getNewValue();
960
961 JList<?> list = getList();
962 if (list!=null && list.getComponentOrientation()!=o) {
963 list.setComponentOrientation(o);
964 }
965
966 if (scroller!=null && scroller.getComponentOrientation()!=o) {
967 scroller.setComponentOrientation(o);
968 }
969
970 if (o!=getComponentOrientation()) {
971 setComponentOrientation(o);
972 }
973 }
974 else if (propertyName == "lightWeightPopupEnabled") {
975 setLightWeightPopupEnabled(comboBox.isLightWeightPopupEnabled());
976 }
977 }
978
979 //
980 // ItemListener
981 //
982 public void itemStateChanged( ItemEvent e ) {
983 if (e.getStateChange() == ItemEvent.SELECTED) {
984 @SuppressWarnings("unchecked")
985 JComboBox<Object> comboBox = (JComboBox)e.getSource();
986 setListSelection(comboBox.getSelectedIndex());
987 }
988 }
989 }
990
991 //
992 // end Event Listeners
993 //=================================================================
994
995
996 /**
997 * Overridden to unconditionally return false.
998 */
999 public boolean isFocusTraversable() {
1000 return false;
1001 }
1002
1003 //===================================================================
1004 // begin Autoscroll methods
1005 //
1159 e.getModifiers(),
1160 convertedPoint.x,
1161 convertedPoint.y,
1162 e.getXOnScreen(),
1163 e.getYOnScreen(),
1164 e.getClickCount(),
1165 e.isPopupTrigger(),
1166 MouseEvent.NOBUTTON );
1167 return newEvent;
1168 }
1169
1170
1171 /**
1172 * Retrieves the height of the popup based on the current
1173 * ListCellRenderer and the maximum row count.
1174 */
1175 protected int getPopupHeightForRowCount(int maxRowCount) {
1176 // Set the cached value of the minimum row count
1177 int minRowCount = Math.min( maxRowCount, comboBox.getItemCount() );
1178 int height = 0;
1179 ListCellRenderer<Object> renderer = list.getCellRenderer();
1180 Object value = null;
1181
1182 for ( int i = 0; i < minRowCount; ++i ) {
1183 value = list.getModel().getElementAt( i );
1184 Component c = renderer.getListCellRendererComponent( list, value, i, false, false );
1185 height += c.getPreferredSize().height;
1186 }
1187
1188 if (height == 0) {
1189 height = comboBox.getHeight();
1190 }
1191
1192 Border border = scroller.getViewportBorder();
1193 if (border != null) {
1194 Insets insets = border.getBorderInsets(null);
1195 height += insets.top + insets.bottom;
1196 }
1197
1198 border = scroller.getBorder();
1199 if (border != null) {
|