6802944: Nimbus initialization is too slow
Reviewed-by: jasper
This commit is contained in:
parent
4e064060c0
commit
d1839690e3
@ -24,6 +24,7 @@
|
||||
*/
|
||||
package org.jdesktop.synthdesigner.generator;
|
||||
|
||||
import java.awt.Color;
|
||||
import org.jdesktop.swingx.designer.Canvas;
|
||||
import org.jdesktop.swingx.designer.font.Typeface;
|
||||
import org.jdesktop.swingx.designer.paint.Matte;
|
||||
@ -133,11 +134,7 @@ public class DefaultsGenerator {
|
||||
|
||||
private static void writeColorPalette(StringBuilder uiDefaultInit, List<UIPaint> colors) {
|
||||
for (UIPaint color : colors) {
|
||||
uiDefaultInit.append(" d.put(\"")
|
||||
.append(color.getName())
|
||||
.append("\",")
|
||||
.append(convertPaint(color.getValue()))
|
||||
.append(");\n");
|
||||
writeMatte(color.getName(), (Matte)color.getValue(), uiDefaultInit);
|
||||
}
|
||||
}
|
||||
|
||||
@ -255,12 +252,8 @@ public class DefaultsGenerator {
|
||||
.append("));\n");
|
||||
break;
|
||||
case COLOR:
|
||||
uiDefaultInit.append(" d.put(\"")
|
||||
.append(prefix)
|
||||
.append(property.getName())
|
||||
.append("\", ")
|
||||
.append(convertPaint((Matte)property.getValue()))
|
||||
.append(");\n");
|
||||
writeMatte(prefix + property.getName(),
|
||||
(Matte) property.getValue(), uiDefaultInit);
|
||||
break;
|
||||
case FONT:
|
||||
writeTypeFace(prefix.replace("\"", "\\\"") + property.getName(),
|
||||
@ -300,7 +293,7 @@ public class DefaultsGenerator {
|
||||
|
||||
private static void writeMatte(String propertyName, Matte matte, StringBuilder uiDefaultInit) {
|
||||
if (matte==null) System.err.println("Error matte is NULL for ["+propertyName+"]");
|
||||
uiDefaultInit.append(" d.put(\"")
|
||||
uiDefaultInit.append(" addColor(d, \"")
|
||||
.append(propertyName)
|
||||
.append("\", ")
|
||||
.append(convertPaint(matte))
|
||||
@ -605,27 +598,23 @@ public class DefaultsGenerator {
|
||||
return s.replace("\"", "\\\"");
|
||||
}
|
||||
|
||||
private static String convertPaint(PaintModel paint){
|
||||
if (paint instanceof Matte){
|
||||
Matte matte = (Matte)paint;
|
||||
if (matte.isAbsolute()){
|
||||
String colorParams = convert(matte.getColor());
|
||||
if (matte.isUiResource()) {
|
||||
return "new ColorUIResource(" + colorParams + ")";
|
||||
} else {
|
||||
return colorParams;
|
||||
}
|
||||
private static String convertPaint(PaintModel paint) {
|
||||
if (paint instanceof Matte) {
|
||||
Matte matte = (Matte) paint;
|
||||
if (matte.isAbsolute()) {
|
||||
Color c = matte.getColor();
|
||||
return c.getRed() + ", " + c.getGreen() + ", " +
|
||||
c.getBlue() + ", " + c.getAlpha();
|
||||
} else {
|
||||
String s = "getDerivedColor(\"" +
|
||||
matte.getUiDefaultParentName()+"\","+
|
||||
matte.getHueOffset()+"f,"+matte.getSaturationOffset()+
|
||||
"f,"+matte.getBrightnessOffset()+"f,"+
|
||||
matte.getAlphaOffset();
|
||||
if (matte.isUiResource()) {
|
||||
return s + ")";
|
||||
} else {
|
||||
return s + ",false)";
|
||||
String s = "\"" + matte.getUiDefaultParentName() + "\", " +
|
||||
matte.getHueOffset() + "f, " +
|
||||
matte.getSaturationOffset() + "f, " +
|
||||
matte.getBrightnessOffset() + "f, " +
|
||||
matte.getAlphaOffset();
|
||||
if (! matte.isUiResource()) {
|
||||
s += ", false";
|
||||
}
|
||||
return s;
|
||||
}
|
||||
} else {
|
||||
//TODO: What about gradients etc here?
|
||||
|
@ -101,14 +101,7 @@ final class ${LAF_NAME}Defaults {
|
||||
*/
|
||||
private FontUIResource defaultFont;
|
||||
|
||||
/**
|
||||
* Map of lists of derived colors keyed by the DerivedColorKeys
|
||||
*/
|
||||
private Map<DerivedColorKey, DerivedColor> derivedColorsMap =
|
||||
new HashMap<DerivedColorKey, DerivedColor>();
|
||||
|
||||
/** Tempory key used for fetching from the derivedColorsMap */
|
||||
private final DerivedColorKey tmpDCKey = new DerivedColorKey();
|
||||
private ColorTree colorTree = new ColorTree();
|
||||
|
||||
/** Listener for changes to user defaults table */
|
||||
private DefaultsListener defaultsListener = new DefaultsListener();
|
||||
@ -117,14 +110,14 @@ final class ${LAF_NAME}Defaults {
|
||||
void initialize() {
|
||||
// add listener for derived colors
|
||||
UIManager.addPropertyChangeListener(defaultsListener);
|
||||
UIManager.getDefaults().addPropertyChangeListener(defaultsListener);
|
||||
UIManager.getDefaults().addPropertyChangeListener(colorTree);
|
||||
}
|
||||
|
||||
/** Called by UIManager when this look and feel is uninstalled. */
|
||||
void uninitialize() {
|
||||
// remove listener for derived colors
|
||||
UIManager.getDefaults().removePropertyChangeListener(defaultsListener);
|
||||
UIManager.removePropertyChangeListener(defaultsListener);
|
||||
UIManager.getDefaults().removePropertyChangeListener(colorTree);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -663,22 +656,23 @@ ${UI_DEFAULT_INIT}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a derived color, derived colors are shared instances and will be
|
||||
* updated when its parent UIDefault color changes.
|
||||
*
|
||||
* @param uiDefaultParentName The parent UIDefault key
|
||||
* @param hOffset The hue offset
|
||||
* @param sOffset The saturation offset
|
||||
* @param bOffset The brightness offset
|
||||
* @param aOffset The alpha offset
|
||||
* @return The stored derived color
|
||||
*/
|
||||
public DerivedColor getDerivedColor(String uiDefaultParentName,
|
||||
float hOffset, float sOffset,
|
||||
float bOffset, int aOffset){
|
||||
return getDerivedColor(uiDefaultParentName, hOffset, sOffset,
|
||||
bOffset, aOffset, true);
|
||||
private void addColor(UIDefaults d, String uin, int r, int g, int b, int a) {
|
||||
Color color = new ColorUIResource(new Color(r, g, b, a));
|
||||
colorTree.addColor(uin, color);
|
||||
d.put(uin, color);
|
||||
}
|
||||
|
||||
private void addColor(UIDefaults d, String uin, String parentUin,
|
||||
float hOffset, float sOffset, float bOffset, int aOffset) {
|
||||
addColor(d, uin, parentUin, hOffset, sOffset, bOffset, aOffset, true);
|
||||
}
|
||||
|
||||
private void addColor(UIDefaults d, String uin, String parentUin,
|
||||
float hOffset, float sOffset, float bOffset,
|
||||
int aOffset, boolean uiResource) {
|
||||
Color color = getDerivedColor(uin, parentUin,
|
||||
hOffset, sOffset, bOffset, aOffset, uiResource);
|
||||
d.put(uin, color);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -694,89 +688,110 @@ ${UI_DEFAULT_INIT}
|
||||
* false if it should not be a UIResource
|
||||
* @return The stored derived color
|
||||
*/
|
||||
public DerivedColor getDerivedColor(String uiDefaultParentName,
|
||||
public DerivedColor getDerivedColor(String parentUin,
|
||||
float hOffset, float sOffset,
|
||||
float bOffset, int aOffset,
|
||||
boolean uiResource){
|
||||
tmpDCKey.set(uiDefaultParentName, hOffset, sOffset, bOffset, aOffset,
|
||||
uiResource);
|
||||
DerivedColor color = derivedColorsMap.get(tmpDCKey);
|
||||
if (color == null){
|
||||
if (uiResource) {
|
||||
color = new DerivedColor.UIResource(uiDefaultParentName,
|
||||
hOffset, sOffset, bOffset, aOffset);
|
||||
} else {
|
||||
color = new DerivedColor(uiDefaultParentName, hOffset, sOffset,
|
||||
bOffset, aOffset);
|
||||
}
|
||||
// calculate the initial value
|
||||
color.rederiveColor();
|
||||
// add the listener so that if the color changes we'll propogate it
|
||||
color.addPropertyChangeListener(defaultsListener);
|
||||
// add to the derived colors table
|
||||
derivedColorsMap.put(new DerivedColorKey(uiDefaultParentName,
|
||||
hOffset, sOffset, bOffset, aOffset, uiResource),color);
|
||||
}
|
||||
return color;
|
||||
return getDerivedColor(null, parentUin,
|
||||
hOffset, sOffset, bOffset, aOffset, uiResource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Key class for derived colors
|
||||
*/
|
||||
private class DerivedColorKey {
|
||||
private String uiDefaultParentName;
|
||||
private float hOffset, sOffset, bOffset;
|
||||
private int aOffset;
|
||||
private boolean uiResource;
|
||||
|
||||
DerivedColorKey(){}
|
||||
|
||||
DerivedColorKey(String uiDefaultParentName, float hOffset,
|
||||
float sOffset, float bOffset, int aOffset,
|
||||
boolean uiResource) {
|
||||
set(uiDefaultParentName, hOffset, sOffset, bOffset, aOffset, uiResource);
|
||||
private DerivedColor getDerivedColor(String uin, String parentUin,
|
||||
float hOffset, float sOffset,
|
||||
float bOffset, int aOffset,
|
||||
boolean uiResource) {
|
||||
DerivedColor color;
|
||||
if (uiResource) {
|
||||
color = new DerivedColor.UIResource(parentUin,
|
||||
hOffset, sOffset, bOffset, aOffset);
|
||||
} else {
|
||||
color = new DerivedColor(parentUin, hOffset, sOffset,
|
||||
bOffset, aOffset);
|
||||
}
|
||||
|
||||
void set (String uiDefaultParentName, float hOffset,
|
||||
float sOffset, float bOffset, int aOffset,
|
||||
boolean uiResource) {
|
||||
this.uiDefaultParentName = uiDefaultParentName;
|
||||
this.hOffset = hOffset;
|
||||
this.sOffset = sOffset;
|
||||
this.bOffset = bOffset;
|
||||
this.aOffset = aOffset;
|
||||
this.uiResource = uiResource;
|
||||
if (derivedColors.containsKey(color)) {
|
||||
return derivedColors.get(color);
|
||||
} else {
|
||||
derivedColors.put(color, color);
|
||||
color.rederiveColor(); /// move to ARP.decodeColor() ?
|
||||
colorTree.addColor(uin, color);
|
||||
return color;
|
||||
}
|
||||
}
|
||||
|
||||
private Map<DerivedColor, DerivedColor> derivedColors =
|
||||
new HashMap<DerivedColor, DerivedColor>();
|
||||
|
||||
private class ColorTree implements PropertyChangeListener {
|
||||
private Node root = new Node(null, null);
|
||||
private Map<String, Node> nodes = new HashMap<String, Node>();
|
||||
|
||||
public Color getColor(String uin) {
|
||||
return nodes.get(uin).color;
|
||||
}
|
||||
|
||||
public void addColor(String uin, Color color) {
|
||||
Node parent = getParentNode(color);
|
||||
Node node = new Node(color, parent);
|
||||
parent.children.add(node);
|
||||
if (uin != null) {
|
||||
nodes.put(uin, node);
|
||||
}
|
||||
}
|
||||
|
||||
private Node getParentNode(Color color) {
|
||||
Node parent = root;
|
||||
if (color instanceof DerivedColor) {
|
||||
String parentUin = ((DerivedColor)color).getUiDefaultParentName();
|
||||
Node p = nodes.get(parentUin);
|
||||
if (p != null) {
|
||||
parent = p;
|
||||
}
|
||||
}
|
||||
return parent;
|
||||
}
|
||||
|
||||
public void update() {
|
||||
root.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof DerivedColorKey)) return false;
|
||||
DerivedColorKey that = (DerivedColorKey) o;
|
||||
if (aOffset != that.aOffset) return false;
|
||||
if (Float.compare(that.bOffset, bOffset) != 0) return false;
|
||||
if (Float.compare(that.hOffset, hOffset) != 0) return false;
|
||||
if (Float.compare(that.sOffset, sOffset) != 0) return false;
|
||||
if (uiDefaultParentName != null ?
|
||||
!uiDefaultParentName.equals(that.uiDefaultParentName) :
|
||||
that.uiDefaultParentName != null) return false;
|
||||
if (this.uiResource != that.uiResource) return false;
|
||||
return true;
|
||||
public void propertyChange(PropertyChangeEvent ev) {
|
||||
String name = ev.getPropertyName();
|
||||
Node node = nodes.get(name);
|
||||
if (node != null) {
|
||||
// this is a registered color
|
||||
node.parent.children.remove(node);
|
||||
Color color = (Color) ev.getNewValue();
|
||||
Node parent = getParentNode(color);
|
||||
node.set(color, parent);
|
||||
parent.children.add(node);
|
||||
node.update();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = super.hashCode();
|
||||
result = 31 * result + uiDefaultParentName.hashCode();
|
||||
result = 31 * result + hOffset != +0.0f ?
|
||||
Float.floatToIntBits(hOffset) : 0;
|
||||
result = 31 * result + sOffset != +0.0f ?
|
||||
Float.floatToIntBits(sOffset) : 0;
|
||||
result = 31 * result + bOffset != +0.0f ?
|
||||
Float.floatToIntBits(bOffset) : 0;
|
||||
result = 31 * result + aOffset;
|
||||
result = 31 * result + (uiResource ? 1 : 0);
|
||||
return result;
|
||||
class Node {
|
||||
Color color;
|
||||
Node parent;
|
||||
List<Node> children = new LinkedList<Node>();
|
||||
|
||||
Node(Color color, Node parent) {
|
||||
set(color, parent);
|
||||
}
|
||||
|
||||
public void set(Color color, Node parent) {
|
||||
this.color = color;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if (color instanceof DerivedColor) {
|
||||
((DerivedColor)color).rederiveColor();
|
||||
}
|
||||
for (Node child: children) {
|
||||
child.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -786,49 +801,12 @@ ${UI_DEFAULT_INIT}
|
||||
private class DefaultsListener implements PropertyChangeListener {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
Object src = evt.getSource();
|
||||
String key = evt.getPropertyName();
|
||||
if (key.equals("lookAndFeel")){
|
||||
if ("lookAndFeel".equals(evt.getPropertyName())) {
|
||||
// LAF has been installed, this is the first point at which we
|
||||
// can access our defaults table via UIManager so before now
|
||||
// all derived colors will be incorrect.
|
||||
// First we need to update
|
||||
for (DerivedColor color : derivedColorsMap.values()) {
|
||||
color.rederiveColor();
|
||||
}
|
||||
} else if (src instanceof DerivedColor && key.equals("rgb")) {
|
||||
// derived color that is in UIManager defaults has changed
|
||||
// update all its dependent colors. Don't worry about doing
|
||||
// this recursively since calling rederiveColor will cause
|
||||
// another PCE to be fired, ending up here and essentially
|
||||
// recursing
|
||||
DerivedColor parentColor = (DerivedColor)src;
|
||||
String parentKey = null;
|
||||
Set<Map.Entry<Object,Object>> entries =
|
||||
UIManager.getDefaults().entrySet();
|
||||
|
||||
for (Map.Entry entry : entries) {
|
||||
Object value = entry.getValue();
|
||||
if (value == parentColor) {
|
||||
parentKey = entry.getKey().toString();
|
||||
}
|
||||
}
|
||||
|
||||
if (parentKey == null) {
|
||||
//couldn't find the DerivedColor in the UIDefaults map,
|
||||
//so we just bail.
|
||||
return;
|
||||
}
|
||||
|
||||
for (Map.Entry entry : entries) {
|
||||
Object value = entry.getValue();
|
||||
if (value instanceof DerivedColor) {
|
||||
DerivedColor color = (DerivedColor)entry.getValue();
|
||||
if (parentKey.equals(color.getUiDefaultParentName())) {
|
||||
color.rederiveColor();
|
||||
}
|
||||
}
|
||||
}
|
||||
colorTree.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -875,4 +853,3 @@ ${UI_DEFAULT_INIT}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,8 +39,6 @@ import java.beans.PropertyChangeListener;
|
||||
* @author Jasper Potts
|
||||
*/
|
||||
class DerivedColor extends Color {
|
||||
private final PropertyChangeSupport changeSupport =
|
||||
new PropertyChangeSupport(this);
|
||||
private final String uiDefaultParentName;
|
||||
private final float hOffset, sOffset, bOffset;
|
||||
private final int aOffset;
|
||||
@ -79,7 +77,6 @@ class DerivedColor extends Color {
|
||||
* Recalculate the derived color from the UIManager parent color and offsets
|
||||
*/
|
||||
public void rederiveColor() {
|
||||
int old = argbValue;
|
||||
Color src = UIManager.getColor(uiDefaultParentName);
|
||||
if (src != null) {
|
||||
float[] tmp = Color.RGBtoHSB(src.getRed(), src.getGreen(), src.getBlue(), null);
|
||||
@ -97,7 +94,6 @@ class DerivedColor extends Color {
|
||||
int alpha = clamp(aOffset);
|
||||
argbValue = (Color.HSBtoRGB(tmp[0], tmp[1], tmp[2]) & 0xFFFFFF) | (alpha << 24);
|
||||
}
|
||||
changeSupport.firePropertyChange("rgb", old, argbValue);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -141,35 +137,6 @@ class DerivedColor extends Color {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a PropertyChangeListener to the listener list.
|
||||
* The listener is registered for all properties.
|
||||
* The same listener object may be added more than once, and will be called
|
||||
* as many times as it is added.
|
||||
* If <code>listener</code> is null, no exception is thrown and no action
|
||||
* is taken.
|
||||
*
|
||||
* @param listener The PropertyChangeListener to be added
|
||||
*/
|
||||
public void addPropertyChangeListener(PropertyChangeListener listener) {
|
||||
changeSupport.addPropertyChangeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a PropertyChangeListener from the listener list.
|
||||
* This removes a PropertyChangeListener that was registered
|
||||
* for all properties.
|
||||
* If <code>listener</code> was added more than once to the same event
|
||||
* source, it will be notified one less time after being removed.
|
||||
* If <code>listener</code> is null, or was never added, no exception is
|
||||
* thrown and no action is taken.
|
||||
*
|
||||
* @param listener The PropertyChangeListener to be removed
|
||||
*/
|
||||
public void removePropertyChangeListener(PropertyChangeListener listener) {
|
||||
changeSupport.removePropertyChangeListener(listener);
|
||||
}
|
||||
|
||||
private float clamp(float value) {
|
||||
if (value < 0) {
|
||||
value = 0;
|
||||
@ -211,5 +178,15 @@ class DerivedColor extends Color {
|
||||
float bOffset, int aOffset) {
|
||||
super(uiDefaultParentName, hOffset, sOffset, bOffset, aOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return (o instanceof UIResource) && super.equals(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return super.hashCode() + 7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,9 @@ import java.awt.Container;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.LayoutManager;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.*;
|
||||
import javax.swing.GrayFilter;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JToolBar;
|
||||
@ -87,6 +90,8 @@ public class NimbusLookAndFeel extends SynthLookAndFeel {
|
||||
*/
|
||||
private UIDefaults uiDefaults;
|
||||
|
||||
private DefaultsListener defaultsListener = new DefaultsListener();
|
||||
|
||||
/**
|
||||
* Create a new NimbusLookAndFeel.
|
||||
*/
|
||||
@ -115,8 +120,7 @@ public class NimbusLookAndFeel extends SynthLookAndFeel {
|
||||
defaults.uninitialize();
|
||||
// clear all cached images to free memory
|
||||
ImageCache.getInstance().flush();
|
||||
// remove the listeners and things installed by NimbusStyle
|
||||
NimbusStyle.uninitialize();
|
||||
UIManager.getDefaults().removePropertyChangeListener(defaultsListener);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -515,4 +519,62 @@ public class NimbusLookAndFeel extends SynthLookAndFeel {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Map<String, Object>> compiledDefaults = null;
|
||||
private boolean defaultListenerAdded = false;
|
||||
|
||||
static String parsePrefix(String key) {
|
||||
if (key == null) {
|
||||
return null;
|
||||
}
|
||||
boolean inquotes = false;
|
||||
for (int i = 0; i < key.length(); i++) {
|
||||
char c = key.charAt(i);
|
||||
if (c == '"') {
|
||||
inquotes = !inquotes;
|
||||
} else if ((c == '[' || c == '.') && !inquotes) {
|
||||
return key.substring(0, i);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Map<String, Object> getDefaultsForPrefix(String prefix) {
|
||||
if (compiledDefaults == null) {
|
||||
compiledDefaults = new HashMap<String, Map<String, Object>>();
|
||||
for (Map.Entry<Object, Object> entry: UIManager.getDefaults().entrySet()) {
|
||||
if (entry.getKey() instanceof String) {
|
||||
addDefault((String) entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
if (! defaultListenerAdded) {
|
||||
UIManager.getDefaults().addPropertyChangeListener(defaultsListener);
|
||||
defaultListenerAdded = true;
|
||||
}
|
||||
}
|
||||
return compiledDefaults.get(prefix);
|
||||
}
|
||||
|
||||
private void addDefault(String key, Object value) {
|
||||
String prefix = parsePrefix(key);
|
||||
if (prefix != null) {
|
||||
Map<String, Object> keys = compiledDefaults.get(prefix);
|
||||
if (keys == null) {
|
||||
keys = new HashMap<String, Object>();
|
||||
compiledDefaults.put(prefix, keys);
|
||||
}
|
||||
keys.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
private class DefaultsListener implements PropertyChangeListener {
|
||||
@Override public void propertyChange(PropertyChangeEvent ev) {
|
||||
String key = ev.getPropertyName();
|
||||
if ("UIDefaults".equals(key)) {
|
||||
compiledDefaults = null;
|
||||
} else {
|
||||
addDefault(key, ev.getNewValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,6 @@ package javax.swing.plaf.nimbus;
|
||||
|
||||
import javax.swing.Painter;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.UIDefaults;
|
||||
import javax.swing.UIManager;
|
||||
@ -39,16 +38,13 @@ import javax.swing.plaf.synth.SynthStyle;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.Insets;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import sun.awt.AppContext;
|
||||
|
||||
/**
|
||||
* <p>A SynthStyle implementation used by Nimbus. Each Region that has been
|
||||
@ -232,42 +228,6 @@ public final class NimbusStyle extends SynthStyle {
|
||||
super.installDefaults(ctx);
|
||||
}
|
||||
|
||||
static String parsePrefix(String key) {
|
||||
if (key == null) return null;
|
||||
boolean inquotes = false;
|
||||
for (int i=0; i<key.length(); i++) {
|
||||
char c = key.charAt(i);
|
||||
if (c == '"') {
|
||||
inquotes = !inquotes;
|
||||
} else if ((c == '[' || c == '.') && !inquotes) {
|
||||
return key.substring(0, i);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by NimbusLookAndFeel when the look and feel is being uninstalled.
|
||||
* Performs general cleanup of any app-context specific data.
|
||||
*/
|
||||
static void uninitialize() {
|
||||
// get the appcontext that we've stored data in
|
||||
AppContext ctx = AppContext.getAppContext();
|
||||
|
||||
// get the pcl stored in app context
|
||||
PropertyChangeListener pcl = (PropertyChangeListener)
|
||||
ctx.get("NimbusStyle.defaults.pcl");
|
||||
|
||||
// if the pcl exists, uninstall it from the UIDefaults tables
|
||||
if (pcl != null) {
|
||||
UIManager.getDefaults().removePropertyChangeListener(pcl);
|
||||
UIManager.getLookAndFeelDefaults().removePropertyChangeListener(pcl);
|
||||
}
|
||||
|
||||
// clear out the compiled defaults
|
||||
ctx.put("NimbusStyle.defaults", null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pulls data out of UIDefaults, if it has not done so already, and sets
|
||||
* up the internal state.
|
||||
@ -283,66 +243,9 @@ public final class NimbusStyle extends SynthStyle {
|
||||
// any Nimbus.Overrides)
|
||||
values = new Values();
|
||||
|
||||
// the profiler revealed that a great deal of CPU time and useless
|
||||
// garbage was being produced by this method and the init method. One
|
||||
// culprit was the creation and reparsing of the entire UIDefaults
|
||||
// map on each call to this method where "values" was null. It turns
|
||||
// out this was happening a lot.
|
||||
// To remove this bottleneck, we store the compiled TreeMaps of defaults
|
||||
// in the appContext for reuse. It is nulled whenever the UIDefaults
|
||||
// changes and recomputed when necessary.
|
||||
final AppContext ctx = AppContext.getAppContext();
|
||||
|
||||
// fetch the defaults from the app context. If null, then create and
|
||||
// store the compiled defaults
|
||||
Map<String, TreeMap<String, Object>> compiledDefaults =
|
||||
(Map<String, TreeMap<String, Object>>)
|
||||
ctx.get("NimbusStyle.defaults");
|
||||
|
||||
if (compiledDefaults == null) {
|
||||
// the entire UIDefaults tables are parsed and compiled into
|
||||
// this map of maps. The key of the compiledDefaults is the
|
||||
// prefix for each style, while the value is a map of
|
||||
// keys->values for that prefix.
|
||||
compiledDefaults = new HashMap<String, TreeMap<String, Object>>();
|
||||
|
||||
// get all the defaults from UIManager.getDefaults() and put them
|
||||
// into the compiledDefaults
|
||||
compileDefaults(compiledDefaults, UIManager.getDefaults());
|
||||
|
||||
// This second statement pulls defaults from the laf defaults
|
||||
UIDefaults lafDefaults = UIManager.getLookAndFeelDefaults();
|
||||
compileDefaults(compiledDefaults, lafDefaults);
|
||||
|
||||
// if it has not already been done, add a listener to both
|
||||
// UIManager.getDefaults() and UIManager.getLookAndFeelDefaults().
|
||||
PropertyChangeListener pcl = (PropertyChangeListener)
|
||||
ctx.get("NimbusStyle.defaults.pcl");
|
||||
|
||||
// if pcl is null, then it has not yet been registered with
|
||||
// the UIManager defaults for this app context
|
||||
if (pcl == null) {
|
||||
// create a PCL which will simply clear out the compiled
|
||||
// defaults from the app context, causing it to be recomputed
|
||||
// on subsequent passes
|
||||
pcl = new DefaultsListener();
|
||||
// add the PCL to both defaults tables that we pay attention
|
||||
// to, so that if the UIDefaults are updated, then the
|
||||
// precompiled defaults will be cleared from the app context
|
||||
// and recomputed on subsequent passes
|
||||
UIManager.getDefaults().addPropertyChangeListener(pcl);
|
||||
UIManager.getLookAndFeelDefaults().addPropertyChangeListener(pcl);
|
||||
// save the PCL to the app context as a marker indicating
|
||||
// that the PCL has been registered so we don't end up adding
|
||||
// more than one listener to the UIDefaults tables.
|
||||
ctx.put("NimbusStyle.defaults.pcl", pcl);
|
||||
}
|
||||
|
||||
// store the defaults for reuse
|
||||
ctx.put("NimbusStyle.defaults", compiledDefaults);
|
||||
}
|
||||
|
||||
TreeMap<String, Object> defaults = compiledDefaults.get(prefix);
|
||||
Map<String, Object> defaults =
|
||||
((NimbusLookAndFeel) UIManager.getLookAndFeel()).
|
||||
getDefaultsForPrefix(prefix);
|
||||
|
||||
// inspect the client properties for the key "Nimbus.Overrides". If the
|
||||
// value is an instance of UIDefaults, then these defaults are used
|
||||
@ -371,52 +274,6 @@ public final class NimbusStyle extends SynthStyle {
|
||||
}
|
||||
}
|
||||
|
||||
// Now that I've accumulated all the defaults pertaining to this
|
||||
// style, call init which will read these defaults and configure
|
||||
// the default "values".
|
||||
init(values, defaults);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over all the keys in the specified UIDefaults and compiles
|
||||
* those keys into the comiledDefaults data structure. It relies on
|
||||
* parsing the "prefix" out of the key. If the key is not a String or is
|
||||
* null then it is ignored. In all other cases a prefix is parsed out
|
||||
* (even if that prefix is the empty String or is a "fake" prefix. That
|
||||
* is, suppose you had a key Foo~~MySpecial.KeyThing~~. In this case this
|
||||
* is not a Nimbus formatted key, but we don't care, we treat it as if it
|
||||
* is. This doesn't pose any harm, it will simply never be used).
|
||||
*
|
||||
* @param compiledDefaults
|
||||
* @param d
|
||||
*/
|
||||
private void compileDefaults(
|
||||
Map<String, TreeMap<String,Object>> compiledDefaults,
|
||||
UIDefaults d) {
|
||||
for (Object obj : new HashSet(d.keySet())) {
|
||||
if (obj instanceof String) {
|
||||
String key = (String)obj;
|
||||
String kp = parsePrefix(key);
|
||||
if (kp == null) continue;
|
||||
TreeMap<String,Object> map = compiledDefaults.get(kp);
|
||||
if (map == null) {
|
||||
map = new TreeMap<String,Object>();
|
||||
compiledDefaults.put(kp, map);
|
||||
}
|
||||
map.put(key, d.get(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the given <code>Values</code> object with the defaults
|
||||
* contained in the given TreeMap.
|
||||
*
|
||||
* @param v The Values object to be initialized
|
||||
* @param myDefaults a map of UIDefaults to use in initializing the Values.
|
||||
* This map must contain only keys associated with this Style.
|
||||
*/
|
||||
private void init(Values v, TreeMap<String, Object> myDefaults) {
|
||||
//a list of the different types of states used by this style. This
|
||||
//list may contain only "standard" states (those defined by Synth),
|
||||
//or it may contain custom states, or it may contain only "standard"
|
||||
@ -433,7 +290,7 @@ public final class NimbusStyle extends SynthStyle {
|
||||
//"values" stateTypes to be a non-null array.
|
||||
//Otherwise, let the "values" stateTypes be null to indicate that
|
||||
//there are no custom states or custom state ordering
|
||||
String statesString = (String)myDefaults.get(prefix + ".States");
|
||||
String statesString = (String)defaults.get(prefix + ".States");
|
||||
if (statesString != null) {
|
||||
String s[] = statesString.split(",");
|
||||
for (int i=0; i<s.length; i++) {
|
||||
@ -442,7 +299,7 @@ public final class NimbusStyle extends SynthStyle {
|
||||
//this is a non-standard state name, so look for the
|
||||
//custom state associated with it
|
||||
String stateName = prefix + "." + s[i];
|
||||
State customState = (State)myDefaults.get(stateName);
|
||||
State customState = (State)defaults.get(stateName);
|
||||
if (customState != null) {
|
||||
states.add(customState);
|
||||
}
|
||||
@ -455,7 +312,7 @@ public final class NimbusStyle extends SynthStyle {
|
||||
//to be non-null. Otherwise, leave it null (meaning, use the
|
||||
//standard synth states).
|
||||
if (states.size() > 0) {
|
||||
v.stateTypes = states.toArray(new State[states.size()]);
|
||||
values.stateTypes = states.toArray(new State[states.size()]);
|
||||
}
|
||||
|
||||
//assign codes for each of the state types
|
||||
@ -490,7 +347,7 @@ public final class NimbusStyle extends SynthStyle {
|
||||
}
|
||||
|
||||
//Now iterate over all the keys in the defaults table
|
||||
for (String key : myDefaults.keySet()) {
|
||||
for (String key : defaults.keySet()) {
|
||||
//The key is something like JButton.Enabled.backgroundPainter,
|
||||
//or JButton.States, or JButton.background.
|
||||
//Remove the "JButton." portion of the key
|
||||
@ -528,11 +385,11 @@ public final class NimbusStyle extends SynthStyle {
|
||||
//otherwise, assume it is a property and install it on the
|
||||
//values object
|
||||
if ("contentMargins".equals(property)) {
|
||||
v.contentMargins = (Insets)myDefaults.get(key);
|
||||
values.contentMargins = (Insets)defaults.get(key);
|
||||
} else if ("States".equals(property)) {
|
||||
//ignore
|
||||
} else {
|
||||
v.defaults.put(property, myDefaults.get(key));
|
||||
values.defaults.put(property, defaults.get(key));
|
||||
}
|
||||
} else {
|
||||
//it is possible that the developer has a malformed UIDefaults
|
||||
@ -582,13 +439,13 @@ public final class NimbusStyle extends SynthStyle {
|
||||
//so put it in the UIDefaults associated with that runtime
|
||||
//state
|
||||
if ("backgroundPainter".equals(property)) {
|
||||
rs.backgroundPainter = (Painter)myDefaults.get(key);
|
||||
rs.backgroundPainter = getPainter(defaults, key);
|
||||
} else if ("foregroundPainter".equals(property)) {
|
||||
rs.foregroundPainter = (Painter) myDefaults.get(key);
|
||||
rs.foregroundPainter = getPainter(defaults, key);
|
||||
} else if ("borderPainter".equals(property)) {
|
||||
rs.borderPainter = (Painter) myDefaults.get(key);
|
||||
rs.borderPainter = getPainter(defaults, key);
|
||||
} else {
|
||||
rs.defaults.put(property, myDefaults.get(key));
|
||||
rs.defaults.put(property, defaults.get(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -598,7 +455,15 @@ public final class NimbusStyle extends SynthStyle {
|
||||
Collections.sort(runtimeStates, STATE_COMPARATOR);
|
||||
|
||||
//finally, set the array of runtime states on the values object
|
||||
v.states = runtimeStates.toArray(new RuntimeState[runtimeStates.size()]);
|
||||
values.states = runtimeStates.toArray(new RuntimeState[runtimeStates.size()]);
|
||||
}
|
||||
|
||||
private Painter getPainter(Map<String, Object> defaults, String key) {
|
||||
Object p = defaults.get(key);
|
||||
if (p instanceof UIDefaults.LazyValue) {
|
||||
p = ((UIDefaults.LazyValue)p).createValue(UIManager.getDefaults());
|
||||
}
|
||||
return (p instanceof Painter ? (Painter)p : null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1245,15 +1110,4 @@ public final class NimbusStyle extends SynthStyle {
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This listener is used to listen to the UIDefaults tables and clear out
|
||||
* the cached-precompiled map of defaults in that case.
|
||||
*/
|
||||
private static final class DefaultsListener implements PropertyChangeListener {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
AppContext.getAppContext().put("NimbusStyle.defaults", null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user