com.jgoodies.looks.windows.WindowsLookAndFeel Maven / Gradle / Ivy
Show all versions of jgoodies-looks Show documentation
/*
* Copyright (c) 2001-2012 JGoodies Karsten Lentzsch. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* o Neither the name of JGoodies Karsten Lentzsch nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jgoodies.looks.windows;
import java.awt.Color;
import java.awt.Font;
import java.awt.Insets;
import java.lang.reflect.Method;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.LookAndFeel;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.plaf.IconUIResource;
import javax.swing.plaf.InsetsUIResource;
import javax.swing.plaf.basic.BasicBorders;
import com.jgoodies.common.base.SystemUtils;
import com.jgoodies.looks.FontPolicies;
import com.jgoodies.looks.FontPolicy;
import com.jgoodies.looks.FontSet;
import com.jgoodies.looks.LookUtils;
import com.jgoodies.looks.MicroLayout;
import com.jgoodies.looks.MicroLayoutPolicies;
import com.jgoodies.looks.MicroLayoutPolicy;
import com.jgoodies.looks.Options;
import com.jgoodies.looks.common.MinimumSizedIcon;
import com.jgoodies.looks.common.RGBGrayFilter;
import com.jgoodies.looks.common.ShadowPopupFactory;
/**
* The main class of the JGoodies Windows Look&Feel.
* This look provides several corrections and extensions to Sun's Windows L&F.
* In addition it tries to provide a unified look for the J2SE 1.4.0x, 1.4.1x,
* 1.4.2, and 1.5 environments.
*
* @author Karsten Lentzsch
* @version $Revision: 1.48 $
*/
public class WindowsLookAndFeel extends com.sun.java.swing.plaf.windows.WindowsLookAndFeel {
/**
* An optional client property key for JMenu and JToolBar
* to set a border style - shadows the header style.
*/
public static final String BORDER_STYLE_KEY = "jgoodies.windows.borderStyle";
/**
* Returns the String "JGoodies Windows".
* Note that this L&f's ID ("Windows") is inherited
* from the superclass, because we don't do any fundamental changes.
*
* @see LookAndFeel#getID()
*/
@Override
public String getName() {
return "JGoodies Windows";
}
@Override
public String getDescription() {
return "The JGoodies Windows Look and Feel"
+ " - \u00a9 2001-2012 JGoodies Karsten Lentzsch";
}
// Optional Settings ******************************************************
/**
* Looks up and retrieves the FontPolicy used by
* the JGoodies Windows Look&Feel.
* If a FontPolicy has been set for this look, it'll be returned.
* Otherwise, this method checks if a FontPolicy or FontSet is defined
* in the system properties or UIDefaults. If so, it is returned.
* If no FontPolicy has been set for this look, in the system
* properties or UIDefaults, the default Windows font policy
* will be returned.
*
* @return the FontPolicy set for this Look&feel - if any,
* the FontPolicy specified in the system properties or UIDefaults
* - if any, or the default Windows font policy.
*
* @see #setFontPolicy
* @see Options#WINDOWS_FONT_POLICY_KEY
* @see FontPolicies
* @see FontPolicies#customSettingsPolicy(FontPolicy)
* @see FontPolicies#getDefaultWindowsPolicy()
*/
public static FontPolicy getFontPolicy() {
FontPolicy policy =
(FontPolicy) UIManager.get(Options.WINDOWS_FONT_POLICY_KEY);
if (policy != null) {
return policy;
}
FontPolicy defaultPolicy = FontPolicies.getDefaultWindowsPolicy();
return FontPolicies.customSettingsPolicy(defaultPolicy);
}
/**
* Sets the FontPolicy to be used with the JGoodies Windows L&F.
* If the specified policy is {@code null}, the default will be reset.
*
* @param fontPolicy the FontPolicy to be used with the JGoodies Windows
* L&F, or {@code null} to reset to the default
*
* @see #getFontPolicy()
* @see Options#WINDOWS_FONT_POLICY_KEY
*/
public static void setFontPolicy(FontPolicy fontPolicy) {
UIManager.put(Options.WINDOWS_FONT_POLICY_KEY, fontPolicy);
}
/**
* Looks up and retrieves the MicroLayoutPolicy used by
* the JGoodies Windows Look&Feel.
* If a MicroLayoutPolicy has been set for this look, it'll be returned.
* Otherwise, the default Windows micro layout policy will be returned.
*
* @return the MicroLayoutPolicy set for this Look&feel - if any,
* or the default Windows MicroLayoutPolicy.
*
* @see #setMicroLayoutPolicy
* @see Options#WINDOWS_MICRO_LAYOUT_POLICY_KEY
* @see MicroLayoutPolicies
* @see MicroLayoutPolicies#getDefaultWindowsPolicy()
*/
public static MicroLayoutPolicy getMicroLayoutPolicy() {
MicroLayoutPolicy policy =
(MicroLayoutPolicy) UIManager.get(Options.WINDOWS_MICRO_LAYOUT_POLICY_KEY);
return policy != null
? policy
: MicroLayoutPolicies.getDefaultWindowsPolicy();
}
/**
* Sets the MicroLayoutPolicy to be used with the JGoodies Windows L&F.
* If the specified policy is {@code null}, the default will be reset.
*
* @param microLayoutPolicy the MicroLayoutPolicy to be used with
* the JGoodies Windows L&F, or {@code null} to reset
* to the default
*
* @see #getMicroLayoutPolicy()
* @see Options#WINDOWS_MICRO_LAYOUT_POLICY_KEY
*/
public static void setMicroLayoutPolicy(MicroLayout microLayoutPolicy) {
UIManager.put(Options.WINDOWS_MICRO_LAYOUT_POLICY_KEY, microLayoutPolicy);
}
// Overriding Superclass Behavior ***************************************
/**
* Invoked during {@code UIManager#setLookAndFeel}. In addition
* to the superclass behavior, we install the ShadowPopupFactory.
*
* @see #uninitialize
*/
@Override
public void initialize() {
super.initialize();
ShadowPopupFactory.install();
}
/**
* Invoked during {@code UIManager#setLookAndFeel}. In addition
* to the superclass behavior, we uninstall the ShadowPopupFactory.
*
* @see #initialize
*/
@Override
public void uninitialize() {
super.uninitialize();
ShadowPopupFactory.uninstall();
}
/**
* Returns an icon with a disabled appearance. This method is used
* to generate a disabled icon when one has not been specified.
*
* This method will be used only on JDK 5.0 and later.
*
* @param component the component that will display the icon, may be null.
* @param icon the icon to generate disabled icon from.
* @return disabled icon, or null if a suitable icon can not be generated.
*/
@Override
public Icon getDisabledIcon(JComponent component, Icon icon) {
Icon disabledIcon = RGBGrayFilter.getDisabledIcon(component, icon);
return disabledIcon != null
? new IconUIResource(disabledIcon)
: null;
}
/**
* Initializes the class defaults, that is, overrides some UI delegates
* with JGoodies Windows implementations.
*/
@Override
protected void initClassDefaults(UIDefaults table) {
super.initClassDefaults(table);
final String windowsPrefix = "com.jgoodies.looks.windows.Windows";
final String commonPrefix = "com.jgoodies.looks.common.ExtBasic";
// Overwrite some of the uiDefaults.
Object[] uiDefaults = {
// Modified size
"ComboBoxUI", windowsPrefix + "ComboBoxUI",
// Modified preferred height: can be even or odd
"ButtonUI", windowsPrefix + "ButtonUI",
// Can installs an optional etched border
"ScrollPaneUI", windowsPrefix + "ScrollPaneUI",
// Optional style and optional special borders
"MenuBarUI", windowsPrefix + "MenuBarUI",
// Provides an option for a no margin border
"PopupMenuUI", windowsPrefix + "PopupMenuUI",
// Honors the screen resolution and uses a minimum button width
"OptionPaneUI", windowsPrefix + "OptionPaneUI",
// 1.4.1 has ugly one touch triangles
"SplitPaneUI", windowsPrefix + "SplitPaneUI",
// Work in progress: Can have a flat presentation
"TabbedPaneUI", windowsPrefix + "TabbedPaneUI",
// Selects text after focus gained via keyboard
"TextFieldUI", windowsPrefix + "TextFieldUI",
"FormattedTextFieldUI", windowsPrefix + "FormattedTextFieldUI",
// Selects text after focus gained via keyboard
// Renders a dot, not the star ("*") character on Java 1.4 and 5
"PasswordFieldUI", windowsPrefix + "PasswordFieldUI",
// Updates the disabled and inactive background
"TextAreaUI", windowsPrefix + "TextAreaUI",
// Corrected position of the tree button icon
"TreeUI", windowsPrefix + "TreeUI",
// Just to use shared UI delegate
"SeparatorUI", windowsPrefix + "SeparatorUI",
"SpinnerUI", windowsPrefix + "SpinnerUI"};
// Aligned menu items
if ( !SystemUtils.IS_OS_WINDOWS_6_OR_LATER
|| !SystemUtils.IS_LAF_WINDOWS_XP_ENABLED) {
uiDefaults = append(uiDefaults,
"MenuItemUI", windowsPrefix + "MenuItemUI");
uiDefaults = append(uiDefaults,
"CheckBoxMenuItemUI", commonPrefix + "CheckBoxMenuItemUI");
uiDefaults = append(uiDefaults,
"RadioButtonMenuItemUI", commonPrefix + "RadioButtonMenuItemUI");
// Has padding above and below the separator lines
uiDefaults = append(uiDefaults,
"PopupMenuSeparatorUI", commonPrefix + "PopupMenuSeparatorUI");
}
if (SystemUtils.IS_LAF_WINDOWS_XP_ENABLED) {
// Aligned menu items
if (!SystemUtils.IS_OS_WINDOWS_6_OR_LATER) {
uiDefaults = append(uiDefaults,
"MenuUI", windowsPrefix + "XPMenuUI");
}
// Optional style and optional special borders;
// rollover borders for compound buttons
uiDefaults = append(uiDefaults,
"ToolBarUI", windowsPrefix + "XPToolBarUI");
// Honors XP table header style for custom user renderers.
uiDefaults = append(uiDefaults,
"TableHeaderUI", windowsPrefix + "XPTableHeaderUI");
} else {
// Aligned menu items
uiDefaults = append(uiDefaults,
"MenuUI", commonPrefix + "MenuUI");
// Optional style and optional special borders;
// rollover borders corrected
uiDefaults = append(uiDefaults,
"ToolBarUI", windowsPrefix + "ToolBarUI");
// Black arrows
uiDefaults = append(uiDefaults,
"ScrollBarUI", windowsPrefix + "ScrollBarUI");
}
table.putDefaults(uiDefaults);
}
/**
* Initializes the component defaults.
*/
@Override
protected void initComponentDefaults(UIDefaults table) {
super.initComponentDefaults(table);
final boolean isXP = SystemUtils.IS_LAF_WINDOWS_XP_ENABLED;
final boolean isClassic = !isXP;
final boolean isVista = SystemUtils.IS_OS_WINDOWS_6_OR_LATER;
initFontDefaults(table);
if (isClassic) {
initComponentDefaultsClassic(table);
}
MicroLayout microLayout = getMicroLayoutPolicy().getMicroLayout("Windows", table);
if (!isVista || !SystemUtils.IS_LAF_WINDOWS_XP_ENABLED) {
initMenuItemDefaults(table, microLayout);
}
Object marginBorder = new BasicBorders.MarginBorder();
Object checkBoxMargin = microLayout.getCheckBoxMargin();
Object etchedBorder = new UIDefaults.ProxyLazyValue(
"javax.swing.plaf.BorderUIResource",
"getEtchedBorderUIResource");
Object buttonBorder = new SimpleProxyLazyValue(
"com.jgoodies.looks.windows.WindowsLookAndFeel",
"getButtonBorder");
Object menuBorder = isXP
? WindowsBorders.getXPMenuBorder()
: WindowsBorders.getMenuBorder();
Object menuBarEmptyBorder = marginBorder;
Object menuBarSeparatorBorder = WindowsBorders.getSeparatorBorder();
Object menuBarEtchedBorder = WindowsBorders.getEtchedBorder();
Object menuBarHeaderBorder = WindowsBorders.getMenuBarHeaderBorder();
Object toolBarEmptyBorder = marginBorder;
Object toolBarSeparatorBorder = WindowsBorders.getSeparatorBorder();
Object toolBarEtchedBorder = WindowsBorders.getEtchedBorder();
Object toolBarHeaderBorder = WindowsBorders.getToolBarHeaderBorder();
Object buttonMargin = microLayout.getButtonMargin();
Object toolBarSeparatorSize = null;
Object textInsets = microLayout.getTextInsets();
Object wrappedTextInsets = microLayout.getWrappedTextInsets();
Insets comboEditorInsets = microLayout.getComboBoxEditorInsets();
int comboBorderSize = microLayout.getComboBorderSize();
int comboPopupBorderSize = microLayout.getComboPopupBorderSize();
int comboRendererGap = comboEditorInsets.left + comboBorderSize - comboPopupBorderSize;
Object comboRendererBorder = new EmptyBorder(1, comboRendererGap, 1, comboRendererGap);
Object comboTableEditorInsets = new Insets(0, 0, 0, 0);
Object popupMenuSeparatorMargin = microLayout.getPopupMenuSeparatorMargin();
// Should be active.
int treeFontSize = table.getFont("Tree.font").getSize();
Integer rowHeight = new Integer(treeFontSize + 6);
Color controlColor = table.getColor("control");
Object disabledTextBackground = table.getColor("TextField.disabledBackground");
Object inactiveTextBackground = table.getColor("TextField.inactiveBackground");
Object comboBoxDisabledBackground = isVista && isXP
? table.getColor("ComboBox.background")
: disabledTextBackground;
Object menuBarBackground = isXP
? table.get("control")
: table.get("menu");
Object menuSelectionBackground = isXP
? table.get("MenuItem.selectionBackground")
: table.get("Menu.background");
Object menuSelectionForeground = isXP
? table.get("MenuItem.selectionForeground")
: table.get("Menu.foreground");
Character passwordEchoChar = new Character(isXP ? '\u25CF' : '*');
Object[] defaults = {
"Button.border", buttonBorder,
"Button.margin", buttonMargin, // Sun's 14px margin is too wide
// 1.4.2 uses a 2 pixel non-standard border that leads to bad
// alignment in the typical case that the border is not painted
"CheckBox.border", marginBorder,
"CheckBox.margin", checkBoxMargin,
"ComboBox.disabledBackground", comboBoxDisabledBackground,
"ComboBox.editorBorder", marginBorder,
"ComboBox.editorColumns", new Integer(5),
"ComboBox.editorInsets", comboEditorInsets, // Added by JGoodies
"ComboBox.tableEditorInsets", comboTableEditorInsets,
"ComboBox.rendererBorder", comboRendererBorder, // Added by JGoodies
"EditorPane.margin", wrappedTextInsets,
// Begin 1.3 und 1.4.0
"Menu.border", menuBorder, // Fixed in 1.4.1
"Menu.borderPainted", Boolean.TRUE,
"Menu.background", menuBarBackground,
"Menu.selectionForeground", menuSelectionForeground,
"Menu.selectionBackground", menuSelectionBackground,
// End 1.3 und 1.4.0
"MenuBar.background", menuBarBackground,
"MenuBar.border", menuBarSeparatorBorder, // 1.4.1 Separator wrong
"MenuBar.emptyBorder", menuBarEmptyBorder, // Added by JGoodies
"MenuBar.separatorBorder", menuBarSeparatorBorder, // Added by JGoodies
"MenuBar.etchedBorder", menuBarEtchedBorder, // Added by JGoodies
"MenuBar.headerBorder", menuBarHeaderBorder, // Added by JGoodies
"FormattedTextField.disabledBackground", disabledTextBackground, // for readonly
"FormattedTextField.inactiveBackground", inactiveTextBackground, // for readonly
"FormattedTextField.margin", textInsets, // Poor in 1.6
"PasswordField.margin", textInsets, // Poor in 1.6
"PasswordField.echoChar", passwordEchoChar,
"PopupMenu.border", WindowsBorders.getPopupMenuBorder(),
"PopupMenu.noMarginBorder", WindowsBorders.getNoMarginPopupMenuBorder(),
"PopupMenuSeparator.margin", popupMenuSeparatorMargin,
"ScrollPane.etchedBorder", etchedBorder, // Added by JGoodies
"Spinner.defaultEditorInsets", textInsets, // Added by JGoodies
// 1.4.1 uses a 2 pixel non-standard border, that leads to bad
// alignment in the typical case that the border is not painted
"RadioButton.border", marginBorder,
"RadioButton.margin", checkBoxMargin,
"Spinner.border", table.get("TextField.border"),
"Table.gridColor", controlColor, // 1.4.1 Bug; active
"TextArea.margin", wrappedTextInsets, // 1.4.1 Bug
"TextArea.disabledBackground", disabledTextBackground,
"TextArea.inactiveBackground", inactiveTextBackground,
"TextField.margin", textInsets, // 1.4.1 Bug
"ToggleButton.margin", buttonMargin, // Sun's 14px margin is too wide
"ToolBar.emptyBorder", toolBarEmptyBorder, // Added by JGoodies
"ToolBar.separatorBorder", toolBarSeparatorBorder, // Added by JGoodies
"ToolBar.etchedBorder", toolBarEtchedBorder, // Added by JGoodies
"ToolBar.headerBorder", toolBarHeaderBorder, // Added by JGoodies
"ToolBar.separatorSize", toolBarSeparatorSize,
"ToolBar.margin", new InsetsUIResource(0, 10, 0, 0),
"Tree.selectionBorderColor", controlColor, // 1.4.1 Bug; active
"Tree.rowHeight", rowHeight, // 1.4.1 Bug
};
table.putDefaults(defaults);
}
/**
* Initializes component defaults required in classic mode only.
*/
private static void initComponentDefaultsClassic(UIDefaults table) {
Object checkBoxIcon = new SimpleProxyLazyValue(
"com.jgoodies.looks.windows.WindowsLookAndFeel",
"getCheckBoxIcon");
Object radioButtonIcon = new SimpleProxyLazyValue(
"com.jgoodies.looks.windows.WindowsLookAndFeel",
"getRadioButtonIcon");
Border winInsetBorder = new BasicBorders.FieldBorder(table
.getColor("controlShadow"), table
.getColor("controlDkShadow"),
table.getColor("controlHighlight"), table
.getColor("controlLtHighlight"));
Object[] defaults = {
"CheckBox.checkColor", table.get("controlText"), // kind-of black
"CheckBox.icon", checkBoxIcon,
"RadioButton.checkColor", table.get("controlText"), // kind-of black
"RadioButton.icon", radioButtonIcon,
"Table.scrollPaneBorder", winInsetBorder, // 1.4.1 Bug
};
table.putDefaults(defaults);
}
/**
* Looks up the correct control font and sets it for all controls.
*/
private static void initFontDefaults(UIDefaults table) {
FontPolicy fontChoicePolicy = getFontPolicy();
FontSet fontSet = fontChoicePolicy.getFontSet("Windows", table);
initFontDefaults(table, fontSet);
}
private static void initMenuItemDefaults(UIDefaults table, MicroLayout microLayout) {
Object menuMargin = microLayout.getMenuMargin();
Object menuItemMargin = microLayout.getMenuItemMargin();
Icon menuItemCheckIcon = new MinimumSizedIcon();
Object[] defaults = {
"Menu.margin", menuMargin, // 1.4.1 Bug
"MenuItem.borderPainted", Boolean.TRUE,
"MenuItem.checkIcon", menuItemCheckIcon, // Aligns menu items
"MenuItem.margin", menuItemMargin, // 1.4.1 Bug
"CheckBoxMenuItem.margin", menuItemMargin, // 1.4.1 Bug
"RadioButtonMenuItem.margin", menuItemMargin, // 1.4.1 Bug
};
table.putDefaults(defaults);
}
/**
* Sets Fonts in the given FontSet as defaults for all known
* component types in the given UIDefaults table.
*
* @param table the UIDefaults table used to set fonts
* @param fontSet describes the set of Fonts to be installed
*/
private static void initFontDefaults(UIDefaults table, FontSet fontSet) {
Font controlFont = fontSet.getControlFont();
Font menuFont = fontSet.getMenuFont();
Font messageFont = fontSet.getMessageFont();
Font toolTipFont = fontSet.getSmallFont();
Font titleFont = fontSet.getTitleFont();
Font windowFont = fontSet.getWindowTitleFont();
Object[] defaults = {
"Button.font", controlFont,
"CheckBox.font", controlFont,
"ColorChooser.font", controlFont,
"ComboBox.font", controlFont,
"EditorPane.font", controlFont,
"FormattedTextField.font", controlFont,
"Label.font", controlFont,
"List.font", controlFont,
"Panel.font", controlFont,
"PasswordField.font", controlFont,
"ProgressBar.font", controlFont,
"RadioButton.font", controlFont,
"ScrollPane.font", controlFont,
"Spinner.font", controlFont,
"TabbedPane.font", controlFont,
"Table.font", controlFont,
"TableHeader.font", controlFont,
"TextArea.font", controlFont,
"TextField.font", controlFont,
"TextPane.font", controlFont,
"ToolBar.font", controlFont,
"ToggleButton.font", controlFont,
"Tree.font", controlFont,
"Viewport.font", controlFont,
"InternalFrame.titleFont", windowFont, // controlBold
"OptionPane.font", messageFont,
"OptionPane.messageFont", messageFont,
"OptionPane.buttonFont", messageFont,
"TitledBorder.font", titleFont,
"ToolTip.font", toolTipFont,
"CheckBoxMenuItem.font", menuFont,
"CheckBoxMenuItem.acceleratorFont", menuFont, // 1.3 only ?
"Menu.font", menuFont,
"Menu.acceleratorFont", menuFont,
"MenuBar.font", menuFont,
"MenuItem.font", menuFont,
"MenuItem.acceleratorFont", menuFont,
"PopupMenu.font", menuFont,
"RadioButtonMenuItem.font", menuFont,
"RadioButtonMenuItem.acceleratorFont", menuFont, // 1.3 only ?
};
table.putDefaults(defaults);
}
// Getters for Proxy Access (Referred classes can stay package visible) ***
public static Border getButtonBorder() {
return WindowsBorders.getButtonBorder();
}
public static Icon getCheckBoxIcon() {
return WindowsIconFactory.getCheckBoxIcon();
}
public static Icon getRadioButtonIcon() {
return WindowsIconFactory.getRadioButtonIcon();
}
// Helper Code ************************************************************
/**
* Appends the key and value to the given source array and returns
* a copy that has the two new elements at its end.
*
* @return an array with the key and value appended
*/
private static Object[] append(Object[] source, String key, Object value) {
int length = source.length;
Object[] destination = new Object[length + 2];
System.arraycopy(source, 0, destination, 0, length);
destination[length] = key;
destination[length + 1] = value;
return destination;
}
// Helper Class ***********************************************************
/**
* This class provides an implementation of {@code LazyValue} that
* can be used to delay loading of the Class for the instance to be created.
* It also avoids creation of an anonymous inner class for the
* {@code LazyValue}
* subclass. Both of these improve performance at the time that a
* a Look and Feel is loaded, at the cost of a slight performance
* reduction the first time {@code createValue} is called
* (since Reflection APIs are used).
*/
private static class SimpleProxyLazyValue implements UIDefaults.LazyValue {
private final String className;
private final String methodName;
/**
* Creates a {@code LazyValue} which will construct an instance
* when asked.
*
* @param c a {@code String} specifying the classname of the class
* containing a static method to be called for instance creation
* @param m a {@code String} specifying the static
* method to be called on class c
*/
public SimpleProxyLazyValue(String c, String m) {
className = c;
methodName = m;
}
/**
* Creates the value retrieved from the {@code UIDefaults} table.
* The object is created each time it is accessed.
*
* @param table a {@code UIDefaults} table
* @return the created {@code Object}
*/
@Override
public Object createValue(UIDefaults table) {
Object instance = null;
try {
Class c;
// We use a separate ClassLoader
ClassLoader classLoader = table != null
? (ClassLoader) table.get("ClassLoader")
: Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = getClass().getClassLoader();
}
c = Class.forName(className, true, classLoader);
Method m = c.getMethod(methodName, (Class[]) null);
instance = m.invoke(c, (Object[]) null);
} catch (Throwable t) {
LookUtils.log("Problem creating " + className + " with method "
+ methodName + t);
}
return instance;
}
}
}