8051548: JColorChooser should have a way to disable transparency controls
authoralexsch
Wed, 26 Aug 2015 17:21:01 +0400
changeset 32488 02db7857c66d
parent 32487 7706754a1498
child 32490 b891099ba2e9
8051548: JColorChooser should have a way to disable transparency controls Reviewed-by: prr, serb
jdk/src/java.desktop/share/classes/javax/swing/JColorChooser.java
jdk/src/java.desktop/share/classes/javax/swing/colorchooser/AbstractColorChooserPanel.java
jdk/src/java.desktop/share/classes/javax/swing/colorchooser/ColorChooserPanel.java
jdk/src/java.desktop/share/classes/javax/swing/colorchooser/ColorPanel.java
jdk/src/java.desktop/share/classes/javax/swing/colorchooser/SlidingSpinner.java
jdk/test/javax/swing/JColorChooser/Test8051548.java
--- 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;
+    }
+}