diff --git a/src/share/classes/javax/swing/plaf/nimbus/Defaults.template b/src/share/classes/javax/swing/plaf/nimbus/Defaults.template index caff0b212a04bc1046618d7e0b6b4f9d35e229d7..10894b5f047c1daea93220896e61be98efc6109a 100644 --- a/src/share/classes/javax/swing/plaf/nimbus/Defaults.template +++ b/src/share/classes/javax/swing/plaf/nimbus/Defaults.template @@ -90,6 +90,10 @@ final class ${LAF_NAME}Defaults { */ private Map registeredRegions = new HashMap(); + + private Map> overridesCache = + new WeakHashMap>(); + /** * Our fallback style to avoid NPEs if the proper style cannot be found in * this class. Not sure if relying on DefaultSynthStyle is the best choice. @@ -251,7 +255,11 @@ ${UI_DEFAULT_INIT} } //return the style, if found, or the default style if not found - return foundStyle == null ? defaultStyle : foundStyle.getStyle(comp); + return foundStyle == null ? defaultStyle : foundStyle.getStyle(comp, r); + } + + public void clearOverridesCache(JComponent c) { + overridesCache.remove(c); } /* @@ -457,15 +465,6 @@ ${UI_DEFAULT_INIT} * Cached shared style. */ private NimbusStyle style; - /** - * A weakly referenced hash map such that if the reference JComponent - * key is garbage collected then the entry is removed from the map. - * This cache exists so that when a JComponent has nimbus overrides - * in its client map, a unique style will be created and returned - * for that JComponent instance, always. In such a situation each - * JComponent instance must have its own instance of NimbusStyle. - */ - private WeakHashMap> overridesCache; /** * Create a new LazyStyle. @@ -513,17 +512,21 @@ ${UI_DEFAULT_INIT} * Gets the style. Creates it if necessary. * @return the style */ - SynthStyle getStyle(JComponent c) { + SynthStyle getStyle(JComponent c, Region r) { // if the component has overrides, it gets its own unique style // instead of the shared style. if (c.getClientProperty("Nimbus.Overrides") != null) { - if (overridesCache == null) - overridesCache = new WeakHashMap>(); - WeakReference ref = overridesCache.get(c); - NimbusStyle s = ref == null ? null : ref.get(); + Map map = overridesCache.get(c); + SynthStyle s = null; + if (map == null) { + map = new HashMap(); + overridesCache.put(c, map); + } else { + s = map.get(r); + } if (s == null) { s = new NimbusStyle(prefix, c); - overridesCache.put(c, new WeakReference(s)); + map.put(r, s); } return s; } diff --git a/src/share/classes/javax/swing/plaf/nimbus/NimbusLookAndFeel.java b/src/share/classes/javax/swing/plaf/nimbus/NimbusLookAndFeel.java index 4062678fb67c6e53b41ba0a3e4d3ea3b15d3ed3e..883727ae65f13f66fcc3ce37a168f5bed63d8370 100644 --- a/src/share/classes/javax/swing/plaf/nimbus/NimbusLookAndFeel.java +++ b/src/share/classes/javax/swing/plaf/nimbus/NimbusLookAndFeel.java @@ -280,11 +280,15 @@ public class NimbusLookAndFeel extends SynthLookAndFeel { protected boolean shouldUpdateStyleOnEvent(PropertyChangeEvent ev) { String eName = ev.getPropertyName(); - // Always update when overrides or size variant change - if ("Nimbus.Overrides" == eName || + // These properties affect style cached inside NimbusDefaults (6860433) + if ("name" == eName || + "ancestor" == eName || + "Nimbus.Overrides" == eName || "Nimbus.Overrides.InheritDefaults" == eName || "JComponent.sizeVariant" == eName) { + JComponent c = (JComponent) ev.getSource(); + defaults.clearOverridesCache(c); return true; } diff --git a/test/javax/swing/plaf/nimbus/ColorCustomizationTest.java b/test/javax/swing/plaf/nimbus/ColorCustomizationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6f5a7a2bc3acb8086ad9be299e9bce61e5922d58 --- /dev/null +++ b/test/javax/swing/plaf/nimbus/ColorCustomizationTest.java @@ -0,0 +1,165 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @bug 6860433 + @summary Tests variuos techniques of Nimbus color customization + @author Peter Zhelezniakov + @run main ColorCustomizationTest +*/ + +import javax.swing.JLabel; +import javax.swing.SwingUtilities; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.image.BufferedImage; +import javax.swing.UnsupportedLookAndFeelException; +import javax.swing.plaf.ColorUIResource; +import javax.swing.plaf.nimbus.NimbusLookAndFeel; +import javax.swing.plaf.synth.Region; + +public class ColorCustomizationTest +{ + final static int WIDTH = 200; + final static int HEIGHT = 100; + + static NimbusLookAndFeel nimbus; + + final JLabel label; + final Graphics g; + + ColorCustomizationTest() { + label = new JLabel(); + label.setSize(200, 100); + + g = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB).getGraphics(); + } + + public static void main(String[] args) throws Exception { + nimbus = new NimbusLookAndFeel(); + try { + UIManager.setLookAndFeel(nimbus); + } catch (UnsupportedLookAndFeelException e) { + throw new Error("Unable to set Nimbus LAF"); + } + SwingUtilities.invokeAndWait(new Runnable() { + @Override public void run() { + new ColorCustomizationTest().test(); + } + }); + } + + void check(Color c) { + SwingUtilities.updateComponentTreeUI(label); + label.paint(g); + if (label.getBackground().getRGB() != c.getRGB()) { + System.err.println("Color mismatch!"); + System.err.println(" found: " + label.getBackground()); + System.err.println(" expected: " + c); + throw new RuntimeException("Test failed"); + } + } + + void test() { + testOverrides(); + testInheritance(); + testNames(); + testBaseColor(); + } + + void testOverrides() { + Color defaultColor = label.getBackground(); + + // override default background + UIDefaults defs = new UIDefaults(); + defs.put("Label.background", new ColorUIResource(Color.RED)); + label.putClientProperty("Nimbus.Overrides", defs); + check(Color.RED); + + // change overriding color + defs = new UIDefaults(); + defs.put("Label.background", new ColorUIResource(Color.GREEN)); + label.putClientProperty("Nimbus.Overrides", defs); + check(Color.GREEN); + + // remove override + label.putClientProperty("Nimbus.Overrides", null); + check(defaultColor); + } + + void testInheritance() { + Color defaultColor = label.getBackground(); + + // more specific setting is in global defaults + UIManager.put("Label[Enabled].background", new ColorUIResource(Color.RED)); + + // less specific one is in overrides + UIDefaults defs = new UIDefaults(); + defs.put("Label.background", new ColorUIResource(Color.GREEN)); + + // global wins + label.putClientProperty("Nimbus.Overrides", defs); + check(Color.RED); + + // now override wins + label.putClientProperty("Nimbus.Overrides.InheritDefaults", false); + check(Color.GREEN); + + // global is back + label.putClientProperty("Nimbus.Overrides.InheritDefaults", true); + check(Color.RED); + + // back to default color + UIManager.put("Label[Enabled].background", null); + label.putClientProperty("Nimbus.Overrides.InheritDefaults", false); + label.putClientProperty("Nimbus.Overrides", null); + check(defaultColor); + } + + void testNames() { + Color defaultColor = label.getBackground(); + + UIManager.put("\"BlueLabel\"[Enabled].background", + new ColorUIResource(Color.BLUE)); + UIManager.put("\"RedLabel\"[Enabled].background", + new ColorUIResource(Color.RED)); + nimbus.register(Region.LABEL, "\"BlueLabel\""); + nimbus.register(Region.LABEL, "\"RedLabel\""); + + label.setName("BlueLabel"); + check(Color.BLUE); + label.setName("RedLabel"); + check(Color.RED); + + // remove name, color goes back to default + label.setName(null); + check(defaultColor); + } + + void testBaseColor() { + UIManager.put("control", Color.GREEN); + check(Color.GREEN); + } +}