Save This Page
Home » openjdk-7 » javax » swing » plaf » synth » [javadoc | source]
    1   /*
    2    * Copyright 2002-2006 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   package javax.swing.plaf.synth;
   26   
   27   import java.awt;
   28   import java.beans;
   29   import java.io;
   30   import java.lang.ref;
   31   import java.net;
   32   import java.security;
   33   import java.text;
   34   import java.util;
   35   import javax.swing;
   36   import javax.swing.plaf;
   37   import javax.swing.plaf.basic;
   38   
   39   import sun.awt;
   40   import sun.security.action;
   41   import sun.swing;
   42   import sun.swing.plaf.synth;
   43   
   44   /**
   45    * SynthLookAndFeel provides the basis for creating a customized look and
   46    * feel. SynthLookAndFeel does not directly provide a look, all painting is
   47    * delegated.
   48    * You need to either provide a configuration file, by way of the
   49    * {@link #load} method, or provide your own {@link SynthStyleFactory}
   50    * to {@link #setStyleFactory}. Refer to the
   51    * <a href="package-summary.html">package summary</a> for an example of
   52    * loading a file, and {@link javax.swing.plaf.synth.SynthStyleFactory} for
   53    * an example of providing your own <code>SynthStyleFactory</code> to
   54    * <code>setStyleFactory</code>.
   55    * <p>
   56    * <strong>Warning:</strong>
   57    * This class implements {@link Serializable} as a side effect of it
   58    * extending {@link BasicLookAndFeel}. It is not intended to be serialized.
   59    * An attempt to serialize it will
   60    * result in {@link NotSerializableException}.
   61    *
   62    * @serial exclude
   63    * @since 1.5
   64    * @author Scott Violet
   65    */
   66   public class SynthLookAndFeel extends BasicLookAndFeel {
   67       /**
   68        * Used in a handful of places where we need an empty Insets.
   69        */
   70       static final Insets EMPTY_UIRESOURCE_INSETS = new InsetsUIResource(
   71                                                               0, 0, 0, 0);
   72   
   73       /**
   74        * AppContext key to get the current SynthStyleFactory.
   75        */
   76       private static final Object STYLE_FACTORY_KEY =
   77                     new StringBuffer("com.sun.java.swing.plaf.gtk.StyleCache");
   78   
   79       /**
   80        * The last SynthStyleFactory that was asked for from AppContext
   81        * <code>lastContext</code>.
   82        */
   83       private static SynthStyleFactory lastFactory;
   84       /**
   85        * If this is true it indicates there is more than one AppContext active
   86        * and that we need to make sure in getStyleCache the requesting
   87        * AppContext matches that of <code>lastContext</code> before returning
   88        * it.
   89        */
   90       private static boolean multipleApps;
   91       /**
   92        * AppContext lastLAF came from.
   93        */
   94       private static AppContext lastContext;
   95   
   96       // Refer to setSelectedUI
   97       static ComponentUI selectedUI;
   98       // Refer to setSelectedUI
   99       static int selectedUIState;
  100   
  101       /**
  102        * SynthStyleFactory for the this SynthLookAndFeel.
  103        */
  104       private SynthStyleFactory factory;
  105   
  106       /**
  107        * Map of defaults table entries. This is populated via the load
  108        * method.
  109        */
  110       private Map defaultsMap;
  111   
  112       private Handler _handler;
  113   
  114       /**
  115        * Used by the renderers. For the most part the renderers are implemented
  116        * as Labels, which is problematic in so far as they are never selected.
  117        * To accomodate this SynthLabelUI checks if the current
  118        * UI matches that of <code>selectedUI</code> (which this methods sets), if
  119        * it does, then a state as set by this method is returned. This provides
  120        * a way for labels to have a state other than selected.
  121        */
  122       static void setSelectedUI(ComponentUI uix, boolean selected,
  123                                 boolean focused, boolean enabled,
  124                                 boolean rollover) {
  125           selectedUI = uix;
  126           selectedUIState = 0;
  127           if (selected) {
  128               selectedUIState = SynthConstants.SELECTED;
  129               if (focused) {
  130                   selectedUIState |= SynthConstants.FOCUSED;
  131               }
  132           }
  133           else if (rollover && enabled) {
  134               selectedUIState |=
  135                       SynthConstants.MOUSE_OVER | SynthConstants.ENABLED;
  136               if (focused) {
  137                   selectedUIState |= SynthConstants.FOCUSED;
  138               }
  139           }
  140           else {
  141               selectedUIState = SynthConstants.FOCUSED;
  142               if (enabled) {
  143                   selectedUIState |= SynthConstants.ENABLED;
  144               }
  145               else {
  146                   selectedUIState |= SynthConstants.DISABLED;
  147               }
  148           }
  149       }
  150   
  151       /**
  152        * Clears out the selected UI that was last set in setSelectedUI.
  153        */
  154       static void resetSelectedUI() {
  155           selectedUI = null;
  156       }
  157   
  158   
  159       /**
  160        * Sets the SynthStyleFactory that the UI classes provided by
  161        * synth will use to obtain a SynthStyle.
  162        *
  163        * @param cache SynthStyleFactory the UIs should use.
  164        */
  165       public static void setStyleFactory(SynthStyleFactory cache) {
  166           // We assume the setter is called BEFORE the getter has been invoked
  167           // for a particular AppContext.
  168           synchronized(SynthLookAndFeel.class) {
  169               AppContext context = AppContext.getAppContext();
  170               if (!multipleApps && context != lastContext &&
  171                                    lastContext != null) {
  172                   multipleApps = true;
  173               }
  174               lastFactory = cache;
  175               lastContext = context;
  176               context.put(STYLE_FACTORY_KEY, cache);
  177           }
  178       }
  179   
  180       /**
  181        * Returns the current SynthStyleFactory.
  182        *
  183        * @return SynthStyleFactory
  184        */
  185       public static SynthStyleFactory getStyleFactory() {
  186           synchronized(SynthLookAndFeel.class) {
  187               if (!multipleApps) {
  188                   return lastFactory;
  189               }
  190               AppContext context = AppContext.getAppContext();
  191   
  192               if (lastContext == context) {
  193                   return lastFactory;
  194               }
  195               lastContext = context;
  196               lastFactory = (SynthStyleFactory)AppContext.getAppContext().get
  197                                              (STYLE_FACTORY_KEY);
  198               return lastFactory;
  199           }
  200       }
  201   
  202       /**
  203        * Returns the component state for the specified component. This should
  204        * only be used for Components that don't have any special state beyond
  205        * that of ENABLED, DISABLED or FOCUSED. For example, buttons shouldn't
  206        * call into this method.
  207        */
  208       static int getComponentState(Component c) {
  209           if (c.isEnabled()) {
  210               if (c.isFocusOwner()) {
  211                   return SynthUI.ENABLED | SynthUI.FOCUSED;
  212               }
  213               return SynthUI.ENABLED;
  214           }
  215           return SynthUI.DISABLED;
  216       }
  217   
  218       /**
  219        * Gets a SynthStyle for the specified region of the specified component.
  220        * This is not for general consumption, only custom UIs should call this
  221        * method.
  222        *
  223        * @param c JComponent to get the SynthStyle for
  224        * @param region Identifies the region of the specified component
  225        * @return SynthStyle to use.
  226        */
  227       public static SynthStyle getStyle(JComponent c, Region region) {
  228           return getStyleFactory().getStyle(c, region);
  229       }
  230   
  231       /**
  232        * Returns true if the Style should be updated in response to the
  233        * specified PropertyChangeEvent. This forwards to
  234        * <code>shouldUpdateStyleOnAncestorChanged</code> as necessary.
  235        */
  236       static boolean shouldUpdateStyle(PropertyChangeEvent event) {
  237           String eName = event.getPropertyName();
  238           if ("name" == eName) {
  239               // Always update on a name change
  240               return true;
  241           }
  242           else if ("componentOrientation" == eName) {
  243               // Always update on a component orientation change
  244               return true;
  245           }
  246           else if ("ancestor" == eName && event.getNewValue() != null) {
  247               // Only update on an ancestor change when getting a valid
  248               // parent and the LookAndFeel wants this.
  249               LookAndFeel laf = UIManager.getLookAndFeel();
  250               return (laf instanceof SynthLookAndFeel &&
  251                       ((SynthLookAndFeel)laf).
  252                        shouldUpdateStyleOnAncestorChanged());
  253           }
  254           return false;
  255       }
  256   
  257       /**
  258        * A convience method that will reset the Style of StyleContext if
  259        * necessary.
  260        *
  261        * @return newStyle
  262        */
  263       static SynthStyle updateStyle(SynthContext context, SynthUI ui) {
  264           SynthStyle newStyle = getStyle(context.getComponent(),
  265                                          context.getRegion());
  266           SynthStyle oldStyle = context.getStyle();
  267   
  268           if (newStyle != oldStyle) {
  269               if (oldStyle != null) {
  270                   oldStyle.uninstallDefaults(context);
  271               }
  272               context.setStyle(newStyle);
  273               newStyle.installDefaults(context, ui);
  274           }
  275           return newStyle;
  276       }
  277   
  278       /**
  279        * Updates the style associated with <code>c</code>, and all its children.
  280        * This is a lighter version of
  281        * <code>SwingUtilities.updateComponentTreeUI</code>.
  282        *
  283        * @param c Component to update style for.
  284        */
  285       public static void updateStyles(Component c) {
  286           _updateStyles(c);
  287           c.repaint();
  288       }
  289   
  290       // Implementation for updateStyles
  291       private static void _updateStyles(Component c) {
  292           if (c instanceof JComponent) {
  293               // Yes, this is hacky. A better solution is to get the UI
  294               // and cast, but JComponent doesn't expose a getter for the UI
  295               // (each of the UIs do), making that approach impractical.
  296               String name = c.getName();
  297               c.setName(null);
  298               if (name != null) {
  299                   c.setName(name);
  300               }
  301               ((JComponent)c).revalidate();
  302           }
  303           Component[] children = null;
  304           if (c instanceof JMenu) {
  305               children = ((JMenu)c).getMenuComponents();
  306           }
  307           else if (c instanceof Container) {
  308               children = ((Container)c).getComponents();
  309           }
  310           if (children != null) {
  311               for(int i = 0; i < children.length; i++) {
  312                   updateStyles(children[i]);
  313               }
  314           }
  315       }
  316   
  317       /**
  318        * Returns the Region for the JComponent <code>c</code>.
  319        *
  320        * @param c JComponent to fetch the Region for
  321        * @return Region corresponding to <code>c</code>
  322        */
  323       public static Region getRegion(JComponent c) {
  324           return Region.getRegion(c);
  325       }
  326   
  327       /**
  328        * A convenience method to return where the foreground should be
  329        * painted for the Component identified by the passed in
  330        * AbstractSynthContext.
  331        */
  332       static Insets getPaintingInsets(SynthContext state, Insets insets) {
  333           if (state.isSubregion()) {
  334               insets = state.getStyle().getInsets(state, insets);
  335           }
  336           else {
  337               insets = state.getComponent().getInsets(insets);
  338           }
  339           return insets;
  340       }
  341   
  342       /**
  343        * A convenience method that handles painting of the background.
  344        * All SynthUI implementations should override update and invoke
  345        * this method.
  346        */
  347       static void update(SynthContext state, Graphics g) {
  348           paintRegion(state, g, null);
  349       }
  350   
  351       /**
  352        * A convenience method that handles painting of the background for
  353        * subregions. All SynthUI's that have subregions should invoke
  354        * this method, than paint the foreground.
  355        */
  356       static void updateSubregion(SynthContext state, Graphics g,
  357                                   Rectangle bounds) {
  358           paintRegion(state, g, bounds);
  359       }
  360   
  361       private static void paintRegion(SynthContext state, Graphics g,
  362                                       Rectangle bounds) {
  363           JComponent c = state.getComponent();
  364           SynthStyle style = state.getStyle();
  365           int x, y, width, height;
  366   
  367           if (bounds == null) {
  368               x = 0;
  369               y = 0;
  370               width = c.getWidth();
  371               height = c.getHeight();
  372           }
  373           else {
  374               x = bounds.x;
  375               y = bounds.y;
  376               width = bounds.width;
  377               height = bounds.height;
  378           }
  379   
  380           // Fill in the background, if necessary.
  381           boolean subregion = state.isSubregion();
  382           if ((subregion && style.isOpaque(state)) ||
  383                             (!subregion && c.isOpaque())) {
  384               g.setColor(style.getColor(state, ColorType.BACKGROUND));
  385               g.fillRect(x, y, width, height);
  386           }
  387       }
  388   
  389       static boolean isLeftToRight(Component c) {
  390           return c.getComponentOrientation().isLeftToRight();
  391       }
  392   
  393       /**
  394        * Returns the ui that is of type <code>klass</code>, or null if
  395        * one can not be found.
  396        */
  397       static Object getUIOfType(ComponentUI ui, Class klass) {
  398           if (klass.isInstance(ui)) {
  399               return ui;
  400           }
  401           return null;
  402       }
  403   
  404       /**
  405        * Creates the Synth look and feel <code>ComponentUI</code> for
  406        * the passed in <code>JComponent</code>.
  407        *
  408        * @param c JComponent to create the <code>ComponentUI</code> for
  409        * @return ComponentUI to use for <code>c</code>
  410        */
  411       public static ComponentUI createUI(JComponent c) {
  412           String key = c.getUIClassID().intern();
  413   
  414           if (key == "ButtonUI") {
  415               return SynthButtonUI.createUI(c);
  416           }
  417           else if (key == "CheckBoxUI") {
  418               return SynthCheckBoxUI.createUI(c);
  419           }
  420           else if (key == "CheckBoxMenuItemUI") {
  421               return SynthCheckBoxMenuItemUI.createUI(c);
  422           }
  423           else if (key == "ColorChooserUI") {
  424               return SynthColorChooserUI.createUI(c);
  425           }
  426           else if (key == "ComboBoxUI") {
  427               return SynthComboBoxUI.createUI(c);
  428           }
  429           else if (key == "DesktopPaneUI") {
  430               return SynthDesktopPaneUI.createUI(c);
  431           }
  432           else if (key == "DesktopIconUI") {
  433               return SynthDesktopIconUI.createUI(c);
  434           }
  435           else if (key == "EditorPaneUI") {
  436               return SynthEditorPaneUI.createUI(c);
  437           }
  438           else if (key == "FileChooserUI") {
  439               return SynthFileChooserUI.createUI(c);
  440           }
  441           else if (key == "FormattedTextFieldUI") {
  442               return SynthFormattedTextFieldUI.createUI(c);
  443           }
  444           else if (key == "InternalFrameUI") {
  445               return SynthInternalFrameUI.createUI(c);
  446           }
  447           else if (key == "LabelUI") {
  448               return SynthLabelUI.createUI(c);
  449           }
  450           else if (key == "ListUI") {
  451               return SynthListUI.createUI(c);
  452           }
  453           else if (key == "MenuBarUI") {
  454               return SynthMenuBarUI.createUI(c);
  455           }
  456           else if (key == "MenuUI") {
  457               return SynthMenuUI.createUI(c);
  458           }
  459           else if (key == "MenuItemUI") {
  460               return SynthMenuItemUI.createUI(c);
  461           }
  462           else if (key == "OptionPaneUI") {
  463               return SynthOptionPaneUI.createUI(c);
  464           }
  465           else if (key == "PanelUI") {
  466               return SynthPanelUI.createUI(c);
  467           }
  468           else if (key == "PasswordFieldUI") {
  469               return SynthPasswordFieldUI.createUI(c);
  470           }
  471           else if (key == "PopupMenuSeparatorUI") {
  472               return SynthSeparatorUI.createUI(c);
  473           }
  474           else if (key == "PopupMenuUI") {
  475               return SynthPopupMenuUI.createUI(c);
  476           }
  477           else if (key == "ProgressBarUI") {
  478               return SynthProgressBarUI.createUI(c);
  479           }
  480           else if (key == "RadioButtonUI") {
  481               return SynthRadioButtonUI.createUI(c);
  482           }
  483           else if (key == "RadioButtonMenuItemUI") {
  484               return SynthRadioButtonMenuItemUI.createUI(c);
  485           }
  486           else if (key == "RootPaneUI") {
  487               return SynthRootPaneUI.createUI(c);
  488           }
  489           else if (key == "ScrollBarUI") {
  490               return SynthScrollBarUI.createUI(c);
  491           }
  492           else if (key == "ScrollPaneUI") {
  493               return SynthScrollPaneUI.createUI(c);
  494           }
  495           else if (key == "SeparatorUI") {
  496               return SynthSeparatorUI.createUI(c);
  497           }
  498           else if (key == "SliderUI") {
  499               return SynthSliderUI.createUI(c);
  500           }
  501           else if (key == "SpinnerUI") {
  502               return SynthSpinnerUI.createUI(c);
  503           }
  504           else if (key == "SplitPaneUI") {
  505               return SynthSplitPaneUI.createUI(c);
  506           }
  507           else if (key == "TabbedPaneUI") {
  508               return SynthTabbedPaneUI.createUI(c);
  509           }
  510           else if (key == "TableUI") {
  511               return SynthTableUI.createUI(c);
  512           }
  513           else if (key == "TableHeaderUI") {
  514               return SynthTableHeaderUI.createUI(c);
  515           }
  516           else if (key == "TextAreaUI") {
  517               return SynthTextAreaUI.createUI(c);
  518           }
  519           else if (key == "TextFieldUI") {
  520               return SynthTextFieldUI.createUI(c);
  521           }
  522           else if (key == "TextPaneUI") {
  523               return SynthTextPaneUI.createUI(c);
  524           }
  525           else if (key == "ToggleButtonUI") {
  526               return SynthToggleButtonUI.createUI(c);
  527           }
  528           else if (key == "ToolBarSeparatorUI") {
  529               return SynthSeparatorUI.createUI(c);
  530           }
  531           else if (key == "ToolBarUI") {
  532               return SynthToolBarUI.createUI(c);
  533           }
  534           else if (key == "ToolTipUI") {
  535               return SynthToolTipUI.createUI(c);
  536           }
  537           else if (key == "TreeUI") {
  538               return SynthTreeUI.createUI(c);
  539           }
  540           else if (key == "ViewportUI") {
  541               return SynthViewportUI.createUI(c);
  542           }
  543           return null;
  544       }
  545   
  546   
  547       /**
  548        * Creates a SynthLookAndFeel.
  549        * <p>
  550        * For the returned <code>SynthLookAndFeel</code> to be useful you need to
  551        * invoke <code>load</code> to specify the set of
  552        * <code>SynthStyle</code>s, or invoke <code>setStyleFactory</code>.
  553        *
  554        * @see #load
  555        * @see #setStyleFactory
  556        */
  557       public SynthLookAndFeel() {
  558           factory = new DefaultSynthStyleFactory();
  559           _handler = new Handler();
  560       }
  561   
  562       /**
  563        * Loads the set of <code>SynthStyle</code>s that will be used by
  564        * this <code>SynthLookAndFeel</code>. <code>resourceBase</code> is
  565        * used to resolve any path based resources, for example an
  566        * <code>Image</code> would be resolved by
  567        * <code>resourceBase.getResource(path)</code>. Refer to
  568        * <a href="doc-files/synthFileFormat.html">Synth File Format</a>
  569        * for more information.
  570        *
  571        * @param input InputStream to load from
  572        * @param resourceBase used to resolve any images or other resources
  573        * @throws ParseException if there is an error in parsing
  574        * @throws IllegalArgumentException if input or resourceBase is <code>null</code>
  575        */
  576       public void load(InputStream input, Class<?> resourceBase) throws
  577                          ParseException {
  578           if (resourceBase == null) {
  579               throw new IllegalArgumentException(
  580                   "You must supply a valid resource base Class");
  581           }
  582   
  583           if (defaultsMap == null) {
  584               defaultsMap = new HashMap();
  585           }
  586   
  587           new SynthParser().parse(input, (DefaultSynthStyleFactory) factory,
  588                                   null, resourceBase, defaultsMap);
  589       }
  590   
  591       /**
  592        * Loads the set of <code>SynthStyle</code>s that will be used by
  593        * this <code>SynthLookAndFeel</code>. Path based resources are resolved
  594        * relatively to the specified <code>URL</code> of the style. For example
  595        * an <code>Image</code> would be resolved by
  596        * <code>new URL(synthFile, path)</code>. Refer to
  597        * <a href="doc-files/synthFileFormat.html">Synth File Format</a> for more
  598        * information.
  599        *
  600        * @param url the <code>URL</code> to load the set of
  601        *     <code>SynthStyle</code> from
  602        * @throws ParseException if there is an error in parsing
  603        * @throws IllegalArgumentException if synthSet is <code>null</code>
  604        * @throws IOException if synthSet cannot be opened as an <code>InputStream</code>
  605        * @since 1.6
  606        */
  607       public void load(URL url) throws ParseException, IOException {
  608           if (url == null) {
  609               throw new IllegalArgumentException(
  610                   "You must supply a valid Synth set URL");
  611           }
  612   
  613           if (defaultsMap == null) {
  614               defaultsMap = new HashMap();
  615           }
  616   
  617           InputStream input = url.openStream();
  618           new SynthParser().parse(input, (DefaultSynthStyleFactory) factory,
  619                                   url, null, defaultsMap);
  620       }
  621   
  622       /**
  623        * Called by UIManager when this look and feel is installed.
  624        */
  625       public void initialize() {
  626           super.initialize();
  627           DefaultLookup.setDefaultLookup(new SynthDefaultLookup());
  628           setStyleFactory(factory);
  629           KeyboardFocusManager.getCurrentKeyboardFocusManager().
  630               addPropertyChangeListener(_handler);
  631       }
  632   
  633       /**
  634        * Called by UIManager when this look and feel is uninstalled.
  635        */
  636       public void uninitialize() {
  637           KeyboardFocusManager.getCurrentKeyboardFocusManager().
  638               removePropertyChangeListener(_handler);
  639           // We should uninstall the StyleFactory here, but unfortunately
  640           // there are a handful of things that retain references to the
  641           // LookAndFeel and expect things to work
  642           super.uninitialize();
  643       }
  644   
  645       /**
  646        * Returns the defaults for this SynthLookAndFeel.
  647        *
  648        * @return Defaults table.
  649        */
  650       public UIDefaults getDefaults() {
  651           UIDefaults table = new UIDefaults(60, 0.75f);
  652   
  653           Region.registerUIs(table);
  654           table.setDefaultLocale(Locale.getDefault());
  655           table.addResourceBundle(
  656                 "com.sun.swing.internal.plaf.basic.resources.basic" );
  657           table.addResourceBundle("com.sun.swing.internal.plaf.synth.resources.synth");
  658   
  659           // SynthTabbedPaneUI supports rollover on tabs, GTK does not
  660           table.put("TabbedPane.isTabRollover", Boolean.TRUE);
  661   
  662           // These need to be defined for JColorChooser to work.
  663           table.put("ColorChooser.swatchesRecentSwatchSize",
  664                     new Dimension(10, 10));
  665           table.put("ColorChooser.swatchesDefaultRecentColor", Color.RED);
  666           table.put("ColorChooser.swatchesSwatchSize", new Dimension(10, 10));
  667   
  668           // These are needed for PopupMenu.
  669           table.put("PopupMenu.selectedWindowInputMapBindings", new Object[] {
  670                     "ESCAPE", "cancel",
  671                       "DOWN", "selectNext",
  672                    "KP_DOWN", "selectNext",
  673                         "UP", "selectPrevious",
  674                      "KP_UP", "selectPrevious",
  675                       "LEFT", "selectParent",
  676                    "KP_LEFT", "selectParent",
  677                      "RIGHT", "selectChild",
  678                   "KP_RIGHT", "selectChild",
  679                      "ENTER", "return",
  680                      "SPACE", "return"
  681           });
  682           table.put("PopupMenu.selectedWindowInputMapBindings.RightToLeft",
  683                     new Object[] {
  684                       "LEFT", "selectChild",
  685                    "KP_LEFT", "selectChild",
  686                      "RIGHT", "selectParent",
  687                   "KP_RIGHT", "selectParent",
  688                     });
  689   
  690           // enabled antialiasing depending on desktop settings
  691           flushUnreferenced();
  692           Object aaTextInfo = getAATextInfo();
  693           table.put(SwingUtilities2.AA_TEXT_PROPERTY_KEY, aaTextInfo);
  694           new AATextListener(this);
  695   
  696           if (defaultsMap != null) {
  697               table.putAll(defaultsMap);
  698           }
  699           return table;
  700       }
  701   
  702       /**
  703        * Returns true, SynthLookAndFeel is always supported.
  704        *
  705        * @return true.
  706        */
  707       public boolean isSupportedLookAndFeel() {
  708           return true;
  709       }
  710   
  711       /**
  712        * Returns false, SynthLookAndFeel is not a native look and feel.
  713        *
  714        * @return false
  715        */
  716       public boolean isNativeLookAndFeel() {
  717           return false;
  718       }
  719   
  720       /**
  721        * Returns a textual description of SynthLookAndFeel.
  722        *
  723        * @return textual description of synth.
  724        */
  725       public String getDescription() {
  726           return "Synth look and feel";
  727       }
  728   
  729       /**
  730        * Return a short string that identifies this look and feel.
  731        *
  732        * @return a short string identifying this look and feel.
  733        */
  734       public String getName() {
  735           return "Synth look and feel";
  736       }
  737   
  738       /**
  739        * Return a string that identifies this look and feel.
  740        *
  741        * @return a short string identifying this look and feel.
  742        */
  743       public String getID() {
  744           return "Synth";
  745       }
  746   
  747       /**
  748        * Returns whether or not the UIs should update their
  749        * <code>SynthStyles</code> from the <code>SynthStyleFactory</code>
  750        * when the ancestor of the <code>JComponent</code> changes. A subclass
  751        * that provided a <code>SynthStyleFactory</code> that based the
  752        * return value from <code>getStyle</code> off the containment hierarchy
  753        * would override this method to return true.
  754        *
  755        * @return whether or not the UIs should update their
  756        * <code>SynthStyles</code> from the <code>SynthStyleFactory</code>
  757        * when the ancestor changed.
  758        */
  759       public boolean shouldUpdateStyleOnAncestorChanged() {
  760           return false;
  761       }
  762   
  763       /**
  764        * Returns the antialiasing information as specified by the host desktop.
  765        * Antialiasing might be forced off if the desktop is GNOME and the user
  766        * has set his locale to Chinese, Japanese or Korean. This is consistent
  767        * with what GTK does. See com.sun.java.swing.plaf.gtk.GtkLookAndFeel
  768        * for more information about CJK and antialiased fonts.
  769        *
  770        * @return the text antialiasing information associated to the desktop
  771        */
  772       private static Object getAATextInfo() {
  773           String language = Locale.getDefault().getLanguage();
  774           String desktop = (String)
  775               AccessController.doPrivileged(new GetPropertyAction("sun.desktop"));
  776   
  777           boolean isCjkLocale = (Locale.CHINESE.getLanguage().equals(language) ||
  778                   Locale.JAPANESE.getLanguage().equals(language) ||
  779                   Locale.KOREAN.getLanguage().equals(language));
  780           boolean isGnome = "gnome".equals(desktop);
  781           boolean isLocal = SwingUtilities2.isLocalDisplay();
  782   
  783           boolean setAA = isLocal && (!isGnome || !isCjkLocale);
  784   
  785           Object aaTextInfo = SwingUtilities2.AATextInfo.getAATextInfo(setAA);
  786           return aaTextInfo;
  787       }
  788   
  789       private static ReferenceQueue queue = new ReferenceQueue();
  790   
  791       private static void flushUnreferenced() {
  792           AATextListener aatl;
  793           while ((aatl = (AATextListener) queue.poll()) != null) {
  794               aatl.dispose();
  795           }
  796       }
  797   
  798       private static class AATextListener
  799           extends WeakReference implements PropertyChangeListener {
  800           private String key = SunToolkit.DESKTOPFONTHINTS;
  801   
  802           AATextListener(LookAndFeel laf) {
  803               super(laf, queue);
  804               Toolkit tk = Toolkit.getDefaultToolkit();
  805               tk.addPropertyChangeListener(key, this);
  806           }
  807   
  808           public void propertyChange(PropertyChangeEvent pce) {
  809               UIDefaults defaults = UIManager.getLookAndFeelDefaults();
  810               if (defaults.getBoolean("Synth.doNotSetTextAA")) {
  811                   dispose();
  812                   return;
  813               }
  814   
  815               LookAndFeel laf = (LookAndFeel) get();
  816               if (laf == null || laf != UIManager.getLookAndFeel()) {
  817                   dispose();
  818                   return;
  819               }
  820   
  821               Object aaTextInfo = getAATextInfo();
  822               defaults.put(SwingUtilities2.AA_TEXT_PROPERTY_KEY, aaTextInfo);
  823   
  824               updateUI();
  825           }
  826   
  827           void dispose() {
  828               Toolkit tk = Toolkit.getDefaultToolkit();
  829               tk.removePropertyChangeListener(key, this);
  830           }
  831   
  832           /**
  833            * Updates the UI of the passed in window and all its children.
  834            */
  835           private static void updateWindowUI(Window window) {
  836               updateStyles(window);
  837               Window ownedWins[] = window.getOwnedWindows();
  838               for (int i = 0; i < ownedWins.length; i++) {
  839                   updateWindowUI(ownedWins[i]);
  840               }
  841           }
  842   
  843           /**
  844            * Updates the UIs of all the known Frames.
  845            */
  846           private static void updateAllUIs() {
  847               Frame appFrames[] = Frame.getFrames();
  848               for (int i = 0; i < appFrames.length; i++) {
  849                   updateWindowUI(appFrames[i]);
  850               }
  851           }
  852   
  853           /**
  854            * Indicates if an updateUI call is pending.
  855            */
  856           private static boolean updatePending;
  857   
  858           /**
  859            * Sets whether or not an updateUI call is pending.
  860            */
  861           private static synchronized void setUpdatePending(boolean update) {
  862               updatePending = update;
  863           }
  864   
  865           /**
  866            * Returns true if a UI update is pending.
  867            */
  868           private static synchronized boolean isUpdatePending() {
  869               return updatePending;
  870           }
  871   
  872           protected void updateUI() {
  873               if (!isUpdatePending()) {
  874                   setUpdatePending(true);
  875                   Runnable uiUpdater = new Runnable() {
  876                       public void run() {
  877                           updateAllUIs();
  878                           setUpdatePending(false);
  879                       }
  880                   };
  881                   SwingUtilities.invokeLater(uiUpdater);
  882               }
  883           }
  884       }
  885   
  886       private void writeObject(java.io.ObjectOutputStream out)
  887               throws IOException {
  888           throw new NotSerializableException(this.getClass().getName());
  889       }
  890   
  891       private class Handler implements PropertyChangeListener {
  892           public void propertyChange(PropertyChangeEvent evt) {
  893               String propertyName = evt.getPropertyName();
  894               Object newValue = evt.getNewValue();
  895               Object oldValue = evt.getOldValue();
  896   
  897               if ("focusOwner" == propertyName) {
  898                   if (oldValue instanceof JComponent) {
  899                       repaintIfBackgroundsDiffer((JComponent)oldValue);
  900   
  901                   }
  902   
  903                   if (newValue instanceof JComponent) {
  904                       repaintIfBackgroundsDiffer((JComponent)newValue);
  905                   }
  906               }
  907               else if ("managingFocus" == propertyName) {
  908                   // De-register listener on old keyboard focus manager and
  909                   // register it on the new one.
  910                   KeyboardFocusManager manager =
  911                       (KeyboardFocusManager)evt.getSource();
  912                   if (((Boolean)newValue).equals(Boolean.FALSE)) {
  913                       manager.removePropertyChangeListener(_handler);
  914                   }
  915                   else {
  916                       manager.addPropertyChangeListener(_handler);
  917                   }
  918               }
  919           }
  920   
  921           /**
  922            * This is a support method that will check if the background colors of
  923            * the specified component differ between focused and unfocused states.
  924            * If the color differ the component will then repaint itself.
  925            *
  926            * @comp the component to check
  927            */
  928           private void repaintIfBackgroundsDiffer(JComponent comp) {
  929               ComponentUI ui = (ComponentUI)comp.getClientProperty(
  930                       SwingUtilities2.COMPONENT_UI_PROPERTY_KEY);
  931               if (ui instanceof SynthUI) {
  932                   SynthUI synthUI = (SynthUI)ui;
  933                   SynthContext context = synthUI.getContext(comp);
  934                   SynthStyle style = context.getStyle();
  935                   int state = context.getComponentState();
  936   
  937                   // Get the current background color.
  938                   Color currBG = style.getColor(context, ColorType.BACKGROUND);
  939   
  940                   // Get the last background color.
  941                   state ^= SynthConstants.FOCUSED;
  942                   context.setComponentState(state);
  943                   Color lastBG = style.getColor(context, ColorType.BACKGROUND);
  944   
  945                   // Reset the component state back to original.
  946                   state ^= SynthConstants.FOCUSED;
  947                   context.setComponentState(state);
  948   
  949                   // Repaint the component if the backgrounds differed.
  950                   if (currBG != null && !currBG.equals(lastBG)) {
  951                       comp.repaint();
  952                   }
  953                   context.dispose();
  954               }
  955           }
  956       }
  957   }

Save This Page
Home » openjdk-7 » javax » swing » plaf » synth » [javadoc | source]