I extended the menu closing mechanism from yesterday so that arbitrary
popups can now register with the BasicLookAndFeel to get autoclosed when
the user clicks outside of the popup. I also changed the BasicComboPopup
to use this, so that now ComboBoxes close automatically and reliably
when the user clicks outside the combobox.
2006-02-24 Roman Kennke <[EMAIL PROTECTED]>
* javax/swing/plaf/basic/BasicLookAndFeel.java
(PopupHelper.autoClosePopups): New field.
(PopupHelper.mousePressed): Also autoclose any registered popups.
(PopupHelper.registerForAutoClose): New method.
(PopupHelper.autoClosePopups): New method.
(popupHelper): Changed type of field to PopupHelper.
(registerForAutoClose): New method.
* javax/swing/plaf/basic/BasicComboPopup.java
(show): Register this popup for autoclosing.
/Roman
Index: javax/swing/plaf/basic/BasicLookAndFeel.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java,v
retrieving revision 1.85
diff -u -r1.85 BasicLookAndFeel.java
--- javax/swing/plaf/basic/BasicLookAndFeel.java 23 Feb 2006 23:57:50 -0000 1.85
+++ javax/swing/plaf/basic/BasicLookAndFeel.java 24 Feb 2006 11:57:38 -0000
@@ -52,7 +52,10 @@
import java.io.InputStream;
import java.io.Serializable;
import java.util.Enumeration;
+import java.util.Iterator;
import java.util.ResourceBundle;
+import java.util.Set;
+import java.util.WeakHashMap;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
@@ -63,9 +66,11 @@
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
+import javax.swing.JPopupMenu;
import javax.swing.KeyStroke;
import javax.swing.LookAndFeel;
import javax.swing.MenuSelectionManager;
+import javax.swing.SwingUtilities;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.border.BevelBorder;
@@ -99,6 +104,11 @@
{
/**
+ * Registered popups for autoclose.
+ */
+ private WeakHashMap autoClosePopups = new WeakHashMap();
+
+ /**
* Receives an event from the event queue.
*
* @param event
@@ -120,12 +130,52 @@
*/
private void mousePressed(MouseEvent ev)
{
+ // Autoclose all menus managed by the MenuSelectionManager.
MenuSelectionManager m = MenuSelectionManager.defaultManager();
Component target = ev.getComponent();
if (target instanceof Container)
target = ((Container) target).findComponentAt(ev.getPoint());
if (! m.isComponentPartOfCurrentMenu(target))
m.clearSelectedPath();
+
+ // Handle other registered popup instances, like ComboBox popups.
+ autoClosePopups(ev, target);
+ }
+
+ /**
+ * Registers Popup and its content to be autoclosed when a mouseclick
+ * occurs outside of the popup.
+ *
+ * @param popup the popup to be autoclosed when clicked outside
+ */
+ void registerForAutoClose(JPopupMenu popup)
+ {
+ autoClosePopups.put(popup, null);
+ }
+
+ /**
+ * Automatically closes all popups that are not 'hit' by the mouse event.
+ *
+ * @param ev the mouse event
+ * @param target the target of the mouse event
+ */
+ private void autoClosePopups(MouseEvent ev, Component target)
+ {
+ if (autoClosePopups.size() != 0)
+ {
+ Set popups = autoClosePopups.keySet();
+ Iterator i = popups.iterator();
+ while (i.hasNext())
+ {
+ JPopupMenu popup = (JPopupMenu) i.next();
+ if (!(target == popup
+ || SwingUtilities.isDescendingFrom(target, popup)))
+ {
+ popup.setVisible(false);
+ i.remove();
+ }
+ }
+ }
}
}
@@ -192,7 +242,7 @@
/**
* Helps closing menu popups when user clicks outside of the menu area.
*/
- private transient AWTEventListener popupHelper;
+ private transient PopupHelper popupHelper;
private ActionMap audioActionMap;
@@ -1598,4 +1648,17 @@
toolkit.removeAWTEventListener(popupHelper);
popupHelper = null;
}
+
+ /**
+ * Registers a JPopupMenu for autoclosing when a mouseclick occurs outside
+ * of the JPopupMenu. This must be called when the popup gets opened. The
+ * popup is unregistered from autoclosing as soon as it either got closed
+ * by this helper, or when it has been garbage collected.
+ *
+ * @param popup the popup menu to autoclose
+ */
+ void registerForAutoClose(JPopupMenu popup)
+ {
+ popupHelper.registerForAutoClose(popup);
+ }
}
Index: javax/swing/plaf/basic/BasicComboPopup.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicComboPopup.java,v
retrieving revision 1.12
diff -u -r1.12 BasicComboPopup.java
--- javax/swing/plaf/basic/BasicComboPopup.java 19 Dec 2005 09:44:31 -0000 1.12
+++ javax/swing/plaf/basic/BasicComboPopup.java 24 Feb 2006 11:57:38 -0000
@@ -69,6 +69,7 @@
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
+import javax.swing.UIManager;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.event.ListSelectionEvent;
@@ -193,6 +194,11 @@
if (selectedIndex > comboBox.getMaximumRowCount())
scrollbar.setValue(getPopupHeightForRowCount(selectedIndex));
+ // Register this popup to be autoclosed when user clicks outside the
+ // popup.
+ BasicLookAndFeel laf = (BasicLookAndFeel) UIManager.getLookAndFeel();
+ laf.registerForAutoClose(this);
+
// location specified is relative to comboBox
super.show(comboBox, 0, cbBounds.height);
}