--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/swing/plaf/nimbus/NimbusLookAndFeel.java Sat Apr 25 21:17:50 2009 +0400
@@ -0,0 +1,520 @@
+/*
+ * Copyright 2005-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.nimbus;
+
+import java.awt.BorderLayout;
+import static java.awt.BorderLayout.*;
+import javax.swing.JComponent;
+import javax.swing.UIDefaults;
+import javax.swing.UIManager;
+import javax.swing.plaf.synth.Region;
+import javax.swing.plaf.synth.SynthLookAndFeel;
+import javax.swing.plaf.synth.SynthStyle;
+import javax.swing.plaf.synth.SynthStyleFactory;
+import javax.swing.plaf.UIResource;
+import java.security.AccessController;
+import java.awt.Color;
+import java.awt.Container;
+import java.awt.Graphics2D;
+import java.awt.LayoutManager;
+import java.awt.image.BufferedImage;
+import javax.swing.GrayFilter;
+import javax.swing.Icon;
+import javax.swing.JToolBar;
+import javax.swing.border.TitledBorder;
+import javax.swing.plaf.BorderUIResource;
+import javax.swing.plaf.ColorUIResource;
+import sun.swing.ImageIconUIResource;
+import sun.swing.plaf.synth.SynthIcon;
+import sun.swing.plaf.GTKKeybindings;
+import sun.swing.plaf.WindowsKeybindings;
+import sun.security.action.GetPropertyAction;
+
+/**
+ * <p>The NimbusLookAndFeel class.</p>
+ *
+ * @author Jasper Potts
+ * @author Richard Bair
+ */
+public class NimbusLookAndFeel extends SynthLookAndFeel {
+
+ /** Set of standard region names for UIDefaults Keys */
+ private static final String[] COMPONENT_KEYS = new String[]{"ArrowButton", "Button",
+ "CheckBox", "CheckBoxMenuItem", "ColorChooser", "ComboBox",
+ "DesktopPane", "DesktopIcon", "EditorPane", "FileChooser",
+ "FormattedTextField", "InternalFrame",
+ "InternalFrameTitlePane", "Label", "List", "Menu",
+ "MenuBar", "MenuItem", "OptionPane", "Panel",
+ "PasswordField", "PopupMenu", "PopupMenuSeparator",
+ "ProgressBar", "RadioButton", "RadioButtonMenuItem",
+ "RootPane", "ScrollBar", "ScrollBarTrack", "ScrollBarThumb",
+ "ScrollPane", "Separator", "Slider", "SliderTrack",
+ "SliderThumb", "Spinner", "SplitPane", "TabbedPane",
+ "Table", "TableHeader", "TextArea", "TextField", "TextPane",
+ "ToggleButton", "ToolBar", "ToolTip", "Tree", "Viewport"};
+
+ /**
+ * A reference to the auto-generated file NimbusDefaults. This file contains
+ * the default mappings and values for the look and feel as specified in the
+ * visual designer.
+ */
+ private NimbusDefaults defaults;
+
+ /**
+ * Reference to populated LAD uidefaults
+ */
+ private UIDefaults uiDefaults;
+
+ /**
+ * Create a new NimbusLookAndFeel.
+ */
+ public NimbusLookAndFeel() {
+ super();
+ defaults = new NimbusDefaults();
+ }
+
+ /** Called by UIManager when this look and feel is installed. */
+ @Override public void initialize() {
+ super.initialize();
+ defaults.initialize();
+ // create synth style factory
+ setStyleFactory(new SynthStyleFactory() {
+ @Override
+ public SynthStyle getStyle(JComponent c, Region r) {
+ return defaults.getStyle(c, r);
+ }
+ });
+ }
+
+
+ /** Called by UIManager when this look and feel is uninstalled. */
+ @Override public void uninitialize() {
+ super.uninitialize();
+ defaults.uninitialize();
+ // clear all cached images to free memory
+ ImageCache.getInstance().flush();
+ // remove the listeners and things installed by NimbusStyle
+ NimbusStyle.uninitialize();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ @Override public UIDefaults getDefaults() {
+ if (uiDefaults == null){
+ // Detect platform
+ String osName = getSystemProperty("os.name");
+ boolean isWindows = osName != null && osName.contains("Windows");
+
+ // We need to call super for basic's properties file.
+ uiDefaults = super.getDefaults();
+ defaults.initializeDefaults(uiDefaults);
+
+ // Install Keybindings
+ if (isWindows) {
+ WindowsKeybindings.installKeybindings(uiDefaults);
+ } else {
+ GTKKeybindings.installKeybindings(uiDefaults);
+ }
+
+ // Add Titled Border
+ uiDefaults.put("TitledBorder.titlePosition",
+ TitledBorder.ABOVE_TOP);
+ uiDefaults.put("TitledBorder.border", new BorderUIResource(
+ new LoweredBorder()));
+ uiDefaults.put("TitledBorder.titleColor",
+ getDerivedColor("text",0.0f,0.0f,0.23f,0,true));
+ uiDefaults.put("TitledBorder.font",
+ new NimbusDefaults.DerivedFont("defaultFont",
+ 1f, true, null));
+
+ // Choose Dialog button positions
+ uiDefaults.put("OptionPane.isYesLast", !isWindows);
+
+ // Store Table ScrollPane Corner Component
+ uiDefaults.put("Table.scrollPaneCornerComponent",
+ TableScrollPaneCorner.class);
+
+ // Setup the settings for ToolBarSeparator which is custom
+ // installed for Nimbus
+ uiDefaults.put("ToolBarSeparator[Enabled].backgroundPainter",
+ new ToolBarSeparatorPainter());
+
+ // Populate UIDefaults with a standard set of properties
+ for (String componentKey : COMPONENT_KEYS) {
+ String key = componentKey+".foreground";
+ if (!uiDefaults.containsKey(key)){
+ uiDefaults.put(key,
+ new NimbusProperty(componentKey,"textForeground"));
+ }
+ key = componentKey+".background";
+ if (!uiDefaults.containsKey(key)){
+ uiDefaults.put(key,
+ new NimbusProperty(componentKey,"background"));
+ }
+ key = componentKey+".font";
+ if (!uiDefaults.containsKey(key)){
+ uiDefaults.put(key,
+ new NimbusProperty(componentKey,"font"));
+ }
+ key = componentKey+".disabledText";
+ if (!uiDefaults.containsKey(key)){
+ uiDefaults.put(key,
+ new NimbusProperty(componentKey,"Disabled",
+ "textForeground"));
+ }
+ key = componentKey+".disabled";
+ if (!uiDefaults.containsKey(key)){
+ uiDefaults.put(key,
+ new NimbusProperty(componentKey,"Disabled",
+ "background"));
+ }
+ }
+
+ // FileView icon keys are used by some applications, we don't have
+ // a computer icon at the moment so using home icon for now
+ uiDefaults.put("FileView.computerIcon",
+ new LinkProperty("FileChooser.homeFolderIcon"));
+ uiDefaults.put("FileView.directoryIcon",
+ new LinkProperty("FileChooser.directoryIcon"));
+ uiDefaults.put("FileView.fileIcon",
+ new LinkProperty("FileChooser.fileIcon"));
+ uiDefaults.put("FileView.floppyDriveIcon",
+ new LinkProperty("FileChooser.floppyDriveIcon"));
+ uiDefaults.put("FileView.hardDriveIcon",
+ new LinkProperty("FileChooser.hardDriveIcon"));
+ }
+ return uiDefaults;
+ }
+
+ /**
+ * Gets the style associated with the given component and region. This
+ * will never return null. If an appropriate component and region cannot
+ * be determined, then a default style is returned.
+ *
+ * @param c a non-null reference to a JComponent
+ * @param r a non-null reference to the region of the component c
+ * @return a non-null reference to a NimbusStyle.
+ */
+ public static NimbusStyle getStyle(JComponent c, Region r) {
+ return (NimbusStyle)SynthLookAndFeel.getStyle(c, r);
+ }
+
+ /**
+ * Return a short string that identifies this look and feel. This
+ * String will be the unquoted String "Nimbus".
+ *
+ * @return a short string identifying this look and feel.
+ */
+ @Override public String getName() {
+ return "Nimbus";
+ }
+
+ /**
+ * Return a string that identifies this look and feel. This String will
+ * be the unquoted String "Nimbus".
+ *
+ * @return a short string identifying this look and feel.
+ */
+ @Override public String getID() {
+ return "Nimbus";
+ }
+
+ /**
+ * Returns a textual description of this look and feel.
+ *
+ * @return textual description of this look and feel.
+ */
+ @Override public String getDescription() {
+ return "Nimbus Look and Feel";
+ }
+
+ /**
+ * @inheritDoc
+ * @return true
+ */
+ @Override public boolean shouldUpdateStyleOnAncestorChanged() {
+ return true;
+ }
+
+ /**
+ * <p>Registers a third party component with the NimbusLookAndFeel.</p>
+ *
+ * <p>Regions represent Components and areas within Components that act as
+ * independent painting areas. Once registered with the NimbusLookAndFeel,
+ * NimbusStyles for these Regions can be retrieved via the
+ * <code>getStyle</code> method.</p>
+ *
+ * <p>The NimbusLookAndFeel uses a standard naming scheme for entries in the
+ * UIDefaults table. The key for each property, state, painter, and other
+ * default registered in UIDefaults for a specific Region will begin with
+ * the specified <code>prefix</code></p>
+ *
+ * <p>For example, suppose I had a component named JFoo. Suppose I then registered
+ * this component with the NimbusLookAndFeel in this manner:</p>
+ *
+ * <pre><code>
+ * laf.register(NimbusFooUI.FOO_REGION, "Foo");
+ * </code></pre>
+ *
+ * <p>In this case, I could then register properties for this component with
+ * UIDefaults in the following manner:</p>
+ *
+ * <pre><code>
+ * UIManager.put("Foo.background", new ColorUIResource(Color.BLACK));
+ * UIManager.put("Foo.Enabled.backgroundPainter", new FooBackgroundPainter());
+ * </code></pre>
+ *
+ * <p>It is also possible to register a named component with Nimbus.
+ * For example, suppose you wanted to style the background of a JPanel
+ * named "MyPanel" differently from other JPanels. You could accomplish this
+ * by doing the following:</p>
+ *
+ * <pre><code>
+ * laf.register(Region.PANEL, "\"MyPanel\"");
+ * UIManager.put("\"MyPanel\".background", new ColorUIResource(Color.RED));
+ * </code></pre>
+ *
+ * @param region The Synth Region that is being registered. Such as Button, or
+ * ScrollBarThumb, or NimbusFooUI.FOO_REGION.
+ * @param prefix The UIDefault prefix. For example, could be ComboBox, or if
+ * a named components, "MyComboBox", or even something like
+ * ToolBar."MyComboBox"."ComboBox.arrowButton"
+ */
+ public void register(Region region, String prefix) {
+ defaults.register(region, prefix);
+ }
+
+ /**
+ * Simple utility method that reads system keys.
+ */
+ private String getSystemProperty(String key) {
+ return AccessController.doPrivileged(new GetPropertyAction(key));
+ }
+
+ @Override
+ public Icon getDisabledIcon(JComponent component, Icon icon) {
+ if (icon instanceof SynthIcon) {
+ SynthIcon si = (SynthIcon)icon;
+ BufferedImage img = EffectUtils.createCompatibleTranslucentImage(
+ si.getIconWidth(), si.getIconHeight());
+ Graphics2D gfx = img.createGraphics();
+ si.paintIcon(component, gfx, 0, 0);
+ gfx.dispose();
+ return new ImageIconUIResource(GrayFilter.createDisabledImage(img));
+ } else {
+ return super.getDisabledIcon(component, icon);
+ }
+ }
+
+ /**
+ * Get a derived color, derived colors are shared instances and is color
+ * value will change when its parent UIDefault color changes.
+ *
+ * @param uiDefaultParentName The parent UIDefault key
+ * @param hOffset The hue offset
+ * @param sOffset The saturation offset
+ * @param bOffset The brightness offset
+ * @param aOffset The alpha offset
+ * @param uiResource True if the derived color should be a
+ * UIResource, false if it should not be
+ * @return The stored derived color
+ */
+ public Color getDerivedColor(String uiDefaultParentName,
+ float hOffset, float sOffset,
+ float bOffset, int aOffset,
+ boolean uiResource) {
+ return defaults.getDerivedColor(uiDefaultParentName, hOffset, sOffset,
+ bOffset, aOffset, uiResource);
+ }
+
+ /**
+ * Decodes and returns a color, which is derived from an offset between two
+ * other colors.
+ *
+ * @param color1 The first color
+ * @param color2 The second color
+ * @param midPoint The offset between color 1 and color 2, a value of 0.0 is
+ * color 1 and 1.0 is color 2;
+ * @param uiResource True if the derived color should be a UIResource
+ * @return The derived color
+ */
+ protected final Color getDerivedColor(Color color1, Color color2,
+ float midPoint, boolean uiResource) {
+ int argb = deriveARGB(color1, color2, midPoint);
+ if (uiResource) {
+ return new ColorUIResource(argb);
+ } else {
+ return new Color(argb);
+ }
+ }
+
+ /**
+ * Decodes and returns a color, which is derived from a offset between two
+ * other colors.
+ *
+ * @param color1 The first color
+ * @param color2 The second color
+ * @param midPoint The offset between color 1 and color 2, a value of 0.0 is
+ * color 1 and 1.0 is color 2;
+ * @return The derived color, which will be a UIResource
+ */
+ protected final Color getDerivedColor(Color color1, Color color2,
+ float midPoint) {
+ return getDerivedColor(color1, color2, midPoint, true);
+ }
+
+ /**
+ * Package private method which returns either BorderLayout.NORTH,
+ * BorderLayout.SOUTH, BorderLayout.EAST, or BorderLayout.WEST depending
+ * on the location of the toolbar in its parent. The toolbar might be
+ * in PAGE_START, PAGE_END, CENTER, or some other position, but will be
+ * resolved to either NORTH,SOUTH,EAST, or WEST based on where the toolbar
+ * actually IS, with CENTER being NORTH.
+ *
+ * This code is used to determine where the border line should be drawn
+ * by the custom toolbar states, and also used by NimbusIcon to determine
+ * whether the handle icon needs to be shifted to look correct.
+ *
+ * Toollbars are unfortunately odd in the way these things are handled,
+ * and so this code exists to unify the logic related to toolbars so it can
+ * be shared among the static files such as NimbusIcon and generated files
+ * such as the ToolBar state classes.
+ */
+ static Object resolveToolbarConstraint(JToolBar toolbar) {
+ //NOTE: we don't worry about component orientation or PAGE_END etc
+ //because the BasicToolBarUI always uses an absolute position of
+ //NORTH/SOUTH/EAST/WEST.
+ if (toolbar != null) {
+ Container parent = toolbar.getParent();
+ if (parent != null) {
+ LayoutManager m = parent.getLayout();
+ if (m instanceof BorderLayout) {
+ BorderLayout b = (BorderLayout)m;
+ Object con = b.getConstraints(toolbar);
+ if (con == SOUTH || con == EAST || con == WEST) {
+ return con;
+ }
+ return NORTH;
+ }
+ }
+ }
+ return NORTH;
+ }
+
+ /**
+ * Derives the ARGB value for a color based on an offset between two
+ * other colors.
+ *
+ * @param color1 The first color
+ * @param color2 The second color
+ * @param midPoint The offset between color 1 and color 2, a value of 0.0 is
+ * color 1 and 1.0 is color 2;
+ * @return the ARGB value for a new color based on this derivation
+ */
+ static int deriveARGB(Color color1, Color color2, float midPoint) {
+ int r = color1.getRed() +
+ (int) ((color2.getRed() - color1.getRed()) * midPoint + 0.5f);
+ int g = color1.getGreen() +
+ (int) ((color2.getGreen() - color1.getGreen()) * midPoint +
+ 0.5f);
+ int b = color1.getBlue() +
+ (int) ((color2.getBlue() - color1.getBlue()) * midPoint + 0.5f);
+ int a = color1.getAlpha() +
+ (int) ((color2.getAlpha() - color1.getAlpha()) * midPoint +
+ 0.5f);
+ return ((a & 0xFF) << 24) |
+ ((r & 0xFF) << 16) |
+ ((g & 0xFF) << 8) |
+ (b & 0xFF);
+ }
+
+ /**
+ * Simple Symbolic Link style UIDefalts Property
+ */
+ private class LinkProperty implements UIDefaults.ActiveValue, UIResource{
+ private String dstPropName;
+
+ private LinkProperty(String dstPropName) {
+ this.dstPropName = dstPropName;
+ }
+
+ @Override
+ public Object createValue(UIDefaults table) {
+ return UIManager.get(dstPropName);
+ }
+ }
+
+ /**
+ * Nimbus Property that looks up Nimbus keys for standard key names. For
+ * example "Button.background" --> "Button[Enabled].backgound"
+ */
+ private class NimbusProperty implements UIDefaults.ActiveValue, UIResource {
+ private String prefix;
+ private String state = null;
+ private String suffix;
+ private boolean isFont;
+
+ private NimbusProperty(String prefix, String suffix) {
+ this.prefix = prefix;
+ this.suffix = suffix;
+ isFont = "font".equals(suffix);
+ }
+
+ private NimbusProperty(String prefix, String state, String suffix) {
+ this(prefix,suffix);
+ this.state = state;
+ }
+
+ /**
+ * Creates the value retrieved from the <code>UIDefaults</code> table.
+ * The object is created each time it is accessed.
+ *
+ * @param table a <code>UIDefaults</code> table
+ * @return the created <code>Object</code>
+ */
+ @Override
+ public Object createValue(UIDefaults table) {
+ Object obj = null;
+ // check specified state
+ if (state!=null){
+ obj = uiDefaults.get(prefix+"["+state+"]."+suffix);
+ }
+ // check enabled state
+ if (obj==null){
+ obj = uiDefaults.get(prefix+"[Enabled]."+suffix);
+ }
+ // check for defaults
+ if (obj==null){
+ if (isFont) {
+ obj = uiDefaults.get("defaultFont");
+ } else {
+ obj = uiDefaults.get(suffix);
+ }
+ }
+ return obj;
+ }
+ }
+}