0001: /*
0002: * Copyright (c) 2001-2007 JGoodies Karsten Lentzsch. All Rights Reserved.
0003: *
0004: * Redistribution and use in source and binary forms, with or without
0005: * modification, are permitted provided that the following conditions are met:
0006: *
0007: * o Redistributions of source code must retain the above copyright notice,
0008: * this list of conditions and the following disclaimer.
0009: *
0010: * o Redistributions in binary form must reproduce the above copyright notice,
0011: * this list of conditions and the following disclaimer in the documentation
0012: * and/or other materials provided with the distribution.
0013: *
0014: * o Neither the name of JGoodies Karsten Lentzsch nor the names of
0015: * its contributors may be used to endorse or promote products derived
0016: * from this software without specific prior written permission.
0017: *
0018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
0020: * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
0021: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
0022: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
0025: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
0026: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
0027: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
0028: * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0029: */
0030:
0031: package com.jgoodies.looks.plastic;
0032:
0033: import java.awt.Color;
0034: import java.awt.Insets;
0035: import java.awt.Toolkit;
0036: import java.lang.reflect.InvocationTargetException;
0037: import java.lang.reflect.Method;
0038: import java.util.ArrayList;
0039: import java.util.Collections;
0040: import java.util.Comparator;
0041: import java.util.List;
0042:
0043: import javax.swing.Icon;
0044: import javax.swing.JComponent;
0045: import javax.swing.UIDefaults;
0046: import javax.swing.UIManager;
0047: import javax.swing.border.Border;
0048: import javax.swing.border.EmptyBorder;
0049: import javax.swing.plaf.*;
0050: import javax.swing.plaf.basic.BasicBorders;
0051: import javax.swing.plaf.metal.MetalLookAndFeel;
0052: import javax.swing.plaf.metal.MetalTheme;
0053:
0054: import com.jgoodies.looks.*;
0055: import com.jgoodies.looks.common.MinimumSizedIcon;
0056: import com.jgoodies.looks.common.RGBGrayFilter;
0057: import com.jgoodies.looks.common.ShadowPopupFactory;
0058: import com.jgoodies.looks.plastic.theme.SkyBluer;
0059:
0060: /**
0061: * The base class for the JGoodies Plastic look&feel family.
0062: * Initializes class and component defaults for the Plastic L&f
0063: * and provides keys and optional features for the Plastic family.
0064: *
0065: * @author Karsten Lentzsch
0066: * @version $Revision: 1.36 $
0067: */
0068: public class PlasticLookAndFeel extends MetalLookAndFeel {
0069:
0070: // System and Client Property Keys ****************************************
0071:
0072: /**
0073: * Client property key to set a border style - shadows the header style.
0074: */
0075: public static final String BORDER_STYLE_KEY = "Plastic.borderStyle";
0076:
0077: /**
0078: * Client property key to disable the pseudo 3D effect.
0079: */
0080: public static final String IS_3D_KEY = "Plastic.is3D";
0081:
0082: /**
0083: * A System property key to set the default theme.
0084: */
0085: public static final String DEFAULT_THEME_KEY = "Plastic.defaultTheme";
0086:
0087: /**
0088: * A System property key that indicates that the high contrast
0089: * focus colors shall be choosen - if applicable.
0090: * If not set, some focus colors look good but have low contrast.
0091: * Basically, the low contrast scheme uses the Plastic colors
0092: * before 1.0.7, and the high contrast scheme is 1.0.7 - 1.0.9.
0093: */
0094: public static final String HIGH_CONTRAST_FOCUS_ENABLED_KEY = "Plastic.highContrastFocus";
0095:
0096: /**
0097: * A System property key for the rendering style of the Plastic
0098: * TabbedPane. Valid values are: <tt>default</tt> for the
0099: * Plastic 1.0 tabs, and <tt>metal</tt> for the Metal L&F tabs.
0100: */
0101: protected static final String TAB_STYLE_KEY = "Plastic.tabStyle";
0102:
0103: /**
0104: * A System property value that indicates that Plastic shall render
0105: * tabs in the Plastic 1.0 style. This is the default.
0106: */
0107: public static final String TAB_STYLE_DEFAULT_VALUE = "default";
0108:
0109: /**
0110: * A System property value that indicates that Plastic shall
0111: * render tabs in the Metal L&F style.
0112: */
0113: public static final String TAB_STYLE_METAL_VALUE = "metal";
0114:
0115: /**
0116: * A UIManager key used to store and retrieve the PlasticTheme in Java 1.4
0117: *
0118: * @see #getPlasticTheme()
0119: * @see #setPlasticTheme(PlasticTheme)
0120: */
0121: private static final Object THEME_KEY = new StringBuffer(
0122: "Plastic.theme");
0123:
0124: // State *****************************************************************
0125:
0126: /**
0127: * Holds whether Plastic uses Metal or Plastic tabbed panes.
0128: */
0129: private static boolean useMetalTabs = LookUtils.getSystemProperty(
0130: TAB_STYLE_KEY, "").equalsIgnoreCase(TAB_STYLE_METAL_VALUE);
0131:
0132: /**
0133: * Holds whether we are using the high contrast focus colors.
0134: */
0135: private static boolean useHighContrastFocusColors = LookUtils
0136: .getSystemProperty(HIGH_CONTRAST_FOCUS_ENABLED_KEY) != null;
0137:
0138: /**
0139: * The List of installed Plastic themes.
0140: */
0141: private static List installedThemes;
0142:
0143: /** The look-global state for the 3D enablement. */
0144: private static boolean is3DEnabled = false;
0145:
0146: private static boolean selectTextOnKeyboardFocusGained = LookUtils.IS_OS_WINDOWS;
0147:
0148: /**
0149: * In Java 5 or later, this field holds the public static method
0150: * <code>MetalLookAndFeel#getCurrentTheme</code>.
0151: */
0152: private static Method getCurrentThemeMethod = null;
0153:
0154: static {
0155: if (LookUtils.IS_JAVA_5_OR_LATER) {
0156: getCurrentThemeMethod = getMethodGetCurrentTheme();
0157: }
0158: }
0159:
0160: // Instance Creation ******************************************************
0161:
0162: /**
0163: * Constructs the PlasticLookAndFeel, creates the default theme
0164: * and sets it as current Plastic theme.
0165: */
0166: public PlasticLookAndFeel() {
0167: getPlasticTheme();
0168: }
0169:
0170: // L&f Description ********************************************************
0171:
0172: public String getID() {
0173: return "JGoodies Plastic";
0174: }
0175:
0176: public String getName() {
0177: return "JGoodies Plastic";
0178: }
0179:
0180: public String getDescription() {
0181: return "The JGoodies Plastic Look and Feel"
0182: + " - \u00a9 2001-2007 JGoodies Karsten Lentzsch";
0183: }
0184:
0185: // Optional Settings ******************************************************
0186:
0187: /**
0188: * Looks up and retrieves the FontPolicy used
0189: * by the JGoodies Plastic Look&Feel family.
0190: * If a FontPolicy has been set, it'll be returned.
0191: * Otherwise, this method checks if a FontPolicy or FontSet is defined
0192: * in the system properties or UIDefaults. If so, it is returned.
0193: * If no FontPolicy has been set for this look, in the system
0194: * properties or UIDefaults, the default Plastic font policy
0195: * will be returned.
0196: *
0197: * @return the FontPolicy set for this Look&feel - if any,
0198: * the FontPolicy specified in the system properties or UIDefaults
0199: * - if any, or the default Plastic font policy.
0200: *
0201: * @see #setFontPolicy
0202: * @see Options#PLASTIC_FONT_POLICY_KEY
0203: * @see FontPolicies
0204: * @see FontPolicies#customSettingsPolicy(FontPolicy)
0205: * @see FontPolicies#getDefaultPlasticPolicy()
0206: */
0207: public static FontPolicy getFontPolicy() {
0208: FontPolicy policy = (FontPolicy) UIManager
0209: .get(Options.PLASTIC_FONT_POLICY_KEY);
0210: if (policy != null)
0211: return policy;
0212:
0213: FontPolicy defaultPolicy = FontPolicies
0214: .getDefaultPlasticPolicy();
0215: return FontPolicies.customSettingsPolicy(defaultPolicy);
0216: }
0217:
0218: /**
0219: * Sets the FontPolicy to be used with the JGoodies Plastic L&F
0220: * family. If the specified policy is <code>null</code>, the default will
0221: * be reset.
0222: *
0223: * @param fontPolicy the FontPolicy to be used with
0224: * the JGoodies Plastic L&F family, or <code>null</code> to reset
0225: * to the default
0226: *
0227: * @see #getFontPolicy()
0228: * @see Options#PLASTIC_FONT_POLICY_KEY
0229: */
0230: public static void setFontPolicy(FontPolicy fontPolicy) {
0231: UIManager.put(Options.PLASTIC_FONT_POLICY_KEY, fontPolicy);
0232: }
0233:
0234: /**
0235: * Looks up and retrieves the MicroLayoutPolicy used by
0236: * the JGoodies Plastic Look&Fs.
0237: * If a MicroLayoutPolicy has been set for this look, it'll be returned.
0238: * Otherwise, the default Plastic micro layout policy will be returned.
0239: *
0240: * @return the MicroLayoutPolicy set for this Look&feel - if any,
0241: * or the default Plastic MicroLayoutPolicy.
0242: *
0243: * @see #setMicroLayoutPolicy
0244: * @see Options#PLASTIC_MICRO_LAYOUT_POLICY_KEY
0245: * @see MicroLayoutPolicies
0246: */
0247: public static MicroLayoutPolicy getMicroLayoutPolicy() {
0248: MicroLayoutPolicy policy = (MicroLayoutPolicy) UIManager
0249: .get(Options.PLASTIC_MICRO_LAYOUT_POLICY_KEY);
0250: return policy != null ? policy : MicroLayoutPolicies
0251: .getDefaultPlasticPolicy();
0252: }
0253:
0254: /**
0255: * Sets the MicroLayoutPolicy to be used with the JGoodies Plastic L&Fs.
0256: * If the specified policy is <code>null</code>, the default will be reset.
0257: *
0258: * @param microLayoutPolicy the MicroLayoutPolicy to be used with
0259: * the JGoodies Plastic L&Fs, or <code>null</code> to reset
0260: * to the default
0261: *
0262: * @see #getMicroLayoutPolicy()
0263: * @see Options#PLASTIC_MICRO_LAYOUT_POLICY_KEY
0264: */
0265: public static void setMicroLayoutPolicy(
0266: MicroLayout microLayoutPolicy) {
0267: UIManager.put(Options.PLASTIC_MICRO_LAYOUT_POLICY_KEY,
0268: microLayoutPolicy);
0269: }
0270:
0271: protected boolean is3DEnabled() {
0272: return is3DEnabled;
0273: }
0274:
0275: public static void set3DEnabled(boolean b) {
0276: is3DEnabled = b;
0277: }
0278:
0279: public static String getTabStyle() {
0280: return useMetalTabs ? TAB_STYLE_METAL_VALUE
0281: : TAB_STYLE_DEFAULT_VALUE;
0282: }
0283:
0284: public static void setTabStyle(String tabStyle) {
0285: useMetalTabs = tabStyle.equalsIgnoreCase(TAB_STYLE_METAL_VALUE);
0286: }
0287:
0288: public static boolean getHighContrastFocusColorsEnabled() {
0289: return useHighContrastFocusColors;
0290: }
0291:
0292: public static void setHighContrastFocusColorsEnabled(boolean b) {
0293: useHighContrastFocusColors = b;
0294: }
0295:
0296: public static boolean isSelectTextOnKeyboardFocusGained() {
0297: return selectTextOnKeyboardFocusGained;
0298: }
0299:
0300: /**
0301: * Sets whether text field text shall be selected when it gains focus
0302: * via the keyboard. This is enabled on Windows by default and
0303: * disabled on all other platforms.
0304: *
0305: * @param b
0306: */
0307: public static void setSelectTextOnKeyboardFocusGained(boolean b) {
0308: selectTextOnKeyboardFocusGained = b;
0309: }
0310:
0311: // Overriding Superclass Behavior ***************************************
0312:
0313: /**
0314: * Invoked during <code>UIManager#setLookAndFeel</code>. In addition
0315: * to the superclass behavior, we install the ShadowPopupFactory.
0316: *
0317: * @see #uninitialize
0318: */
0319: public void initialize() {
0320: super .initialize();
0321: ShadowPopupFactory.install();
0322: }
0323:
0324: /**
0325: * Invoked during <code>UIManager#setLookAndFeel</code>. In addition
0326: * to the superclass behavior, we uninstall the ShadowPopupFactory.
0327: *
0328: * @see #initialize
0329: */
0330: public void uninitialize() {
0331: super .uninitialize();
0332: ShadowPopupFactory.uninstall();
0333: }
0334:
0335: /**
0336: * Returns an icon with a disabled appearance. This method is used
0337: * to generate a disabled icon when one has not been specified.<p>
0338: *
0339: * This method will be used only on JDK 5.0 and later.
0340: *
0341: * @param component the component that will display the icon, may be null.
0342: * @param icon the icon to generate disabled icon from.
0343: * @return disabled icon, or null if a suitable icon can not be generated.
0344: */
0345: public Icon getDisabledIcon(JComponent component, Icon icon) {
0346: Icon disabledIcon = RGBGrayFilter.getDisabledIcon(component,
0347: icon);
0348: return disabledIcon != null ? new IconUIResource(disabledIcon)
0349: : null;
0350: }
0351:
0352: /**
0353: * Initializes the class defaults, that is, overrides some UI delegates
0354: * with JGoodies Plastic implementations.
0355: *
0356: * @param table the UIDefaults table to work with
0357: * @see javax.swing.plaf.basic.BasicLookAndFeel#getDefaults()
0358: */
0359: protected void initClassDefaults(UIDefaults table) {
0360: super .initClassDefaults(table);
0361:
0362: final String plasticPrefix = "com.jgoodies.looks.plastic.Plastic";
0363: final String commonPrefix = "com.jgoodies.looks.common.ExtBasic";
0364:
0365: // Overwrite some of the uiDefaults.
0366: Object[] uiDefaults = {
0367: // 3D effect; optional narrow margins
0368: "ButtonUI",
0369: plasticPrefix + "ButtonUI",
0370: "ToggleButtonUI",
0371: plasticPrefix + "ToggleButtonUI",
0372:
0373: // 3D effect
0374: "ComboBoxUI",
0375: plasticPrefix + "ComboBoxUI",
0376: "ScrollBarUI",
0377: plasticPrefix + "ScrollBarUI",
0378: "SpinnerUI",
0379: plasticPrefix + "SpinnerUI",
0380:
0381: // Special borders defined by border style or header style, see LookUtils
0382: "MenuBarUI",
0383: plasticPrefix + "MenuBarUI",
0384: "ToolBarUI",
0385: plasticPrefix + "ToolBarUI",
0386:
0387: // Aligns menu icons
0388: "MenuUI",
0389: plasticPrefix + "MenuUI",
0390: "MenuItemUI",
0391: commonPrefix + "MenuItemUI",
0392: "CheckBoxMenuItemUI",
0393: commonPrefix + "CheckBoxMenuItemUI",
0394: "RadioButtonMenuItemUI",
0395: commonPrefix + "RadioButtonMenuItemUI",
0396:
0397: // Provides an option for a no margin border
0398: "PopupMenuUI",
0399: plasticPrefix + "PopupMenuUI",
0400:
0401: // Has padding above and below the separator lines
0402: "PopupMenuSeparatorUI",
0403: commonPrefix + "PopupMenuSeparatorUI",
0404:
0405: // Honors the screen resolution and uses a minimum button width
0406: "OptionPaneUI",
0407: plasticPrefix + "OptionPaneUI",
0408:
0409: // Can installs an optional etched border
0410: "ScrollPaneUI",
0411: plasticPrefix + "ScrollPaneUI",
0412:
0413: // Uses a modified split divider
0414: "SplitPaneUI",
0415: plasticPrefix + "SplitPaneUI",
0416:
0417: // Renders a circle, not a star '*' in Java 1.4 and Java 5
0418: // Selects all text after focus gain via keyboard.
0419: "PasswordFieldUI",
0420: plasticPrefix + "PasswordFieldUI",
0421:
0422: // Updates the disabled and inactive background
0423: "TextAreaUI",
0424: plasticPrefix + "TextAreaUI",
0425:
0426: // Modified icons and lines
0427: "TreeUI",
0428: plasticPrefix + "TreeUI",
0429:
0430: // Just to use Plastic colors
0431: "InternalFrameUI",
0432: plasticPrefix + "InternalFrameUI",
0433:
0434: // Share the UI delegate instances
0435: "SeparatorUI", plasticPrefix + "SeparatorUI",
0436: "ToolBarSeparatorUI",
0437: plasticPrefix + "ToolBarSeparatorUI",
0438:
0439: // Optionally looks up the system icons
0440: "FileChooserUI", plasticPrefix + "FileChooserUI"
0441:
0442: };
0443: if (!useMetalTabs) {
0444: // Modified tabs and ability use a version with reduced borders.
0445: uiDefaults = append(uiDefaults, "TabbedPaneUI",
0446: plasticPrefix + "TabbedPaneUI");
0447: }
0448: if (isSelectTextOnKeyboardFocusGained()) {
0449: // Selects all text after focus gain via keyboard.
0450: uiDefaults = append(uiDefaults, "TextFieldUI",
0451: plasticPrefix + "TextFieldUI");
0452: uiDefaults = append(uiDefaults, "FormattedTextFieldUI",
0453: plasticPrefix + "FormattedTextFieldUI");
0454: }
0455: table.putDefaults(uiDefaults);
0456: }
0457:
0458: protected void initComponentDefaults(UIDefaults table) {
0459: super .initComponentDefaults(table);
0460:
0461: MicroLayout microLayout = getMicroLayoutPolicy()
0462: .getMicroLayout(getName(), table);
0463: Insets buttonBorderInsets = microLayout.getButtonBorderInsets();
0464:
0465: Object marginBorder = new BasicBorders.MarginBorder();
0466:
0467: Object buttonBorder = PlasticBorders
0468: .getButtonBorder(buttonBorderInsets);
0469: Object comboBoxButtonBorder = PlasticBorders
0470: .getComboBoxArrowButtonBorder();
0471: Border comboBoxEditorBorder = PlasticBorders
0472: .getComboBoxEditorBorder();
0473: Object menuItemBorder = PlasticBorders.getMenuItemBorder();
0474: Object textFieldBorder = PlasticBorders.getTextFieldBorder();
0475: Object toggleButtonBorder = PlasticBorders
0476: .getToggleButtonBorder(buttonBorderInsets);
0477:
0478: Object scrollPaneBorder = PlasticBorders.getScrollPaneBorder();
0479: Object tableHeaderBorder = new BorderUIResource((Border) table
0480: .get("TableHeader.cellBorder"));
0481:
0482: Object menuBarEmptyBorder = marginBorder;
0483: Object menuBarSeparatorBorder = PlasticBorders
0484: .getSeparatorBorder();
0485: Object menuBarEtchedBorder = PlasticBorders.getEtchedBorder();
0486: Object menuBarHeaderBorder = PlasticBorders
0487: .getMenuBarHeaderBorder();
0488:
0489: Object toolBarEmptyBorder = marginBorder;
0490: Object toolBarSeparatorBorder = PlasticBorders
0491: .getSeparatorBorder();
0492: Object toolBarEtchedBorder = PlasticBorders.getEtchedBorder();
0493: Object toolBarHeaderBorder = PlasticBorders
0494: .getToolBarHeaderBorder();
0495:
0496: Object internalFrameBorder = getInternalFrameBorder();
0497: Object paletteBorder = getPaletteBorder();
0498:
0499: Color controlColor = table.getColor("control");
0500:
0501: Object checkBoxIcon = PlasticIconFactory.getCheckBoxIcon();
0502: Object checkBoxMargin = microLayout.getCheckBoxMargin();
0503:
0504: Object buttonMargin = microLayout.getButtonMargin();
0505: Object textInsets = microLayout.getTextInsets();
0506: Object wrappedTextInsets = microLayout.getWrappedTextInsets();
0507: Insets comboEditorInsets = microLayout
0508: .getComboBoxEditorInsets();
0509:
0510: Insets comboEditorBorderInsets = comboBoxEditorBorder
0511: .getBorderInsets(null);
0512: int comboBorderSize = comboEditorBorderInsets.left;
0513: int comboPopupBorderSize = microLayout
0514: .getComboPopupBorderSize();
0515: int comboRendererGap = comboEditorInsets.left + comboBorderSize
0516: - comboPopupBorderSize;
0517: Object comboRendererBorder = new EmptyBorder(1,
0518: comboRendererGap, 1, comboRendererGap);
0519: Object comboTableEditorInsets = new Insets(0, 0, 0, 0);
0520:
0521: Object menuItemMargin = microLayout.getMenuItemMargin();
0522: Object menuMargin = microLayout.getMenuMargin();
0523:
0524: Icon menuItemCheckIcon = new MinimumSizedIcon();
0525: Icon checkBoxMenuItemIcon = PlasticIconFactory
0526: .getCheckBoxMenuItemIcon();
0527: Icon radioButtonMenuItemIcon = PlasticIconFactory
0528: .getRadioButtonMenuItemIcon();
0529:
0530: Color menuItemForeground = table
0531: .getColor("MenuItem.foreground");
0532:
0533: Color inactiveTextBackground = table
0534: .getColor("TextField.inactiveBackground");
0535:
0536: // Should be active.
0537: int treeFontSize = table.getFont("Tree.font").getSize();
0538: Integer rowHeight = new Integer(treeFontSize + 6);
0539: Object treeExpandedIcon = PlasticIconFactory
0540: .getExpandedTreeIcon();
0541: Object treeCollapsedIcon = PlasticIconFactory
0542: .getCollapsedTreeIcon();
0543: ColorUIResource gray = new ColorUIResource(Color.GRAY);
0544:
0545: Boolean is3D = Boolean.valueOf(is3DEnabled());
0546:
0547: Character passwordEchoChar = new Character(
0548: LookUtils.IS_OS_WINDOWS ? '\u25CF' : '\u2022');
0549:
0550: String iconPrefix = "icons/"
0551: + (LookUtils.IS_LOW_RESOLUTION ? "32x32/" : "48x48/");
0552: Object errorIcon = makeIcon(getClass(), iconPrefix
0553: + "dialog-error.png");
0554: Object informationIcon = makeIcon(getClass(), iconPrefix
0555: + "dialog-information.png");
0556: Object questionIcon = makeIcon(getClass(), iconPrefix
0557: + "dialog-question.png");
0558: Object warningIcon = makeIcon(getClass(), iconPrefix
0559: + "dialog-warning.png");
0560:
0561: Object[] defaults = {
0562: "Button.border",
0563: buttonBorder,
0564: "Button.margin",
0565: buttonMargin,
0566:
0567: "CheckBox.margin",
0568: checkBoxMargin,
0569:
0570: // Use a modified check
0571: "CheckBox.icon",
0572: checkBoxIcon,
0573:
0574: "CheckBoxMenuItem.border",
0575: menuItemBorder,
0576: "CheckBoxMenuItem.margin",
0577: menuItemMargin, // 1.4.1 Bug
0578: "CheckBoxMenuItem.checkIcon",
0579: checkBoxMenuItemIcon,
0580: "CheckBoxMenuItem.background",
0581: getMenuItemBackground(),// Added by JGoodies
0582: "CheckBoxMenuItem.selectionForeground",
0583: getMenuItemSelectedForeground(),
0584: "CheckBoxMenuItem.selectionBackground",
0585: getMenuItemSelectedBackground(),
0586: "CheckBoxMenuItem.acceleratorForeground",
0587: menuItemForeground,
0588: "CheckBoxMenuItem.acceleratorSelectionForeground",
0589: getMenuItemSelectedForeground(),
0590: "CheckBoxMenuItem.acceleratorSelectionBackground",
0591: getMenuItemSelectedBackground(),
0592:
0593: // ComboBox uses menu item selection colors
0594: "ComboBox.selectionForeground",
0595: getMenuSelectedForeground(),
0596: "ComboBox.selectionBackground",
0597: getMenuSelectedBackground(),
0598: "ComboBox.arrowButtonBorder",
0599: comboBoxButtonBorder,
0600: "ComboBox.editorBorder",
0601: comboBoxEditorBorder,
0602: "ComboBox.editorColumns",
0603: new Integer(5),
0604: "ComboBox.editorBorderInsets",
0605: comboEditorBorderInsets, // Added by JGoodies
0606: "ComboBox.editorInsets",
0607: textInsets, // Added by JGoodies
0608: "ComboBox.tableEditorInsets",
0609: comboTableEditorInsets,
0610: "ComboBox.rendererBorder",
0611: comboRendererBorder, // Added by JGoodies
0612:
0613: "EditorPane.margin",
0614: wrappedTextInsets,
0615:
0616: "InternalFrame.border",
0617: internalFrameBorder,
0618: "InternalFrame.paletteBorder",
0619: paletteBorder,
0620:
0621: "List.font",
0622: getControlTextFont(),
0623: "Menu.border",
0624: PlasticBorders.getMenuBorder(),
0625: "Menu.margin",
0626: menuMargin,
0627: "Menu.arrowIcon",
0628: PlasticIconFactory.getMenuArrowIcon(),
0629:
0630: "MenuBar.emptyBorder",
0631: menuBarEmptyBorder, // Added by JGoodies
0632: "MenuBar.separatorBorder",
0633: menuBarSeparatorBorder, // Added by JGoodies
0634: "MenuBar.etchedBorder",
0635: menuBarEtchedBorder, // Added by JGoodies
0636: "MenuBar.headerBorder",
0637: menuBarHeaderBorder, // Added by JGoodies
0638:
0639: "MenuItem.border",
0640: menuItemBorder,
0641: "MenuItem.checkIcon",
0642: menuItemCheckIcon, // Aligns menu items
0643: "MenuItem.margin",
0644: menuItemMargin, // 1.4.1 Bug
0645: "MenuItem.background",
0646: getMenuItemBackground(),// Added by JGoodies
0647: "MenuItem.selectionForeground",
0648: getMenuItemSelectedForeground(),// Added by JGoodies
0649: "MenuItem.selectionBackground",
0650: getMenuItemSelectedBackground(),// Added by JGoodies
0651: "MenuItem.acceleratorForeground",
0652: menuItemForeground,
0653: "MenuItem.acceleratorSelectionForeground",
0654: getMenuItemSelectedForeground(),
0655: "MenuItem.acceleratorSelectionBackground",
0656: getMenuItemSelectedBackground(),
0657:
0658: "OptionPane.errorIcon",
0659: errorIcon,
0660: "OptionPane.informationIcon",
0661: informationIcon,
0662: "OptionPane.questionIcon",
0663: questionIcon,
0664: "OptionPane.warningIcon",
0665: warningIcon,
0666:
0667: //"DesktopIcon.icon", makeIcon(superclass, "icons/DesktopIcon.gif"),
0668: "FileView.computerIcon",
0669: makeIcon(getClass(), "icons/Computer.gif"),
0670: "FileView.directoryIcon",
0671: makeIcon(getClass(), "icons/TreeClosed.gif"),
0672: "FileView.fileIcon",
0673: makeIcon(getClass(), "icons/File.gif"),
0674: "FileView.floppyDriveIcon",
0675: makeIcon(getClass(), "icons/FloppyDrive.gif"),
0676: "FileView.hardDriveIcon",
0677: makeIcon(getClass(), "icons/HardDrive.gif"),
0678: "FileChooser.homeFolderIcon",
0679: makeIcon(getClass(), "icons/HomeFolder.gif"),
0680: "FileChooser.newFolderIcon",
0681: makeIcon(getClass(), "icons/NewFolder.gif"),
0682: "FileChooser.upFolderIcon",
0683: makeIcon(getClass(), "icons/UpFolder.gif"),
0684: "Tree.closedIcon",
0685: makeIcon(getClass(), "icons/TreeClosed.gif"),
0686: "Tree.openIcon",
0687: makeIcon(getClass(), "icons/TreeOpen.gif"),
0688: "Tree.leafIcon",
0689: makeIcon(getClass(), "icons/TreeLeaf.gif"),
0690:
0691: "FormattedTextField.border",
0692: textFieldBorder,
0693: "FormattedTextField.margin",
0694: textInsets,
0695:
0696: "PasswordField.border",
0697: textFieldBorder,
0698: "PasswordField.margin",
0699: textInsets,
0700: "PasswordField.echoChar",
0701: passwordEchoChar,
0702:
0703: "PopupMenu.border",
0704: PlasticBorders.getPopupMenuBorder(),
0705: "PopupMenu.noMarginBorder",
0706: PlasticBorders.getNoMarginPopupMenuBorder(),
0707: "PopupMenuSeparator.margin",
0708: new InsetsUIResource(3, 4, 3, 4),
0709:
0710: "RadioButton.margin",
0711: checkBoxMargin,
0712: "RadioButtonMenuItem.border",
0713: menuItemBorder,
0714: "RadioButtonMenuItem.checkIcon",
0715: radioButtonMenuItemIcon,
0716: "RadioButtonMenuItem.margin",
0717: menuItemMargin, // 1.4.1 Bug
0718: "RadioButtonMenuItem.background",
0719: getMenuItemBackground(),// Added by JGoodies
0720: "RadioButtonMenuItem.selectionForeground",
0721: getMenuItemSelectedForeground(),
0722: "RadioButtonMenuItem.selectionBackground",
0723: getMenuItemSelectedBackground(),
0724: "RadioButtonMenuItem.acceleratorForeground",
0725: menuItemForeground,
0726: "RadioButtonMenuItem.acceleratorSelectionForeground",
0727: getMenuItemSelectedForeground(),
0728: "RadioButtonMenuItem.acceleratorSelectionBackground",
0729: getMenuItemSelectedBackground(),
0730: "Separator.foreground",
0731: getControlDarkShadow(),
0732: "ScrollPane.border",
0733: scrollPaneBorder,
0734: "ScrollPane.etchedBorder",
0735: scrollPaneBorder,
0736: // "ScrollPane.background", table.get("window"),
0737:
0738: "SimpleInternalFrame.activeTitleForeground",
0739: getSimpleInternalFrameForeground(),
0740: "SimpleInternalFrame.activeTitleBackground",
0741: getSimpleInternalFrameBackground(),
0742:
0743: "Spinner.border",
0744: PlasticBorders.getFlush3DBorder(),
0745: "Spinner.defaultEditorInsets",
0746: textInsets,
0747:
0748: "SplitPane.dividerSize",
0749: new Integer(7),
0750: "TabbedPane.focus",
0751: getFocusColor(),
0752: "TabbedPane.tabInsets",
0753: new InsetsUIResource(1, 9, 1, 8),
0754: "Table.foreground",
0755: table.get("textText"),
0756: "Table.gridColor",
0757: controlColor, //new ColorUIResource(new Color(216, 216, 216)),
0758: "Table.scrollPaneBorder",
0759: scrollPaneBorder,
0760: "TableHeader.cellBorder",
0761: tableHeaderBorder,
0762: "TextArea.inactiveBackground",
0763: inactiveTextBackground,
0764: "TextArea.margin",
0765: wrappedTextInsets,
0766: "TextField.border",
0767: textFieldBorder,
0768: "TextField.margin",
0769: textInsets,
0770: "TitledBorder.font",
0771: getTitleTextFont(),
0772: "TitledBorder.titleColor",
0773: getTitleTextColor(),
0774: "ToggleButton.border",
0775: toggleButtonBorder,
0776: "ToggleButton.margin",
0777: buttonMargin,
0778:
0779: "ToolBar.emptyBorder",
0780: toolBarEmptyBorder, // Added by JGoodies
0781: "ToolBar.separatorBorder",
0782: toolBarSeparatorBorder, // Added by JGoodies
0783: "ToolBar.etchedBorder",
0784: toolBarEtchedBorder, // Added by JGoodies
0785: "ToolBar.headerBorder",
0786: toolBarHeaderBorder, // Added by JGoodies
0787:
0788: "ToolTip.hideAccelerator", Boolean.TRUE,
0789:
0790: "Tree.expandedIcon", treeExpandedIcon,
0791: "Tree.collapsedIcon", treeCollapsedIcon, "Tree.line",
0792: gray, "Tree.hash", gray, "Tree.rowHeight", rowHeight,
0793:
0794: "Button.is3DEnabled", is3D, "ComboBox.is3DEnabled",
0795: is3D, "MenuBar.is3DEnabled",
0796: is3D,
0797: "ToolBar.is3DEnabled",
0798: is3D,
0799: "ScrollBar.is3DEnabled",
0800: is3D,
0801: "ToggleButton.is3DEnabled",
0802: is3D,
0803:
0804: // 1.4.1 uses a 2 pixel non-standard border, that leads to bad
0805: // alignment in the typical case that the border is not painted
0806: "CheckBox.border", marginBorder,
0807: "RadioButton.border",
0808: marginBorder,
0809:
0810: // Fix of the issue #21
0811: "ProgressBar.selectionForeground",
0812: getSystemTextColor(),
0813: "ProgressBar.selectionBackground", getSystemTextColor() };
0814: table.putDefaults(defaults);
0815:
0816: // Set paths to sounds for auditory feedback
0817: String soundPathPrefix = "/javax/swing/plaf/metal/";
0818: Object[] auditoryCues = (Object[]) table
0819: .get("AuditoryCues.allAuditoryCues");
0820: if (auditoryCues != null) {
0821: Object[] audioDefaults = new String[auditoryCues.length * 2];
0822: for (int i = 0; i < auditoryCues.length; i++) {
0823: Object auditoryCue = auditoryCues[i];
0824: audioDefaults[2 * i] = auditoryCue;
0825: audioDefaults[2 * i + 1] = soundPathPrefix
0826: + table.getString(auditoryCue);
0827: }
0828: table.putDefaults(audioDefaults);
0829: }
0830: }
0831:
0832: /**
0833: * Unlike my superclass I register a unified shadow color.
0834: * This color is used by my ThinBevelBorder class.
0835: *
0836: * @param table the UIDefaults table to work with
0837: */
0838: protected void initSystemColorDefaults(UIDefaults table) {
0839: super .initSystemColorDefaults(table);
0840: table.put("unifiedControlShadow", table
0841: .getColor("controlDkShadow"));
0842: table.put("primaryControlHighlight",
0843: getPrimaryControlHighlight());
0844: }
0845:
0846: // Color Theme Behavior *************************************************************
0847:
0848: private static final String THEME_CLASSNAME_PREFIX = "com.jgoodies.looks.plastic.theme.";
0849:
0850: /**
0851: * Creates and returns the default color theme. Honors the current platform
0852: * and platform flavor - if available.
0853: *
0854: * @return the default color theme for the current environemt
0855: */
0856: public static PlasticTheme createMyDefaultTheme() {
0857: String defaultName;
0858: if (LookUtils.IS_LAF_WINDOWS_XP_ENABLED) {
0859: defaultName = getDefaultXPTheme();
0860: } else if (LookUtils.IS_OS_WINDOWS_MODERN) {
0861: defaultName = "DesertBluer";
0862: } else {
0863: defaultName = "SkyBlue";
0864: }
0865: // Don't use the default now, so we can detect that the users tried to set one.
0866: String userName = LookUtils.getSystemProperty(
0867: DEFAULT_THEME_KEY, "");
0868: boolean overridden = userName.length() > 0;
0869: String themeName = overridden ? userName : defaultName;
0870: PlasticTheme theme = createTheme(themeName);
0871: PlasticTheme result = theme != null ? theme : new SkyBluer();
0872:
0873: // In case the user tried to set a theme, log a message.
0874: if (overridden) {
0875: String className = result.getClass().getName().substring(
0876: THEME_CLASSNAME_PREFIX.length());
0877: if (className.equals(userName)) {
0878: LookUtils.log("I have successfully installed the '"
0879: + result.getName() + "' theme.");
0880: } else {
0881: LookUtils.log("I could not install the Plastic theme '"
0882: + userName + "'.");
0883: LookUtils.log("I have installed the '"
0884: + result.getName() + "' theme, instead.");
0885: }
0886: }
0887: return result;
0888: }
0889:
0890: private static String getDefaultXPTheme() {
0891: String fallbackName = "ExperienceBlue";
0892: Toolkit toolkit = Toolkit.getDefaultToolkit();
0893: String xpstyleDll = (String) toolkit
0894: .getDesktopProperty("win.xpstyle.dllName");
0895: if (xpstyleDll == null) {
0896: return fallbackName;
0897: }
0898: boolean isStyleLuna = xpstyleDll.endsWith("luna.msstyles");
0899: boolean isStyleRoyale = xpstyleDll.endsWith("Royale.msstyles");
0900: boolean isStyleAero = xpstyleDll.endsWith("Aero.msstyles");
0901: if (isStyleRoyale) {
0902: return "ExperienceRoyale";
0903: } else if (isStyleLuna) {
0904: String xpstyleColorName = (String) toolkit
0905: .getDesktopProperty("win.xpstyle.colorName");
0906: if (xpstyleColorName == null) {
0907: return fallbackName;
0908: }
0909: if (xpstyleColorName.equalsIgnoreCase("HomeStead")) {
0910: return "ExperienceGreen";
0911: } else if (xpstyleColorName.equalsIgnoreCase("Metallic")) {
0912: return "Silver";
0913: } else {
0914: return fallbackName;
0915: }
0916: } else if (isStyleAero) {
0917: return "LightGray";
0918: }
0919: return fallbackName;
0920: }
0921:
0922: /**
0923: * Lazily initializes and returns the <code>List</code> of installed
0924: * color themes.
0925: *
0926: * @return a list of installed color/font themes
0927: */
0928: public static List getInstalledThemes() {
0929: if (null == installedThemes)
0930: installDefaultThemes();
0931:
0932: Collections.sort(installedThemes, new Comparator() {
0933: public int compare(Object o1, Object o2) {
0934: MetalTheme theme1 = (MetalTheme) o1;
0935: MetalTheme theme2 = (MetalTheme) o2;
0936: return theme1.getName().compareTo(theme2.getName());
0937: }
0938: });
0939:
0940: return installedThemes;
0941: }
0942:
0943: /**
0944: * Install the default color themes.
0945: */
0946: protected static void installDefaultThemes() {
0947: installedThemes = new ArrayList();
0948: String[] themeNames = { "BrownSugar", "DarkStar", "DesertBlue",
0949: "DesertBluer", "DesertGreen", "DesertRed",
0950: "DesertYellow", "ExperienceBlue", "ExperienceGreen",
0951: "ExperienceRoyale", "LightGray", "Silver", "SkyBlue",
0952: "SkyBluer", "SkyGreen", "SkyKrupp", "SkyPink",
0953: "SkyRed", "SkyYellow" };
0954: for (int i = themeNames.length - 1; i >= 0; i--)
0955: installTheme(createTheme(themeNames[i]));
0956: }
0957:
0958: /**
0959: * Creates and returns a color theme from the specified theme name.
0960: *
0961: * @param themeName the unqualified name of the theme to create
0962: * @return the associated color theme or <code>null</code> in case of
0963: * a problem
0964: */
0965: protected static PlasticTheme createTheme(String themeName) {
0966: String className = THEME_CLASSNAME_PREFIX + themeName;
0967: try {
0968: Class cl = Class.forName(className);
0969: return (PlasticTheme) (cl.newInstance());
0970: } catch (ClassNotFoundException e) {
0971: // Ignore the exception here and log below.
0972: } catch (IllegalAccessException e) {
0973: // Ignore the exception here and log below.
0974: } catch (InstantiationException e) {
0975: // Ignore the exception here and log below.
0976: }
0977: LookUtils.log("Can't create theme " + className);
0978: return null;
0979: }
0980:
0981: /**
0982: * Installs a color theme.
0983: *
0984: * @param theme the theme to install
0985: */
0986: public static void installTheme(PlasticTheme theme) {
0987: if (null == installedThemes)
0988: installDefaultThemes();
0989: installedThemes.add(theme);
0990: }
0991:
0992: /**
0993: * Lazily initializes and returns the PlasticTheme.
0994: * In Java 5 or later, this method looks up the theme
0995: * using <code>MetalLookAndFeel#getCurrentTheme</code>.
0996: * In Java 1.4 it is requested from the UIManager.
0997: * Both access methods use an AppContext to store the theme,
0998: * so that applets in different contexts don't share the theme.
0999: *
1000: * @return the current PlasticTheme
1001: */
1002: public static PlasticTheme getPlasticTheme() {
1003: if (LookUtils.IS_JAVA_5_OR_LATER) {
1004: MetalTheme theme = getCurrentTheme0();
1005: if (theme instanceof PlasticTheme)
1006: return (PlasticTheme) theme;
1007: }
1008: PlasticTheme uimanagerTheme = (PlasticTheme) UIManager
1009: .get(THEME_KEY);
1010: if (uimanagerTheme != null)
1011: return uimanagerTheme;
1012:
1013: PlasticTheme initialTheme = createMyDefaultTheme();
1014: setPlasticTheme(initialTheme);
1015: return initialTheme;
1016: }
1017:
1018: /**
1019: * Sets the theme for colors and fonts used by the Plastic L&F.<p>
1020: *
1021: * After setting the theme, you need to re-install the Look&Feel,
1022: * as well as update the UI's of any previously created components
1023: * - just as if you'd change the Look&Feel.
1024: *
1025: * @param theme the PlasticTheme to be set
1026: *
1027: * @throws NullPointerException if the theme is null.
1028: *
1029: * @see #getPlasticTheme()
1030: */
1031: public static void setPlasticTheme(PlasticTheme theme) {
1032: if (theme == null)
1033: throw new NullPointerException(
1034: "The theme must not be null.");
1035:
1036: UIManager.put(THEME_KEY, theme);
1037: // Also set the theme in the superclass.
1038: setCurrentTheme(theme);
1039: }
1040:
1041: // Accessed by ProxyLazyValues ******************************************
1042:
1043: public static BorderUIResource getInternalFrameBorder() {
1044: return new BorderUIResource(PlasticBorders
1045: .getInternalFrameBorder());
1046: }
1047:
1048: public static BorderUIResource getPaletteBorder() {
1049: return new BorderUIResource(PlasticBorders.getPaletteBorder());
1050: }
1051:
1052: // Accessing Theme Colors and Fonts *************************************
1053:
1054: public static ColorUIResource getPrimaryControlDarkShadow() {
1055: return getPlasticTheme().getPrimaryControlDarkShadow();
1056: }
1057:
1058: public static ColorUIResource getPrimaryControlHighlight() {
1059: return getPlasticTheme().getPrimaryControlHighlight();
1060: }
1061:
1062: public static ColorUIResource getPrimaryControlInfo() {
1063: return getPlasticTheme().getPrimaryControlInfo();
1064: }
1065:
1066: public static ColorUIResource getPrimaryControlShadow() {
1067: return getPlasticTheme().getPrimaryControlShadow();
1068: }
1069:
1070: public static ColorUIResource getPrimaryControl() {
1071: return getPlasticTheme().getPrimaryControl();
1072: }
1073:
1074: public static ColorUIResource getControlHighlight() {
1075: return getPlasticTheme().getControlHighlight();
1076: }
1077:
1078: public static ColorUIResource getControlDarkShadow() {
1079: return getPlasticTheme().getControlDarkShadow();
1080: }
1081:
1082: public static ColorUIResource getControl() {
1083: return getPlasticTheme().getControl();
1084: }
1085:
1086: public static ColorUIResource getFocusColor() {
1087: return getPlasticTheme().getFocusColor();
1088: }
1089:
1090: public static ColorUIResource getMenuItemBackground() {
1091: return getPlasticTheme().getMenuItemBackground();
1092: }
1093:
1094: public static ColorUIResource getMenuItemSelectedBackground() {
1095: return getPlasticTheme().getMenuItemSelectedBackground();
1096: }
1097:
1098: public static ColorUIResource getMenuItemSelectedForeground() {
1099: return getPlasticTheme().getMenuItemSelectedForeground();
1100: }
1101:
1102: public static ColorUIResource getWindowTitleBackground() {
1103: return getPlasticTheme().getWindowTitleBackground();
1104: }
1105:
1106: public static ColorUIResource getWindowTitleForeground() {
1107: return getPlasticTheme().getWindowTitleForeground();
1108: }
1109:
1110: public static ColorUIResource getWindowTitleInactiveBackground() {
1111: return getPlasticTheme().getWindowTitleInactiveBackground();
1112: }
1113:
1114: public static ColorUIResource getWindowTitleInactiveForeground() {
1115: return getPlasticTheme().getWindowTitleInactiveForeground();
1116: }
1117:
1118: public static ColorUIResource getSimpleInternalFrameForeground() {
1119: return getPlasticTheme().getSimpleInternalFrameForeground();
1120: }
1121:
1122: public static ColorUIResource getSimpleInternalFrameBackground() {
1123: return getPlasticTheme().getSimpleInternalFrameBackground();
1124: }
1125:
1126: public static ColorUIResource getTitleTextColor() {
1127: return getPlasticTheme().getTitleTextColor();
1128: }
1129:
1130: public static FontUIResource getTitleTextFont() {
1131: return getPlasticTheme().getTitleTextFont();
1132: }
1133:
1134: // Helper Code ************************************************************
1135:
1136: private static MetalTheme getCurrentTheme0() {
1137: if (getCurrentThemeMethod != null) {
1138: try {
1139: return (MetalTheme) getCurrentThemeMethod.invoke(null,
1140: null);
1141: } catch (IllegalArgumentException e) {
1142: // Return null
1143: } catch (IllegalAccessException e) {
1144: // Return null
1145: } catch (InvocationTargetException e) {
1146: // Return null
1147: }
1148: }
1149: return null;
1150: }
1151:
1152: private static Method getMethodGetCurrentTheme() {
1153: try {
1154: Class clazz = MetalLookAndFeel.class;
1155: return clazz.getMethod("getCurrentTheme", new Class[] {});
1156: } catch (SecurityException e) {
1157: // returns null
1158: } catch (NoSuchMethodException e) {
1159: // returns null
1160: }
1161: return null;
1162: }
1163:
1164: // Helper Code ************************************************************
1165:
1166: /**
1167: * Appends the key and value to the given source array and returns
1168: * a copy that has the two new elements at its end.
1169: *
1170: * @return an array with the key and value appended
1171: */
1172: private static Object[] append(Object[] source, String key,
1173: Object value) {
1174: int length = source.length;
1175: Object[] destination = new Object[length + 2];
1176: System.arraycopy(source, 0, destination, 0, length);
1177: destination[length] = key;
1178: destination[length + 1] = value;
1179: return destination;
1180: }
1181:
1182: }
|