/* * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Sun designates this * particular file as subject to the "Classpath" exception as provided * by Sun in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ package javax.swing.plaf.metal; import java.awt.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.plaf.*; import javax.swing.*; import javax.swing.plaf.basic.*; import javax.swing.text.DefaultEditorKit; import java.awt.Color; import java.awt.event.KeyEvent; import java.lang.reflect.*; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.security.AccessController; import java.security.PrivilegedAction; import sun.awt.*; import sun.security.action.GetPropertyAction; import sun.swing.DefaultLayoutStyle; import sun.swing.SwingLazyValue; import sun.swing.SwingUtilities2; /** * The Java Look and Feel, otherwise known as Metal. *
* Each of the {@code ComponentUI}s provided by {@code * MetalLookAndFeel} derives its behavior from the defaults * table. Unless otherwise noted each of the {@code ComponentUI} * implementations in this package document the set of defaults they * use. Unless otherwise noted the defaults are installed at the time * {@code installUI} is invoked, and follow the recommendations * outlined in {@code LookAndFeel} for installing defaults. *
* {@code MetalLookAndFeel} derives it's color palette and fonts from * {@code MetalTheme}. The default theme is {@code OceanTheme}. The theme * can be changed using the {@code setCurrentTheme} method, refer to it * for details on changing the theme. Prior to 1.5 the default * theme was {@code DefaultMetalTheme}. The system property * {@code "swing.metalTheme"} can be set to {@code "steel"} to indicate * the default should be {@code DefaultMetalTheme}. *
* Warning:
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeansTM
* has been added to the java.beans
package.
* Please see {@link java.beans.XMLEncoder}.
*
* @see MetalTheme
* @see DefaultMetalTheme
* @see OceanTheme
*
* @author Steve Wilson
*/
public class MetalLookAndFeel extends BasicLookAndFeel
{
private static boolean METAL_LOOK_AND_FEEL_INITED = false;
/**
* True if checked for windows yet.
*/
private static boolean checkedWindows;
/**
* True if running on Windows.
*/
private static boolean isWindows;
/**
* Set to true first time we've checked swing.useSystemFontSettings.
*/
private static boolean checkedSystemFontSettings;
/**
* True indicates we should use system fonts, unless the developer has
* specified otherwise with Application.useSystemFontSettings.
*/
private static boolean useSystemFonts;
/**
* Returns true if running on Windows.
*/
static boolean isWindows() {
if (!checkedWindows) {
OSInfo.OSType osType = AccessController.doPrivileged(OSInfo.getOSTypeAction());
if (osType == OSInfo.OSType.WINDOWS) {
isWindows = true;
String systemFonts = AccessController.doPrivileged(
new GetPropertyAction("swing.useSystemFontSettings"));
useSystemFonts = (systemFonts != null &&
(Boolean.valueOf(systemFonts).booleanValue()));
}
checkedWindows = true;
}
return isWindows;
}
/**
* Returns true if system fonts should be used, this is only useful
* for windows.
*/
static boolean useSystemFonts() {
if (isWindows() && useSystemFonts) {
if (METAL_LOOK_AND_FEEL_INITED) {
Object value = UIManager.get(
"Application.useSystemFontSettings");
return (value == null || Boolean.TRUE.equals(value));
}
// If an instanceof MetalLookAndFeel hasn't been inited yet, we
// don't want to trigger loading of a UI by asking the UIManager
// for a property, assume the user wants system fonts. This will
// be properly adjusted when install is invoked on the
// MetalTheme
return true;
}
return false;
}
/**
* Returns true if the high contrast theme should be used as the default
* theme.
*/
private static boolean useHighContrastTheme() {
if (isWindows() && useSystemFonts()) {
Boolean highContrast = (Boolean)Toolkit.getDefaultToolkit().
getDesktopProperty("win.highContrast.on");
return (highContrast == null) ? false : highContrast.
booleanValue();
}
return false;
}
/**
* Returns true if we're using the Ocean Theme.
*/
static boolean usingOcean() {
return (getCurrentTheme() instanceof OceanTheme);
}
/**
* Returns the name of this look and feel. This returns
* {@code "Metal"}.
*
* @return the name of this look and feel
*/
public String getName() {
return "Metal";
}
/**
* Returns an identifier for this look and feel. This returns
* {@code "Metal"}.
*
* @return the identifier of this look and feel
*/
public String getID() {
return "Metal";
}
/**
* Returns a short description of this look and feel. This returns
* {@code "The Java(tm) Look and Feel"}.
* @return a short description for the look and feel
*/
public String getDescription() {
return "The Java(tm) Look and Feel";
}
/**
* Returns {@code false}; {@code MetalLookAndFeel} is not a native
* look and feel.
*
* @return {@code false}
*/
public boolean isNativeLookAndFeel() {
return false;
}
/**
* Returns {@code true}; {@code MetalLookAndFeel} can be run on
* any platform.
*
* @return {@code true}
*/
public boolean isSupportedLookAndFeel() {
return true;
}
/**
* Returns {@code true}; metal can provide {@code Window}
* decorations.
*
* @return {@code true}
*
* @see JDialog#setDefaultLookAndFeelDecorated
* @see JFrame#setDefaultLookAndFeelDecorated
* @see JRootPane#setWindowDecorationStyle
* @since 1.4
*/
public boolean getSupportsWindowDecorations() {
return true;
}
/**
* Populates {@code table} with mappings from {@code uiClassID} to
* the fully qualified name of the ui class. {@code
* MetalLookAndFeel} registers an entry for each of the classes in
* the package {@code javax.swing.plaf.metal} that are named
* MetalXXXUI. The string {@code XXX} is one of Swing's uiClassIDs. For
* the {@code uiClassIDs} that do not have a class in metal, the
* corresponding class in {@code javax.swing.plaf.basic} is
* used. For example, metal does not have a class named {@code
* "MetalColorChooserUI"}, as such, {@code
* javax.swing.plaf.basic.BasicColorChooserUI} is used.
*
* @param table the {@code UIDefaults} instance the entries are
* added to
* @throws NullPointerException if {@code table} is {@code null}
*
* @see javax.swing.plaf.basic.BasicLookAndFeel#initClassDefaults
*/
protected void initClassDefaults(UIDefaults table)
{
super.initClassDefaults(table);
final String metalPackageName = "javax.swing.plaf.metal.";
Object[] uiDefaults = {
"ButtonUI", metalPackageName + "MetalButtonUI",
"CheckBoxUI", metalPackageName + "MetalCheckBoxUI",
"ComboBoxUI", metalPackageName + "MetalComboBoxUI",
"DesktopIconUI", metalPackageName + "MetalDesktopIconUI",
"FileChooserUI", metalPackageName + "MetalFileChooserUI",
"InternalFrameUI", metalPackageName + "MetalInternalFrameUI",
"LabelUI", metalPackageName + "MetalLabelUI",
"PopupMenuSeparatorUI", metalPackageName + "MetalPopupMenuSeparatorUI",
"ProgressBarUI", metalPackageName + "MetalProgressBarUI",
"RadioButtonUI", metalPackageName + "MetalRadioButtonUI",
"ScrollBarUI", metalPackageName + "MetalScrollBarUI",
"ScrollPaneUI", metalPackageName + "MetalScrollPaneUI",
"SeparatorUI", metalPackageName + "MetalSeparatorUI",
"SliderUI", metalPackageName + "MetalSliderUI",
"SplitPaneUI", metalPackageName + "MetalSplitPaneUI",
"TabbedPaneUI", metalPackageName + "MetalTabbedPaneUI",
"TextFieldUI", metalPackageName + "MetalTextFieldUI",
"ToggleButtonUI", metalPackageName + "MetalToggleButtonUI",
"ToolBarUI", metalPackageName + "MetalToolBarUI",
"ToolTipUI", metalPackageName + "MetalToolTipUI",
"TreeUI", metalPackageName + "MetalTreeUI",
"RootPaneUI", metalPackageName + "MetalRootPaneUI",
};
table.putDefaults(uiDefaults);
}
/**
* Populates {@code table} with system colors. The following values are
* added to {@code table}:
*
Key * | Value * |
---|---|
"desktop" * | {@code theme.getDesktopColor()} * |
"activeCaption" * | {@code theme.getWindowTitleBackground()} * |
"activeCaptionText" * | {@code theme.getWindowTitleForeground()} * |
"activeCaptionBorder" * | {@code theme.getPrimaryControlShadow()} * |
"inactiveCaption" * | {@code theme.getWindowTitleInactiveBackground()} * |
"inactiveCaptionText" * | {@code theme.getWindowTitleInactiveForeground()} * |
"inactiveCaptionBorder" * | {@code theme.getControlShadow()} * |
"window" * | {@code theme.getWindowBackground()} * |
"windowBorder" * | {@code theme.getControl()} * |
"windowText" * | {@code theme.getUserTextColor()} * |
"menu" * | {@code theme.getMenuBackground()} * |
"menuText" * | {@code theme.getMenuForeground()} * |
"text" * | {@code theme.getWindowBackground()} * |
"textText" * | {@code theme.getUserTextColor()} * |
"textHighlight" * | {@code theme.getTextHighlightColor()} * |
"textHighlightText" * | {@code theme.getHighlightedTextColor()} * |
"textInactiveText" * | {@code theme.getInactiveSystemTextColor()} * |
"control" * | {@code theme.getControl()} * |
"controlText" * | {@code theme.getControlTextColor()} * |
"controlHighlight" * | {@code theme.getControlHighlight()} * |
"controlLtHighlight" * | {@code theme.getControlHighlight()} * |
"controlShadow" * | {@code theme.getControlShadow()} * |
"controlDkShadow" * | {@code theme.getControlDarkShadow()} * |
"scrollbar" * | {@code theme.getControl()} * |
"info" * | {@code theme.getPrimaryControl()} * |
"infoText" * | {@code theme.getPrimaryControlInfo()} * |
* While this method is public, it should only be invoked by the
* {@code UIManager} when the look and feel is set as the current
* look and feel and after {@code initialize} has been invoked.
*
* @return the look and feel defaults
*
* @see #createDefaultTheme
* @see javax.swing.plaf.basic.BasicLookAndFeel#getDefaults()
* @see MetalTheme#addCustomEntriesToTable(UIDefaults)
*/
public UIDefaults getDefaults() {
// PENDING: move this to initialize when API changes are allowed
METAL_LOOK_AND_FEEL_INITED = true;
createDefaultTheme();
UIDefaults table = super.getDefaults();
MetalTheme currentTheme = getCurrentTheme();
currentTheme.addCustomEntriesToTable(table);
currentTheme.install();
return table;
}
/**
* {@inheritDoc}
*
* @since 1.4
*/
public void provideErrorFeedback(Component component) {
super.provideErrorFeedback(component);
}
/**
* Set the theme used by MetalLookAndFeel
.
*
* After the theme is set, {@code MetalLookAndFeel} needs to be * re-installed and the uis need to be recreated. The following * shows how to do this: *
* MetalLookAndFeel.setCurrentTheme(theme); * * // re-install the Metal Look and Feel * UIManager.setLookAndFeel(new MetalLookAndFeel()); * * // Update the ComponentUIs for all Components. This * // needs to be invoked for all windows. * SwingUtilities.updateComponentTreeUI(rootComponent); ** If this is not done the results are undefined. * * @param theme the theme to use * @throws NullPointerException if {@code theme} is {@code null} * @see #getCurrentTheme */ public static void setCurrentTheme(MetalTheme theme) { // NOTE: because you need to recreate the look and feel after // this step, we don't bother blowing away any potential windows // values. if (theme == null) { throw new NullPointerException("Can't have null theme"); } AppContext.getAppContext().put( "currentMetalTheme", theme ); } /** * Return the theme currently being used by
MetalLookAndFeel
.
* If the current theme is {@code null}, the default theme is created.
*
* @return the current theme
* @see #setCurrentTheme
* @since 1.5
*/
public static MetalTheme getCurrentTheme() {
MetalTheme currentTheme;
AppContext context = AppContext.getAppContext();
currentTheme = (MetalTheme) context.get( "currentMetalTheme" );
if (currentTheme == null) {
// This will happen in two cases:
// . When MetalLookAndFeel is first being initialized.
// . When a new AppContext has been created that hasn't
// triggered UIManager to load a LAF. Rather than invoke
// a method on the UIManager, which would trigger the loading
// of a potentially different LAF, we directly set the
// Theme here.
if (useHighContrastTheme()) {
currentTheme = new MetalHighContrastTheme();
}
else {
// Create the default theme. We prefer Ocean, but will
// use DefaultMetalTheme if told to.
String theme = AccessController.doPrivileged(
new GetPropertyAction("swing.metalTheme"));
if ("steel".equals(theme)) {
currentTheme = new DefaultMetalTheme();
}
else {
currentTheme = new OceanTheme();
}
}
setCurrentTheme(currentTheme);
}
return currentTheme;
}
/**
* Returns an Icon
with a disabled appearance.
* This method is used to generate a disabled Icon
when
* one has not been specified. For example, if you create a
* JButton
and only specify an Icon
via
* setIcon
this method will be called to generate the
* disabled Icon
. If null is passed as icon
* this method returns null.
*
* Some look and feels might not render the disabled Icon, in which
* case they will ignore this.
*
* @param component JComponent that will display the Icon, may be null
* @param icon Icon to generate disable icon from.
* @return Disabled icon, or null if a suitable Icon can not be
* generated.
* @since 1.5
*/
public Icon getDisabledIcon(JComponent component, Icon icon) {
if ((icon instanceof ImageIcon) && MetalLookAndFeel.usingOcean()) {
return MetalUtils.getOceanDisabledButtonIcon(
((ImageIcon)icon).getImage());
}
return super.getDisabledIcon(component, icon);
}
/**
* Returns an Icon
for use by disabled
* components that are also selected. This method is used to generate an
* Icon
for components that are in both the disabled and
* selected states but do not have a specific Icon
for this
* state. For example, if you create a JButton
and only
* specify an Icon
via setIcon
this method
* will be called to generate the disabled and selected
* Icon
. If null is passed as icon
this method
* returns null.
*
* Some look and feels might not render the disabled and selected Icon,
* in which case they will ignore this.
*
* @param component JComponent that will display the Icon, may be null
* @param icon Icon to generate disabled and selected icon from.
* @return Disabled and Selected icon, or null if a suitable Icon can not
* be generated.
* @since 1.5
*/
public Icon getDisabledSelectedIcon(JComponent component, Icon icon) {
if ((icon instanceof ImageIcon) && MetalLookAndFeel.usingOcean()) {
return MetalUtils.getOceanDisabledButtonIcon(
((ImageIcon)icon).getImage());
}
return super.getDisabledSelectedIcon(component, icon);
}
/**
* Returns the control text font of the current theme. This is a
* cover method for {@code getCurrentTheme().getControlTextColor()}.
*
* @return the control text font
*
* @see MetalTheme
*/
public static FontUIResource getControlTextFont() { return getCurrentTheme().getControlTextFont();}
/**
* Returns the sytem text font of the current theme. This is a
* cover method for {@code getCurrentTheme().getSystemTextFont()}.
*
* @return the system text font
*
* @see MetalTheme
*/
public static FontUIResource getSystemTextFont() { return getCurrentTheme().getSystemTextFont();}
/**
* Returns the user text font of the current theme. This is a
* cover method for {@code getCurrentTheme().getUserTextFont()}.
*
* @return the user text font
*
* @see MetalTheme
*/
public static FontUIResource getUserTextFont() { return getCurrentTheme().getUserTextFont();}
/**
* Returns the menu text font of the current theme. This is a
* cover method for {@code getCurrentTheme().getMenuTextFont()}.
*
* @return the menu text font
*
* @see MetalTheme
*/
public static FontUIResource getMenuTextFont() { return getCurrentTheme().getMenuTextFont();}
/**
* Returns the window title font of the current theme. This is a
* cover method for {@code getCurrentTheme().getWindowTitleFont()}.
*
* @return the window title font
*
* @see MetalTheme
*/
public static FontUIResource getWindowTitleFont() { return getCurrentTheme().getWindowTitleFont();}
/**
* Returns the sub-text font of the current theme. This is a
* cover method for {@code getCurrentTheme().getSubTextFont()}.
*
* @return the sub-text font
*
* @see MetalTheme
*/
public static FontUIResource getSubTextFont() { return getCurrentTheme().getSubTextFont();}
/**
* Returns the desktop color of the current theme. This is a
* cover method for {@code getCurrentTheme().getDesktopColor()}.
*
* @return the desktop color
*
* @see MetalTheme
*/
public static ColorUIResource getDesktopColor() { return getCurrentTheme().getDesktopColor(); }
/**
* Returns the focus color of the current theme. This is a
* cover method for {@code getCurrentTheme().getFocusColor()}.
*
* @return the focus color
*
* @see MetalTheme
*/
public static ColorUIResource getFocusColor() { return getCurrentTheme().getFocusColor(); }
/**
* Returns the white color of the current theme. This is a
* cover method for {@code getCurrentTheme().getWhite()}.
*
* @return the white color
*
* @see MetalTheme
*/
public static ColorUIResource getWhite() { return getCurrentTheme().getWhite(); }
/**
* Returns the black color of the current theme. This is a
* cover method for {@code getCurrentTheme().getBlack()}.
*
* @return the black color
*
* @see MetalTheme
*/
public static ColorUIResource getBlack() { return getCurrentTheme().getBlack(); }
/**
* Returns the control color of the current theme. This is a
* cover method for {@code getCurrentTheme().getControl()}.
*
* @return the control color
*
* @see MetalTheme
*/
public static ColorUIResource getControl() { return getCurrentTheme().getControl(); }
/**
* Returns the control shadow color of the current theme. This is a
* cover method for {@code getCurrentTheme().getControlShadow()}.
*
* @return the control shadow color
*
* @see MetalTheme
*/
public static ColorUIResource getControlShadow() { return getCurrentTheme().getControlShadow(); }
/**
* Returns the control dark shadow color of the current theme. This is a
* cover method for {@code getCurrentTheme().getControlDarkShadow()}.
*
* @return the control dark shadow color
*
* @see MetalTheme
*/
public static ColorUIResource getControlDarkShadow() { return getCurrentTheme().getControlDarkShadow(); }
/**
* Returns the control info color of the current theme. This is a
* cover method for {@code getCurrentTheme().getControlInfo()}.
*
* @return the control info color
*
* @see MetalTheme
*/
public static ColorUIResource getControlInfo() { return getCurrentTheme().getControlInfo(); }
/**
* Returns the control highlight color of the current theme. This is a
* cover method for {@code getCurrentTheme().getControlHighlight()}.
*
* @return the control highlight color
*
* @see MetalTheme
*/
public static ColorUIResource getControlHighlight() { return getCurrentTheme().getControlHighlight(); }
/**
* Returns the control disabled color of the current theme. This is a
* cover method for {@code getCurrentTheme().getControlDisabled()}.
*
* @return the control disabled color
*
* @see MetalTheme
*/
public static ColorUIResource getControlDisabled() { return getCurrentTheme().getControlDisabled(); }
/**
* Returns the primary control color of the current theme. This is a
* cover method for {@code getCurrentTheme().getPrimaryControl()}.
*
* @return the primary control color
*
* @see MetalTheme
*/
public static ColorUIResource getPrimaryControl() { return getCurrentTheme().getPrimaryControl(); }
/**
* Returns the primary control shadow color of the current theme. This is a
* cover method for {@code getCurrentTheme().getPrimaryControlShadow()}.
*
* @return the primary control shadow color
*
* @see MetalTheme
*/
public static ColorUIResource getPrimaryControlShadow() { return getCurrentTheme().getPrimaryControlShadow(); }
/**
* Returns the primary control dark shadow color of the current
* theme. This is a cover method for {@code
* getCurrentTheme().getPrimaryControlDarkShadow()}.
*
* @return the primary control dark shadow color
*
* @see MetalTheme
*/
public static ColorUIResource getPrimaryControlDarkShadow() { return getCurrentTheme().getPrimaryControlDarkShadow(); }
/**
* Returns the primary control info color of the current theme. This is a
* cover method for {@code getCurrentTheme().getPrimaryControlInfo()}.
*
* @return the primary control info color
*
* @see MetalTheme
*/
public static ColorUIResource getPrimaryControlInfo() { return getCurrentTheme().getPrimaryControlInfo(); }
/**
* Returns the primary control highlight color of the current
* theme. This is a cover method for {@code
* getCurrentTheme().getPrimaryControlHighlight()}.
*
* @return the primary control highlight color
*
* @see MetalTheme
*/
public static ColorUIResource getPrimaryControlHighlight() { return getCurrentTheme().getPrimaryControlHighlight(); }
/**
* Returns the system text color of the current theme. This is a
* cover method for {@code getCurrentTheme().getSystemTextColor()}.
*
* @return the system text color
*
* @see MetalTheme
*/
public static ColorUIResource getSystemTextColor() { return getCurrentTheme().getSystemTextColor(); }
/**
* Returns the control text color of the current theme. This is a
* cover method for {@code getCurrentTheme().getControlTextColor()}.
*
* @return the control text color
*
* @see MetalTheme
*/
public static ColorUIResource getControlTextColor() { return getCurrentTheme().getControlTextColor(); }
/**
* Returns the inactive control text color of the current theme. This is a
* cover method for {@code
* getCurrentTheme().getInactiveControlTextColor()}.
*
* @return the inactive control text color
*
* @see MetalTheme
*/
public static ColorUIResource getInactiveControlTextColor() { return getCurrentTheme().getInactiveControlTextColor(); }
/**
* Returns the inactive system text color of the current theme. This is a
* cover method for {@code
* getCurrentTheme().getInactiveSystemTextColor()}.
*
* @return the inactive system text color
*
* @see MetalTheme
*/
public static ColorUIResource getInactiveSystemTextColor() { return getCurrentTheme().getInactiveSystemTextColor(); }
/**
* Returns the user text color of the current theme. This is a
* cover method for {@code getCurrentTheme().getUserTextColor()}.
*
* @return the user text color
*
* @see MetalTheme
*/
public static ColorUIResource getUserTextColor() { return getCurrentTheme().getUserTextColor(); }
/**
* Returns the text highlight color of the current theme. This is a
* cover method for {@code getCurrentTheme().getTextHighlightColor()}.
*
* @return the text highlight color
*
* @see MetalTheme
*/
public static ColorUIResource getTextHighlightColor() { return getCurrentTheme().getTextHighlightColor(); }
/**
* Returns the highlighted text color of the current theme. This is a
* cover method for {@code getCurrentTheme().getHighlightedTextColor()}.
*
* @return the highlighted text color
*
* @see MetalTheme
*/
public static ColorUIResource getHighlightedTextColor() { return getCurrentTheme().getHighlightedTextColor(); }
/**
* Returns the window background color of the current theme. This is a
* cover method for {@code getCurrentTheme().getWindowBackground()}.
*
* @return the window background color
*
* @see MetalTheme
*/
public static ColorUIResource getWindowBackground() { return getCurrentTheme().getWindowBackground(); }
/**
* Returns the window title background color of the current
* theme. This is a cover method for {@code
* getCurrentTheme().getWindowTitleBackground()}.
*
* @return the window title background color
*
* @see MetalTheme
*/
public static ColorUIResource getWindowTitleBackground() { return getCurrentTheme().getWindowTitleBackground(); }
/**
* Returns the window title foreground color of the current
* theme. This is a cover method for {@code
* getCurrentTheme().getWindowTitleForeground()}.
*
* @return the window title foreground color
*
* @see MetalTheme
*/
public static ColorUIResource getWindowTitleForeground() { return getCurrentTheme().getWindowTitleForeground(); }
/**
* Returns the window title inactive background color of the current
* theme. This is a cover method for {@code
* getCurrentTheme().getWindowTitleInactiveBackground()}.
*
* @return the window title inactive background color
*
* @see MetalTheme
*/
public static ColorUIResource getWindowTitleInactiveBackground() { return getCurrentTheme().getWindowTitleInactiveBackground(); }
/**
* Returns the window title inactive foreground color of the current
* theme. This is a cover method for {@code
* getCurrentTheme().getWindowTitleInactiveForeground()}.
*
* @return the window title inactive foreground color
*
* @see MetalTheme
*/
public static ColorUIResource getWindowTitleInactiveForeground() { return getCurrentTheme().getWindowTitleInactiveForeground(); }
/**
* Returns the menu background color of the current theme. This is
* a cover method for {@code getCurrentTheme().getMenuBackground()}.
*
* @return the menu background color
*
* @see MetalTheme
*/
public static ColorUIResource getMenuBackground() { return getCurrentTheme().getMenuBackground(); }
/**
* Returns the menu foreground color of the current theme. This is
* a cover method for {@code getCurrentTheme().getMenuForeground()}.
*
* @return the menu foreground color
*
* @see MetalTheme
*/
public static ColorUIResource getMenuForeground() { return getCurrentTheme().getMenuForeground(); }
/**
* Returns the menu selected background color of the current theme. This is
* a cover method for
* {@code getCurrentTheme().getMenuSelectedBackground()}.
*
* @return the menu selected background color
*
* @see MetalTheme
*/
public static ColorUIResource getMenuSelectedBackground() { return getCurrentTheme().getMenuSelectedBackground(); }
/**
* Returns the menu selected foreground color of the current theme. This is
* a cover method for
* {@code getCurrentTheme().getMenuSelectedForeground()}.
*
* @return the menu selected foreground color
*
* @see MetalTheme
*/
public static ColorUIResource getMenuSelectedForeground() { return getCurrentTheme().getMenuSelectedForeground(); }
/**
* Returns the menu disabled foreground color of the current theme. This is
* a cover method for
* {@code getCurrentTheme().getMenuDisabledForeground()}.
*
* @return the menu disabled foreground color
*
* @see MetalTheme
*/
public static ColorUIResource getMenuDisabledForeground() { return getCurrentTheme().getMenuDisabledForeground(); }
/**
* Returns the separator background color of the current theme. This is
* a cover method for {@code getCurrentTheme().getSeparatorBackground()}.
*
* @return the separator background color
*
* @see MetalTheme
*/
public static ColorUIResource getSeparatorBackground() { return getCurrentTheme().getSeparatorBackground(); }
/**
* Returns the separator foreground color of the current theme. This is
* a cover method for {@code getCurrentTheme().getSeparatorForeground()}.
*
* @return the separator foreground color
*
* @see MetalTheme
*/
public static ColorUIResource getSeparatorForeground() { return getCurrentTheme().getSeparatorForeground(); }
/**
* Returns the accelerator foreground color of the current theme. This is
* a cover method for {@code getCurrentTheme().getAcceleratorForeground()}.
*
* @return the separator accelerator foreground color
*
* @see MetalTheme
*/
public static ColorUIResource getAcceleratorForeground() { return getCurrentTheme().getAcceleratorForeground(); }
/**
* Returns the accelerator selected foreground color of the
* current theme. This is a cover method for {@code
* getCurrentTheme().getAcceleratorSelectedForeground()}.
*
* @return the accelerator selected foreground color
*
* @see MetalTheme
*/
public static ColorUIResource getAcceleratorSelectedForeground() { return getCurrentTheme().getAcceleratorSelectedForeground(); }
/**
* Returns a {@code LayoutStyle} implementing the Java look and feel
* design guidelines as specified at
* http://java.sun.com/products/jlf/ed2/book/HIG.Visual2.html.
*
* @return LayoutStyle implementing the Java look and feel design
* guidelines
* @since 1.6
*/
public LayoutStyle getLayoutStyle() {
return MetalLayoutStyle.INSTANCE;
}
/**
* MetalLazyValue is a slimmed down version of ProxyLaxyValue
.
* The code is duplicate so that it can get at the package private
* classes in metal.
*/
private static class MetalLazyValue implements UIDefaults.LazyValue {
/**
* Name of the class to create.
*/
private String className;
private String methodName;
MetalLazyValue(String name) {
this.className = name;
}
MetalLazyValue(String name, String methodName) {
this(name);
this.methodName = methodName;
}
public Object createValue(UIDefaults table) {
try {
final Class c = Class.forName(className);
if (methodName == null) {
return c.newInstance();
}
Method method = (Method)AccessController.doPrivileged(
new PrivilegedAction() {
public Object run() {
Method[] methods = c.getDeclaredMethods();
for (int counter = methods.length - 1; counter >= 0;
counter--) {
if (methods[counter].getName().equals(methodName)){
methods[counter].setAccessible(true);
return methods[counter];
}
}
return null;
}
});
if (method != null) {
return method.invoke(null, (Object[])null);
}
} catch (ClassNotFoundException cnfe) {
} catch (InstantiationException ie) {
} catch (IllegalAccessException iae) {
} catch (InvocationTargetException ite) {
}
return null;
}
}
/**
* FontActiveValue redirects to the appropriate metal theme method.
*/
private static class FontActiveValue implements UIDefaults.ActiveValue {
private int type;
private MetalTheme theme;
FontActiveValue(MetalTheme theme, int type) {
this.theme = theme;
this.type = type;
}
public Object createValue(UIDefaults table) {
Object value = null;
switch (type) {
case MetalTheme.CONTROL_TEXT_FONT:
value = theme.getControlTextFont();
break;
case MetalTheme.SYSTEM_TEXT_FONT:
value = theme.getSystemTextFont();
break;
case MetalTheme.USER_TEXT_FONT:
value = theme.getUserTextFont();
break;
case MetalTheme.MENU_TEXT_FONT:
value = theme.getMenuTextFont();
break;
case MetalTheme.WINDOW_TITLE_FONT:
value = theme.getWindowTitleFont();
break;
case MetalTheme.SUB_TEXT_FONT:
value = theme.getSubTextFont();
break;
}
return value;
}
}
static ReferenceQueue queue = new ReferenceQueue();
static void flushUnreferenced() {
AATextListener aatl;
while ((aatl = (AATextListener)queue.poll()) != null) {
aatl.dispose();
}
}
static class AATextListener
extends WeakReference implements PropertyChangeListener {
private String key = SunToolkit.DESKTOPFONTHINTS;
AATextListener(LookAndFeel laf) {
super(laf, queue);
Toolkit tk = Toolkit.getDefaultToolkit();
tk.addPropertyChangeListener(key, this);
}
public void propertyChange(PropertyChangeEvent pce) {
LookAndFeel laf = (LookAndFeel)get();
if (laf == null || laf != UIManager.getLookAndFeel()) {
dispose();
return;
}
UIDefaults defaults = UIManager.getLookAndFeelDefaults();
boolean lafCond = SwingUtilities2.isLocalDisplay();
Object aaTextInfo =
SwingUtilities2.AATextInfo.getAATextInfo(lafCond);
defaults.put(SwingUtilities2.AA_TEXT_PROPERTY_KEY, aaTextInfo);
updateUI();
}
void dispose() {
Toolkit tk = Toolkit.getDefaultToolkit();
tk.removePropertyChangeListener(key, this);
}
/**
* Updates the UI of the passed in window and all its children.
*/
private static void updateWindowUI(Window window) {
SwingUtilities.updateComponentTreeUI(window);
Window ownedWins[] = window.getOwnedWindows();
for (int i=0; i < ownedWins.length; i++) {
updateWindowUI(ownedWins[i]);
}
}
/**
* Updates the UIs of all the known Frames.
*/
private static void updateAllUIs() {
Frame appFrames[] = Frame.getFrames();
for (int j=0; j < appFrames.length; j++) {
updateWindowUI(appFrames[j]);
}
}
/**
* Indicates if an updateUI call is pending.
*/
private static boolean updatePending;
/**
* Sets whether or not an updateUI call is pending.
*/
private static synchronized void setUpdatePending(boolean update) {
updatePending = update;
}
/**
* Returns true if a UI update is pending.
*/
private static synchronized boolean isUpdatePending() {
return updatePending;
}
protected void updateUI() {
if (!isUpdatePending()) {
setUpdatePending(true);
Runnable uiUpdater = new Runnable() {
public void run() {
updateAllUIs();
setUpdatePending(false);
}
};
SwingUtilities.invokeLater(uiUpdater);
}
}
}
// From the JLF Design Guidelines:
// http://java.sun.com/products/jlf/ed2/book/HIG.Visual2.html
private static class MetalLayoutStyle extends DefaultLayoutStyle {
private static MetalLayoutStyle INSTANCE = new MetalLayoutStyle();
@Override
public int getPreferredGap(JComponent component1,
JComponent component2, ComponentPlacement type, int position,
Container parent) {
// Checks args
super.getPreferredGap(component1, component2, type, position,
parent);
int offset = 0;
switch(type) {
case INDENT:
// Metal doesn't spec this.
if (position == SwingConstants.EAST ||
position == SwingConstants.WEST) {
int indent = getIndent(component1, position);
if (indent > 0) {
return indent;
}
return 12;
}
// Fall through to related.
case RELATED:
if (component1.getUIClassID() == "ToggleButtonUI" &&
component2.getUIClassID() == "ToggleButtonUI") {
ButtonModel sourceModel = ((JToggleButton)component1).
getModel();
ButtonModel targetModel = ((JToggleButton)component2).
getModel();
if ((sourceModel instanceof DefaultButtonModel) &&
(targetModel instanceof DefaultButtonModel) &&
(((DefaultButtonModel)sourceModel).getGroup() ==
((DefaultButtonModel)targetModel).getGroup()) &&
((DefaultButtonModel)sourceModel).getGroup() != null) {
// When toggle buttons are exclusive (that is,
// they form a radio button set), separate
// them with 2 pixels. This rule applies
// whether the toggle buttons appear in a
// toolbar or elsewhere in the interface.
// Note: this number does not appear to
// include any borders and so is not adjusted
// by the border of the toggle button
return 2;
}
// When toggle buttons are independent (like
// checkboxes) and used outside a toolbar,
// separate them with 5 pixels.
if (usingOcean()) {
return 6;
}
return 5;
}
offset = 6;
break;
case UNRELATED:
offset = 12;
break;
}
if (isLabelAndNonlabel(component1, component2, position)) {
// Insert 12 pixels between the trailing edge of a
// label and any associated components. Insert 12
// pixels between the trailing edge of a label and the
// component it describes when labels are
// right-aligned. When labels are left-aligned, insert
// 12 pixels between the trailing edge of the longest
// label and its associated component
return getButtonGap(component1, component2, position,
offset + 6);
}
return getButtonGap(component1, component2, position, offset);
}
@Override
public int getContainerGap(JComponent component, int position,
Container parent) {
super.getContainerGap(component, position, parent);
// Include 11 pixels between the bottom and right
// borders of a dialog box and its command
// buttons. (To the eye, the 11-pixel spacing appears
// to be 12 pixels because the white borders on the
// lower and right edges of the button components are
// not visually significant.)
// NOTE: this last text was designed with Steel in mind,
// not Ocean.
//
// Insert 12 pixels between the edges of the panel and the
// titled border. Insert 11 pixels between the top of the
// title and the component above the titled border. Insert 12
// pixels between the bottom of the title and the top of the
// first label in the panel. Insert 11 pixels between
// component groups and between the bottom of the last
// component and the lower border.
return getButtonGap(component, position, 12 -
getButtonAdjustment(component, position));
}
@Override
protected int getButtonGap(JComponent source, JComponent target,
int position, int offset) {
offset = super.getButtonGap(source, target, position, offset);
if (offset > 0) {
int buttonAdjustment = getButtonAdjustment(source, position);
if (buttonAdjustment == 0) {
buttonAdjustment = getButtonAdjustment(
target, flipDirection(position));
}
offset -= buttonAdjustment;
}
if (offset < 0) {
return 0;
}
return offset;
}
private int getButtonAdjustment(JComponent source, int edge) {
String classID = source.getUIClassID();
if (classID == "ButtonUI" || classID == "ToggleButtonUI") {
if (!usingOcean() && (edge == SwingConstants.EAST ||
edge == SwingConstants.SOUTH)) {
if (source.getBorder() instanceof UIResource) {
return 1;
}
}
}
else if (edge == SwingConstants.SOUTH) {
if ((classID == "RadioButtonUI" || classID == "CheckBoxUI") &&
!usingOcean()) {
return 1;
}
}
return 0;
}
}
}