mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-21 11:34:38 +02:00
6802944: Nimbus initialization is too slow
Reviewed-by: jasper
This commit is contained in:
parent
4e064060c0
commit
d1839690e3
5 changed files with 230 additions and 371 deletions
|
@ -24,6 +24,7 @@
|
||||||
*/
|
*/
|
||||||
package org.jdesktop.synthdesigner.generator;
|
package org.jdesktop.synthdesigner.generator;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
import org.jdesktop.swingx.designer.Canvas;
|
import org.jdesktop.swingx.designer.Canvas;
|
||||||
import org.jdesktop.swingx.designer.font.Typeface;
|
import org.jdesktop.swingx.designer.font.Typeface;
|
||||||
import org.jdesktop.swingx.designer.paint.Matte;
|
import org.jdesktop.swingx.designer.paint.Matte;
|
||||||
|
@ -133,11 +134,7 @@ public class DefaultsGenerator {
|
||||||
|
|
||||||
private static void writeColorPalette(StringBuilder uiDefaultInit, List<UIPaint> colors) {
|
private static void writeColorPalette(StringBuilder uiDefaultInit, List<UIPaint> colors) {
|
||||||
for (UIPaint color : colors) {
|
for (UIPaint color : colors) {
|
||||||
uiDefaultInit.append(" d.put(\"")
|
writeMatte(color.getName(), (Matte)color.getValue(), uiDefaultInit);
|
||||||
.append(color.getName())
|
|
||||||
.append("\",")
|
|
||||||
.append(convertPaint(color.getValue()))
|
|
||||||
.append(");\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,12 +252,8 @@ public class DefaultsGenerator {
|
||||||
.append("));\n");
|
.append("));\n");
|
||||||
break;
|
break;
|
||||||
case COLOR:
|
case COLOR:
|
||||||
uiDefaultInit.append(" d.put(\"")
|
writeMatte(prefix + property.getName(),
|
||||||
.append(prefix)
|
(Matte) property.getValue(), uiDefaultInit);
|
||||||
.append(property.getName())
|
|
||||||
.append("\", ")
|
|
||||||
.append(convertPaint((Matte)property.getValue()))
|
|
||||||
.append(");\n");
|
|
||||||
break;
|
break;
|
||||||
case FONT:
|
case FONT:
|
||||||
writeTypeFace(prefix.replace("\"", "\\\"") + property.getName(),
|
writeTypeFace(prefix.replace("\"", "\\\"") + property.getName(),
|
||||||
|
@ -300,7 +293,7 @@ public class DefaultsGenerator {
|
||||||
|
|
||||||
private static void writeMatte(String propertyName, Matte matte, StringBuilder uiDefaultInit) {
|
private static void writeMatte(String propertyName, Matte matte, StringBuilder uiDefaultInit) {
|
||||||
if (matte==null) System.err.println("Error matte is NULL for ["+propertyName+"]");
|
if (matte==null) System.err.println("Error matte is NULL for ["+propertyName+"]");
|
||||||
uiDefaultInit.append(" d.put(\"")
|
uiDefaultInit.append(" addColor(d, \"")
|
||||||
.append(propertyName)
|
.append(propertyName)
|
||||||
.append("\", ")
|
.append("\", ")
|
||||||
.append(convertPaint(matte))
|
.append(convertPaint(matte))
|
||||||
|
@ -609,23 +602,19 @@ public class DefaultsGenerator {
|
||||||
if (paint instanceof Matte) {
|
if (paint instanceof Matte) {
|
||||||
Matte matte = (Matte) paint;
|
Matte matte = (Matte) paint;
|
||||||
if (matte.isAbsolute()) {
|
if (matte.isAbsolute()) {
|
||||||
String colorParams = convert(matte.getColor());
|
Color c = matte.getColor();
|
||||||
if (matte.isUiResource()) {
|
return c.getRed() + ", " + c.getGreen() + ", " +
|
||||||
return "new ColorUIResource(" + colorParams + ")";
|
c.getBlue() + ", " + c.getAlpha();
|
||||||
} else {
|
} else {
|
||||||
return colorParams;
|
String s = "\"" + matte.getUiDefaultParentName() + "\", " +
|
||||||
}
|
matte.getHueOffset() + "f, " +
|
||||||
} else {
|
matte.getSaturationOffset() + "f, " +
|
||||||
String s = "getDerivedColor(\"" +
|
matte.getBrightnessOffset() + "f, " +
|
||||||
matte.getUiDefaultParentName()+"\","+
|
|
||||||
matte.getHueOffset()+"f,"+matte.getSaturationOffset()+
|
|
||||||
"f,"+matte.getBrightnessOffset()+"f,"+
|
|
||||||
matte.getAlphaOffset();
|
matte.getAlphaOffset();
|
||||||
if (matte.isUiResource()) {
|
if (! matte.isUiResource()) {
|
||||||
return s + ")";
|
s += ", false";
|
||||||
} else {
|
|
||||||
return s + ",false)";
|
|
||||||
}
|
}
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//TODO: What about gradients etc here?
|
//TODO: What about gradients etc here?
|
||||||
|
|
|
@ -101,14 +101,7 @@ final class ${LAF_NAME}Defaults {
|
||||||
*/
|
*/
|
||||||
private FontUIResource defaultFont;
|
private FontUIResource defaultFont;
|
||||||
|
|
||||||
/**
|
private ColorTree colorTree = new ColorTree();
|
||||||
* 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();
|
|
||||||
|
|
||||||
/** Listener for changes to user defaults table */
|
/** Listener for changes to user defaults table */
|
||||||
private DefaultsListener defaultsListener = new DefaultsListener();
|
private DefaultsListener defaultsListener = new DefaultsListener();
|
||||||
|
@ -117,14 +110,14 @@ final class ${LAF_NAME}Defaults {
|
||||||
void initialize() {
|
void initialize() {
|
||||||
// add listener for derived colors
|
// add listener for derived colors
|
||||||
UIManager.addPropertyChangeListener(defaultsListener);
|
UIManager.addPropertyChangeListener(defaultsListener);
|
||||||
UIManager.getDefaults().addPropertyChangeListener(defaultsListener);
|
UIManager.getDefaults().addPropertyChangeListener(colorTree);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called by UIManager when this look and feel is uninstalled. */
|
/** Called by UIManager when this look and feel is uninstalled. */
|
||||||
void uninitialize() {
|
void uninitialize() {
|
||||||
// remove listener for derived colors
|
// remove listener for derived colors
|
||||||
UIManager.getDefaults().removePropertyChangeListener(defaultsListener);
|
|
||||||
UIManager.removePropertyChangeListener(defaultsListener);
|
UIManager.removePropertyChangeListener(defaultsListener);
|
||||||
|
UIManager.getDefaults().removePropertyChangeListener(colorTree);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -663,22 +656,23 @@ ${UI_DEFAULT_INIT}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void addColor(UIDefaults d, String uin, int r, int g, int b, int a) {
|
||||||
* Get a derived color, derived colors are shared instances and will be
|
Color color = new ColorUIResource(new Color(r, g, b, a));
|
||||||
* updated when its parent UIDefault color changes.
|
colorTree.addColor(uin, color);
|
||||||
*
|
d.put(uin, color);
|
||||||
* @param uiDefaultParentName The parent UIDefault key
|
}
|
||||||
* @param hOffset The hue offset
|
|
||||||
* @param sOffset The saturation offset
|
private void addColor(UIDefaults d, String uin, String parentUin,
|
||||||
* @param bOffset The brightness offset
|
float hOffset, float sOffset, float bOffset, int aOffset) {
|
||||||
* @param aOffset The alpha offset
|
addColor(d, uin, parentUin, hOffset, sOffset, bOffset, aOffset, true);
|
||||||
* @return The stored derived color
|
}
|
||||||
*/
|
|
||||||
public DerivedColor getDerivedColor(String uiDefaultParentName,
|
private void addColor(UIDefaults d, String uin, String parentUin,
|
||||||
float hOffset, float sOffset,
|
float hOffset, float sOffset, float bOffset,
|
||||||
float bOffset, int aOffset){
|
int aOffset, boolean uiResource) {
|
||||||
return getDerivedColor(uiDefaultParentName, hOffset, sOffset,
|
Color color = getDerivedColor(uin, parentUin,
|
||||||
bOffset, aOffset, true);
|
hOffset, sOffset, bOffset, aOffset, uiResource);
|
||||||
|
d.put(uin, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -694,89 +688,110 @@ ${UI_DEFAULT_INIT}
|
||||||
* false if it should not be a UIResource
|
* false if it should not be a UIResource
|
||||||
* @return The stored derived color
|
* @return The stored derived color
|
||||||
*/
|
*/
|
||||||
public DerivedColor getDerivedColor(String uiDefaultParentName,
|
public DerivedColor getDerivedColor(String parentUin,
|
||||||
float hOffset, float sOffset,
|
float hOffset, float sOffset,
|
||||||
float bOffset, int aOffset,
|
float bOffset, int aOffset,
|
||||||
boolean uiResource){
|
boolean uiResource){
|
||||||
tmpDCKey.set(uiDefaultParentName, hOffset, sOffset, bOffset, aOffset,
|
return getDerivedColor(null, parentUin,
|
||||||
uiResource);
|
hOffset, sOffset, bOffset, aOffset, uiResource);
|
||||||
DerivedColor color = derivedColorsMap.get(tmpDCKey);
|
}
|
||||||
if (color == null){
|
|
||||||
|
private DerivedColor getDerivedColor(String uin, String parentUin,
|
||||||
|
float hOffset, float sOffset,
|
||||||
|
float bOffset, int aOffset,
|
||||||
|
boolean uiResource) {
|
||||||
|
DerivedColor color;
|
||||||
if (uiResource) {
|
if (uiResource) {
|
||||||
color = new DerivedColor.UIResource(uiDefaultParentName,
|
color = new DerivedColor.UIResource(parentUin,
|
||||||
hOffset, sOffset, bOffset, aOffset);
|
hOffset, sOffset, bOffset, aOffset);
|
||||||
} else {
|
} else {
|
||||||
color = new DerivedColor(uiDefaultParentName, hOffset, sOffset,
|
color = new DerivedColor(parentUin, hOffset, sOffset,
|
||||||
bOffset, aOffset);
|
bOffset, aOffset);
|
||||||
}
|
}
|
||||||
// calculate the initial value
|
|
||||||
color.rederiveColor();
|
if (derivedColors.containsKey(color)) {
|
||||||
// add the listener so that if the color changes we'll propogate it
|
return derivedColors.get(color);
|
||||||
color.addPropertyChangeListener(defaultsListener);
|
} else {
|
||||||
// add to the derived colors table
|
derivedColors.put(color, color);
|
||||||
derivedColorsMap.put(new DerivedColorKey(uiDefaultParentName,
|
color.rederiveColor(); /// move to ARP.decodeColor() ?
|
||||||
hOffset, sOffset, bOffset, aOffset, uiResource),color);
|
colorTree.addColor(uin, color);
|
||||||
}
|
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void set (String uiDefaultParentName, float hOffset,
|
private Map<DerivedColor, DerivedColor> derivedColors =
|
||||||
float sOffset, float bOffset, int aOffset,
|
new HashMap<DerivedColor, DerivedColor>();
|
||||||
boolean uiResource) {
|
|
||||||
this.uiDefaultParentName = uiDefaultParentName;
|
private class ColorTree implements PropertyChangeListener {
|
||||||
this.hOffset = hOffset;
|
private Node root = new Node(null, null);
|
||||||
this.sOffset = sOffset;
|
private Map<String, Node> nodes = new HashMap<String, Node>();
|
||||||
this.bOffset = bOffset;
|
|
||||||
this.aOffset = aOffset;
|
public Color getColor(String uin) {
|
||||||
this.uiResource = uiResource;
|
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
|
@Override
|
||||||
public boolean equals(Object o) {
|
public void propertyChange(PropertyChangeEvent ev) {
|
||||||
if (this == o) return true;
|
String name = ev.getPropertyName();
|
||||||
if (!(o instanceof DerivedColorKey)) return false;
|
Node node = nodes.get(name);
|
||||||
DerivedColorKey that = (DerivedColorKey) o;
|
if (node != null) {
|
||||||
if (aOffset != that.aOffset) return false;
|
// this is a registered color
|
||||||
if (Float.compare(that.bOffset, bOffset) != 0) return false;
|
node.parent.children.remove(node);
|
||||||
if (Float.compare(that.hOffset, hOffset) != 0) return false;
|
Color color = (Color) ev.getNewValue();
|
||||||
if (Float.compare(that.sOffset, sOffset) != 0) return false;
|
Node parent = getParentNode(color);
|
||||||
if (uiDefaultParentName != null ?
|
node.set(color, parent);
|
||||||
!uiDefaultParentName.equals(that.uiDefaultParentName) :
|
parent.children.add(node);
|
||||||
that.uiDefaultParentName != null) return false;
|
node.update();
|
||||||
if (this.uiResource != that.uiResource) return false;
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
class Node {
|
||||||
public int hashCode() {
|
Color color;
|
||||||
int result = super.hashCode();
|
Node parent;
|
||||||
result = 31 * result + uiDefaultParentName.hashCode();
|
List<Node> children = new LinkedList<Node>();
|
||||||
result = 31 * result + hOffset != +0.0f ?
|
|
||||||
Float.floatToIntBits(hOffset) : 0;
|
Node(Color color, Node parent) {
|
||||||
result = 31 * result + sOffset != +0.0f ?
|
set(color, parent);
|
||||||
Float.floatToIntBits(sOffset) : 0;
|
}
|
||||||
result = 31 * result + bOffset != +0.0f ?
|
|
||||||
Float.floatToIntBits(bOffset) : 0;
|
public void set(Color color, Node parent) {
|
||||||
result = 31 * result + aOffset;
|
this.color = color;
|
||||||
result = 31 * result + (uiResource ? 1 : 0);
|
this.parent = parent;
|
||||||
return result;
|
}
|
||||||
|
|
||||||
|
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 {
|
private class DefaultsListener implements PropertyChangeListener {
|
||||||
@Override
|
@Override
|
||||||
public void propertyChange(PropertyChangeEvent evt) {
|
public void propertyChange(PropertyChangeEvent evt) {
|
||||||
Object src = evt.getSource();
|
if ("lookAndFeel".equals(evt.getPropertyName())) {
|
||||||
String key = evt.getPropertyName();
|
|
||||||
if (key.equals("lookAndFeel")){
|
|
||||||
// LAF has been installed, this is the first point at which we
|
// LAF has been installed, this is the first point at which we
|
||||||
// can access our defaults table via UIManager so before now
|
// can access our defaults table via UIManager so before now
|
||||||
// all derived colors will be incorrect.
|
// all derived colors will be incorrect.
|
||||||
// First we need to update
|
// First we need to update
|
||||||
for (DerivedColor color : derivedColorsMap.values()) {
|
colorTree.update();
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -875,4 +853,3 @@ ${UI_DEFAULT_INIT}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,8 +39,6 @@ import java.beans.PropertyChangeListener;
|
||||||
* @author Jasper Potts
|
* @author Jasper Potts
|
||||||
*/
|
*/
|
||||||
class DerivedColor extends Color {
|
class DerivedColor extends Color {
|
||||||
private final PropertyChangeSupport changeSupport =
|
|
||||||
new PropertyChangeSupport(this);
|
|
||||||
private final String uiDefaultParentName;
|
private final String uiDefaultParentName;
|
||||||
private final float hOffset, sOffset, bOffset;
|
private final float hOffset, sOffset, bOffset;
|
||||||
private final int aOffset;
|
private final int aOffset;
|
||||||
|
@ -79,7 +77,6 @@ class DerivedColor extends Color {
|
||||||
* Recalculate the derived color from the UIManager parent color and offsets
|
* Recalculate the derived color from the UIManager parent color and offsets
|
||||||
*/
|
*/
|
||||||
public void rederiveColor() {
|
public void rederiveColor() {
|
||||||
int old = argbValue;
|
|
||||||
Color src = UIManager.getColor(uiDefaultParentName);
|
Color src = UIManager.getColor(uiDefaultParentName);
|
||||||
if (src != null) {
|
if (src != null) {
|
||||||
float[] tmp = Color.RGBtoHSB(src.getRed(), src.getGreen(), src.getBlue(), null);
|
float[] tmp = Color.RGBtoHSB(src.getRed(), src.getGreen(), src.getBlue(), null);
|
||||||
|
@ -97,7 +94,6 @@ class DerivedColor extends Color {
|
||||||
int alpha = clamp(aOffset);
|
int alpha = clamp(aOffset);
|
||||||
argbValue = (Color.HSBtoRGB(tmp[0], tmp[1], tmp[2]) & 0xFFFFFF) | (alpha << 24);
|
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;
|
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) {
|
private float clamp(float value) {
|
||||||
if (value < 0) {
|
if (value < 0) {
|
||||||
value = 0;
|
value = 0;
|
||||||
|
@ -211,5 +178,15 @@ class DerivedColor extends Color {
|
||||||
float bOffset, int aOffset) {
|
float bOffset, int aOffset) {
|
||||||
super(uiDefaultParentName, hOffset, sOffset, bOffset, 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.Graphics2D;
|
||||||
import java.awt.LayoutManager;
|
import java.awt.LayoutManager;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.beans.PropertyChangeEvent;
|
||||||
|
import java.beans.PropertyChangeListener;
|
||||||
|
import java.util.*;
|
||||||
import javax.swing.GrayFilter;
|
import javax.swing.GrayFilter;
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
import javax.swing.JToolBar;
|
import javax.swing.JToolBar;
|
||||||
|
@ -87,6 +90,8 @@ public class NimbusLookAndFeel extends SynthLookAndFeel {
|
||||||
*/
|
*/
|
||||||
private UIDefaults uiDefaults;
|
private UIDefaults uiDefaults;
|
||||||
|
|
||||||
|
private DefaultsListener defaultsListener = new DefaultsListener();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new NimbusLookAndFeel.
|
* Create a new NimbusLookAndFeel.
|
||||||
*/
|
*/
|
||||||
|
@ -115,8 +120,7 @@ public class NimbusLookAndFeel extends SynthLookAndFeel {
|
||||||
defaults.uninitialize();
|
defaults.uninitialize();
|
||||||
// clear all cached images to free memory
|
// clear all cached images to free memory
|
||||||
ImageCache.getInstance().flush();
|
ImageCache.getInstance().flush();
|
||||||
// remove the listeners and things installed by NimbusStyle
|
UIManager.getDefaults().removePropertyChangeListener(defaultsListener);
|
||||||
NimbusStyle.uninitialize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -515,4 +519,62 @@ public class NimbusLookAndFeel extends SynthLookAndFeel {
|
||||||
return obj;
|
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 javax.swing.Painter;
|
||||||
|
|
||||||
import java.beans.PropertyChangeEvent;
|
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.UIDefaults;
|
import javax.swing.UIDefaults;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
|
@ -39,16 +38,13 @@ import javax.swing.plaf.synth.SynthStyle;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.awt.Insets;
|
import java.awt.Insets;
|
||||||
import java.beans.PropertyChangeListener;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import sun.awt.AppContext;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>A SynthStyle implementation used by Nimbus. Each Region that has been
|
* <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);
|
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
|
* Pulls data out of UIDefaults, if it has not done so already, and sets
|
||||||
* up the internal state.
|
* up the internal state.
|
||||||
|
@ -283,66 +243,9 @@ public final class NimbusStyle extends SynthStyle {
|
||||||
// any Nimbus.Overrides)
|
// any Nimbus.Overrides)
|
||||||
values = new Values();
|
values = new Values();
|
||||||
|
|
||||||
// the profiler revealed that a great deal of CPU time and useless
|
Map<String, Object> defaults =
|
||||||
// garbage was being produced by this method and the init method. One
|
((NimbusLookAndFeel) UIManager.getLookAndFeel()).
|
||||||
// culprit was the creation and reparsing of the entire UIDefaults
|
getDefaultsForPrefix(prefix);
|
||||||
// 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);
|
|
||||||
|
|
||||||
// inspect the client properties for the key "Nimbus.Overrides". If the
|
// inspect the client properties for the key "Nimbus.Overrides". If the
|
||||||
// value is an instance of UIDefaults, then these defaults are used
|
// 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
|
//a list of the different types of states used by this style. This
|
||||||
//list may contain only "standard" states (those defined by Synth),
|
//list may contain only "standard" states (those defined by Synth),
|
||||||
//or it may contain custom states, or it may contain only "standard"
|
//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.
|
//"values" stateTypes to be a non-null array.
|
||||||
//Otherwise, let the "values" stateTypes be null to indicate that
|
//Otherwise, let the "values" stateTypes be null to indicate that
|
||||||
//there are no custom states or custom state ordering
|
//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) {
|
if (statesString != null) {
|
||||||
String s[] = statesString.split(",");
|
String s[] = statesString.split(",");
|
||||||
for (int i=0; i<s.length; i++) {
|
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
|
//this is a non-standard state name, so look for the
|
||||||
//custom state associated with it
|
//custom state associated with it
|
||||||
String stateName = prefix + "." + s[i];
|
String stateName = prefix + "." + s[i];
|
||||||
State customState = (State)myDefaults.get(stateName);
|
State customState = (State)defaults.get(stateName);
|
||||||
if (customState != null) {
|
if (customState != null) {
|
||||||
states.add(customState);
|
states.add(customState);
|
||||||
}
|
}
|
||||||
|
@ -455,7 +312,7 @@ public final class NimbusStyle extends SynthStyle {
|
||||||
//to be non-null. Otherwise, leave it null (meaning, use the
|
//to be non-null. Otherwise, leave it null (meaning, use the
|
||||||
//standard synth states).
|
//standard synth states).
|
||||||
if (states.size() > 0) {
|
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
|
//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
|
//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,
|
//The key is something like JButton.Enabled.backgroundPainter,
|
||||||
//or JButton.States, or JButton.background.
|
//or JButton.States, or JButton.background.
|
||||||
//Remove the "JButton." portion of the key
|
//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
|
//otherwise, assume it is a property and install it on the
|
||||||
//values object
|
//values object
|
||||||
if ("contentMargins".equals(property)) {
|
if ("contentMargins".equals(property)) {
|
||||||
v.contentMargins = (Insets)myDefaults.get(key);
|
values.contentMargins = (Insets)defaults.get(key);
|
||||||
} else if ("States".equals(property)) {
|
} else if ("States".equals(property)) {
|
||||||
//ignore
|
//ignore
|
||||||
} else {
|
} else {
|
||||||
v.defaults.put(property, myDefaults.get(key));
|
values.defaults.put(property, defaults.get(key));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//it is possible that the developer has a malformed UIDefaults
|
//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
|
//so put it in the UIDefaults associated with that runtime
|
||||||
//state
|
//state
|
||||||
if ("backgroundPainter".equals(property)) {
|
if ("backgroundPainter".equals(property)) {
|
||||||
rs.backgroundPainter = (Painter)myDefaults.get(key);
|
rs.backgroundPainter = getPainter(defaults, key);
|
||||||
} else if ("foregroundPainter".equals(property)) {
|
} else if ("foregroundPainter".equals(property)) {
|
||||||
rs.foregroundPainter = (Painter) myDefaults.get(key);
|
rs.foregroundPainter = getPainter(defaults, key);
|
||||||
} else if ("borderPainter".equals(property)) {
|
} else if ("borderPainter".equals(property)) {
|
||||||
rs.borderPainter = (Painter) myDefaults.get(key);
|
rs.borderPainter = getPainter(defaults, key);
|
||||||
} else {
|
} 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);
|
Collections.sort(runtimeStates, STATE_COMPARATOR);
|
||||||
|
|
||||||
//finally, set the array of runtime states on the values object
|
//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;
|
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…
Add table
Add a link
Reference in a new issue