8165234: Provide a way to not close toggle menu items on mouse click on component level
Reviewed-by: serb, ssadetsky
This commit is contained in:
parent
d055089575
commit
63a1a87940
@ -33,6 +33,7 @@ import javax.swing.plaf.basic.BasicCheckBoxMenuItemUI;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import sun.swing.SwingUtilities2;
|
||||
|
||||
|
||||
/**
|
||||
@ -89,7 +90,8 @@ public class MotifCheckBoxMenuItemUI extends BasicCheckBoxMenuItemUI
|
||||
Point p = e.getPoint();
|
||||
if(p.x >= 0 && p.x < menuItem.getWidth() &&
|
||||
p.y >= 0 && p.y < menuItem.getHeight()) {
|
||||
if (UIManager.getBoolean("CheckBoxMenuItem.closeOnMouseClick")) {
|
||||
String property = "CheckBoxMenuItem.doNotCloseOnMouseClick";
|
||||
if (!SwingUtilities2.getBoolean(menuItem, property)) {
|
||||
manager.clearSelectedPath();
|
||||
}
|
||||
menuItem.doClick(0);
|
||||
|
@ -33,6 +33,7 @@ import javax.swing.plaf.basic.BasicRadioButtonMenuItemUI;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.io.Serializable;
|
||||
import sun.swing.SwingUtilities2;
|
||||
|
||||
|
||||
/**
|
||||
@ -97,8 +98,8 @@ public class MotifRadioButtonMenuItemUI extends BasicRadioButtonMenuItemUI
|
||||
Point p = e.getPoint();
|
||||
if(p.x >= 0 && p.x < menuItem.getWidth() &&
|
||||
p.y >= 0 && p.y < menuItem.getHeight()) {
|
||||
String property = "RadioButtonMenuItem.closeOnMouseClick";
|
||||
if (UIManager.getBoolean(property)) {
|
||||
String property = "RadioButtonMenuItem.doNotCloseOnMouseClick";
|
||||
if (!SwingUtilities2.getBoolean(menuItem, property)) {
|
||||
manager.clearSelectedPath();
|
||||
}
|
||||
menuItem.doClick(0);
|
||||
|
@ -58,10 +58,13 @@ import javax.accessibility.*;
|
||||
* <p>
|
||||
* Some times it is required to select several check box menu items from a menu.
|
||||
* In this case it is useful that clicking on one check box menu item does not
|
||||
* close the menu. Such behavior can be controlled by the Look and Feel property
|
||||
* named {@code "CheckBoxMenuItem.closeOnMouseClick"}. The default value is
|
||||
* {@code true}. Setting the property to {@code false} prevents the menu from
|
||||
* closing when it is clicked by the mouse.
|
||||
* close the menu. Such behavior can be controlled either by client
|
||||
* {@link JComponent#putClientProperty} or the Look and Feel
|
||||
* {@link UIManager#put} property named
|
||||
* {@code "CheckBoxMenuItem.doNotCloseOnMouseClick"}. The default value is
|
||||
* {@code false}. Setting the property to {@code true} prevents the menu from
|
||||
* closing when it is clicked by the mouse. If the client property is set its
|
||||
* value is always used; otherwise the {@literal L&F} property is queried.
|
||||
* Note: some {@code L&F}s may ignore this property. All built-in {@code L&F}s
|
||||
* inherit this behaviour.
|
||||
* <p>
|
||||
|
@ -52,10 +52,13 @@ import javax.accessibility.*;
|
||||
* <p>
|
||||
* Some menus can have several button groups with radio button menu items. In
|
||||
* this case it is useful that clicking on one radio button menu item does not
|
||||
* close the menu. Such behavior can be controlled by the Look and Feel property
|
||||
* named {@code "RadioButtonMenuItem.closeOnMouseClick"}. The default value is
|
||||
* {@code true}. Setting the property to {@code false} prevents the menu from
|
||||
* closing when it is clicked by the mouse.
|
||||
* close the menu. Such behavior can be controlled either by client
|
||||
* {@link JComponent#putClientProperty} or the Look and Feel
|
||||
* {@link UIManager#put} property named
|
||||
* {@code "RadioButtonMenuItem.doNotCloseOnMouseClick"}. The default value is
|
||||
* {@code false}. Setting the property to {@code true} prevents the menu from
|
||||
* closing when it is clicked by the mouse. If the client property is set its
|
||||
* value is always used; otherwise the {@literal L&F} property is queried.
|
||||
* Note: some {@code L&F}s may ignore this property. All built-in {@code L&F}s
|
||||
* inherit this behaviour.
|
||||
* <p>
|
||||
|
@ -1055,7 +1055,6 @@ public abstract class BasicLookAndFeel extends LookAndFeel implements Serializab
|
||||
"RadioButtonMenuItem.checkIcon", radioButtonMenuItemIcon,
|
||||
"RadioButtonMenuItem.arrowIcon", menuItemArrowIcon,
|
||||
"RadioButtonMenuItem.commandSound", null,
|
||||
"RadioButtonMenuItem.closeOnMouseClick", Boolean.TRUE,
|
||||
|
||||
"CheckBoxMenuItem.font", dialogPlain12,
|
||||
"CheckBoxMenuItem.acceleratorFont", dialogPlain12,
|
||||
@ -1072,7 +1071,6 @@ public abstract class BasicLookAndFeel extends LookAndFeel implements Serializab
|
||||
"CheckBoxMenuItem.checkIcon", checkBoxMenuItemIcon,
|
||||
"CheckBoxMenuItem.arrowIcon", menuItemArrowIcon,
|
||||
"CheckBoxMenuItem.commandSound", null,
|
||||
"CheckBoxMenuItem.closeOnMouseClick", Boolean.TRUE,
|
||||
|
||||
"Menu.font", dialogPlain12,
|
||||
"Menu.acceleratorFont", dialogPlain12,
|
||||
|
@ -936,13 +936,15 @@ public class BasicMenuItemUI extends MenuItemUI
|
||||
}
|
||||
}
|
||||
|
||||
boolean closeOnMouseClick() {
|
||||
boolean doNotCloseOnMouseClick() {
|
||||
if (menuItem instanceof JCheckBoxMenuItem) {
|
||||
return UIManager.getBoolean("CheckBoxMenuItem.closeOnMouseClick");
|
||||
String property = "CheckBoxMenuItem.doNotCloseOnMouseClick";
|
||||
return SwingUtilities2.getBoolean(menuItem, property);
|
||||
} else if (menuItem instanceof JRadioButtonMenuItem) {
|
||||
return UIManager.getBoolean("RadioButtonMenuItem.closeOnMouseClick");
|
||||
String property = "RadioButtonMenuItem.doNotCloseOnMouseClick";
|
||||
return SwingUtilities2.getBoolean(menuItem, property);
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -967,7 +969,7 @@ public class BasicMenuItemUI extends MenuItemUI
|
||||
BasicLookAndFeel.playSound(menuItem, getPropertyPrefix() +
|
||||
".commandSound");
|
||||
}
|
||||
if (closeOnMouseClick()) {
|
||||
if (!doNotCloseOnMouseClick()) {
|
||||
// Visual feedback
|
||||
if (msm == null) {
|
||||
msm = MenuSelectionManager.defaultManager();
|
||||
|
@ -2046,6 +2046,25 @@ public class SwingUtilities2 {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the client property for the given key if it is set; otherwise
|
||||
* returns the {@L&F} property.
|
||||
*
|
||||
* @param component the component
|
||||
* @param key an {@code String} specifying the key for the desired boolean value
|
||||
* @return the boolean value of the client property if it is set or the {@L&F}
|
||||
* property in other case.
|
||||
*/
|
||||
public static boolean getBoolean(JComponent component, String key) {
|
||||
Object clientProperty = component.getClientProperty(key);
|
||||
|
||||
if (clientProperty instanceof Boolean) {
|
||||
return Boolean.TRUE.equals(clientProperty);
|
||||
}
|
||||
|
||||
return UIManager.getBoolean(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to listen to "blit" repaints in RepaintManager.
|
||||
*/
|
||||
|
@ -37,45 +37,67 @@ import javax.swing.UIManager;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8158566 8160879 8160977
|
||||
* @bug 8158566 8160879 8160977 8158566
|
||||
* @summary Provide a Swing property which modifies MenuItemUI behaviour
|
||||
*/
|
||||
public class CloseOnMouseClickPropertyTest {
|
||||
|
||||
private static final String CHECK_BOX_PROP = "CheckBoxMenuItem."
|
||||
+ "doNotCloseOnMouseClick";
|
||||
private static final String RADIO_BUTTON_PROP = "RadioButtonMenuItem"
|
||||
+ ".doNotCloseOnMouseClick";
|
||||
|
||||
private static JFrame frame;
|
||||
private static JMenu menu;
|
||||
|
||||
private static TestItem[] TEST_ITEMS = {
|
||||
new TestItem(TestType.CHECK_BOX_MENU_ITEM, true, true),
|
||||
new TestItem(TestType.CHECK_BOX_MENU_ITEM, true, false),
|
||||
new TestItem(TestType.CHECK_BOX_MENU_ITEM, false, true),
|
||||
new TestItem(TestType.CHECK_BOX_MENU_ITEM, false, false),
|
||||
|
||||
new TestItem(TestType.CHECK_BOX_MENU_ITEM, null, true),
|
||||
new TestItem(TestType.CHECK_BOX_MENU_ITEM, null, false),
|
||||
new TestItem(TestType.CHECK_BOX_MENU_ITEM, true, null),
|
||||
new TestItem(TestType.CHECK_BOX_MENU_ITEM, false, null),
|
||||
|
||||
|
||||
new TestItem(TestType.RADIO_BUTTON_MENU_ITEM, true, true),
|
||||
new TestItem(TestType.RADIO_BUTTON_MENU_ITEM, true, false),
|
||||
new TestItem(TestType.RADIO_BUTTON_MENU_ITEM, false, true),
|
||||
new TestItem(TestType.RADIO_BUTTON_MENU_ITEM, false, false),
|
||||
|
||||
new TestItem(TestType.RADIO_BUTTON_MENU_ITEM, true, null),
|
||||
new TestItem(TestType.RADIO_BUTTON_MENU_ITEM, false, null),
|
||||
new TestItem(TestType.RADIO_BUTTON_MENU_ITEM, null, true),
|
||||
new TestItem(TestType.RADIO_BUTTON_MENU_ITEM, null, false),
|
||||
|
||||
new TestItem(TestType.MENU_ITEM, true, true),
|
||||
new TestItem(TestType.MENU_ITEM, true, false),
|
||||
new TestItem(TestType.MENU_ITEM, false, true),
|
||||
new TestItem(TestType.MENU_ITEM, false, false),
|
||||
|
||||
new TestItem(TestType.MENU_ITEM, true, null),
|
||||
new TestItem(TestType.MENU_ITEM, false, null),
|
||||
new TestItem(TestType.MENU_ITEM, null, true),
|
||||
new TestItem(TestType.MENU_ITEM, null, false),
|
||||
};
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
|
||||
UIManager.setLookAndFeel(info.getClassName());
|
||||
test(true);
|
||||
|
||||
setProperty(false);
|
||||
test(false);
|
||||
|
||||
setProperty(true);
|
||||
test(true);
|
||||
for (TestItem testItem : TEST_ITEMS) {
|
||||
test(testItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void setProperty(boolean closeOnMouseClick) {
|
||||
UIManager.put("CheckBoxMenuItem.closeOnMouseClick", closeOnMouseClick);
|
||||
UIManager.put("RadioButtonMenuItem.closeOnMouseClick", closeOnMouseClick);
|
||||
}
|
||||
|
||||
private static void test(boolean closeOnMouseClick) throws Exception {
|
||||
for (TestType testType : TestType.values()) {
|
||||
test(testType, closeOnMouseClick);
|
||||
}
|
||||
}
|
||||
|
||||
private static void test(TestType testType, boolean closeOnMouseClick)
|
||||
throws Exception {
|
||||
private static void test(TestItem item) throws Exception {
|
||||
|
||||
Robot robot = new Robot();
|
||||
robot.setAutoDelay(50);
|
||||
SwingUtilities.invokeAndWait(() -> createAndShowGUI(testType));
|
||||
SwingUtilities.invokeAndWait(() -> createAndShowGUI(item));
|
||||
robot.waitForIdle();
|
||||
|
||||
Point point = getClickPoint(true);
|
||||
@ -94,21 +116,13 @@ public class CloseOnMouseClickPropertyTest {
|
||||
JMenuItem menuItem = menu.getItem(0);
|
||||
boolean isShowing = menuItem.isShowing();
|
||||
frame.dispose();
|
||||
|
||||
if (TestType.MENU_ITEM.equals(testType)) {
|
||||
if (isShowing) {
|
||||
throw new RuntimeException("Menu Item is not closed!");
|
||||
}
|
||||
} else {
|
||||
if (isShowing ^ !closeOnMouseClick) {
|
||||
throw new RuntimeException("Property is not taken into account:"
|
||||
+ " closeOnMouseClick");
|
||||
}
|
||||
if (isShowing ^ item.doNotCloseOnMouseClick()) {
|
||||
throw new RuntimeException("Property is not taken into account!");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void createAndShowGUI(TestType testType) {
|
||||
private static void createAndShowGUI(TestItem testItem) {
|
||||
|
||||
frame = new JFrame();
|
||||
frame.setSize(300, 300);
|
||||
@ -116,23 +130,15 @@ public class CloseOnMouseClickPropertyTest {
|
||||
|
||||
JMenuBar menuBar = new JMenuBar();
|
||||
menu = new JMenu("Menu");
|
||||
menu.add(getMenuItem(testType));
|
||||
JMenuItem menuItem = testItem.getMenuItem();
|
||||
testItem.setProperties(menuItem);
|
||||
menu.add(menuItem);
|
||||
menuBar.add(menu);
|
||||
|
||||
frame.setJMenuBar(menuBar);
|
||||
frame.setVisible(true);
|
||||
}
|
||||
|
||||
private static JMenuItem getMenuItem(TestType testType) {
|
||||
switch (testType) {
|
||||
case CHECK_BOX_MENU_ITEM:
|
||||
return new JCheckBoxMenuItem("Check Box");
|
||||
case RADIO_BUTTON_MENU_ITEM:
|
||||
return new JRadioButtonMenuItem("Radio Button");
|
||||
default:
|
||||
return new JMenuItem("Menu Item");
|
||||
}
|
||||
}
|
||||
|
||||
private static Point getClickPoint(boolean parent) throws Exception {
|
||||
Point points[] = new Point[1];
|
||||
|
||||
@ -157,4 +163,60 @@ public class CloseOnMouseClickPropertyTest {
|
||||
CHECK_BOX_MENU_ITEM,
|
||||
RADIO_BUTTON_MENU_ITEM
|
||||
}
|
||||
}
|
||||
|
||||
static class TestItem {
|
||||
|
||||
TestType type;
|
||||
Boolean compDoNotCloseOnMouseClick;
|
||||
Boolean lafDoNotCloseOnMouseClick;
|
||||
|
||||
public TestItem(TestType type,
|
||||
Boolean compDoNotCloseOnMouseClick,
|
||||
Boolean lafDoNotCloseOnMouseClick)
|
||||
{
|
||||
this.type = type;
|
||||
this.compDoNotCloseOnMouseClick = compDoNotCloseOnMouseClick;
|
||||
this.lafDoNotCloseOnMouseClick = lafDoNotCloseOnMouseClick;
|
||||
}
|
||||
|
||||
boolean doNotCloseOnMouseClick() {
|
||||
switch (type) {
|
||||
case MENU_ITEM:
|
||||
return false;
|
||||
default:
|
||||
return compDoNotCloseOnMouseClick != null
|
||||
? compDoNotCloseOnMouseClick
|
||||
: lafDoNotCloseOnMouseClick;
|
||||
}
|
||||
}
|
||||
|
||||
void setProperties(JMenuItem menuItem) {
|
||||
switch (type) {
|
||||
case CHECK_BOX_MENU_ITEM:
|
||||
menuItem.putClientProperty(CHECK_BOX_PROP, compDoNotCloseOnMouseClick);
|
||||
UIManager.put(CHECK_BOX_PROP, lafDoNotCloseOnMouseClick);
|
||||
break;
|
||||
case RADIO_BUTTON_MENU_ITEM:
|
||||
menuItem.putClientProperty(RADIO_BUTTON_PROP, compDoNotCloseOnMouseClick);
|
||||
UIManager.put(RADIO_BUTTON_PROP, lafDoNotCloseOnMouseClick);
|
||||
break;
|
||||
default:
|
||||
menuItem.putClientProperty(CHECK_BOX_PROP, compDoNotCloseOnMouseClick);
|
||||
menuItem.putClientProperty(RADIO_BUTTON_PROP, compDoNotCloseOnMouseClick);
|
||||
UIManager.put(CHECK_BOX_PROP, lafDoNotCloseOnMouseClick);
|
||||
UIManager.put(RADIO_BUTTON_PROP, lafDoNotCloseOnMouseClick);
|
||||
}
|
||||
}
|
||||
|
||||
JMenuItem getMenuItem() {
|
||||
switch (type) {
|
||||
case CHECK_BOX_MENU_ITEM:
|
||||
return new JCheckBoxMenuItem("Check Box");
|
||||
case RADIO_BUTTON_MENU_ITEM:
|
||||
return new JRadioButtonMenuItem("Radio Button");
|
||||
default:
|
||||
return new JMenuItem("Menu Item");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user