8051548: JColorChooser should have a way to disable transparency controls
Reviewed-by: prr, serb
--- a/jdk/src/java.desktop/share/classes/javax/swing/JColorChooser.java Wed Aug 26 18:03:21 2015 +0300
+++ b/jdk/src/java.desktop/share/classes/javax/swing/JColorChooser.java Wed Aug 26 17:21:01 2015 +0400
@@ -133,13 +133,42 @@
* returns true.
* @see java.awt.GraphicsEnvironment#isHeadless
*/
+ public static Color showDialog(Component component,
+ String title, Color initialColor) throws HeadlessException {
+ return showDialog(component, title, initialColor, true);
+ }
+
+ /**
+ * Shows a modal color-chooser dialog and blocks until the
+ * dialog is hidden. If the user presses the "OK" button, then
+ * this method hides/disposes the dialog and returns the selected color.
+ * If the user presses the "Cancel" button or closes the dialog without
+ * pressing "OK", then this method hides/disposes the dialog and returns
+ * <code>null</code>.
+ *
+ * @param component the parent <code>Component</code> for the dialog
+ * @param title the String containing the dialog's title
+ * @param initialColor the initial Color set when the color-chooser is shown
+ * @param colorTransparencySelectionEnabled true if the transparency of
+ * a color can be selected
+ * @return the selected color or <code>null</code> if the user opted out
+ * @exception HeadlessException if GraphicsEnvironment.isHeadless()
+ * returns true.
+ * @see java.awt.GraphicsEnvironment#isHeadless
+ */
@SuppressWarnings("deprecation")
- public static Color showDialog(Component component,
- String title, Color initialColor) throws HeadlessException {
+ public static Color showDialog(Component component, String title,
+ Color initialColor, boolean colorTransparencySelectionEnabled)
+ throws HeadlessException {
final JColorChooser pane = new JColorChooser(initialColor != null?
initialColor : Color.white);
+ for (AbstractColorChooserPanel ccPanel : pane.getChooserPanels()) {
+ ccPanel.setColorTransparencySelectionEnabled(
+ colorTransparencySelectionEnabled);
+ }
+
ColorTracker ok = new ColorTracker(pane);
JDialog dialog = createDialog(component, title, true, pane, ok, null);
@@ -150,7 +179,6 @@
return ok.getColor();
}
-
/**
* Creates and returns a new dialog containing the specified
* <code>ColorChooser</code> pane along with "OK", "Cancel", and "Reset"
--- a/jdk/src/java.desktop/share/classes/javax/swing/colorchooser/AbstractColorChooserPanel.java Wed Aug 26 18:03:21 2015 +0300
+++ b/jdk/src/java.desktop/share/classes/javax/swing/colorchooser/AbstractColorChooserPanel.java Wed Aug 26 17:21:01 2015 +0400
@@ -50,6 +50,14 @@
@SuppressWarnings("serial") // Same-version serialization only
public abstract class AbstractColorChooserPanel extends JPanel {
+
+ /**
+ * Identifies that the transparency of the color (alpha value) can be
+ * selected
+ */
+ public static final String TRANSPARENCY_ENABLED_PROPERTY
+ = "TransparencyEnabled";
+
private final PropertyChangeListener enabledListener = new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
Object value = event.getNewValue();
@@ -202,6 +210,40 @@
}
/**
+ * Sets whether color chooser panel allows to select the transparency
+ * (alpha value) of a color.
+ * This method fires a property-changed event, using the string value of
+ * {@code TRANSPARENCY_ENABLED_PROPERTY} as the name
+ * of the property.
+ *
+ * <p>The value is a hint and may not be applicable to all types of chooser
+ * panel.
+ *
+ * <p>The default value is {@code true}.
+ *
+ * @param b true if the transparency of a color can be selected
+ *
+ * @beaninfo
+ * bound: true
+ * description: Sets the transparency of a color selection on or off.
+ *
+ * @see #isColorTransparencySelectionEnabled()
+ */
+ public void setColorTransparencySelectionEnabled(boolean b){
+ }
+
+ /**
+ * Gets whether color chooser panel allows to select the transparency
+ * (alpha value) of a color.
+ *
+ * @return true if the transparency of a color can be selected
+ * @see #setColorTransparencySelectionEnabled(boolean)
+ */
+ public boolean isColorTransparencySelectionEnabled(){
+ return true;
+ }
+
+ /**
* Draws the panel.
* @param g the <code>Graphics</code> object
*/
--- a/jdk/src/java.desktop/share/classes/javax/swing/colorchooser/ColorChooserPanel.java Wed Aug 26 18:03:21 2015 +0300
+++ b/jdk/src/java.desktop/share/classes/javax/swing/colorchooser/ColorChooserPanel.java Wed Aug 26 17:21:01 2015 +0400
@@ -176,6 +176,21 @@
return null;
}
+ @Override
+ public void setColorTransparencySelectionEnabled(boolean b){
+ boolean oldValue = isColorTransparencySelectionEnabled();
+ if (b != oldValue) {
+ panel.setColorTransparencySelectionEnabled(b);
+ firePropertyChange(TRANSPARENCY_ENABLED_PROPERTY,
+ oldValue, b);
+ }
+ }
+
+ @Override
+ public boolean isColorTransparencySelectionEnabled(){
+ return panel.isColorTransparencySelectionEnabled();
+ }
+
public void propertyChange(PropertyChangeEvent event) {
ColorSelectionModel model = getColorSelectionModel();
if (model != null) {
--- a/jdk/src/java.desktop/share/classes/javax/swing/colorchooser/ColorPanel.java Wed Aug 26 18:03:21 2015 +0300
+++ b/jdk/src/java.desktop/share/classes/javax/swing/colorchooser/ColorPanel.java Wed Aug 26 17:21:01 2015 +0400
@@ -145,7 +145,7 @@
}
void colorChanged() {
- this.color = new Color(getColor(0), true);
+ this.color = new Color(getColor(0), isColorTransparencySelectionEnabled());
Object parent = getParent();
if (parent instanceof ColorChooserPanel) {
ColorChooserPanel chooser = (ColorChooserPanel) parent;
@@ -208,6 +208,17 @@
return this.model.getColor(this.values);
}
+ void setColorTransparencySelectionEnabled(boolean b) {
+ if (spinners[model.getCount() - 1].isVisible() != b) {
+ spinners[model.getCount() - 1].setVisible(b);
+ colorChanged();
+ }
+ }
+
+ boolean isColorTransparencySelectionEnabled() {
+ return spinners[model.getCount() - 1].isVisible();
+ }
+
private void setValue(int index) {
this.values[index] = this.spinners[index].getValue();
}
--- a/jdk/src/java.desktop/share/classes/javax/swing/colorchooser/SlidingSpinner.java Wed Aug 26 18:03:21 2015 +0300
+++ b/jdk/src/java.desktop/share/classes/javax/swing/colorchooser/SlidingSpinner.java Wed Aug 26 17:21:01 2015 +0400
@@ -95,6 +95,10 @@
this.spinner.setVisible(visible);
}
+ boolean isVisible() {
+ return this.slider.isVisible();
+ }
+
public void stateChanged(ChangeEvent event) {
if (!this.internal) {
if (this.spinner == event.getSource()) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/JColorChooser/Test8051548.java Wed Aug 26 17:21:01 2015 +0400
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Frame;
+import java.awt.Robot;
+import java.awt.event.KeyEvent;
+import java.util.function.Predicate;
+import javax.swing.JColorChooser;
+import javax.swing.JFormattedTextField;
+import javax.swing.JFrame;
+import javax.swing.JTabbedPane;
+import javax.swing.SwingUtilities;
+import javax.swing.colorchooser.AbstractColorChooserPanel;
+
+/*
+ * @test
+ * @bug 8051548
+ * @summary JColorChooser should have a way to disable transparency controls
+ * @author Alexandr Scherbatiy
+ * @run main Test8051548
+ */
+
+public class Test8051548 {
+
+ private static final String[][] TABS = {
+ {"HSV", "0"},
+ {"HSL", "0"},
+ {"RGB", "255"},
+ {"CMYK", "255"}
+ };
+
+ private static JColorChooser colorChooser;
+ private static boolean propertyChangeListenerInvoked;
+ private static volatile Color color;
+
+ public static void main(String[] args) throws Exception {
+ testColorPanels();
+ testShowDialog(true);
+ testShowDialog(false);
+ }
+
+ private static void testColorPanels() throws Exception {
+ SwingUtilities.invokeAndWait(() -> createAndShowGUI());
+
+ Robot robot = new Robot();
+ robot.setAutoDelay(50);
+ robot.waitForIdle();
+
+ for (String[] tabs : TABS) {
+ final String tab = tabs[0];
+ final String initialValue = tabs[1];
+
+ SwingUtilities.invokeAndWait(() -> {
+
+ colorChooser.setColor(new Color(50, 100, 85));
+ JTabbedPane tabbedPane =
+ (JTabbedPane) findComponent(colorChooser, "JTabbedPane");
+ int index = tabbedPane.indexOfTab(tab);
+ tabbedPane.setSelectedIndex(index);
+
+ AbstractColorChooserPanel colorChooserPanel
+ = (AbstractColorChooserPanel) findComponent(
+ tabbedPane.getComponent(index), "ColorChooserPanel");
+
+ propertyChangeListenerInvoked = false;
+ colorChooserPanel.addPropertyChangeListener((e) -> {
+ if (AbstractColorChooserPanel.TRANSPARENCY_ENABLED_PROPERTY.
+ equals(e.getPropertyName())) {
+ propertyChangeListenerInvoked = true;
+ if(!(Boolean)e.getOldValue()){
+ throw new RuntimeException("Old color transparency"
+ + " selection property should be true!");
+ }
+ if((Boolean)e.getNewValue()){
+ throw new RuntimeException("New color transparency"
+ + " selection property should be false!");
+ }
+ }
+ });
+
+ if (!colorChooserPanel.isColorTransparencySelectionEnabled()) {
+ throw new RuntimeException("Color transparency selection"
+ + " should be enabled by default");
+ }
+
+ JFormattedTextField transparencyTextField = (JFormattedTextField)
+ findTextField(colorChooserPanel, initialValue);
+
+ if (!transparencyTextField.isEnabled()) {
+ throw new RuntimeException("Transparency controls are"
+ + " disabled by default!");
+ }
+
+ transparencyTextField.setValue(50);
+
+ if(!colorHasAlpha()){
+ throw new RuntimeException("Transparency selection should"
+ + " be enabled!");
+ }
+
+ colorChooserPanel.setColorTransparencySelectionEnabled(false);
+
+ if (colorChooserPanel.isColorTransparencySelectionEnabled()) {
+ throw new RuntimeException("Color transparency selection"
+ + " should be disabled!");
+ }
+
+ if(!propertyChangeListenerInvoked){
+ throw new RuntimeException("Property change listener is not"
+ + " invoked!");
+ }
+
+ if(colorHasAlpha()){
+ throw new RuntimeException("Transparency selection should"
+ + " be disabled!");
+ }
+ });
+
+ robot.waitForIdle();
+ }
+
+ }
+
+ static void testShowDialog(boolean colorTransparencySelectionEnabled) throws Exception {
+ int alphaValue = 123;
+ Robot robot = new Robot();
+ robot.setAutoDelay(50);
+
+ SwingUtilities.invokeLater(() -> {
+ color = JColorChooser.showDialog(null, "Change Color",
+ new Color(10, 20, 30, alphaValue),
+ colorTransparencySelectionEnabled);
+ });
+
+ SwingUtilities.invokeAndWait(() -> {
+ // wait for dialog is shown
+ });
+
+ robot.waitForIdle();
+
+ robot.keyPress(KeyEvent.VK_ENTER);
+ robot.keyRelease(KeyEvent.VK_ENTER);
+ robot.waitForIdle();
+
+ if (colorTransparencySelectionEnabled) {
+ if (color.getAlpha() != alphaValue) {
+ throw new RuntimeException("Color alpha has not bee reseted!");
+ }
+ } else {
+ if (color.getAlpha() != 255) {
+ throw new RuntimeException("Color alpha has not bee reseted!");
+ }
+ }
+ }
+
+ private static boolean colorHasAlpha(){
+ return colorChooser.getColor().getAlpha() != 255;
+ }
+
+ private static void createAndShowGUI() {
+ JFrame frame = new JFrame();
+ frame.setSize(700, 500);
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ colorChooser = new JColorChooser();
+ frame.getContentPane().add(colorChooser);
+ frame.setVisible(true);
+ }
+
+ private static Component findComponent(Component component, String name) {
+ return findComponent(component,
+ (comp) -> comp.getClass().getName().contains(name));
+ }
+
+ private static Component findTextField(Component component, String value) {
+ return findComponent(component, (comp) -> {
+
+ if (comp instanceof JFormattedTextField) {
+ JFormattedTextField textField = (JFormattedTextField) comp;
+ return value.equals(textField.getText());
+ }
+ return false;
+ });
+ }
+
+ private static Component findComponent(Component component,
+ Predicate<Component> predicate) {
+
+ if (predicate.test(component)) {
+ return component;
+ }
+
+ if (component instanceof Container) {
+ Container container = (Container) component;
+ for (int i = 0; i < container.getComponentCount(); i++) {
+ Component child = findComponent(container.getComponent(i),
+ predicate);
+ if (child != null) {
+ return child;
+ }
+ }
+ }
+
+ return null;
+ }
+}