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