0N/A/*
3261N/A * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/Apackage javax.swing.plaf.synth;
0N/A
0N/Aimport java.awt.*;
0N/Aimport java.beans.*;
0N/Aimport java.io.*;
0N/Aimport java.lang.ref.*;
0N/Aimport java.net.*;
0N/Aimport java.security.*;
0N/Aimport java.text.*;
0N/Aimport java.util.*;
0N/Aimport javax.swing.*;
0N/Aimport javax.swing.plaf.*;
0N/Aimport javax.swing.plaf.basic.*;
0N/A
0N/Aimport sun.awt.*;
0N/Aimport sun.security.action.*;
0N/Aimport sun.swing.*;
0N/Aimport sun.swing.plaf.synth.*;
0N/A
0N/A/**
0N/A * SynthLookAndFeel provides the basis for creating a customized look and
0N/A * feel. SynthLookAndFeel does not directly provide a look, all painting is
0N/A * delegated.
0N/A * You need to either provide a configuration file, by way of the
0N/A * {@link #load} method, or provide your own {@link SynthStyleFactory}
0N/A * to {@link #setStyleFactory}. Refer to the
0N/A * <a href="package-summary.html">package summary</a> for an example of
0N/A * loading a file, and {@link javax.swing.plaf.synth.SynthStyleFactory} for
0N/A * an example of providing your own <code>SynthStyleFactory</code> to
0N/A * <code>setStyleFactory</code>.
0N/A * <p>
0N/A * <strong>Warning:</strong>
0N/A * This class implements {@link Serializable} as a side effect of it
0N/A * extending {@link BasicLookAndFeel}. It is not intended to be serialized.
0N/A * An attempt to serialize it will
0N/A * result in {@link NotSerializableException}.
0N/A *
0N/A * @serial exclude
0N/A * @since 1.5
0N/A * @author Scott Violet
0N/A */
0N/Apublic class SynthLookAndFeel extends BasicLookAndFeel {
0N/A /**
0N/A * Used in a handful of places where we need an empty Insets.
0N/A */
0N/A static final Insets EMPTY_UIRESOURCE_INSETS = new InsetsUIResource(
0N/A 0, 0, 0, 0);
0N/A
0N/A /**
0N/A * AppContext key to get the current SynthStyleFactory.
0N/A */
0N/A private static final Object STYLE_FACTORY_KEY =
0N/A new StringBuffer("com.sun.java.swing.plaf.gtk.StyleCache");
0N/A
0N/A /**
5088N/A * AppContext key to get selectedUI.
5088N/A */
5088N/A private static final Object SELECTED_UI_KEY = new StringBuilder("selectedUI");
5088N/A
5088N/A /**
5088N/A * AppContext key to get selectedUIState.
5088N/A */
5088N/A private static final Object SELECTED_UI_STATE_KEY = new StringBuilder("selectedUIState");
5088N/A
5088N/A /**
0N/A * The last SynthStyleFactory that was asked for from AppContext
0N/A * <code>lastContext</code>.
0N/A */
0N/A private static SynthStyleFactory lastFactory;
0N/A /**
0N/A * AppContext lastLAF came from.
0N/A */
0N/A private static AppContext lastContext;
0N/A
0N/A /**
0N/A * SynthStyleFactory for the this SynthLookAndFeel.
0N/A */
0N/A private SynthStyleFactory factory;
0N/A
0N/A /**
0N/A * Map of defaults table entries. This is populated via the load
0N/A * method.
0N/A */
614N/A private Map<String, Object> defaultsMap;
0N/A
0N/A private Handler _handler;
0N/A
5088N/A static ComponentUI getSelectedUI() {
5088N/A return (ComponentUI) AppContext.getAppContext().get(SELECTED_UI_KEY);
5088N/A }
5088N/A
0N/A /**
0N/A * Used by the renderers. For the most part the renderers are implemented
0N/A * as Labels, which is problematic in so far as they are never selected.
0N/A * To accomodate this SynthLabelUI checks if the current
0N/A * UI matches that of <code>selectedUI</code> (which this methods sets), if
0N/A * it does, then a state as set by this method is returned. This provides
0N/A * a way for labels to have a state other than selected.
0N/A */
0N/A static void setSelectedUI(ComponentUI uix, boolean selected,
0N/A boolean focused, boolean enabled,
0N/A boolean rollover) {
5088N/A int selectedUIState = 0;
5088N/A
0N/A if (selected) {
0N/A selectedUIState = SynthConstants.SELECTED;
0N/A if (focused) {
0N/A selectedUIState |= SynthConstants.FOCUSED;
0N/A }
0N/A }
0N/A else if (rollover && enabled) {
0N/A selectedUIState |=
0N/A SynthConstants.MOUSE_OVER | SynthConstants.ENABLED;
0N/A if (focused) {
0N/A selectedUIState |= SynthConstants.FOCUSED;
0N/A }
0N/A }
0N/A else {
0N/A if (enabled) {
0N/A selectedUIState |= SynthConstants.ENABLED;
5088N/A if (focused) {
5088N/A selectedUIState |= SynthConstants.FOCUSED;
5088N/A }
0N/A }
0N/A else {
0N/A selectedUIState |= SynthConstants.DISABLED;
0N/A }
0N/A }
5088N/A
5088N/A AppContext context = AppContext.getAppContext();
5088N/A
5088N/A context.put(SELECTED_UI_KEY, uix);
5088N/A context.put(SELECTED_UI_STATE_KEY, Integer.valueOf(selectedUIState));
5088N/A }
5088N/A
5088N/A static int getSelectedUIState() {
5088N/A Integer result = (Integer) AppContext.getAppContext().get(SELECTED_UI_STATE_KEY);
5088N/A
5088N/A return result == null ? 0 : result.intValue();
0N/A }
0N/A
0N/A /**
0N/A * Clears out the selected UI that was last set in setSelectedUI.
0N/A */
0N/A static void resetSelectedUI() {
5088N/A AppContext.getAppContext().remove(SELECTED_UI_KEY);
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Sets the SynthStyleFactory that the UI classes provided by
0N/A * synth will use to obtain a SynthStyle.
0N/A *
0N/A * @param cache SynthStyleFactory the UIs should use.
0N/A */
0N/A public static void setStyleFactory(SynthStyleFactory cache) {
0N/A // We assume the setter is called BEFORE the getter has been invoked
0N/A // for a particular AppContext.
0N/A synchronized(SynthLookAndFeel.class) {
0N/A AppContext context = AppContext.getAppContext();
0N/A lastFactory = cache;
0N/A lastContext = context;
0N/A context.put(STYLE_FACTORY_KEY, cache);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Returns the current SynthStyleFactory.
0N/A *
0N/A * @return SynthStyleFactory
0N/A */
0N/A public static SynthStyleFactory getStyleFactory() {
0N/A synchronized(SynthLookAndFeel.class) {
0N/A AppContext context = AppContext.getAppContext();
0N/A
0N/A if (lastContext == context) {
0N/A return lastFactory;
0N/A }
0N/A lastContext = context;
5088N/A lastFactory = (SynthStyleFactory) context.get(STYLE_FACTORY_KEY);
0N/A return lastFactory;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Returns the component state for the specified component. This should
0N/A * only be used for Components that don't have any special state beyond
0N/A * that of ENABLED, DISABLED or FOCUSED. For example, buttons shouldn't
0N/A * call into this method.
0N/A */
0N/A static int getComponentState(Component c) {
0N/A if (c.isEnabled()) {
0N/A if (c.isFocusOwner()) {
0N/A return SynthUI.ENABLED | SynthUI.FOCUSED;
0N/A }
0N/A return SynthUI.ENABLED;
0N/A }
0N/A return SynthUI.DISABLED;
0N/A }
0N/A
0N/A /**
0N/A * Gets a SynthStyle for the specified region of the specified component.
0N/A * This is not for general consumption, only custom UIs should call this
0N/A * method.
0N/A *
0N/A * @param c JComponent to get the SynthStyle for
0N/A * @param region Identifies the region of the specified component
0N/A * @return SynthStyle to use.
0N/A */
0N/A public static SynthStyle getStyle(JComponent c, Region region) {
0N/A return getStyleFactory().getStyle(c, region);
0N/A }
0N/A
0N/A /**
0N/A * Returns true if the Style should be updated in response to the
0N/A * specified PropertyChangeEvent. This forwards to
0N/A * <code>shouldUpdateStyleOnAncestorChanged</code> as necessary.
0N/A */
0N/A static boolean shouldUpdateStyle(PropertyChangeEvent event) {
1999N/A LookAndFeel laf = UIManager.getLookAndFeel();
1999N/A return (laf instanceof SynthLookAndFeel &&
1999N/A ((SynthLookAndFeel) laf).shouldUpdateStyleOnEvent(event));
0N/A }
0N/A
0N/A /**
0N/A * A convience method that will reset the Style of StyleContext if
0N/A * necessary.
0N/A *
0N/A * @return newStyle
0N/A */
0N/A static SynthStyle updateStyle(SynthContext context, SynthUI ui) {
0N/A SynthStyle newStyle = getStyle(context.getComponent(),
0N/A context.getRegion());
0N/A SynthStyle oldStyle = context.getStyle();
0N/A
0N/A if (newStyle != oldStyle) {
0N/A if (oldStyle != null) {
0N/A oldStyle.uninstallDefaults(context);
0N/A }
0N/A context.setStyle(newStyle);
0N/A newStyle.installDefaults(context, ui);
0N/A }
0N/A return newStyle;
0N/A }
0N/A
0N/A /**
0N/A * Updates the style associated with <code>c</code>, and all its children.
0N/A * This is a lighter version of
0N/A * <code>SwingUtilities.updateComponentTreeUI</code>.
0N/A *
0N/A * @param c Component to update style for.
0N/A */
0N/A public static void updateStyles(Component c) {
0N/A if (c instanceof JComponent) {
0N/A // Yes, this is hacky. A better solution is to get the UI
0N/A // and cast, but JComponent doesn't expose a getter for the UI
0N/A // (each of the UIs do), making that approach impractical.
0N/A String name = c.getName();
0N/A c.setName(null);
0N/A if (name != null) {
0N/A c.setName(name);
0N/A }
0N/A ((JComponent)c).revalidate();
0N/A }
0N/A Component[] children = null;
0N/A if (c instanceof JMenu) {
0N/A children = ((JMenu)c).getMenuComponents();
0N/A }
0N/A else if (c instanceof Container) {
0N/A children = ((Container)c).getComponents();
0N/A }
0N/A if (children != null) {
614N/A for (Component child : children) {
614N/A updateStyles(child);
0N/A }
0N/A }
1999N/A c.repaint();
0N/A }
0N/A
0N/A /**
0N/A * Returns the Region for the JComponent <code>c</code>.
0N/A *
0N/A * @param c JComponent to fetch the Region for
0N/A * @return Region corresponding to <code>c</code>
0N/A */
0N/A public static Region getRegion(JComponent c) {
0N/A return Region.getRegion(c);
0N/A }
0N/A
0N/A /**
0N/A * A convenience method to return where the foreground should be
0N/A * painted for the Component identified by the passed in
0N/A * AbstractSynthContext.
0N/A */
0N/A static Insets getPaintingInsets(SynthContext state, Insets insets) {
0N/A if (state.isSubregion()) {
0N/A insets = state.getStyle().getInsets(state, insets);
0N/A }
0N/A else {
0N/A insets = state.getComponent().getInsets(insets);
0N/A }
0N/A return insets;
0N/A }
0N/A
0N/A /**
0N/A * A convenience method that handles painting of the background.
0N/A * All SynthUI implementations should override update and invoke
0N/A * this method.
0N/A */
0N/A static void update(SynthContext state, Graphics g) {
0N/A paintRegion(state, g, null);
0N/A }
0N/A
0N/A /**
0N/A * A convenience method that handles painting of the background for
0N/A * subregions. All SynthUI's that have subregions should invoke
0N/A * this method, than paint the foreground.
0N/A */
0N/A static void updateSubregion(SynthContext state, Graphics g,
0N/A Rectangle bounds) {
0N/A paintRegion(state, g, bounds);
0N/A }
0N/A
0N/A private static void paintRegion(SynthContext state, Graphics g,
0N/A Rectangle bounds) {
0N/A JComponent c = state.getComponent();
0N/A SynthStyle style = state.getStyle();
0N/A int x, y, width, height;
0N/A
0N/A if (bounds == null) {
0N/A x = 0;
0N/A y = 0;
0N/A width = c.getWidth();
0N/A height = c.getHeight();
0N/A }
0N/A else {
0N/A x = bounds.x;
0N/A y = bounds.y;
0N/A width = bounds.width;
0N/A height = bounds.height;
0N/A }
0N/A
0N/A // Fill in the background, if necessary.
0N/A boolean subregion = state.isSubregion();
0N/A if ((subregion && style.isOpaque(state)) ||
0N/A (!subregion && c.isOpaque())) {
0N/A g.setColor(style.getColor(state, ColorType.BACKGROUND));
0N/A g.fillRect(x, y, width, height);
0N/A }
0N/A }
0N/A
0N/A static boolean isLeftToRight(Component c) {
0N/A return c.getComponentOrientation().isLeftToRight();
0N/A }
0N/A
0N/A /**
0N/A * Returns the ui that is of type <code>klass</code>, or null if
0N/A * one can not be found.
0N/A */
0N/A static Object getUIOfType(ComponentUI ui, Class klass) {
0N/A if (klass.isInstance(ui)) {
0N/A return ui;
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A /**
0N/A * Creates the Synth look and feel <code>ComponentUI</code> for
0N/A * the passed in <code>JComponent</code>.
0N/A *
0N/A * @param c JComponent to create the <code>ComponentUI</code> for
0N/A * @return ComponentUI to use for <code>c</code>
0N/A */
0N/A public static ComponentUI createUI(JComponent c) {
0N/A String key = c.getUIClassID().intern();
0N/A
0N/A if (key == "ButtonUI") {
0N/A return SynthButtonUI.createUI(c);
0N/A }
0N/A else if (key == "CheckBoxUI") {
0N/A return SynthCheckBoxUI.createUI(c);
0N/A }
0N/A else if (key == "CheckBoxMenuItemUI") {
0N/A return SynthCheckBoxMenuItemUI.createUI(c);
0N/A }
0N/A else if (key == "ColorChooserUI") {
0N/A return SynthColorChooserUI.createUI(c);
0N/A }
0N/A else if (key == "ComboBoxUI") {
0N/A return SynthComboBoxUI.createUI(c);
0N/A }
0N/A else if (key == "DesktopPaneUI") {
0N/A return SynthDesktopPaneUI.createUI(c);
0N/A }
0N/A else if (key == "DesktopIconUI") {
0N/A return SynthDesktopIconUI.createUI(c);
0N/A }
0N/A else if (key == "EditorPaneUI") {
0N/A return SynthEditorPaneUI.createUI(c);
0N/A }
0N/A else if (key == "FileChooserUI") {
0N/A return SynthFileChooserUI.createUI(c);
0N/A }
0N/A else if (key == "FormattedTextFieldUI") {
0N/A return SynthFormattedTextFieldUI.createUI(c);
0N/A }
0N/A else if (key == "InternalFrameUI") {
0N/A return SynthInternalFrameUI.createUI(c);
0N/A }
0N/A else if (key == "LabelUI") {
0N/A return SynthLabelUI.createUI(c);
0N/A }
0N/A else if (key == "ListUI") {
0N/A return SynthListUI.createUI(c);
0N/A }
0N/A else if (key == "MenuBarUI") {
0N/A return SynthMenuBarUI.createUI(c);
0N/A }
0N/A else if (key == "MenuUI") {
0N/A return SynthMenuUI.createUI(c);
0N/A }
0N/A else if (key == "MenuItemUI") {
0N/A return SynthMenuItemUI.createUI(c);
0N/A }
0N/A else if (key == "OptionPaneUI") {
0N/A return SynthOptionPaneUI.createUI(c);
0N/A }
0N/A else if (key == "PanelUI") {
0N/A return SynthPanelUI.createUI(c);
0N/A }
0N/A else if (key == "PasswordFieldUI") {
0N/A return SynthPasswordFieldUI.createUI(c);
0N/A }
0N/A else if (key == "PopupMenuSeparatorUI") {
0N/A return SynthSeparatorUI.createUI(c);
0N/A }
0N/A else if (key == "PopupMenuUI") {
0N/A return SynthPopupMenuUI.createUI(c);
0N/A }
0N/A else if (key == "ProgressBarUI") {
0N/A return SynthProgressBarUI.createUI(c);
0N/A }
0N/A else if (key == "RadioButtonUI") {
0N/A return SynthRadioButtonUI.createUI(c);
0N/A }
0N/A else if (key == "RadioButtonMenuItemUI") {
0N/A return SynthRadioButtonMenuItemUI.createUI(c);
0N/A }
0N/A else if (key == "RootPaneUI") {
0N/A return SynthRootPaneUI.createUI(c);
0N/A }
0N/A else if (key == "ScrollBarUI") {
0N/A return SynthScrollBarUI.createUI(c);
0N/A }
0N/A else if (key == "ScrollPaneUI") {
0N/A return SynthScrollPaneUI.createUI(c);
0N/A }
0N/A else if (key == "SeparatorUI") {
0N/A return SynthSeparatorUI.createUI(c);
0N/A }
0N/A else if (key == "SliderUI") {
0N/A return SynthSliderUI.createUI(c);
0N/A }
0N/A else if (key == "SpinnerUI") {
0N/A return SynthSpinnerUI.createUI(c);
0N/A }
0N/A else if (key == "SplitPaneUI") {
0N/A return SynthSplitPaneUI.createUI(c);
0N/A }
0N/A else if (key == "TabbedPaneUI") {
0N/A return SynthTabbedPaneUI.createUI(c);
0N/A }
0N/A else if (key == "TableUI") {
0N/A return SynthTableUI.createUI(c);
0N/A }
0N/A else if (key == "TableHeaderUI") {
0N/A return SynthTableHeaderUI.createUI(c);
0N/A }
0N/A else if (key == "TextAreaUI") {
0N/A return SynthTextAreaUI.createUI(c);
0N/A }
0N/A else if (key == "TextFieldUI") {
0N/A return SynthTextFieldUI.createUI(c);
0N/A }
0N/A else if (key == "TextPaneUI") {
0N/A return SynthTextPaneUI.createUI(c);
0N/A }
0N/A else if (key == "ToggleButtonUI") {
0N/A return SynthToggleButtonUI.createUI(c);
0N/A }
0N/A else if (key == "ToolBarSeparatorUI") {
0N/A return SynthSeparatorUI.createUI(c);
0N/A }
0N/A else if (key == "ToolBarUI") {
0N/A return SynthToolBarUI.createUI(c);
0N/A }
0N/A else if (key == "ToolTipUI") {
0N/A return SynthToolTipUI.createUI(c);
0N/A }
0N/A else if (key == "TreeUI") {
0N/A return SynthTreeUI.createUI(c);
0N/A }
0N/A else if (key == "ViewportUI") {
0N/A return SynthViewportUI.createUI(c);
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Creates a SynthLookAndFeel.
0N/A * <p>
0N/A * For the returned <code>SynthLookAndFeel</code> to be useful you need to
0N/A * invoke <code>load</code> to specify the set of
0N/A * <code>SynthStyle</code>s, or invoke <code>setStyleFactory</code>.
0N/A *
0N/A * @see #load
0N/A * @see #setStyleFactory
0N/A */
0N/A public SynthLookAndFeel() {
0N/A factory = new DefaultSynthStyleFactory();
0N/A _handler = new Handler();
0N/A }
0N/A
0N/A /**
0N/A * Loads the set of <code>SynthStyle</code>s that will be used by
0N/A * this <code>SynthLookAndFeel</code>. <code>resourceBase</code> is
0N/A * used to resolve any path based resources, for example an
0N/A * <code>Image</code> would be resolved by
0N/A * <code>resourceBase.getResource(path)</code>. Refer to
0N/A * <a href="doc-files/synthFileFormat.html">Synth File Format</a>
0N/A * for more information.
0N/A *
0N/A * @param input InputStream to load from
0N/A * @param resourceBase used to resolve any images or other resources
0N/A * @throws ParseException if there is an error in parsing
0N/A * @throws IllegalArgumentException if input or resourceBase is <code>null</code>
0N/A */
0N/A public void load(InputStream input, Class<?> resourceBase) throws
0N/A ParseException {
0N/A if (resourceBase == null) {
0N/A throw new IllegalArgumentException(
0N/A "You must supply a valid resource base Class");
0N/A }
0N/A
0N/A if (defaultsMap == null) {
614N/A defaultsMap = new HashMap<String, Object>();
0N/A }
0N/A
0N/A new SynthParser().parse(input, (DefaultSynthStyleFactory) factory,
0N/A null, resourceBase, defaultsMap);
0N/A }
0N/A
0N/A /**
0N/A * Loads the set of <code>SynthStyle</code>s that will be used by
0N/A * this <code>SynthLookAndFeel</code>. Path based resources are resolved
0N/A * relatively to the specified <code>URL</code> of the style. For example
0N/A * an <code>Image</code> would be resolved by
0N/A * <code>new URL(synthFile, path)</code>. Refer to
0N/A * <a href="doc-files/synthFileFormat.html">Synth File Format</a> for more
0N/A * information.
0N/A *
0N/A * @param url the <code>URL</code> to load the set of
0N/A * <code>SynthStyle</code> from
0N/A * @throws ParseException if there is an error in parsing
0N/A * @throws IllegalArgumentException if synthSet is <code>null</code>
0N/A * @throws IOException if synthSet cannot be opened as an <code>InputStream</code>
0N/A * @since 1.6
0N/A */
0N/A public void load(URL url) throws ParseException, IOException {
0N/A if (url == null) {
0N/A throw new IllegalArgumentException(
0N/A "You must supply a valid Synth set URL");
0N/A }
0N/A
0N/A if (defaultsMap == null) {
614N/A defaultsMap = new HashMap<String, Object>();
0N/A }
0N/A
0N/A InputStream input = url.openStream();
0N/A new SynthParser().parse(input, (DefaultSynthStyleFactory) factory,
0N/A url, null, defaultsMap);
0N/A }
0N/A
0N/A /**
0N/A * Called by UIManager when this look and feel is installed.
0N/A */
1173N/A @Override
0N/A public void initialize() {
0N/A super.initialize();
0N/A DefaultLookup.setDefaultLookup(new SynthDefaultLookup());
0N/A setStyleFactory(factory);
0N/A KeyboardFocusManager.getCurrentKeyboardFocusManager().
0N/A addPropertyChangeListener(_handler);
0N/A }
0N/A
0N/A /**
0N/A * Called by UIManager when this look and feel is uninstalled.
0N/A */
1173N/A @Override
0N/A public void uninitialize() {
0N/A KeyboardFocusManager.getCurrentKeyboardFocusManager().
0N/A removePropertyChangeListener(_handler);
0N/A // We should uninstall the StyleFactory here, but unfortunately
0N/A // there are a handful of things that retain references to the
0N/A // LookAndFeel and expect things to work
0N/A super.uninitialize();
0N/A }
0N/A
0N/A /**
0N/A * Returns the defaults for this SynthLookAndFeel.
0N/A *
0N/A * @return Defaults table.
0N/A */
1173N/A @Override
0N/A public UIDefaults getDefaults() {
0N/A UIDefaults table = new UIDefaults(60, 0.75f);
0N/A
0N/A Region.registerUIs(table);
0N/A table.setDefaultLocale(Locale.getDefault());
0N/A table.addResourceBundle(
0N/A "com.sun.swing.internal.plaf.basic.resources.basic" );
0N/A table.addResourceBundle("com.sun.swing.internal.plaf.synth.resources.synth");
0N/A
0N/A // SynthTabbedPaneUI supports rollover on tabs, GTK does not
0N/A table.put("TabbedPane.isTabRollover", Boolean.TRUE);
0N/A
0N/A // These need to be defined for JColorChooser to work.
0N/A table.put("ColorChooser.swatchesRecentSwatchSize",
0N/A new Dimension(10, 10));
0N/A table.put("ColorChooser.swatchesDefaultRecentColor", Color.RED);
0N/A table.put("ColorChooser.swatchesSwatchSize", new Dimension(10, 10));
0N/A
2212N/A // These need to be defined for ImageView.
2212N/A table.put("html.pendingImage", SwingUtilities2.makeIcon(getClass(),
2212N/A BasicLookAndFeel.class,
2212N/A "icons/image-delayed.png"));
2212N/A table.put("html.missingImage", SwingUtilities2.makeIcon(getClass(),
2212N/A BasicLookAndFeel.class,
2212N/A "icons/image-failed.png"));
2212N/A
0N/A // These are needed for PopupMenu.
0N/A table.put("PopupMenu.selectedWindowInputMapBindings", new Object[] {
0N/A "ESCAPE", "cancel",
0N/A "DOWN", "selectNext",
0N/A "KP_DOWN", "selectNext",
0N/A "UP", "selectPrevious",
0N/A "KP_UP", "selectPrevious",
0N/A "LEFT", "selectParent",
0N/A "KP_LEFT", "selectParent",
0N/A "RIGHT", "selectChild",
0N/A "KP_RIGHT", "selectChild",
0N/A "ENTER", "return",
0N/A "SPACE", "return"
0N/A });
0N/A table.put("PopupMenu.selectedWindowInputMapBindings.RightToLeft",
0N/A new Object[] {
0N/A "LEFT", "selectChild",
0N/A "KP_LEFT", "selectChild",
0N/A "RIGHT", "selectParent",
0N/A "KP_RIGHT", "selectParent",
0N/A });
0N/A
0N/A // enabled antialiasing depending on desktop settings
0N/A flushUnreferenced();
0N/A Object aaTextInfo = getAATextInfo();
0N/A table.put(SwingUtilities2.AA_TEXT_PROPERTY_KEY, aaTextInfo);
0N/A new AATextListener(this);
0N/A
0N/A if (defaultsMap != null) {
0N/A table.putAll(defaultsMap);
0N/A }
0N/A return table;
0N/A }
0N/A
0N/A /**
0N/A * Returns true, SynthLookAndFeel is always supported.
0N/A *
0N/A * @return true.
0N/A */
1173N/A @Override
0N/A public boolean isSupportedLookAndFeel() {
0N/A return true;
0N/A }
0N/A
0N/A /**
0N/A * Returns false, SynthLookAndFeel is not a native look and feel.
0N/A *
0N/A * @return false
0N/A */
1173N/A @Override
0N/A public boolean isNativeLookAndFeel() {
0N/A return false;
0N/A }
0N/A
0N/A /**
0N/A * Returns a textual description of SynthLookAndFeel.
0N/A *
0N/A * @return textual description of synth.
0N/A */
1173N/A @Override
0N/A public String getDescription() {
0N/A return "Synth look and feel";
0N/A }
0N/A
0N/A /**
0N/A * Return a short string that identifies this look and feel.
0N/A *
0N/A * @return a short string identifying this look and feel.
0N/A */
1173N/A @Override
0N/A public String getName() {
0N/A return "Synth look and feel";
0N/A }
0N/A
0N/A /**
0N/A * Return a string that identifies this look and feel.
0N/A *
0N/A * @return a short string identifying this look and feel.
0N/A */
1173N/A @Override
0N/A public String getID() {
0N/A return "Synth";
0N/A }
0N/A
0N/A /**
0N/A * Returns whether or not the UIs should update their
0N/A * <code>SynthStyles</code> from the <code>SynthStyleFactory</code>
0N/A * when the ancestor of the <code>JComponent</code> changes. A subclass
0N/A * that provided a <code>SynthStyleFactory</code> that based the
0N/A * return value from <code>getStyle</code> off the containment hierarchy
0N/A * would override this method to return true.
0N/A *
0N/A * @return whether or not the UIs should update their
0N/A * <code>SynthStyles</code> from the <code>SynthStyleFactory</code>
0N/A * when the ancestor changed.
0N/A */
0N/A public boolean shouldUpdateStyleOnAncestorChanged() {
0N/A return false;
0N/A }
0N/A
0N/A /**
1999N/A * Returns whether or not the UIs should update their styles when a
1999N/A * particular event occurs.
1999N/A *
1999N/A * @param ev a {@code PropertyChangeEvent}
1999N/A * @return whether or not the UIs should update their styles
1999N/A * @since 1.7
1999N/A */
1999N/A protected boolean shouldUpdateStyleOnEvent(PropertyChangeEvent ev) {
1999N/A String eName = ev.getPropertyName();
1999N/A if ("name" == eName || "componentOrientation" == eName) {
1999N/A return true;
1999N/A }
1999N/A if ("ancestor" == eName && ev.getNewValue() != null) {
1999N/A // Only update on an ancestor change when getting a valid
1999N/A // parent and the LookAndFeel wants this.
1999N/A return shouldUpdateStyleOnAncestorChanged();
1999N/A }
1999N/A return false;
1999N/A }
1999N/A
1999N/A /**
0N/A * Returns the antialiasing information as specified by the host desktop.
0N/A * Antialiasing might be forced off if the desktop is GNOME and the user
0N/A * has set his locale to Chinese, Japanese or Korean. This is consistent
0N/A * with what GTK does. See com.sun.java.swing.plaf.gtk.GtkLookAndFeel
0N/A * for more information about CJK and antialiased fonts.
0N/A *
0N/A * @return the text antialiasing information associated to the desktop
0N/A */
0N/A private static Object getAATextInfo() {
0N/A String language = Locale.getDefault().getLanguage();
614N/A String desktop =
0N/A AccessController.doPrivileged(new GetPropertyAction("sun.desktop"));
0N/A
0N/A boolean isCjkLocale = (Locale.CHINESE.getLanguage().equals(language) ||
0N/A Locale.JAPANESE.getLanguage().equals(language) ||
0N/A Locale.KOREAN.getLanguage().equals(language));
0N/A boolean isGnome = "gnome".equals(desktop);
0N/A boolean isLocal = SwingUtilities2.isLocalDisplay();
0N/A
0N/A boolean setAA = isLocal && (!isGnome || !isCjkLocale);
0N/A
0N/A Object aaTextInfo = SwingUtilities2.AATextInfo.getAATextInfo(setAA);
0N/A return aaTextInfo;
0N/A }
0N/A
614N/A private static ReferenceQueue<LookAndFeel> queue = new ReferenceQueue<LookAndFeel>();
0N/A
0N/A private static void flushUnreferenced() {
0N/A AATextListener aatl;
0N/A while ((aatl = (AATextListener) queue.poll()) != null) {
0N/A aatl.dispose();
0N/A }
0N/A }
0N/A
0N/A private static class AATextListener
614N/A extends WeakReference<LookAndFeel> implements PropertyChangeListener {
0N/A private String key = SunToolkit.DESKTOPFONTHINTS;
0N/A
0N/A AATextListener(LookAndFeel laf) {
0N/A super(laf, queue);
0N/A Toolkit tk = Toolkit.getDefaultToolkit();
0N/A tk.addPropertyChangeListener(key, this);
0N/A }
0N/A
1173N/A @Override
0N/A public void propertyChange(PropertyChangeEvent pce) {
0N/A UIDefaults defaults = UIManager.getLookAndFeelDefaults();
0N/A if (defaults.getBoolean("Synth.doNotSetTextAA")) {
0N/A dispose();
0N/A return;
0N/A }
0N/A
614N/A LookAndFeel laf = get();
0N/A if (laf == null || laf != UIManager.getLookAndFeel()) {
0N/A dispose();
0N/A return;
0N/A }
0N/A
0N/A Object aaTextInfo = getAATextInfo();
0N/A defaults.put(SwingUtilities2.AA_TEXT_PROPERTY_KEY, aaTextInfo);
0N/A
0N/A updateUI();
0N/A }
0N/A
0N/A void dispose() {
0N/A Toolkit tk = Toolkit.getDefaultToolkit();
0N/A tk.removePropertyChangeListener(key, this);
0N/A }
0N/A
0N/A /**
0N/A * Updates the UI of the passed in window and all its children.
0N/A */
0N/A private static void updateWindowUI(Window window) {
0N/A updateStyles(window);
0N/A Window ownedWins[] = window.getOwnedWindows();
614N/A for (Window w : ownedWins) {
614N/A updateWindowUI(w);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Updates the UIs of all the known Frames.
0N/A */
0N/A private static void updateAllUIs() {
0N/A Frame appFrames[] = Frame.getFrames();
614N/A for (Frame frame : appFrames) {
614N/A updateWindowUI(frame);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Indicates if an updateUI call is pending.
0N/A */
0N/A private static boolean updatePending;
0N/A
0N/A /**
0N/A * Sets whether or not an updateUI call is pending.
0N/A */
0N/A private static synchronized void setUpdatePending(boolean update) {
0N/A updatePending = update;
0N/A }
0N/A
0N/A /**
0N/A * Returns true if a UI update is pending.
0N/A */
0N/A private static synchronized boolean isUpdatePending() {
0N/A return updatePending;
0N/A }
0N/A
0N/A protected void updateUI() {
0N/A if (!isUpdatePending()) {
0N/A setUpdatePending(true);
0N/A Runnable uiUpdater = new Runnable() {
1173N/A @Override
0N/A public void run() {
0N/A updateAllUIs();
0N/A setUpdatePending(false);
0N/A }
0N/A };
0N/A SwingUtilities.invokeLater(uiUpdater);
0N/A }
0N/A }
0N/A }
0N/A
0N/A private void writeObject(java.io.ObjectOutputStream out)
0N/A throws IOException {
0N/A throw new NotSerializableException(this.getClass().getName());
0N/A }
0N/A
0N/A private class Handler implements PropertyChangeListener {
1173N/A @Override
0N/A public void propertyChange(PropertyChangeEvent evt) {
0N/A String propertyName = evt.getPropertyName();
0N/A Object newValue = evt.getNewValue();
0N/A Object oldValue = evt.getOldValue();
0N/A
0N/A if ("focusOwner" == propertyName) {
0N/A if (oldValue instanceof JComponent) {
0N/A repaintIfBackgroundsDiffer((JComponent)oldValue);
0N/A
0N/A }
0N/A
0N/A if (newValue instanceof JComponent) {
0N/A repaintIfBackgroundsDiffer((JComponent)newValue);
0N/A }
0N/A }
0N/A else if ("managingFocus" == propertyName) {
0N/A // De-register listener on old keyboard focus manager and
0N/A // register it on the new one.
0N/A KeyboardFocusManager manager =
0N/A (KeyboardFocusManager)evt.getSource();
614N/A if (newValue.equals(Boolean.FALSE)) {
0N/A manager.removePropertyChangeListener(_handler);
0N/A }
0N/A else {
0N/A manager.addPropertyChangeListener(_handler);
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * This is a support method that will check if the background colors of
0N/A * the specified component differ between focused and unfocused states.
0N/A * If the color differ the component will then repaint itself.
0N/A *
0N/A * @comp the component to check
0N/A */
0N/A private void repaintIfBackgroundsDiffer(JComponent comp) {
0N/A ComponentUI ui = (ComponentUI)comp.getClientProperty(
0N/A SwingUtilities2.COMPONENT_UI_PROPERTY_KEY);
0N/A if (ui instanceof SynthUI) {
0N/A SynthUI synthUI = (SynthUI)ui;
0N/A SynthContext context = synthUI.getContext(comp);
0N/A SynthStyle style = context.getStyle();
0N/A int state = context.getComponentState();
0N/A
0N/A // Get the current background color.
0N/A Color currBG = style.getColor(context, ColorType.BACKGROUND);
0N/A
0N/A // Get the last background color.
0N/A state ^= SynthConstants.FOCUSED;
0N/A context.setComponentState(state);
0N/A Color lastBG = style.getColor(context, ColorType.BACKGROUND);
0N/A
0N/A // Reset the component state back to original.
0N/A state ^= SynthConstants.FOCUSED;
0N/A context.setComponentState(state);
0N/A
0N/A // Repaint the component if the backgrounds differed.
0N/A if (currBG != null && !currBG.equals(lastBG)) {
0N/A comp.repaint();
0N/A }
0N/A context.dispose();
0N/A }
0N/A }
0N/A }
0N/A}