|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
package com.sun.java.swing.plaf.windows; |
|
|
|
import java.awt.*; |
|
import java.beans.*; |
|
import java.lang.ref.*; |
|
import javax.swing.*; |
|
import javax.swing.plaf.*; |
|
|
|
/** |
|
* Wrapper for a value from the desktop. The value is lazily looked up, and |
|
* can be accessed using the <code>UIManager.ActiveValue</code> method |
|
* <code>createValue</code>. If the underlying desktop property changes this |
|
* will force the UIs to update all known Frames. You can invoke |
|
* <code>invalidate</code> to force the value to be fetched again. |
|
* |
|
*/ |
|
// NOTE: Don't rely on this class staying in this location. It is likely |
|
|
|
public class DesktopProperty implements UIDefaults.ActiveValue { |
|
|
|
|
|
*/ |
|
private static boolean updatePending; |
|
|
|
|
|
|
|
*/ |
|
private static final ReferenceQueue<DesktopProperty> queue = new ReferenceQueue<DesktopProperty>(); |
|
|
|
|
|
|
|
*/ |
|
private WeakPCL pcl; |
|
|
|
|
|
*/ |
|
private final String key; |
|
|
|
|
|
*/ |
|
private Object value; |
|
|
|
|
|
*/ |
|
private final Object fallback; |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static void flushUnreferencedProperties() { |
|
WeakPCL pcl; |
|
|
|
while ((pcl = (WeakPCL)queue.poll()) != null) { |
|
pcl.dispose(); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private static synchronized void setUpdatePending(boolean update) { |
|
updatePending = update; |
|
} |
|
|
|
|
|
|
|
*/ |
|
private static synchronized boolean isUpdatePending() { |
|
return updatePending; |
|
} |
|
|
|
|
|
|
|
*/ |
|
private static void updateAllUIs() { |
|
// Check if the current UI is WindowsLookAndfeel and flush the XP style map. |
|
|
|
Class uiClass = UIManager.getLookAndFeel().getClass(); |
|
if (uiClass.getPackage().equals(DesktopProperty.class.getPackage())) { |
|
XPStyle.invalidateStyle(); |
|
} |
|
Frame appFrames[] = Frame.getFrames(); |
|
for (Frame appFrame : appFrames) { |
|
updateWindowUI(appFrame); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
private static void updateWindowUI(Window window) { |
|
SwingUtilities.updateComponentTreeUI(window); |
|
Window ownedWins[] = window.getOwnedWindows(); |
|
for (Window ownedWin : ownedWins) { |
|
updateWindowUI(ownedWin); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public DesktopProperty(String key, Object fallback) { |
|
this.key = key; |
|
this.fallback = fallback; |
|
// The only sure fire way to clear our references is to create a |
|
// Thread and wait for a reference to be added to the queue. |
|
// Because it is so rare that you will actually change the look |
|
// and feel, this stepped is forgoed and a middle ground of |
|
// flushing references from the constructor is instead done. |
|
// The implication is that once one DesktopProperty is created |
|
// there will most likely be n (number of DesktopProperties created |
|
// by the LookAndFeel) WeakPCLs around, but this number will not |
|
|
|
flushUnreferencedProperties(); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public Object createValue(UIDefaults table) { |
|
if (value == null) { |
|
value = configureValue(getValueFromDesktop()); |
|
if (value == null) { |
|
value = configureValue(getDefaultValue()); |
|
} |
|
} |
|
return value; |
|
} |
|
|
|
|
|
|
|
*/ |
|
protected Object getValueFromDesktop() { |
|
Toolkit toolkit = Toolkit.getDefaultToolkit(); |
|
|
|
if (pcl == null) { |
|
pcl = new WeakPCL(this, getKey(), UIManager.getLookAndFeel()); |
|
toolkit.addPropertyChangeListener(getKey(), pcl); |
|
} |
|
|
|
return toolkit.getDesktopProperty(getKey()); |
|
} |
|
|
|
|
|
|
|
*/ |
|
protected Object getDefaultValue() { |
|
return fallback; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void invalidate(LookAndFeel laf) { |
|
invalidate(); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public void invalidate() { |
|
value = null; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected void updateUI() { |
|
if (!isUpdatePending()) { |
|
setUpdatePending(true); |
|
Runnable uiUpdater = new Runnable() { |
|
public void run() { |
|
updateAllUIs(); |
|
setUpdatePending(false); |
|
} |
|
}; |
|
SwingUtilities.invokeLater(uiUpdater); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
protected Object configureValue(Object value) { |
|
if (value != null) { |
|
if (value instanceof Color) { |
|
return new ColorUIResource((Color)value); |
|
} |
|
else if (value instanceof Font) { |
|
return new FontUIResource((Font)value); |
|
} |
|
else if (value instanceof UIDefaults.LazyValue) { |
|
value = ((UIDefaults.LazyValue)value).createValue(null); |
|
} |
|
else if (value instanceof UIDefaults.ActiveValue) { |
|
value = ((UIDefaults.ActiveValue)value).createValue(null); |
|
} |
|
} |
|
return value; |
|
} |
|
|
|
|
|
|
|
*/ |
|
protected String getKey() { |
|
return key; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static class WeakPCL extends WeakReference<DesktopProperty> |
|
implements PropertyChangeListener { |
|
private String key; |
|
private LookAndFeel laf; |
|
|
|
WeakPCL(DesktopProperty target, String key, LookAndFeel laf) { |
|
super(target, queue); |
|
this.key = key; |
|
this.laf = laf; |
|
} |
|
|
|
public void propertyChange(PropertyChangeEvent pce) { |
|
DesktopProperty property = get(); |
|
|
|
if (property == null || laf != UIManager.getLookAndFeel()) { |
|
// The property was GC'ed, we're no longer interested in |
|
|
|
dispose(); |
|
} |
|
else { |
|
property.invalidate(laf); |
|
property.updateUI(); |
|
} |
|
} |
|
|
|
void dispose() { |
|
Toolkit.getDefaultToolkit().removePropertyChangeListener(key, this); |
|
} |
|
} |
|
} |