1 7 8 package javax.swing.plaf.basic; 9 10 import javax.accessibility.AccessibleContext ; 11 import javax.swing.*; 12 import javax.swing.border.Border ; 13 import javax.swing.border.LineBorder ; 14 import javax.swing.event.*; 15 import java.awt.*; 16 import java.awt.event.*; 17 import java.beans.PropertyChangeListener ; 18 import java.beans.PropertyChangeEvent ; 19 import java.io.Serializable ; 20 21 22 46 public class BasicComboPopup extends JPopupMenu implements ComboPopup { 47 private static class EmptyListModelClass implements ListModel, 50 Serializable { 51 public int getSize() { return 0; } 52 public Object getElementAt(int index) { return null; } 53 public void addListDataListener(ListDataListener l) {} 54 public void removeListDataListener(ListDataListener l) {} 55 }; 56 57 static final ListModel EmptyListModel = new EmptyListModelClass(); 58 59 private static Border LIST_BORDER = new LineBorder (Color.BLACK, 1); 60 61 protected JComboBox comboBox; 62 69 protected JList list; 70 76 protected JScrollPane scroller; 77 78 82 protected boolean valueIsAdjusting = false; 83 84 86 89 private Handler handler; 90 91 98 protected MouseMotionListener mouseMotionListener; 99 106 protected MouseListener mouseListener; 107 108 115 protected KeyListener keyListener; 116 117 123 protected ListSelectionListener listSelectionListener; 124 125 132 protected MouseListener listMouseListener; 133 139 protected MouseMotionListener listMouseMotionListener; 140 141 148 protected PropertyChangeListener propertyChangeListener; 149 150 157 protected ListDataListener listDataListener; 158 159 165 protected ItemListener itemListener; 166 167 171 protected Timer autoscrollTimer; 172 protected boolean hasEntered = false; 173 protected boolean isAutoScrolling = false; 174 protected int scrollDirection = SCROLL_UP; 175 176 protected static final int SCROLL_UP = 0; 177 protected static final int SCROLL_DOWN = 1; 178 179 180 184 187 public void show() { 188 setListSelection(comboBox.getSelectedIndex()); 189 190 Point location = getPopupLocation(); 191 show( comboBox, location.x, location.y ); 192 } 193 194 195 198 public void hide() { 199 MenuSelectionManager manager = MenuSelectionManager.defaultManager(); 200 MenuElement [] selection = manager.getSelectedPath(); 201 for ( int i = 0 ; i < selection.length ; i++ ) { 202 if ( selection[i] == this ) { 203 manager.clearSelectedPath(); 204 break; 205 } 206 } 207 if (selection.length > 0) { 208 comboBox.repaint(); 209 } 210 } 211 212 215 public JList getList() { 216 return list; 217 } 218 219 225 public MouseListener getMouseListener() { 226 if (mouseListener == null) { 227 mouseListener = createMouseListener(); 228 } 229 return mouseListener; 230 } 231 232 238 public MouseMotionListener getMouseMotionListener() { 239 if (mouseMotionListener == null) { 240 mouseMotionListener = createMouseMotionListener(); 241 } 242 return mouseMotionListener; 243 } 244 245 251 public KeyListener getKeyListener() { 252 if (keyListener == null) { 253 keyListener = createKeyListener(); 254 } 255 return keyListener; 256 } 257 258 263 public void uninstallingUI() { 264 if (propertyChangeListener != null) { 265 comboBox.removePropertyChangeListener( propertyChangeListener ); 266 } 267 if (itemListener != null) { 268 comboBox.removeItemListener( itemListener ); 269 } 270 uninstallComboBoxModelListeners(comboBox.getModel()); 271 uninstallKeyboardActions(); 272 uninstallListListeners(); 273 list.setModel(EmptyListModel); 277 } 278 279 283 289 protected void uninstallComboBoxModelListeners( ComboBoxModel model ) { 290 if (model != null && listDataListener != null) { 291 model.removeListDataListener(listDataListener); 292 } 293 } 294 295 protected void uninstallKeyboardActions() { 296 } 299 300 301 302 public BasicComboPopup( JComboBox combo ) { 306 super(); 307 setName("ComboPopup.popup"); 308 comboBox = combo; 309 310 setLightWeightPopupEnabled( comboBox.isLightWeightPopupEnabled() ); 311 312 list = createList(); 314 list.setName("ComboBox.list"); 315 configureList(); 316 scroller = createScroller(); 317 scroller.setName("ComboBox.scrollPane"); 318 configureScroller(); 319 configurePopup(); 320 321 installComboBoxListeners(); 322 installKeyboardActions(); 323 } 324 325 328 protected void firePopupMenuWillBecomeVisible() { 329 super.firePopupMenuWillBecomeVisible(); 330 comboBox.firePopupMenuWillBecomeVisible(); 331 } 332 333 protected void firePopupMenuWillBecomeInvisible() { 334 super.firePopupMenuWillBecomeInvisible(); 335 comboBox.firePopupMenuWillBecomeInvisible(); 336 } 337 338 protected void firePopupMenuCanceled() { 339 super.firePopupMenuCanceled(); 340 comboBox.firePopupMenuCanceled(); 341 } 342 343 354 protected MouseListener createMouseListener() { 355 return getHandler(); 356 } 357 358 369 protected MouseMotionListener createMouseMotionListener() { 370 return getHandler(); 371 } 372 373 379 protected KeyListener createKeyListener() { 380 return null; 381 } 382 383 390 protected ListSelectionListener createListSelectionListener() { 391 return null; 392 } 393 394 401 protected ListDataListener createListDataListener() { 402 return null; 403 } 404 405 412 protected MouseListener createListMouseListener() { 413 return getHandler(); 414 } 415 416 423 protected MouseMotionListener createListMouseMotionListener() { 424 return getHandler(); 425 } 426 427 434 protected PropertyChangeListener createPropertyChangeListener() { 435 return getHandler(); 436 } 437 438 448 protected ItemListener createItemListener() { 449 return getHandler(); 450 } 451 452 private Handler getHandler() { 453 if (handler == null) { 454 handler = new Handler(); 455 } 456 return handler; 457 } 458 459 466 protected JList createList() { 467 return new JList( comboBox.getModel() ) { 468 public void processMouseEvent(MouseEvent e) { 469 if (e.isControlDown()) { 470 e = new MouseEvent((Component)e.getSource(), e.getID(), e.getWhen(), 473 e.getModifiers() ^ InputEvent.CTRL_MASK, 474 e.getX(), e.getY(), e.getClickCount(), e.isPopupTrigger()); 475 } 476 super.processMouseEvent(e); 477 } 478 }; 479 } 480 481 488 protected void configureList() { 489 list.setFont( comboBox.getFont() ); 490 list.setForeground( comboBox.getForeground() ); 491 list.setBackground( comboBox.getBackground() ); 492 list.setSelectionForeground( UIManager.getColor( "ComboBox.selectionForeground" ) ); 493 list.setSelectionBackground( UIManager.getColor( "ComboBox.selectionBackground" ) ); 494 list.setBorder( null ); 495 list.setCellRenderer( comboBox.getRenderer() ); 496 list.setFocusable( false ); 497 list.setSelectionMode( ListSelectionModel.SINGLE_SELECTION ); 498 setListSelection( comboBox.getSelectedIndex() ); 499 installListListeners(); 500 } 501 502 505 protected void installListListeners() { 506 if ((listMouseListener = createListMouseListener()) != null) { 507 list.addMouseListener( listMouseListener ); 508 } 509 if ((listMouseMotionListener = createListMouseMotionListener()) != null) { 510 list.addMouseMotionListener( listMouseMotionListener ); 511 } 512 if ((listSelectionListener = createListSelectionListener()) != null) { 513 list.addListSelectionListener( listSelectionListener ); 514 } 515 } 516 517 void uninstallListListeners() { 518 if (listMouseListener != null) { 519 list.removeMouseListener(listMouseListener); 520 listMouseListener = null; 521 } 522 if (listMouseMotionListener != null) { 523 list.removeMouseMotionListener(listMouseMotionListener); 524 listMouseMotionListener = null; 525 } 526 if (listSelectionListener != null) { 527 list.removeListSelectionListener(listSelectionListener); 528 listSelectionListener = null; 529 } 530 handler = null; 531 } 532 533 536 protected JScrollPane createScroller() { 537 JScrollPane sp = new JScrollPane( list, 538 ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, 539 ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER ); 540 sp.setHorizontalScrollBar(null); 541 return sp; 542 } 543 544 549 protected void configureScroller() { 550 scroller.setFocusable( false ); 551 scroller.getVerticalScrollBar().setFocusable( false ); 552 scroller.setBorder( null ); 553 } 554 555 559 protected void configurePopup() { 560 setLayout( new BoxLayout( this, BoxLayout.Y_AXIS ) ); 561 setBorderPainted( true ); 562 setBorder(LIST_BORDER); 563 setOpaque( false ); 564 add( scroller ); 565 setDoubleBuffered( true ); 566 setFocusable( false ); 567 } 568 569 572 protected void installComboBoxListeners() { 573 if ((propertyChangeListener = createPropertyChangeListener()) != null) { 574 comboBox.addPropertyChangeListener(propertyChangeListener); 575 } 576 if ((itemListener = createItemListener()) != null) { 577 comboBox.addItemListener(itemListener); 578 } 579 installComboBoxModelListeners(comboBox.getModel()); 580 } 581 582 590 protected void installComboBoxModelListeners( ComboBoxModel model ) { 591 if (model != null && (listDataListener = createListDataListener()) != null) { 592 model.addListDataListener(listDataListener); 593 } 594 } 595 596 protected void installKeyboardActions() { 597 598 607 608 } 609 610 614 615 619 640 protected class InvocationMouseHandler extends MouseAdapter { 641 646 public void mousePressed( MouseEvent e ) { 647 getHandler().mousePressed(e); 648 } 649 650 656 public void mouseReleased( MouseEvent e ) { 657 getHandler().mouseReleased(e); 658 } 659 } 660 661 665 protected class InvocationMouseMotionHandler extends MouseMotionAdapter { 666 public void mouseDragged( MouseEvent e ) { 667 getHandler().mouseDragged(e); 668 } 669 } 670 671 678 public class InvocationKeyHandler extends KeyAdapter { 679 public void keyReleased( KeyEvent e ) {} 680 } 681 682 687 protected class ListSelectionHandler implements ListSelectionListener { 688 public void valueChanged( ListSelectionEvent e ) {} 689 } 690 691 700 public class ListDataHandler implements ListDataListener { 701 public void contentsChanged( ListDataEvent e ) {} 702 703 public void intervalAdded( ListDataEvent e ) { 704 } 705 706 public void intervalRemoved( ListDataEvent e ) { 707 } 708 } 709 710 713 protected class ListMouseHandler extends MouseAdapter { 714 public void mousePressed( MouseEvent e ) { 715 } 716 public void mouseReleased(MouseEvent anEvent) { 717 getHandler().mouseReleased(anEvent); 718 } 719 } 720 721 725 protected class ListMouseMotionHandler extends MouseMotionAdapter { 726 public void mouseMoved( MouseEvent anEvent ) { 727 getHandler().mouseMoved(anEvent); 728 } 729 } 730 731 735 protected class ItemHandler implements ItemListener { 736 public void itemStateChanged( ItemEvent e ) { 737 getHandler().itemStateChanged(e); 738 } 739 } 740 741 751 protected class PropertyChangeHandler implements PropertyChangeListener { 752 public void propertyChange( PropertyChangeEvent e ) { 753 getHandler().propertyChange(e); 754 } 755 } 756 757 758 private class AutoScrollActionHandler implements ActionListener { 759 private int direction; 760 761 AutoScrollActionHandler(int direction) { 762 this.direction = direction; 763 } 764 765 public void actionPerformed(ActionEvent e) { 766 if (direction == SCROLL_UP) { 767 autoScrollUp(); 768 } 769 else { 770 autoScrollDown(); 771 } 772 } 773 } 774 775 776 private class Handler implements ItemListener, MouseListener, 777 MouseMotionListener, PropertyChangeListener , 778 Serializable { 779 public void mouseClicked(MouseEvent e) { 784 } 785 786 public void mousePressed(MouseEvent e) { 787 if (e.getSource() == list) { 788 return; 789 } 790 if (!SwingUtilities.isLeftMouseButton(e) || !comboBox.isEnabled()) 791 return; 792 793 if ( comboBox.isEditable() ) { 794 Component comp = comboBox.getEditor().getEditorComponent(); 795 if ((!(comp instanceof JComponent)) || ((JComponent)comp).isRequestFocusEnabled()) { 796 comp.requestFocus(); 797 } 798 } 799 else if (comboBox.isRequestFocusEnabled()) { 800 comboBox.requestFocus(); 801 } 802 togglePopup(); 803 } 804 805 public void mouseReleased(MouseEvent e) { 806 if (e.getSource() == list) { 807 comboBox.setSelectedIndex( list.getSelectedIndex() ); 809 comboBox.setPopupVisible(false); 810 if (comboBox.isEditable() && comboBox.getEditor() != null) { 812 comboBox.configureEditor(comboBox.getEditor(), 813 comboBox.getSelectedItem()); 814 } 815 return; 816 } 817 Component source = (Component)e.getSource(); 819 Dimension size = source.getSize(); 820 Rectangle bounds = new Rectangle( 0, 0, size.width - 1, size.height - 1 ); 821 if ( !bounds.contains( e.getPoint() ) ) { 822 MouseEvent newEvent = convertMouseEvent( e ); 823 Point location = newEvent.getPoint(); 824 Rectangle r = new Rectangle(); 825 list.computeVisibleRect( r ); 826 if ( r.contains( location ) ) { 827 comboBox.setSelectedIndex( list.getSelectedIndex() ); 828 } 829 comboBox.setPopupVisible(false); 830 } 831 hasEntered = false; 832 stopAutoScrolling(); 833 } 834 835 public void mouseEntered(MouseEvent e) { 836 } 837 838 public void mouseExited(MouseEvent e) { 839 } 840 841 public void mouseMoved(MouseEvent anEvent) { 846 if (anEvent.getSource() == list) { 847 Point location = anEvent.getPoint(); 848 Rectangle r = new Rectangle(); 849 list.computeVisibleRect( r ); 850 if ( r.contains( location ) ) { 851 updateListBoxSelectionForEvent( anEvent, false ); 852 } 853 } 854 } 855 856 public void mouseDragged( MouseEvent e ) { 857 if (e.getSource() == list) { 858 return; 859 } 860 if ( isVisible() ) { 861 MouseEvent newEvent = convertMouseEvent( e ); 862 Rectangle r = new Rectangle(); 863 list.computeVisibleRect( r ); 864 865 if ( newEvent.getPoint().y >= r.y && newEvent.getPoint().y <= r.y + r.height - 1 ) { 866 hasEntered = true; 867 if ( isAutoScrolling ) { 868 stopAutoScrolling(); 869 } 870 Point location = newEvent.getPoint(); 871 if ( r.contains( location ) ) { 872 updateListBoxSelectionForEvent( newEvent, false ); 873 } 874 } 875 else { 876 if ( hasEntered ) { 877 int directionToScroll = newEvent.getPoint().y < r.y ? SCROLL_UP : SCROLL_DOWN; 878 if ( isAutoScrolling && scrollDirection != directionToScroll ) { 879 stopAutoScrolling(); 880 startAutoScrolling( directionToScroll ); 881 } 882 else if ( !isAutoScrolling ) { 883 startAutoScrolling( directionToScroll ); 884 } 885 } 886 else { 887 if ( e.getPoint().y < 0 ) { 888 hasEntered = true; 889 startAutoScrolling( SCROLL_UP ); 890 } 891 } 892 } 893 } 894 } 895 896 public void propertyChange(PropertyChangeEvent e) { 900 JComboBox comboBox = (JComboBox)e.getSource(); 901 String propertyName = e.getPropertyName(); 902 903 if ( propertyName == "model" ) { 904 ComboBoxModel oldModel = (ComboBoxModel)e.getOldValue(); 905 ComboBoxModel newModel = (ComboBoxModel)e.getNewValue(); 906 uninstallComboBoxModelListeners(oldModel); 907 installComboBoxModelListeners(newModel); 908 909 list.setModel(newModel); 910 911 if ( isVisible() ) { 912 hide(); 913 } 914 } 915 else if ( propertyName == "renderer" ) { 916 list.setCellRenderer( comboBox.getRenderer() ); 917 if ( isVisible() ) { 918 hide(); 919 } 920 } 921 else if (propertyName == "componentOrientation") { 922 925 ComponentOrientation o =(ComponentOrientation)e.getNewValue(); 926 927 JList list = getList(); 928 if (list!=null && list.getComponentOrientation()!=o) { 929 list.setComponentOrientation(o); 930 } 931 932 if (scroller!=null && scroller.getComponentOrientation()!=o) { 933 scroller.setComponentOrientation(o); 934 } 935 936 if (o!=getComponentOrientation()) { 937 setComponentOrientation(o); 938 } 939 } 940 else if (propertyName == "lightWeightPopupEnabled") { 941 setLightWeightPopupEnabled(comboBox.isLightWeightPopupEnabled()); 942 } 943 } 944 945 public void itemStateChanged( ItemEvent e ) { 949 if (e.getStateChange() == ItemEvent.SELECTED) { 950 JComboBox comboBox = (JComboBox)e.getSource(); 951 setListSelection(comboBox.getSelectedIndex()); 952 } 953 } 954 } 955 956 960 961 964 public boolean isFocusTraversable() { 965 return false; 966 } 967 968 972 976 protected void startAutoScrolling( int direction ) { 977 if ( isAutoScrolling ) { 980 autoscrollTimer.stop(); 981 } 982 983 isAutoScrolling = true; 984 985 if ( direction == SCROLL_UP ) { 986 scrollDirection = SCROLL_UP; 987 Point convertedPoint = SwingUtilities.convertPoint( scroller, new Point( 1, 1 ), list ); 988 int top = list.locationToIndex( convertedPoint ); 989 list.setSelectedIndex( top ); 990 991 autoscrollTimer = new Timer( 100, new AutoScrollActionHandler( 992 SCROLL_UP) ); 993 } 994 else if ( direction == SCROLL_DOWN ) { 995 scrollDirection = SCROLL_DOWN; 996 Dimension size = scroller.getSize(); 997 Point convertedPoint = SwingUtilities.convertPoint( scroller, 998 new Point( 1, (size.height - 1) - 2 ), 999 list ); 1000 int bottom = list.locationToIndex( convertedPoint ); 1001 list.setSelectedIndex( bottom ); 1002 1003 autoscrollTimer = new Timer(100, new AutoScrollActionHandler( 1004 SCROLL_DOWN)); 1005 } 1006 autoscrollTimer.start(); 1007 } 1008 1009 1013 protected void stopAutoScrolling() { 1014 isAutoScrolling = false; 1015 1016 if ( autoscrollTimer != null ) { 1017 autoscrollTimer.stop(); 1018 autoscrollTimer = null; 1019 } 1020 } 1021 1022 1026 protected void autoScrollUp() { 1027 int index = list.getSelectedIndex(); 1028 if ( index > 0 ) { 1029 list.setSelectedIndex( index - 1 ); 1030 list.ensureIndexIsVisible( index - 1 ); 1031 } 1032 } 1033 1034 1038 protected void autoScrollDown() { 1039 int index = list.getSelectedIndex(); 1040 int lastItem = list.getModel().getSize() - 1; 1041 if ( index < lastItem ) { 1042 list.setSelectedIndex( index + 1 ); 1043 list.ensureIndexIsVisible( index + 1 ); 1044 } 1045 } 1046 1047 1051 1052 1056 1063 public AccessibleContext getAccessibleContext() { 1064 AccessibleContext context = super.getAccessibleContext(); 1065 context.setAccessibleParent(comboBox); 1066 return context; 1067 } 1068 1069 1070 1076 protected void delegateFocus( MouseEvent e ) { 1077 if ( comboBox.isEditable() ) { 1078 Component comp = comboBox.getEditor().getEditorComponent(); 1079 if ((!(comp instanceof JComponent)) || ((JComponent)comp).isRequestFocusEnabled()) { 1080 comp.requestFocus(); 1081 } 1082 } 1083 else if (comboBox.isRequestFocusEnabled()) { 1084 comboBox.requestFocus(); 1085 } 1086 } 1087 1088 1092 protected void togglePopup() { 1093 if ( isVisible() ) { 1094 hide(); 1095 } 1096 else { 1097 show(); 1098 } 1099 } 1100 1101 1108 private void setListSelection(int selectedIndex) { 1109 if ( selectedIndex == -1 ) { 1110 list.clearSelection(); 1111 } 1112 else { 1113 list.setSelectedIndex( selectedIndex ); 1114 list.ensureIndexIsVisible( selectedIndex ); 1115 } 1116 } 1117 1118 protected MouseEvent convertMouseEvent( MouseEvent e ) { 1119 Point convertedPoint = SwingUtilities.convertPoint( (Component)e.getSource(), 1120 e.getPoint(), list ); 1121 MouseEvent newEvent = new MouseEvent( (Component)e.getSource(), 1122 e.getID(), 1123 e.getWhen(), 1124 e.getModifiers(), 1125 convertedPoint.x, 1126 convertedPoint.y, 1127 e.getClickCount(), 1128 e.isPopupTrigger() ); 1129 return newEvent; 1130 } 1131 1132 1133 1137 protected int getPopupHeightForRowCount(int maxRowCount) { 1138 int minRowCount = Math.min( maxRowCount, comboBox.getItemCount() ); 1140 int height = 0; 1141 ListCellRenderer renderer = list.getCellRenderer(); 1142 Object value = null; 1143 1144 for ( int i = 0; i < minRowCount; ++i ) { 1145 value = list.getModel().getElementAt( i ); 1146 Component c = renderer.getListCellRendererComponent( list, value, i, false, false ); 1147 height += c.getPreferredSize().height; 1148 } 1149 1150 return height == 0 ? 100 : height; 1151 } 1152 1153 1165 protected Rectangle computePopupBounds(int px,int py,int pw,int ph) { 1166 Toolkit toolkit = Toolkit.getDefaultToolkit(); 1167 Rectangle screenBounds; 1168 1169 GraphicsConfiguration gc = comboBox.getGraphicsConfiguration(); 1171 Point p = new Point(); 1172 SwingUtilities.convertPointFromScreen(p, comboBox); 1173 if (gc != null) { 1174 Insets screenInsets = toolkit.getScreenInsets(gc); 1175 screenBounds = gc.getBounds(); 1176 screenBounds.width -= (screenInsets.left + screenInsets.right); 1177 screenBounds.height -= (screenInsets.top + screenInsets.bottom); 1178 screenBounds.x += (p.x + screenInsets.left); 1179 screenBounds.y += (p.y + screenInsets.top); 1180 } 1181 else { 1182 screenBounds = new Rectangle(p, toolkit.getScreenSize()); 1183 } 1184 1185 Rectangle rect = new Rectangle(px,py,pw,ph); 1186 if (py+ph > screenBounds.y+screenBounds.height 1187 && ph < screenBounds.height) { 1188 rect.y = -rect.height; 1189 } 1190 return rect; 1191 } 1192 1193 1196 private Point getPopupLocation() { 1197 Dimension popupSize = comboBox.getSize(); 1198 Insets insets = getInsets(); 1199 1200 popupSize.setSize(popupSize.width - (insets.right + insets.left), 1203 getPopupHeightForRowCount( comboBox.getMaximumRowCount())); 1204 Rectangle popupBounds = computePopupBounds( 0, comboBox.getBounds().height, 1205 popupSize.width, popupSize.height); 1206 Dimension scrollSize = popupBounds.getSize(); 1207 Point popupLocation = popupBounds.getLocation(); 1208 1209 scroller.setMaximumSize( scrollSize ); 1210 scroller.setPreferredSize( scrollSize ); 1211 scroller.setMinimumSize( scrollSize ); 1212 1213 list.revalidate(); 1214 1215 return popupLocation; 1216 } 1217 1218 1222 protected void updateListBoxSelectionForEvent(MouseEvent anEvent,boolean shouldScroll) { 1223 Point location = anEvent.getPoint(); 1226 if ( list == null ) 1227 return; 1228 int index = list.locationToIndex(location); 1229 if ( index == -1 ) { 1230 if ( location.y < 0 ) 1231 index = 0; 1232 else 1233 index = comboBox.getModel().getSize() - 1; 1234 } 1235 if ( list.getSelectedIndex() != index ) { 1236 list.setSelectedIndex(index); 1237 if ( shouldScroll ) 1238 list.ensureIndexIsVisible(index); 1239 } 1240 } 1241 1242 } 1246 1247 1248 | Popular Tags |