GNU Classpath (0.20) | |
Frames | No Frames |
1: /* BasicComboPopup.java -- 2: Copyright (C) 2004, 2005 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.Dimension; 44: import java.awt.Point; 45: import java.awt.Rectangle; 46: import java.awt.event.ItemEvent; 47: import java.awt.event.ItemListener; 48: import java.awt.event.KeyAdapter; 49: import java.awt.event.KeyEvent; 50: import java.awt.event.KeyListener; 51: import java.awt.event.MouseAdapter; 52: import java.awt.event.MouseEvent; 53: import java.awt.event.MouseListener; 54: import java.awt.event.MouseMotionAdapter; 55: import java.awt.event.MouseMotionListener; 56: import java.beans.PropertyChangeEvent; 57: import java.beans.PropertyChangeListener; 58: 59: import javax.swing.BorderFactory; 60: import javax.swing.ComboBoxModel; 61: import javax.swing.JComboBox; 62: import javax.swing.JLabel; 63: import javax.swing.JList; 64: import javax.swing.JPopupMenu; 65: import javax.swing.JScrollBar; 66: import javax.swing.JScrollPane; 67: import javax.swing.ListCellRenderer; 68: import javax.swing.ListSelectionModel; 69: import javax.swing.SwingConstants; 70: import javax.swing.SwingUtilities; 71: import javax.swing.Timer; 72: import javax.swing.event.ListDataEvent; 73: import javax.swing.event.ListDataListener; 74: import javax.swing.event.ListSelectionEvent; 75: import javax.swing.event.ListSelectionListener; 76: import javax.swing.event.PopupMenuEvent; 77: import javax.swing.event.PopupMenuListener; 78: 79: /** 80: * UI Delegate for ComboPopup 81: * 82: * @author Olga Rodimina 83: */ 84: public class BasicComboPopup extends JPopupMenu implements ComboPopup 85: { 86: /* Timer for autoscrolling */ 87: protected Timer autoscrollTimer; 88: 89: /** ComboBox associated with this popup */ 90: protected JComboBox comboBox; 91: 92: /** FIXME: Need to document */ 93: protected boolean hasEntered; 94: 95: /** 96: * Indicates whether the scroll bar located in popup menu with comboBox's 97: * list of items is currently autoscrolling. This happens when mouse event 98: * originated in the combo box and is dragged outside of its bounds 99: */ 100: protected boolean isAutoScrolling; 101: 102: /** ItemListener listening to the selection changes in the combo box */ 103: protected ItemListener itemListener; 104: 105: /** This listener is not used */ 106: protected KeyListener keyListener; 107: 108: /** JList which is used to display item is the combo box */ 109: protected JList list; 110: 111: /** This listener is not used */ 112: protected ListDataListener listDataListener; 113: 114: /** 115: * MouseListener listening to mouse events occuring in the combo box's 116: * list. 117: */ 118: protected MouseListener listMouseListener; 119: 120: /** 121: * MouseMotionListener listening to mouse motion events occuring in the 122: * combo box's list 123: */ 124: protected MouseMotionListener listMouseMotionListener; 125: 126: /** This listener is not used */ 127: protected ListSelectionListener listSelectionListener; 128: 129: /** MouseListener listening to mouse events occuring in the combo box */ 130: protected MouseListener mouseListener; 131: 132: /** 133: * MouseMotionListener listening to mouse motion events occuring in the 134: * combo box 135: */ 136: protected MouseMotionListener mouseMotionListener; 137: 138: /** 139: * PropertyChangeListener listening to changes occuring in the bound 140: * properties of the combo box 141: */ 142: protected PropertyChangeListener propertyChangeListener; 143: 144: /** direction for scrolling down list of combo box's items */ 145: protected static final int SCROLL_DOWN = 1; 146: 147: /** direction for scrolling up list of combo box's items */ 148: protected static final int SCROLL_UP = 0; 149: 150: /** Indicates auto scrolling direction */ 151: protected int scrollDirection; 152: 153: /** JScrollPane that contains list portion of the combo box */ 154: protected JScrollPane scroller; 155: 156: /** This field is not used */ 157: protected boolean valueIsAdjusting; 158: 159: /** 160: * Creates a new BasicComboPopup object. 161: * 162: * @param comboBox the combo box with which this popup should be associated 163: */ 164: public BasicComboPopup(JComboBox comboBox) 165: { 166: this.comboBox = comboBox; 167: installComboBoxListeners(); 168: configurePopup(); 169: setLightWeightPopupEnabled(comboBox.isLightWeightPopupEnabled()); 170: } 171: 172: /** 173: * This method displays drow down list of combo box items on the screen. 174: */ 175: public void show() 176: { 177: Rectangle cbBounds = comboBox.getBounds(); 178: 179: // popup should have same width as the comboBox and should be hight anough 180: // to display number of rows equal to 'maximumRowCount' property 181: int popupHeight = getPopupHeightForRowCount(comboBox.getMaximumRowCount()); 182: 183: scroller.setPreferredSize(new Dimension(cbBounds.width, popupHeight)); 184: pack(); 185: 186: // Highlight selected item in the combo box's drop down list 187: if (comboBox.getSelectedIndex() != -1) 188: list.setSelectedIndex(comboBox.getSelectedIndex()); 189: 190: //scroll scrollbar s.t. selected item is visible 191: JScrollBar scrollbar = scroller.getVerticalScrollBar(); 192: int selectedIndex = comboBox.getSelectedIndex(); 193: if (selectedIndex > comboBox.getMaximumRowCount()) 194: scrollbar.setValue(getPopupHeightForRowCount(selectedIndex)); 195: 196: // location specified is relative to comboBox 197: super.show(comboBox, 0, cbBounds.height); 198: } 199: 200: /** 201: * This method hides drop down list of items 202: */ 203: public void hide() 204: { 205: super.setVisible(false); 206: } 207: 208: /** 209: * Return list cointaining JComboBox's items 210: * 211: * @return list cointaining JComboBox's items 212: */ 213: public JList getList() 214: { 215: return list; 216: } 217: 218: /** 219: * Returns MouseListener that is listening to mouse events occuring in the 220: * combo box. 221: * 222: * @return MouseListener 223: */ 224: public MouseListener getMouseListener() 225: { 226: return mouseListener; 227: } 228: 229: /** 230: * Returns MouseMotionListener that is listening to mouse motion events 231: * occuring in the combo box. 232: * 233: * @return MouseMotionListener 234: */ 235: public MouseMotionListener getMouseMotionListener() 236: { 237: return mouseMotionListener; 238: } 239: 240: /** 241: * Returns KeyListener listening to key events occuring in the combo box. 242: * This method returns null because KeyHandler is not longer used. 243: * 244: * @return KeyListener 245: */ 246: public KeyListener getKeyListener() 247: { 248: return keyListener; 249: } 250: 251: /** 252: * This method uninstalls the UI for the given JComponent. 253: */ 254: public void uninstallingUI() 255: { 256: uninstallComboBoxModelListeners(comboBox.getModel()); 257: 258: uninstallListeners(); 259: uninstallKeyboardActions(); 260: } 261: 262: /** 263: * This method uninstalls listeners that were listening to changes occuring 264: * in the comb box's data model 265: * 266: * @param model data model for the combo box from which to uninstall 267: * listeners 268: */ 269: protected void uninstallComboBoxModelListeners(ComboBoxModel model) 270: { 271: model.removeListDataListener(listDataListener); 272: } 273: 274: /** 275: * This method uninstalls keyboard actions installed by the UI. 276: */ 277: protected void uninstallKeyboardActions() 278: { 279: // FIXME: Need to implement 280: } 281: 282: /** 283: * This method fires PopupMenuEvent indicating that combo box's popup list 284: * of items will become visible 285: */ 286: protected void firePopupMenuWillBecomeVisible() 287: { 288: PopupMenuListener[] ll = comboBox.getPopupMenuListeners(); 289: 290: for (int i = 0; i < ll.length; i++) 291: ll[i].popupMenuWillBecomeVisible(new PopupMenuEvent(comboBox)); 292: } 293: 294: /** 295: * This method fires PopupMenuEvent indicating that combo box's popup list 296: * of items will become invisible. 297: */ 298: protected void firePopupMenuWillBecomeInvisible() 299: { 300: PopupMenuListener[] ll = comboBox.getPopupMenuListeners(); 301: 302: for (int i = 0; i < ll.length; i++) 303: ll[i].popupMenuWillBecomeInvisible(new PopupMenuEvent(comboBox)); 304: } 305: 306: /** 307: * This method fires PopupMenuEvent indicating that combo box's popup list 308: * of items was closed without selection. 309: */ 310: protected void firePopupMenuCanceled() 311: { 312: PopupMenuListener[] ll = comboBox.getPopupMenuListeners(); 313: 314: for (int i = 0; i < ll.length; i++) 315: ll[i].popupMenuCanceled(new PopupMenuEvent(comboBox)); 316: } 317: 318: /** 319: * Creates MouseListener to listen to mouse events occuring in the combo 320: * box. Note that this listener doesn't listen to mouse events occuring in 321: * the popup portion of the combo box, it only listens to main combo box 322: * part. 323: * 324: * @return new MouseMotionListener that listens to mouse events occuring in 325: * the combo box 326: */ 327: protected MouseListener createMouseListener() 328: { 329: return new InvocationMouseHandler(); 330: } 331: 332: /** 333: * Create Mouse listener that listens to mouse dragging events occuring in 334: * the combo box. This listener is responsible for changing the selection 335: * in the combo box list to the component over which mouse is being 336: * currently dragged 337: * 338: * @return new MouseMotionListener that listens to mouse dragging events 339: * occuring in the combo box 340: */ 341: protected MouseMotionListener createMouseMotionListener() 342: { 343: return new InvocationMouseMotionHandler(); 344: } 345: 346: /** 347: * KeyListener created in this method is not used anymore. 348: * 349: * @return KeyListener that does nothing 350: */ 351: protected KeyListener createKeyListener() 352: { 353: return new InvocationKeyHandler(); 354: } 355: 356: /** 357: * ListSelectionListener created in this method is not used anymore 358: * 359: * @return ListSelectionListener that does nothing 360: */ 361: protected ListSelectionListener createListSelectionListener() 362: { 363: return new ListSelectionHandler(); 364: } 365: 366: /** 367: * Creates ListDataListener. This method returns null, because 368: * ListDataHandler class is obsolete and is no longer used. 369: * 370: * @return null 371: */ 372: protected ListDataListener createListDataListener() 373: { 374: return null; 375: } 376: 377: /** 378: * This method creates ListMouseListener to listen to mouse events occuring 379: * in the combo box's item list. 380: * 381: * @return MouseListener to listen to mouse events occuring in the combo 382: * box's items list. 383: */ 384: protected MouseListener createListMouseListener() 385: { 386: return new ListMouseHandler(); 387: } 388: 389: /** 390: * Creates ListMouseMotionlistener to listen to mouse motion events occuring 391: * in the combo box's list. This listener is responsible for highlighting 392: * items in the list when mouse is moved over them. 393: * 394: * @return MouseMotionListener that handles mouse motion events occuring in 395: * the list of the combo box. 396: */ 397: protected MouseMotionListener createListMouseMotionListener() 398: { 399: return new ListMouseMotionHandler(); 400: } 401: 402: /** 403: * Creates PropertyChangeListener to handle changes in the JComboBox's bound 404: * properties. 405: * 406: * @return PropertyChangeListener to handle changes in the JComboBox's bound 407: * properties. 408: */ 409: protected PropertyChangeListener createPropertyChangeListener() 410: { 411: return new PropertyChangeHandler(); 412: } 413: 414: /** 415: * Creates new ItemListener that will listen to ItemEvents occuring in the 416: * combo box. 417: * 418: * @return ItemListener to listen to ItemEvents occuring in the combo box. 419: */ 420: protected ItemListener createItemListener() 421: { 422: return new ItemHandler(); 423: } 424: 425: /** 426: * Creates JList that will be used to display items in the combo box. 427: * 428: * @return JList that will be used to display items in the combo box. 429: */ 430: protected JList createList() 431: { 432: JList l = new JList(comboBox.getModel()); 433: l.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); 434: return l; 435: } 436: 437: /** 438: * This method configures the list of comboBox's items by setting default 439: * properties and installing listeners. 440: */ 441: protected void configureList() 442: { 443: list.setModel(comboBox.getModel()); 444: list.setVisibleRowCount(comboBox.getMaximumRowCount()); 445: list.setFocusable(false); 446: installListListeners(); 447: } 448: 449: /** 450: * This method installs list listeners. 451: */ 452: protected void installListListeners() 453: { 454: // mouse listener listening to mouse events occuring in the 455: // combo box's list of items. 456: listMouseListener = createListMouseListener(); 457: list.addMouseListener(listMouseListener); 458: 459: // mouse listener listening to mouse motion events occuring in the 460: // combo box's list of items 461: listMouseMotionListener = createListMouseMotionListener(); 462: list.addMouseMotionListener(listMouseMotionListener); 463: 464: listSelectionListener = createListSelectionListener(); 465: list.addListSelectionListener(listSelectionListener); 466: } 467: 468: /** 469: * This method creates scroll pane that will contain the list of comboBox's 470: * items inside of it. 471: * 472: * @return JScrollPane 473: */ 474: protected JScrollPane createScroller() 475: { 476: return new JScrollPane(); 477: } 478: 479: /** 480: * This method configures scroll pane to contain list of comboBox's items 481: */ 482: protected void configureScroller() 483: { 484: scroller.setBorder(null); 485: scroller.getViewport().setView(list); 486: scroller.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 487: } 488: 489: /** 490: * This method configures popup menu that will be used to display Scrollpane 491: * with list of items inside of it. 492: */ 493: protected void configurePopup() 494: { 495: setBorder(BorderFactory.createLineBorder(Color.BLACK)); 496: // initialize list that will be used to display combo box's items 497: this.list = createList(); 498: ((JLabel) list.getCellRenderer()).setHorizontalAlignment(SwingConstants.LEFT); 499: configureList(); 500: 501: // initialize scroller. Add list to the scroller. 502: scroller = createScroller(); 503: configureScroller(); 504: 505: // add scroller with list inside of it to JPopupMenu 506: super.add(scroller); 507: } 508: 509: /* 510: * This method installs listeners that will listen to changes occuring 511: * in the combo box. 512: */ 513: protected void installComboBoxListeners() 514: { 515: // mouse listener that listens to mouse event in combo box 516: mouseListener = createMouseListener(); 517: comboBox.addMouseListener(mouseListener); 518: 519: // mouse listener that listens to mouse dragging events in the combo box 520: mouseMotionListener = createMouseMotionListener(); 521: comboBox.addMouseMotionListener(mouseMotionListener); 522: 523: // item listener listenening to selection events in the combo box 524: itemListener = createItemListener(); 525: comboBox.addItemListener(itemListener); 526: 527: propertyChangeListener = createPropertyChangeListener(); 528: comboBox.addPropertyChangeListener(propertyChangeListener); 529: } 530: 531: /** 532: * This method installs listeners that will listen to changes occuring in 533: * the comb box's data model 534: * 535: * @param model data model for the combo box for which to install listeners 536: */ 537: protected void installComboBoxModelListeners(ComboBoxModel model) 538: { 539: // list data listener to listen for ListDataEvents in combo box. 540: // This listener is now obsolete and nothing is done here 541: listDataListener = createListDataListener(); 542: comboBox.getModel().addListDataListener(listDataListener); 543: } 544: 545: /** 546: * DOCUMENT ME! 547: */ 548: protected void installKeyboardActions() 549: { 550: // FIXME: Need to implement 551: } 552: 553: /** 554: * This method always returns false to indicate that items in the combo box 555: * list are not focus traversable. 556: * 557: * @return false 558: */ 559: public boolean isFocusTraversable() 560: { 561: return false; 562: } 563: 564: /** 565: * This method start scrolling combo box's list of items either up or down 566: * depending on the specified 'direction' 567: * 568: * @param direction of the scrolling. 569: */ 570: protected void startAutoScrolling(int direction) 571: { 572: // FIXME: add timer 573: isAutoScrolling = true; 574: 575: if (direction == SCROLL_UP) 576: autoScrollUp(); 577: else 578: autoScrollDown(); 579: } 580: 581: /** 582: * This method stops scrolling the combo box's list of items 583: */ 584: protected void stopAutoScrolling() 585: { 586: // FIXME: add timer 587: isAutoScrolling = false; 588: } 589: 590: /** 591: * This method scrolls up list of combo box's items up and highlights that 592: * just became visible. 593: */ 594: protected void autoScrollUp() 595: { 596: // scroll up the scroll bar to make the item above visible 597: JScrollBar scrollbar = scroller.getVerticalScrollBar(); 598: int scrollToNext = list.getScrollableUnitIncrement(super.getBounds(), 599: SwingConstants.VERTICAL, 600: SCROLL_UP); 601: 602: scrollbar.setValue(scrollbar.getValue() - scrollToNext); 603: 604: // If we haven't reached the begging of the combo box's list of items, 605: // then highlight next element above currently highlighted element 606: if (list.getSelectedIndex() != 0) 607: list.setSelectedIndex(list.getSelectedIndex() - 1); 608: } 609: 610: /** 611: * This method scrolls down list of combo box's and highlights item in the 612: * list that just became visible. 613: */ 614: protected void autoScrollDown() 615: { 616: // scroll scrollbar down to make next item visible 617: JScrollBar scrollbar = scroller.getVerticalScrollBar(); 618: int scrollToNext = list.getScrollableUnitIncrement(super.getBounds(), 619: SwingConstants.VERTICAL, 620: SCROLL_DOWN); 621: scrollbar.setValue(scrollbar.getValue() + scrollToNext); 622: 623: // If we haven't reached the end of the combo box's list of items 624: // then highlight next element below currently highlighted element 625: if (list.getSelectedIndex() + 1 != comboBox.getItemCount()) 626: list.setSelectedIndex(list.getSelectedIndex() + 1); 627: } 628: 629: /** 630: * This method helps to delegate focus to the right component in the 631: * JComboBox. If the comboBox is editable then focus is sent to 632: * ComboBoxEditor, otherwise it is delegated to JComboBox. 633: * 634: * @param e MouseEvent 635: */ 636: protected void delegateFocus(MouseEvent e) 637: { 638: // FIXME: Need to implement 639: } 640: 641: /** 642: * This method displays combo box popup if the popup is not currently shown 643: * on the screen and hides it if it is currently visible 644: */ 645: protected void togglePopup() 646: { 647: if (BasicComboPopup.this.isVisible()) 648: hide(); 649: else 650: show(); 651: } 652: 653: /** 654: * DOCUMENT ME! 655: * 656: * @param e DOCUMENT ME! 657: * 658: * @return DOCUMENT ME! 659: */ 660: protected MouseEvent convertMouseEvent(MouseEvent e) 661: { 662: return null; 663: } 664: 665: /** 666: * Returns required height of the popup such that number of items visible in 667: * it are equal to the maximum row count. By default 668: * comboBox.maximumRowCount=8 669: * 670: * @param maxRowCount number of maximum visible rows in the combo box's 671: * popup list of items 672: * 673: * @return height of the popup required to fit number of items equal to 674: * JComboBox.maximumRowCount. 675: */ 676: protected int getPopupHeightForRowCount(int maxRowCount) 677: { 678: int totalHeight = 0; 679: ListCellRenderer rend = list.getCellRenderer(); 680: 681: if (comboBox.getItemCount() < maxRowCount) 682: maxRowCount = comboBox.getItemCount(); 683: 684: for (int i = 0; i < maxRowCount; i++) 685: { 686: Component comp = rend.getListCellRendererComponent(list, 687: comboBox.getModel() 688: .getElementAt(i), 689: -1, false, false); 690: Dimension dim = comp.getPreferredSize(); 691: totalHeight += dim.height; 692: } 693: 694: return totalHeight; 695: } 696: 697: /** 698: * DOCUMENT ME! 699: * 700: * @param px DOCUMENT ME! 701: * @param py DOCUMENT ME! 702: * @param pw DOCUMENT ME! 703: * @param ph DOCUMENT ME! 704: * 705: * @return DOCUMENT ME! 706: */ 707: protected Rectangle computePopupBounds(int px, int py, int pw, int ph) 708: { 709: return new Rectangle(px, py, pw, ph); 710: } 711: 712: /** 713: * This method changes the selection in the list to the item over which the 714: * mouse is currently located. 715: * 716: * @param anEvent MouseEvent 717: * @param shouldScroll DOCUMENT ME! 718: */ 719: protected void updateListBoxSelectionForEvent(MouseEvent anEvent, 720: boolean shouldScroll) 721: { 722: // TODO: We need to handle the shouldScroll parameter somehow. 723: int index = list.locationToIndex(anEvent.getPoint()); 724: // Check for valid index. 725: if (index >= 0) 726: list.setSelectedIndex(index); 727: } 728: 729: /** 730: * InvocationMouseHandler is a listener that listens to mouse events 731: * occuring in the combo box. Note that this listener doesn't listen to 732: * mouse events occuring in the popup portion of the combo box, it only 733: * listens to main combo box part(area that displays selected item). This 734: * listener is responsible for showing and hiding popup portion of the 735: * combo box. 736: */ 737: protected class InvocationMouseHandler extends MouseAdapter 738: { 739: /** 740: * Creates a new InvocationMouseHandler object. 741: */ 742: protected InvocationMouseHandler() 743: { 744: // Nothing to do here. 745: } 746: 747: /** 748: * This method is invoked whenever mouse is being pressed over the main 749: * part of the combo box. This method will show popup if the popup is 750: * not shown on the screen right now, and it will hide popup otherwise. 751: * 752: * @param e MouseEvent that should be handled 753: */ 754: public void mousePressed(MouseEvent e) 755: { 756: if (comboBox.isEnabled()) 757: togglePopup(); 758: } 759: 760: /** 761: * This method is invoked whenever mouse event was originated in the combo 762: * box and released either in the combBox list of items or in the combo 763: * box itself. 764: * 765: * @param e MouseEvent that should be handled 766: */ 767: public void mouseReleased(MouseEvent e) 768: { 769: // Get component over which mouse was released 770: Component src = (Component) e.getSource(); 771: int x = e.getX(); 772: int y = e.getY(); 773: Component releasedComponent = SwingUtilities.getDeepestComponentAt(src, 774: x, y); 775: 776: // if mouse was released inside the bounds of combo box then do nothing, 777: // Otherwise if mouse was released inside the list of combo box items 778: // then change selection and close popup 779: if (! (releasedComponent instanceof JComboBox)) 780: { 781: // List model contains the item over which mouse is released, 782: // since it is updated every time the mouse is moved over a different 783: // item in the list. Now that the mouse is released we need to 784: // update model of the combo box as well. 785: comboBox.setSelectedIndex(list.getSelectedIndex()); 786: 787: if (isAutoScrolling) 788: stopAutoScrolling(); 789: hide(); 790: } 791: } 792: } 793: 794: /** 795: * InvocationMouseMotionListener is a mouse listener that listens to mouse 796: * dragging events occuring in the combo box. 797: */ 798: protected class InvocationMouseMotionHandler extends MouseMotionAdapter 799: { 800: /** 801: * Creates a new InvocationMouseMotionHandler object. 802: */ 803: protected InvocationMouseMotionHandler() 804: { 805: // Nothing to do here. 806: } 807: 808: /** 809: * This method is responsible for highlighting item in the drop down list 810: * over which the mouse is currently being dragged. 811: */ 812: public void mouseDragged(MouseEvent e) 813: { 814: // convert point of the drag event relative to combo box list component 815: // figure out over which list cell the mouse is currently being dragged 816: // and highlight the cell. The list model is changed but the change has 817: // no effect on combo box's data model. The list model is changed so 818: // that the appropriate item would be highlighted in the combo box's 819: // list. 820: if (BasicComboPopup.this.isVisible()) 821: { 822: int cbHeight = (int) comboBox.getPreferredSize().getHeight(); 823: int popupHeight = BasicComboPopup.this.getSize().height; 824: 825: // if mouse is dragged inside the the combo box's items list. 826: if (e.getY() > cbHeight && ! (e.getY() - cbHeight >= popupHeight)) 827: { 828: int index = list.locationToIndex(new Point(e.getX(), 829: (int) (e.getY() 830: - cbHeight))); 831: 832: int firstVisibleIndex = list.getFirstVisibleIndex(); 833: 834: // list.locationToIndex returns item's index that would 835: // be located at the specified point if the first item that 836: // is visible is item 0. However in the JComboBox it is not 837: // necessarily the case since list is contained in the 838: // JScrollPane so we need to adjust the index returned. 839: if (firstVisibleIndex != 0) 840: // FIXME: adjusted index here is off by one. I am adding one 841: // here to compensate for that. This should be 842: // index += firstVisibleIndex. Remove +1 once the bug is fixed. 843: index += firstVisibleIndex + 1; 844: 845: list.setSelectedIndex(index); 846: } 847: else 848: { 849: // if mouse is being dragged at the bottom of combo box's list 850: // of items or at the very top then scroll the list in the 851: // desired direction. 852: boolean movingUP = e.getY() < cbHeight; 853: boolean movingDown = e.getY() > cbHeight; 854: 855: if (movingUP) 856: { 857: scrollDirection = SCROLL_UP; 858: startAutoScrolling(SCROLL_UP); 859: } 860: else if (movingDown) 861: { 862: scrollDirection = SCROLL_DOWN; 863: startAutoScrolling(SCROLL_DOWN); 864: } 865: } 866: } 867: } 868: } 869: 870: /** 871: * ItemHandler is an item listener that listens to selection events occuring 872: * in the combo box. FIXME: should specify here what it does when item is 873: * selected or deselected in the combo box list. 874: */ 875: protected class ItemHandler extends Object implements ItemListener 876: { 877: /** 878: * Creates a new ItemHandler object. 879: */ 880: protected ItemHandler() 881: { 882: // Nothing to do here. 883: } 884: 885: /** 886: * This method responds to the selection events occuring in the combo box. 887: * 888: * @param e ItemEvent specifying the combo box's selection 889: */ 890: public void itemStateChanged(ItemEvent e) 891: { 892: // TODO: What should be done here? 893: } 894: } 895: 896: /** 897: * ListMouseHandler is a listener that listens to mouse events occuring in 898: * the combo box's list of items. This class is responsible for hiding 899: * popup portion of the combo box if the mouse is released inside the combo 900: * box's list. 901: */ 902: protected class ListMouseHandler extends MouseAdapter 903: { 904: protected ListMouseHandler() 905: { 906: // Nothing to do here. 907: } 908: 909: public void mousePressed(MouseEvent e) 910: { 911: // TODO: What should be do here? 912: } 913: 914: public void mouseReleased(MouseEvent anEvent) 915: { 916: int index = list.locationToIndex(anEvent.getPoint()); 917: // Check for valid index. 918: if (index >= 0) 919: comboBox.setSelectedIndex(index); 920: hide(); 921: } 922: } 923: 924: /** 925: * ListMouseMotionHandler listens to mouse motion events occuring in the 926: * combo box's list. This class is responsible for highlighting items in 927: * the list when mouse is moved over them 928: */ 929: protected class ListMouseMotionHandler extends MouseMotionAdapter 930: { 931: protected ListMouseMotionHandler() 932: { 933: // Nothing to do here. 934: } 935: 936: public void mouseMoved(MouseEvent anEvent) 937: { 938: updateListBoxSelectionForEvent(anEvent, false); 939: } 940: } 941: 942: /** 943: * This class listens to changes occuring in the bound properties of the 944: * combo box 945: */ 946: protected class PropertyChangeHandler extends Object 947: implements PropertyChangeListener 948: { 949: protected PropertyChangeHandler() 950: { 951: // Nothing to do here. 952: } 953: 954: public void propertyChange(PropertyChangeEvent e) 955: { 956: if (e.getPropertyName().equals("renderer")) 957: { 958: list.setCellRenderer((ListCellRenderer) e.getNewValue()); 959: revalidate(); 960: repaint(); 961: } 962: if (e.getPropertyName().equals("dataModel")) 963: { 964: list.setModel((ComboBoxModel) e.getNewValue()); 965: revalidate(); 966: repaint(); 967: } 968: } 969: } 970: 971: // ------ private helper methods -------------------- 972: 973: /** 974: * This method uninstalls listeners installed by the UI 975: */ 976: private void uninstallListeners() 977: { 978: uninstallListListeners(); 979: uninstallComboBoxListeners(); 980: uninstallComboBoxModelListeners(comboBox.getModel()); 981: } 982: 983: /** 984: * This method uninstalls Listeners registered with combo boxes list of 985: * items 986: */ 987: private void uninstallListListeners() 988: { 989: list.removeMouseListener(listMouseListener); 990: listMouseListener = null; 991: 992: list.removeMouseMotionListener(listMouseMotionListener); 993: listMouseMotionListener = null; 994: } 995: 996: /** 997: * This method uninstalls listeners listening to combo box associated with 998: * this popup menu 999: */ 1000: private void uninstallComboBoxListeners() 1001: { 1002: comboBox.removeMouseListener(mouseListener); 1003: mouseListener = null; 1004: 1005: comboBox.removeMouseMotionListener(mouseMotionListener); 1006: mouseMotionListener = null; 1007: 1008: comboBox.removeItemListener(itemListener); 1009: itemListener = null; 1010: 1011: comboBox.removePropertyChangeListener(propertyChangeListener); 1012: propertyChangeListener = null; 1013: } 1014: 1015: // -------------------------------------------------------------------- 1016: // The following classes are here only for backwards API compatibility 1017: // They aren't used. 1018: // -------------------------------------------------------------------- 1019: 1020: /** 1021: * This class is not used any more. 1022: */ 1023: public class ListDataHandler extends Object implements ListDataListener 1024: { 1025: public ListDataHandler() 1026: { 1027: // Nothing to do here. 1028: } 1029: 1030: public void contentsChanged(ListDataEvent e) 1031: { 1032: // Nothing to do here. 1033: } 1034: 1035: public void intervalAdded(ListDataEvent e) 1036: { 1037: // Nothing to do here. 1038: } 1039: 1040: public void intervalRemoved(ListDataEvent e) 1041: { 1042: // Nothing to do here. 1043: } 1044: } 1045: 1046: /** 1047: * This class is not used anymore 1048: */ 1049: protected class ListSelectionHandler extends Object 1050: implements ListSelectionListener 1051: { 1052: protected ListSelectionHandler() 1053: { 1054: // Nothing to do here. 1055: } 1056: 1057: public void valueChanged(ListSelectionEvent e) 1058: { 1059: // Nothing to do here. 1060: } 1061: } 1062: 1063: /** 1064: * This class is not used anymore 1065: */ 1066: public class InvocationKeyHandler extends KeyAdapter 1067: { 1068: public InvocationKeyHandler() 1069: { 1070: // Nothing to do here. 1071: } 1072: 1073: public void keyReleased(KeyEvent e) 1074: { 1075: // Nothing to do here. 1076: } 1077: } 1078: }
GNU Classpath (0.20) |