6860433: [Nimbus] Code to set a single slider's thumb background doesn't work as specified
authorpeterz
Mon, 21 Dec 2009 19:26:58 +0300
changeset 4841 ae658e3b0f27
parent 4840 74d64c277d62
child 4842 c9f791782a29
6860433: [Nimbus] Code to set a single slider's thumb background doesn't work as specified Reviewed-by: rupashka
jdk/src/share/classes/javax/swing/plaf/nimbus/Defaults.template
jdk/src/share/classes/javax/swing/plaf/nimbus/NimbusLookAndFeel.java
jdk/test/javax/swing/plaf/nimbus/ColorCustomizationTest.java
--- a/jdk/src/share/classes/javax/swing/plaf/nimbus/Defaults.template	Wed Dec 16 16:25:08 2009 -0800
+++ b/jdk/src/share/classes/javax/swing/plaf/nimbus/Defaults.template	Mon Dec 21 19:26:58 2009 +0300
@@ -90,6 +90,10 @@
      */
     private Map<String, Region> registeredRegions =
             new HashMap<String, Region>();
+
+    private Map<JComponent, Map<Region, SynthStyle>> overridesCache =
+            new WeakHashMap<JComponent, Map<Region, SynthStyle>>();
+    
     /**
      * 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 @@
         }
 
         //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 @@
          * 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<JComponent, WeakReference<NimbusStyle>> overridesCache;
 
         /**
          * Create a new LazyStyle.
@@ -513,17 +512,21 @@
          * 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<JComponent, WeakReference<NimbusStyle>>();
-                WeakReference<NimbusStyle> ref = overridesCache.get(c);
-                NimbusStyle s = ref == null ? null : ref.get();
+                Map<Region, SynthStyle> map = overridesCache.get(c);
+                SynthStyle s = null;
+                if (map == null) {
+                    map = new HashMap<Region, SynthStyle>();
+                    overridesCache.put(c, map);
+                } else {
+                    s = map.get(r);
+                }
                 if (s == null) {
                     s = new NimbusStyle(prefix, c);
-                    overridesCache.put(c, new WeakReference<NimbusStyle>(s));
+                    map.put(r, s);
                 }
                 return s;
             }
--- a/jdk/src/share/classes/javax/swing/plaf/nimbus/NimbusLookAndFeel.java	Wed Dec 16 16:25:08 2009 -0800
+++ b/jdk/src/share/classes/javax/swing/plaf/nimbus/NimbusLookAndFeel.java	Mon Dec 21 19:26:58 2009 +0300
@@ -280,11 +280,15 @@
     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;
         }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/plaf/nimbus/ColorCustomizationTest.java	Mon Dec 21 19:26:58 2009 +0300
@@ -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);
+    }
+}