summaryrefslogtreecommitdiff
path: root/javax/swing/plaf/basic/BasicComboPopup.java
diff options
context:
space:
mode:
authorRoman Kennke <roman@kennke.org>2006-03-17 15:37:01 +0000
committerRoman Kennke <roman@kennke.org>2006-03-17 15:37:01 +0000
commite619403db6c54e61295a3f30da29a3c32cab021b (patch)
tree762b38112fe32ca782126625bd6bb0ba5832818f /javax/swing/plaf/basic/BasicComboPopup.java
parent476d62cbd231c9e24881a3cbcb8a99de5164cbbe (diff)
downloadclasspath-e619403db6c54e61295a3f30da29a3c32cab021b.tar.gz
2006-03-17 Roman Kennke <kennke@aicas.com>
* javax/swing/plaf/basic/BasicComboPopup.java (BasicComboPopup): Create listeners here. Configure components here. (show): Correctly calculate bounds using computePopupBounds(). Make scroller fixed-size. Removed special autocloser handling. (hide): Rewritten to use MenuSelectionHandler. (createList): Don't set selection mode here. (configureList): Correctly install colors and fonts and selectionMode. (createScroller): Set scrollpane policies. (configureScroller): Make scroller and scrollbar not-focusable. (configurePopup): Make popup opaque and borderPainted. (installComboBoxListeners): Don't install mouse listener on ComboBox. (delegateFocus): Implemented. (convertMouseEvent): Implemented. (updateListBoxSelectionForEvent): Implemented to also handle autoscrolling. (InvocationMouseHandler.mousePressed): Delegate focus correctly. Only open popup on left mouse-click. (InvocationMouseHandler.mouseReleased): Rewritten. (InvocationMouseMotionHandler.mouseDragged): Rewritten to better support autoscrolling. (ItemHandler.itemStateChanged): Implemented to sync selection with the comboBox. (ListMouseHandler.mouseReleased): Fetch selected index directly from list. (ListMouseMotionHandler.mouseMoved): Only update when mouse is inside the list box. (PropertyChangeHandler.propertyChange): Don't revalidate/repaint here. When model changes, then update listeners correctly. (uninstallListeners): Don't uninstall list listeners. (uninstallComboBoxListeners): Don't uninstall mouse listeners from comboBox. (syncSelection): New helper method.
Diffstat (limited to 'javax/swing/plaf/basic/BasicComboPopup.java')
-rw-r--r--javax/swing/plaf/basic/BasicComboPopup.java347
1 files changed, 184 insertions, 163 deletions
diff --git a/javax/swing/plaf/basic/BasicComboPopup.java b/javax/swing/plaf/basic/BasicComboPopup.java
index 798101d0d..aa058b87d 100644
--- a/javax/swing/plaf/basic/BasicComboPopup.java
+++ b/javax/swing/plaf/basic/BasicComboPopup.java
@@ -59,13 +59,13 @@ import java.beans.PropertyChangeListener;
import javax.swing.BorderFactory;
import javax.swing.ComboBoxModel;
import javax.swing.JComboBox;
-import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPopupMenu;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.ListCellRenderer;
import javax.swing.ListSelectionModel;
+import javax.swing.MenuSelectionManager;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
@@ -165,9 +165,17 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup
public BasicComboPopup(JComboBox comboBox)
{
this.comboBox = comboBox;
- installComboBoxListeners();
+ mouseListener = createMouseListener();
+ mouseMotionListener = createMouseMotionListener();
+ keyListener = createKeyListener();
+
+ list = createList();
+ configureList();
+ scroller = createScroller();
+ configureScroller();
configurePopup();
- setLightWeightPopupEnabled(comboBox.isLightWeightPopupEnabled());
+ installComboBoxListeners();
+ installKeyboardActions();
}
/**
@@ -175,50 +183,40 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup
*/
public void show()
{
- Rectangle cbBounds = comboBox.getBounds();
+ Dimension size = comboBox.getSize();
+ size.height = getPopupHeightForRowCount(comboBox.getMaximumRowCount());
+ Rectangle bounds = computePopupBounds(0, comboBox.getBounds().height,
+ size.width, size.height);
- // popup should have same width as the comboBox and should be hight anough
- // to display number of rows equal to 'maximumRowCount' property
- int popupHeight = getPopupHeightForRowCount(comboBox.getMaximumRowCount());
+ scroller.setMaximumSize(bounds.getSize());
+ scroller.setPreferredSize(bounds.getSize());
+ scroller.setMinimumSize(bounds.getSize());
+ list.invalidate();
- scroller.setPreferredSize(new Dimension(cbBounds.width, popupHeight));
- pack();
-
- // Highlight selected item in the combo box's drop down list
- if (comboBox.getSelectedIndex() != -1)
- list.setSelectedIndex(comboBox.getSelectedIndex());
-
- //scroll scrollbar s.t. selected item is visible
- JScrollBar scrollbar = scroller.getVerticalScrollBar();
- int selectedIndex = comboBox.getSelectedIndex();
- if (selectedIndex > comboBox.getMaximumRowCount())
- scrollbar.setValue(getPopupHeightForRowCount(selectedIndex));
-
- // We put the autoclose-registration inside an InvocationEvent, so that
- // the same event that triggered this show() call won't hide the popup
- // immediately.
- SwingUtilities.invokeLater
- (new Runnable()
- {
- public void run()
- {
- // Register this popup to be autoclosed when user clicks outside the
- // popup.
- BasicLookAndFeel laf = (BasicLookAndFeel) UIManager.getLookAndFeel();
- laf.registerForAutoClose(BasicComboPopup.this);
- }});
-
- // location specified is relative to comboBox
- super.show(comboBox, 0, cbBounds.height);
+ syncListSelection();
- }
+ list.ensureIndexIsVisible(list.getSelectedIndex());
+ setLightWeightPopupEnabled(comboBox.isLightWeightPopupEnabled());
+ show(comboBox, bounds.x, bounds.y); }
/**
* This method hides drop down list of items
*/
public void hide()
{
- super.setVisible(false);
+ MenuSelectionManager menuSelectionManager =
+ MenuSelectionManager.defaultManager();
+ javax.swing.MenuElement[] menuElements =
+ menuSelectionManager.getSelectedPath();
+ for (int i = 0; i < menuElements.length; i++)
+ {
+ if (menuElements[i] == this)
+ {
+ menuSelectionManager.clearSelectedPath();
+ break;
+ }
+ }
+ comboBox.repaint();
}
/**
@@ -270,7 +268,6 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup
public void uninstallingUI()
{
uninstallComboBoxModelListeners(comboBox.getModel());
-
uninstallListeners();
uninstallKeyboardActions();
}
@@ -446,7 +443,6 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup
protected JList createList()
{
JList l = new JList(comboBox.getModel());
- l.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
return l;
}
@@ -456,9 +452,18 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup
*/
protected void configureList()
{
- list.setModel(comboBox.getModel());
- list.setVisibleRowCount(comboBox.getMaximumRowCount());
+ list.setFont(comboBox.getFont());
+ list.setForeground(comboBox.getForeground());
+ list.setBackground(comboBox.getBackground());
+ Color sfg = UIManager.getColor("ComboBox.selectionForeground");
+ list.setSelectionForeground(sfg);
+ Color sbg = UIManager.getColor("ComboBox.selectionBackground");
+ list.setSelectionBackground(sbg);
+ list.setBorder(null);
+ list.setCellRenderer(comboBox.getRenderer());
list.setFocusable(false);
+ syncListSelection();
+ list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
installListListeners();
}
@@ -489,7 +494,8 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup
*/
protected JScrollPane createScroller()
{
- return new JScrollPane();
+ return new JScrollPane(list, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
+ JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
}
/**
@@ -498,8 +504,8 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup
protected void configureScroller()
{
scroller.setBorder(null);
- scroller.getViewport().setView(list);
- scroller.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+ scroller.setFocusable(false);
+ scroller.getVerticalScrollBar().setFocusable(false);
}
/**
@@ -508,18 +514,11 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup
*/
protected void configurePopup()
{
+ setBorderPainted(true);
setBorder(BorderFactory.createLineBorder(Color.BLACK));
- // initialize list that will be used to display combo box's items
- this.list = createList();
- ((JLabel) list.getCellRenderer()).setHorizontalAlignment(SwingConstants.LEFT);
- configureList();
-
- // initialize scroller. Add list to the scroller.
- scroller = createScroller();
- configureScroller();
-
- // add scroller with list inside of it to JPopupMenu
- super.add(scroller);
+ setOpaque(false);
+ add(scroller);
+ setFocusable(false);
}
/*
@@ -528,20 +527,14 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup
*/
protected void installComboBoxListeners()
{
- // mouse listener that listens to mouse event in combo box
- mouseListener = createMouseListener();
- comboBox.addMouseListener(mouseListener);
-
- // mouse listener that listens to mouse dragging events in the combo box
- mouseMotionListener = createMouseMotionListener();
- comboBox.addMouseMotionListener(mouseMotionListener);
-
// item listener listenening to selection events in the combo box
itemListener = createItemListener();
comboBox.addItemListener(itemListener);
propertyChangeListener = createPropertyChangeListener();
comboBox.addPropertyChangeListener(propertyChangeListener);
+
+ installComboBoxModelListeners(comboBox.getModel());
}
/**
@@ -651,7 +644,10 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup
*/
protected void delegateFocus(MouseEvent e)
{
- // FIXME: Need to implement
+ if (comboBox.isEditable())
+ comboBox.getEditor().getEditorComponent().requestFocus();
+ else
+ comboBox.requestFocus();
}
/**
@@ -660,7 +656,7 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup
*/
protected void togglePopup()
{
- if (BasicComboPopup.this.isVisible())
+ if (isVisible())
hide();
else
show();
@@ -675,7 +671,14 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup
*/
protected MouseEvent convertMouseEvent(MouseEvent e)
{
- return null;
+ Point point = SwingUtilities.convertPoint((Component) e.getSource(),
+ e.getPoint(), list);
+ MouseEvent newEvent= new MouseEvent((Component) e.getSource(),
+ e.getID(), e.getWhen(),
+ e.getModifiers(), point.x, point.y,
+ e.getModifiers(),
+ e.isPopupTrigger());
+ return newEvent;
}
/**
@@ -735,11 +738,24 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup
protected void updateListBoxSelectionForEvent(MouseEvent anEvent,
boolean shouldScroll)
{
- // TODO: We need to handle the shouldScroll parameter somehow.
- int index = list.locationToIndex(anEvent.getPoint());
- // Check for valid index.
- if (index >= 0)
- list.setSelectedIndex(index);
+ Point point = anEvent.getPoint();
+ if (list != null)
+ {
+ int index = list.locationToIndex(point);
+ if (index == -1)
+ {
+ if (point.y < 0)
+ index = 0;
+ else
+ index = comboBox.getModel().getSize() - 1;
+ }
+ if (list.getSelectedIndex() != index)
+ {
+ list.setSelectedIndex(index);
+ if (shouldScroll)
+ list.ensureIndexIsVisible(index);
+ }
+ }
}
/**
@@ -769,8 +785,11 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup
*/
public void mousePressed(MouseEvent e)
{
- if (comboBox.isEnabled())
- togglePopup();
+ if (SwingUtilities.isLeftMouseButton(e) && comboBox.isEnabled())
+ {
+ delegateFocus(e);
+ togglePopup();
+ }
}
/**
@@ -782,28 +801,27 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup
*/
public void mouseReleased(MouseEvent e)
{
- // Get component over which mouse was released
- Component src = (Component) e.getSource();
- int x = e.getX();
- int y = e.getY();
- Component releasedComponent = SwingUtilities.getDeepestComponentAt(src,
- x, y);
-
- // if mouse was released inside the bounds of combo box then do nothing,
+ Component component = (Component) e.getSource();
+ Dimension size = component.getSize();
+ Rectangle bounds = new Rectangle(0, 0, size.width - 1, size.height - 1);
+ // If mouse was released inside the bounds of combo box then do nothing,
// Otherwise if mouse was released inside the list of combo box items
// then change selection and close popup
- if (! (releasedComponent instanceof JComboBox))
+ if (! bounds.contains(e.getPoint()))
{
- // List model contains the item over which mouse is released,
- // since it is updated every time the mouse is moved over a different
- // item in the list. Now that the mouse is released we need to
- // update model of the combo box as well.
- comboBox.setSelectedIndex(list.getSelectedIndex());
-
- if (isAutoScrolling)
- stopAutoScrolling();
+ MouseEvent convEvent = convertMouseEvent(e);
+ Point point = convEvent.getPoint();
+ Rectangle visRect = new Rectangle();
+ list.computeVisibleRect(visRect);
+ if (visRect.contains(point))
+ {
+ updateListBoxSelectionForEvent(convEvent, false);
+ comboBox.setSelectedIndex(list.getSelectedIndex());
+ }
hide();
}
+ hasEntered = false;
+ stopAutoScrolling();
}
}
@@ -827,58 +845,42 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup
*/
public void mouseDragged(MouseEvent e)
{
- // convert point of the drag event relative to combo box list component
- // figure out over which list cell the mouse is currently being dragged
- // and highlight the cell. The list model is changed but the change has
- // no effect on combo box's data model. The list model is changed so
- // that the appropriate item would be highlighted in the combo box's
- // list.
- if (BasicComboPopup.this.isVisible())
+ if (isVisible())
{
- int cbHeight = (int) comboBox.getPreferredSize().getHeight();
- int popupHeight = BasicComboPopup.this.getSize().height;
-
- // if mouse is dragged inside the the combo box's items list.
- if (e.getY() > cbHeight && ! (e.getY() - cbHeight >= popupHeight))
- {
- int index = list.locationToIndex(new Point(e.getX(),
- (int) (e.getY()
- - cbHeight)));
-
- int firstVisibleIndex = list.getFirstVisibleIndex();
-
- // list.locationToIndex returns item's index that would
- // be located at the specified point if the first item that
- // is visible is item 0. However in the JComboBox it is not
- // necessarily the case since list is contained in the
- // JScrollPane so we need to adjust the index returned.
- if (firstVisibleIndex != 0)
- // FIXME: adjusted index here is off by one. I am adding one
- // here to compensate for that. This should be
- // index += firstVisibleIndex. Remove +1 once the bug is fixed.
- index += firstVisibleIndex + 1;
-
- list.setSelectedIndex(index);
- }
- else
- {
- // if mouse is being dragged at the bottom of combo box's list
- // of items or at the very top then scroll the list in the
- // desired direction.
- boolean movingUP = e.getY() < cbHeight;
- boolean movingDown = e.getY() > cbHeight;
-
- if (movingUP)
- {
- scrollDirection = SCROLL_UP;
- startAutoScrolling(SCROLL_UP);
- }
- else if (movingDown)
- {
- scrollDirection = SCROLL_DOWN;
- startAutoScrolling(SCROLL_DOWN);
- }
- }
+ MouseEvent convEvent = convertMouseEvent(e);
+ Rectangle visRect = new Rectangle();
+ list.computeVisibleRect(visRect);
+ if (convEvent.getPoint().y >= visRect.y
+ && (convEvent.getPoint().y <= visRect.y + visRect.height - 1))
+ {
+ hasEntered = true;
+ if (isAutoScrolling)
+ stopAutoScrolling();
+ Point point = convEvent.getPoint();
+ if (visRect.contains(point))
+ {
+ valueIsAdjusting = true;
+ updateListBoxSelectionForEvent(convEvent, false);
+ valueIsAdjusting = false;
+ }
+ }
+ else if (hasEntered)
+ {
+ int dir = convEvent.getPoint().y < visRect.y ? SCROLL_UP
+ : SCROLL_DOWN;
+ if (isAutoScrolling && scrollDirection != dir)
+ {
+ stopAutoScrolling();
+ startAutoScrolling(dir);
+ }
+ else if (!isAutoScrolling)
+ startAutoScrolling(dir);
+ }
+ else if (e.getPoint().y < 0)
+ {
+ hasEntered = true;
+ startAutoScrolling(SCROLL_UP);
+ }
}
}
}
@@ -905,7 +907,13 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup
*/
public void itemStateChanged(ItemEvent e)
{
- // TODO: What should be done here?
+ if (e.getStateChange() == ItemEvent.SELECTED && ! valueIsAdjusting)
+ {
+ valueIsAdjusting = true;
+ syncListSelection();
+ valueIsAdjusting = false;
+ list.ensureIndexIsVisible(comboBox.getSelectedIndex());
+ }
}
}
@@ -924,15 +932,12 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup
public void mousePressed(MouseEvent e)
{
- // TODO: What should be do here?
+ // Nothing to do here.
}
public void mouseReleased(MouseEvent anEvent)
{
- int index = list.locationToIndex(anEvent.getPoint());
- // Check for valid index.
- if (index >= 0)
- comboBox.setSelectedIndex(index);
+ comboBox.setSelectedIndex(list.getSelectedIndex());
hide();
}
}
@@ -951,7 +956,15 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup
public void mouseMoved(MouseEvent anEvent)
{
- updateListBoxSelectionForEvent(anEvent, false);
+ Point point = anEvent.getPoint();
+ Rectangle visRect = new Rectangle();
+ list.computeVisibleRect(visRect);
+ if (visRect.contains(point))
+ {
+ valueIsAdjusting = true;
+ updateListBoxSelectionForEvent(anEvent, false);
+ valueIsAdjusting = false;
+ }
}
}
@@ -971,15 +984,21 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup
{
if (e.getPropertyName().equals("renderer"))
{
- list.setCellRenderer((ListCellRenderer) e.getNewValue());
- revalidate();
- repaint();
+ list.setCellRenderer(comboBox.getRenderer());
+ if (isVisible())
+ hide();
}
- if (e.getPropertyName().equals("dataModel"))
+ if (e.getPropertyName().equals("model"))
{
- list.setModel((ComboBoxModel) e.getNewValue());
- revalidate();
- repaint();
+ ComboBoxModel oldModel = (ComboBoxModel) e.getOldValue();
+ uninstallComboBoxModelListeners(oldModel);
+ ComboBoxModel newModel = (ComboBoxModel) e.getNewValue();
+ list.setModel(newModel);
+ installComboBoxModelListeners(newModel);
+ if (comboBox.getItemCount() > 0)
+ comboBox.setSelectedIndex(0);
+ if (isVisible())
+ hide();
}
}
}
@@ -991,7 +1010,6 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup
*/
private void uninstallListeners()
{
- uninstallListListeners();
uninstallComboBoxListeners();
uninstallComboBoxModelListeners(comboBox.getModel());
}
@@ -1015,12 +1033,6 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup
*/
private void uninstallComboBoxListeners()
{
- comboBox.removeMouseListener(mouseListener);
- mouseListener = null;
-
- comboBox.removeMouseMotionListener(mouseMotionListener);
- mouseMotionListener = null;
-
comboBox.removeItemListener(itemListener);
itemListener = null;
@@ -1028,6 +1040,15 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup
propertyChangeListener = null;
}
+ void syncListSelection()
+ {
+ int index = comboBox.getSelectedIndex();
+ if (index == -1)
+ list.clearSelection();
+ else
+ list.setSelectedIndex(index);
+ }
+
// --------------------------------------------------------------------
// The following classes are here only for backwards API compatibility
// They aren't used.