diff --git a/src/java.desktop/share/classes/javax/swing/DefaultListCellRenderer.java b/src/java.desktop/share/classes/javax/swing/DefaultListCellRenderer.java index 64b24c8b9f5..a0750a13bfa 100644 --- a/src/java.desktop/share/classes/javax/swing/DefaultListCellRenderer.java +++ b/src/java.desktop/share/classes/javax/swing/DefaultListCellRenderer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2023, 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 @@ -25,15 +25,15 @@ package javax.swing; -import javax.swing.*; -import javax.swing.event.*; -import javax.swing.border.*; - -import java.awt.Component; import java.awt.Color; +import java.awt.Component; import java.awt.Rectangle; - import java.io.Serializable; + +import javax.swing.border.Border; +import javax.swing.border.EmptyBorder; +import javax.swing.plaf.synth.SynthListUI; + import sun.swing.DefaultLookup; import sun.swing.SwingUtilities2; @@ -157,7 +157,11 @@ public class DefaultListCellRenderer extends JLabel setText((value == null) ? "" : value.toString()); } - setEnabled(list.isEnabled()); + if (list.getName() == null || !list.getName().equals("ComboBox.list") + || !(list.getUI() instanceof SynthListUI)) { + setEnabled(list.isEnabled()); + } + setFont(list.getFont()); Border border = null; diff --git a/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthComboBoxUI.java b/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthComboBoxUI.java index 70560f093c7..77ca2a1fc05 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthComboBoxUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthComboBoxUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2023, 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 @@ -39,6 +39,7 @@ import java.beans.PropertyChangeListener; import javax.swing.ComboBoxEditor; import javax.swing.DefaultButtonModel; +import javax.swing.DefaultListCellRenderer; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JComboBox; @@ -108,6 +109,8 @@ public class SynthComboBoxUI extends BasicComboBoxUI implements */ private EditorFocusHandler editorFocusHandler; + private DlcrEnabledHandler dlcrEnabledHandler; + /** * If true, then the cell renderer will be forced to be non-opaque when * used for rendering the selected item in the combo box (not in the list), @@ -187,6 +190,7 @@ public class SynthComboBoxUI extends BasicComboBoxUI implements comboBox.addPropertyChangeListener(this); comboBox.addMouseListener(buttonHandler); editorFocusHandler = new EditorFocusHandler(comboBox); + dlcrEnabledHandler = new DlcrEnabledHandler(comboBox); super.installListeners(); } @@ -219,6 +223,7 @@ public class SynthComboBoxUI extends BasicComboBoxUI implements @Override protected void uninstallListeners() { editorFocusHandler.unregister(); + dlcrEnabledHandler.unregister(); comboBox.removePropertyChangeListener(this); comboBox.removeMouseListener(buttonHandler); buttonHandler.pressed = false; @@ -822,4 +827,36 @@ public class SynthComboBoxUI extends BasicComboBoxUI implements } } } + + /** + * Handler for updating combobox enabled status when renderer enabled + * status changes + */ + private static class DlcrEnabledHandler implements PropertyChangeListener { + private JComboBox comboBox; + + private DlcrEnabledHandler(JComboBox comboBox) { + this.comboBox = comboBox; + comboBox.addPropertyChangeListener("enabled",this); + } + + public void unregister() { + comboBox.removePropertyChangeListener("enabled", this); + } + + /** + * Called when the combos enabled status changes + * + * @param evt A PropertyChangeEvent object describing the event source + * and the property that has changed. + */ + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("enabled")) { + if (comboBox.getRenderer() instanceof DefaultListCellRenderer) { + ((DefaultListCellRenderer) comboBox.getRenderer()) + .setEnabled((boolean) evt.getNewValue()); + } + } + } + } } diff --git a/test/jdk/javax/swing/JComboBox/DisabledComboBoxFontTestAuto.java b/test/jdk/javax/swing/JComboBox/DisabledComboBoxFontTestAuto.java new file mode 100644 index 00000000000..49b1dbc016a --- /dev/null +++ b/test/jdk/javax/swing/JComboBox/DisabledComboBoxFontTestAuto.java @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2023, 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. + */ + +/* + * @test + * @bug 7093691 + * @summary Tests if JComboBox has correct font color when disabled/enabled + * @run main/othervm -Dsun.java2d.uiScale=1 DisabledComboBoxFontTestAuto + */ + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; + +import javax.imageio.ImageIO; +import javax.swing.DefaultListCellRenderer; +import javax.swing.JComboBox; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; + +import static java.awt.image.BufferedImage.TYPE_INT_ARGB; + +public class DisabledComboBoxFontTestAuto { + private static JComboBox combo, combo2; + private static BufferedImage enabledImage, disabledImage, enabledImage2, disabledImage2; + private static Path testDir; + private static String lafName; + private static StringBuffer failingLafs; + private static int COMBO_HEIGHT, COMBO_WIDTH, COMBO2_HEIGHT, COMBO2_WIDTH; + + private static void createCombo() { + combo = new JComboBox(); + combo.addItem("Simple JComboBox"); + combo.setRenderer(new DefaultListCellRenderer()); + combo2 = new JComboBox(); + combo2.addItem("Simple JComboBox"); + COMBO_WIDTH = (int) combo.getPreferredSize().getWidth(); + COMBO_HEIGHT = (int) combo.getPreferredSize().getHeight(); + COMBO2_WIDTH = (int) combo2.getPreferredSize().getWidth(); + COMBO2_HEIGHT = (int) combo2.getPreferredSize().getHeight(); + combo.setSize(COMBO_WIDTH, COMBO_HEIGHT); + combo2.setSize(COMBO2_WIDTH, COMBO2_HEIGHT); + } + + private static void paintCombo() { + combo.setEnabled(true); + enabledImage = new BufferedImage(COMBO_WIDTH, COMBO_HEIGHT, TYPE_INT_ARGB); + Graphics2D graphics2D = enabledImage.createGraphics(); + combo.paint(graphics2D); + graphics2D.dispose(); + combo.setEnabled(false); + disabledImage = new BufferedImage(COMBO_WIDTH, COMBO_HEIGHT, TYPE_INT_ARGB); + graphics2D = disabledImage.createGraphics(); + combo.paint(graphics2D); + graphics2D.dispose(); + combo2.setEnabled(true); + enabledImage2 = new BufferedImage(COMBO2_WIDTH, COMBO2_HEIGHT, TYPE_INT_ARGB); + graphics2D = enabledImage2.createGraphics(); + combo2.paint(graphics2D); + graphics2D.dispose(); + combo2.setEnabled(false); + disabledImage2 = new BufferedImage(COMBO2_WIDTH, COMBO2_HEIGHT, TYPE_INT_ARGB); + graphics2D = disabledImage2.createGraphics(); + combo2.paint(graphics2D); + graphics2D.dispose(); + } + + private static void testMethod() throws IOException { + ImageIO.write(enabledImage, "png", new File(testDir + + "/" + lafName + "Enabled.png")); + ImageIO.write(disabledImage, "png", new File(testDir + + "/" + lafName + "Disabled.png")); + ImageIO.write(enabledImage2, "png", new File(testDir + + "/" + lafName + "EnabledDLCR.png")); + ImageIO.write(disabledImage2, "png", new File(testDir + + "/" + lafName + "DisabledDLCR.png")); + + boolean isIdentical = true; + Color eColor1, eColor2, dColor1, dColor2; + + // Use center line to compare RGB values + int y = 10; + for (int x = (enabledImage.getWidth() / 2) - 20; + x < (enabledImage.getWidth() / 2) + 20; x++) { + // Nimbus has a pixel offset in coordinates since Nimbus is 2px + // smaller in width than other L&F's + if (lafName.equals("Nimbus")) { + eColor1 = new Color(enabledImage.getRGB(x + 1, y)); + eColor2 = new Color(enabledImage2.getRGB(x, y)); + dColor1 = new Color(disabledImage.getRGB(x + 1, y)); + dColor2 = new Color(disabledImage2.getRGB(x, y)); + } else { + eColor1 = new Color(enabledImage.getRGB(x, y)); + eColor2 = new Color(enabledImage2.getRGB(x, y)); + dColor1 = new Color(disabledImage.getRGB(x, y)); + dColor2 = new Color(disabledImage2.getRGB(x, y)); + } + if ((!isColorMatching(eColor1, eColor2)) || (!isColorMatching(dColor1, dColor2))) { + isIdentical = false; + break; + } + } + + if (isIdentical) { + System.out.println("PASSED"); + } else { + failingLafs.append(lafName + ", "); + } + } + + private static boolean isColorMatching(Color c1, Color c2) { + if ((c1.getRed() != c2.getRed()) + || (c1.getBlue() != c2.getBlue()) + || (c1.getGreen() != c2.getGreen())) { + + System.out.println(lafName + " Enabled RGB failure: " + + c1.getRed() + ", " + + c1.getBlue() + ", " + + c1.getGreen() + " vs " + + c2.getRed() + ", " + + c2.getBlue() + ", " + + c2.getGreen()); + return false; + } + return true; + } + + private static void setLookAndFeel(UIManager.LookAndFeelInfo laf) { + try { + UIManager.setLookAndFeel(laf.getClassName()); + } catch (UnsupportedLookAndFeelException ignored){ + System.out.println("Unsupported LookAndFeel: " + laf.getClassName()); + } catch (ClassNotFoundException | InstantiationException | + IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + public static void main(String[] args) throws Exception { + lafName = "null"; + failingLafs = new StringBuffer(); + testDir = Path.of(System.getProperty("test.classes", ".")); + for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) { + // Change Motif LAF name to avoid using slash in saved image file path + lafName = laf.getName().equals("CDE/Motif") ? "Motif" : laf.getName(); + SwingUtilities.invokeAndWait(() -> setLookAndFeel(laf)); + SwingUtilities.invokeAndWait(DisabledComboBoxFontTestAuto::createCombo); + SwingUtilities.invokeAndWait(DisabledComboBoxFontTestAuto::paintCombo); + testMethod(); + } + if (!failingLafs.isEmpty()) { + // Remove trailing comma and whitespace + failingLafs.setLength(failingLafs.length() - 2); + throw new RuntimeException("FAIL - Enabled and disabled ComboBox " + + "does not match in these LAFs: " + failingLafs); + } + } +}