Save This Page
Home » openjdk-7 » javax » swing » plaf » basic » [javadoc | source]
    1   /*
    2    * Copyright 1997-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   
   26   package javax.swing.plaf.basic;
   27   
   28   import sun.swing.SwingUtilities2;
   29   import sun.swing.DefaultLookup;
   30   import sun.swing.UIAction;
   31   import javax.swing;
   32   import javax.swing.plaf;
   33   import javax.swing.text.View;
   34   
   35   import java.awt.event.ActionEvent;
   36   import java.awt.event.ActionListener;
   37   import java.awt.event.KeyEvent;
   38   import java.awt.Component;
   39   import java.awt.Container;
   40   import java.awt.Dimension;
   41   import java.awt.Rectangle;
   42   import java.awt.Insets;
   43   import java.awt.Color;
   44   import java.awt.Graphics;
   45   import java.awt.Font;
   46   import java.awt.FontMetrics;
   47   import java.beans.PropertyChangeEvent;
   48   import java.beans.PropertyChangeListener;
   49   
   50   /**
   51    * A Windows L&F implementation of LabelUI.  This implementation
   52    * is completely static, i.e. there's only one UIView implementation
   53    * that's shared by all JLabel objects.
   54    *
   55    * @author Hans Muller
   56    */
   57   public class BasicLabelUI extends LabelUI implements  PropertyChangeListener
   58   {
   59      /**
   60       * The default <code>BasicLabelUI</code> instance. This field might
   61       * not be used. To change the default instance use a subclass which
   62       * overrides the <code>createUI</code> method, and place that class
   63       * name in defaults table under the key "LabelUI".
   64       */
   65       protected static BasicLabelUI labelUI = new BasicLabelUI();
   66       private final static BasicLabelUI SAFE_BASIC_LABEL_UI = new BasicLabelUI();
   67   
   68       static void loadActionMap(LazyActionMap map) {
   69           map.put(new Actions(Actions.PRESS));
   70           map.put(new Actions(Actions.RELEASE));
   71       }
   72   
   73       /**
   74        * Forwards the call to SwingUtilities.layoutCompoundLabel().
   75        * This method is here so that a subclass could do Label specific
   76        * layout and to shorten the method name a little.
   77        *
   78        * @see SwingUtilities#layoutCompoundLabel
   79        */
   80       protected String layoutCL(
   81           JLabel label,
   82           FontMetrics fontMetrics,
   83           String text,
   84           Icon icon,
   85           Rectangle viewR,
   86           Rectangle iconR,
   87           Rectangle textR)
   88       {
   89           return SwingUtilities.layoutCompoundLabel(
   90               (JComponent) label,
   91               fontMetrics,
   92               text,
   93               icon,
   94               label.getVerticalAlignment(),
   95               label.getHorizontalAlignment(),
   96               label.getVerticalTextPosition(),
   97               label.getHorizontalTextPosition(),
   98               viewR,
   99               iconR,
  100               textR,
  101               label.getIconTextGap());
  102       }
  103   
  104       /**
  105        * Paint clippedText at textX, textY with the labels foreground color.
  106        *
  107        * @see #paint
  108        * @see #paintDisabledText
  109        */
  110       protected void paintEnabledText(JLabel l, Graphics g, String s, int textX, int textY)
  111       {
  112           int mnemIndex = l.getDisplayedMnemonicIndex();
  113           g.setColor(l.getForeground());
  114           SwingUtilities2.drawStringUnderlineCharAt(l, g, s, mnemIndex,
  115                                                        textX, textY);
  116       }
  117   
  118   
  119       /**
  120        * Paint clippedText at textX, textY with background.lighter() and then
  121        * shifted down and to the right by one pixel with background.darker().
  122        *
  123        * @see #paint
  124        * @see #paintEnabledText
  125        */
  126       protected void paintDisabledText(JLabel l, Graphics g, String s, int textX, int textY)
  127       {
  128           int accChar = l.getDisplayedMnemonicIndex();
  129           Color background = l.getBackground();
  130           g.setColor(background.brighter());
  131           SwingUtilities2.drawStringUnderlineCharAt(l, g, s, accChar,
  132                                                      textX + 1, textY + 1);
  133           g.setColor(background.darker());
  134           SwingUtilities2.drawStringUnderlineCharAt(l, g, s, accChar,
  135                                                      textX, textY);
  136       }
  137   
  138   
  139       /* These rectangles/insets are allocated once for this shared LabelUI
  140        * implementation.  Re-using rectangles rather than allocating
  141        * them in each paint call halved the time it took paint to run.
  142        */
  143       private static Rectangle paintIconR = new Rectangle();
  144       private static Rectangle paintTextR = new Rectangle();
  145       private static Rectangle paintViewR = new Rectangle();
  146       private static Insets paintViewInsets = new Insets(0, 0, 0, 0);
  147   
  148   
  149       /**
  150        * Paint the label text in the foreground color, if the label
  151        * is opaque then paint the entire background with the background
  152        * color.  The Label text is drawn by paintEnabledText() or
  153        * paintDisabledText().  The locations of the label parts are computed
  154        * by layoutCL.
  155        *
  156        * @see #paintEnabledText
  157        * @see #paintDisabledText
  158        * @see #layoutCL
  159        */
  160       public void paint(Graphics g, JComponent c)
  161       {
  162           JLabel label = (JLabel)c;
  163           String text = label.getText();
  164           Icon icon = (label.isEnabled()) ? label.getIcon() : label.getDisabledIcon();
  165   
  166           if ((icon == null) && (text == null)) {
  167               return;
  168           }
  169   
  170           FontMetrics fm = SwingUtilities2.getFontMetrics(label, g);
  171           String clippedText = layout(label, fm, c.getWidth(), c.getHeight());
  172   
  173           if (icon != null) {
  174               icon.paintIcon(c, g, paintIconR.x, paintIconR.y);
  175           }
  176   
  177           if (text != null) {
  178               View v = (View) c.getClientProperty(BasicHTML.propertyKey);
  179               if (v != null) {
  180                   v.paint(g, paintTextR);
  181               } else {
  182                   int textX = paintTextR.x;
  183                   int textY = paintTextR.y + fm.getAscent();
  184   
  185                   if (label.isEnabled()) {
  186                       paintEnabledText(label, g, clippedText, textX, textY);
  187                   }
  188                   else {
  189                       paintDisabledText(label, g, clippedText, textX, textY);
  190                   }
  191               }
  192           }
  193       }
  194   
  195       private String layout(JLabel label, FontMetrics fm,
  196                             int width, int height) {
  197           Insets insets = label.getInsets(paintViewInsets);
  198           String text = label.getText();
  199           Icon icon = (label.isEnabled()) ? label.getIcon() :
  200                                             label.getDisabledIcon();
  201           paintViewR.x = insets.left;
  202           paintViewR.y = insets.top;
  203           paintViewR.width = width - (insets.left + insets.right);
  204           paintViewR.height = height - (insets.top + insets.bottom);
  205           paintIconR.x = paintIconR.y = paintIconR.width = paintIconR.height = 0;
  206           paintTextR.x = paintTextR.y = paintTextR.width = paintTextR.height = 0;
  207           return layoutCL(label, fm, text, icon, paintViewR, paintIconR,
  208                           paintTextR);
  209       }
  210   
  211   
  212       /* These rectangles/insets are allocated once for this shared LabelUI
  213        * implementation.  Re-using rectangles rather than allocating
  214        * them in each getPreferredSize call sped up the method substantially.
  215        */
  216       private static Rectangle iconR = new Rectangle();
  217       private static Rectangle textR = new Rectangle();
  218       private static Rectangle viewR = new Rectangle();
  219       private static Insets viewInsets = new Insets(0, 0, 0, 0);
  220   
  221   
  222       public Dimension getPreferredSize(JComponent c)
  223       {
  224           JLabel label = (JLabel)c;
  225           String text = label.getText();
  226           Icon icon = (label.isEnabled()) ? label.getIcon() :
  227                                             label.getDisabledIcon();
  228           Insets insets = label.getInsets(viewInsets);
  229           Font font = label.getFont();
  230   
  231           int dx = insets.left + insets.right;
  232           int dy = insets.top + insets.bottom;
  233   
  234           if ((icon == null) &&
  235               ((text == null) ||
  236                ((text != null) && (font == null)))) {
  237               return new Dimension(dx, dy);
  238           }
  239           else if ((text == null) || ((icon != null) && (font == null))) {
  240               return new Dimension(icon.getIconWidth() + dx,
  241                                    icon.getIconHeight() + dy);
  242           }
  243           else {
  244               FontMetrics fm = label.getFontMetrics(font);
  245   
  246               iconR.x = iconR.y = iconR.width = iconR.height = 0;
  247               textR.x = textR.y = textR.width = textR.height = 0;
  248               viewR.x = dx;
  249               viewR.y = dy;
  250               viewR.width = viewR.height = Short.MAX_VALUE;
  251   
  252               layoutCL(label, fm, text, icon, viewR, iconR, textR);
  253               int x1 = Math.min(iconR.x, textR.x);
  254               int x2 = Math.max(iconR.x + iconR.width, textR.x + textR.width);
  255               int y1 = Math.min(iconR.y, textR.y);
  256               int y2 = Math.max(iconR.y + iconR.height, textR.y + textR.height);
  257               Dimension rv = new Dimension(x2 - x1, y2 - y1);
  258   
  259               rv.width += dx;
  260               rv.height += dy;
  261               return rv;
  262           }
  263       }
  264   
  265   
  266       /**
  267        * @return getPreferredSize(c)
  268        */
  269       public Dimension getMinimumSize(JComponent c) {
  270           Dimension d = getPreferredSize(c);
  271           View v = (View) c.getClientProperty(BasicHTML.propertyKey);
  272           if (v != null) {
  273               d.width -= v.getPreferredSpan(View.X_AXIS) - v.getMinimumSpan(View.X_AXIS);
  274           }
  275           return d;
  276       }
  277   
  278       /**
  279        * @return getPreferredSize(c)
  280        */
  281       public Dimension getMaximumSize(JComponent c) {
  282           Dimension d = getPreferredSize(c);
  283           View v = (View) c.getClientProperty(BasicHTML.propertyKey);
  284           if (v != null) {
  285               d.width += v.getMaximumSpan(View.X_AXIS) - v.getPreferredSpan(View.X_AXIS);
  286           }
  287           return d;
  288       }
  289   
  290       /**
  291        * Returns the baseline.
  292        *
  293        * @throws NullPointerException {@inheritDoc}
  294        * @throws IllegalArgumentException {@inheritDoc}
  295        * @see javax.swing.JComponent#getBaseline(int, int)
  296        * @since 1.6
  297        */
  298       public int getBaseline(JComponent c, int width, int height) {
  299           super.getBaseline(c, width, height);
  300           JLabel label = (JLabel)c;
  301           String text = label.getText();
  302           if (text == null || "".equals(text) || label.getFont() == null) {
  303               return -1;
  304           }
  305           FontMetrics fm = label.getFontMetrics(label.getFont());
  306           layout(label, fm, width, height);
  307           return BasicHTML.getBaseline(label, paintTextR.y, fm.getAscent(),
  308                                        paintTextR.width, paintTextR.height);
  309       }
  310   
  311       /**
  312        * Returns an enum indicating how the baseline of the component
  313        * changes as the size changes.
  314        *
  315        * @throws NullPointerException {@inheritDoc}
  316        * @see javax.swing.JComponent#getBaseline(int, int)
  317        * @since 1.6
  318        */
  319       public Component.BaselineResizeBehavior getBaselineResizeBehavior(
  320               JComponent c) {
  321           super.getBaselineResizeBehavior(c);
  322           if (c.getClientProperty(BasicHTML.propertyKey) != null) {
  323               return Component.BaselineResizeBehavior.OTHER;
  324           }
  325           switch(((JLabel)c).getVerticalAlignment()) {
  326           case JLabel.TOP:
  327               return Component.BaselineResizeBehavior.CONSTANT_ASCENT;
  328           case JLabel.BOTTOM:
  329               return Component.BaselineResizeBehavior.CONSTANT_DESCENT;
  330           case JLabel.CENTER:
  331               return Component.BaselineResizeBehavior.CENTER_OFFSET;
  332           }
  333           return Component.BaselineResizeBehavior.OTHER;
  334       }
  335   
  336   
  337       public void installUI(JComponent c) {
  338           installDefaults((JLabel)c);
  339           installComponents((JLabel)c);
  340           installListeners((JLabel)c);
  341           installKeyboardActions((JLabel)c);
  342       }
  343   
  344   
  345       public void uninstallUI(JComponent c) {
  346           uninstallDefaults((JLabel)c);
  347           uninstallComponents((JLabel)c);
  348           uninstallListeners((JLabel)c);
  349           uninstallKeyboardActions((JLabel)c);
  350       }
  351   
  352        protected void installDefaults(JLabel c){
  353            LookAndFeel.installColorsAndFont(c, "Label.background", "Label.foreground", "Label.font");
  354            LookAndFeel.installProperty(c, "opaque", Boolean.FALSE);
  355         }
  356   
  357       protected void installListeners(JLabel c){
  358           c.addPropertyChangeListener(this);
  359       }
  360   
  361       protected void installComponents(JLabel c){
  362           BasicHTML.updateRenderer(c, c.getText());
  363           c.setInheritsPopupMenu(true);
  364       }
  365   
  366       protected void installKeyboardActions(JLabel l) {
  367           int dka = l.getDisplayedMnemonic();
  368           Component lf = l.getLabelFor();
  369           if ((dka != 0) && (lf != null)) {
  370               LazyActionMap.installLazyActionMap(l, BasicLabelUI.class,
  371                                                  "Label.actionMap");
  372               InputMap inputMap = SwingUtilities.getUIInputMap
  373                               (l, JComponent.WHEN_IN_FOCUSED_WINDOW);
  374               if (inputMap == null) {
  375                   inputMap = new ComponentInputMapUIResource(l);
  376                   SwingUtilities.replaceUIInputMap(l,
  377                                   JComponent.WHEN_IN_FOCUSED_WINDOW, inputMap);
  378               }
  379               inputMap.clear();
  380               inputMap.put(KeyStroke.getKeyStroke(dka, ActionEvent.ALT_MASK,
  381                                                 false), "press");
  382           }
  383           else {
  384               InputMap inputMap = SwingUtilities.getUIInputMap
  385                               (l, JComponent.WHEN_IN_FOCUSED_WINDOW);
  386               if (inputMap != null) {
  387                   inputMap.clear();
  388               }
  389           }
  390       }
  391   
  392       protected void uninstallDefaults(JLabel c){
  393       }
  394   
  395       protected void uninstallListeners(JLabel c){
  396           c.removePropertyChangeListener(this);
  397       }
  398   
  399       protected void uninstallComponents(JLabel c){
  400           BasicHTML.updateRenderer(c, "");
  401       }
  402   
  403       protected void uninstallKeyboardActions(JLabel c) {
  404           SwingUtilities.replaceUIInputMap(c, JComponent.WHEN_FOCUSED, null);
  405           SwingUtilities.replaceUIInputMap(c, JComponent.WHEN_IN_FOCUSED_WINDOW,
  406                                          null);
  407           SwingUtilities.replaceUIActionMap(c, null);
  408       }
  409   
  410       public static ComponentUI createUI(JComponent c) {
  411           if (System.getSecurityManager() != null) {
  412               return SAFE_BASIC_LABEL_UI;
  413           } else {
  414               return labelUI;
  415           }
  416       }
  417   
  418       public void propertyChange(PropertyChangeEvent e) {
  419           String name = e.getPropertyName();
  420           if (name == "text" || "font" == name || "foreground" == name) {
  421               // remove the old html view client property if one
  422               // existed, and install a new one if the text installed
  423               // into the JLabel is html source.
  424               JLabel lbl = ((JLabel) e.getSource());
  425               String text = lbl.getText();
  426               BasicHTML.updateRenderer(lbl, text);
  427           }
  428           else if (name == "labelFor" || name == "displayedMnemonic") {
  429               installKeyboardActions((JLabel) e.getSource());
  430           }
  431       }
  432   
  433       // When the accelerator is pressed, temporarily make the JLabel
  434       // focusTraversable by registering a WHEN_FOCUSED action for the
  435       // release of the accelerator.  Then give it focus so it can
  436       // prevent unwanted keyTyped events from getting to other components.
  437       private static class Actions extends UIAction {
  438           private static final String PRESS = "press";
  439           private static final String RELEASE = "release";
  440   
  441           Actions(String key) {
  442               super(key);
  443           }
  444   
  445           public void actionPerformed(ActionEvent e) {
  446               JLabel label = (JLabel)e.getSource();
  447               String key = getName();
  448               if (key == PRESS) {
  449                   doPress(label);
  450               }
  451               else if (key == RELEASE) {
  452                   doRelease(label);
  453               }
  454           }
  455   
  456           private void doPress(JLabel label) {
  457               Component labelFor = label.getLabelFor();
  458               if (labelFor != null && labelFor.isEnabled()) {
  459                   InputMap inputMap = SwingUtilities.getUIInputMap(label, JComponent.WHEN_FOCUSED);
  460                   if (inputMap == null) {
  461                       inputMap = new InputMapUIResource();
  462                       SwingUtilities.replaceUIInputMap(label, JComponent.WHEN_FOCUSED, inputMap);
  463                   }
  464                   int dka = label.getDisplayedMnemonic();
  465                   inputMap.put(KeyStroke.getKeyStroke(dka, ActionEvent.ALT_MASK, true), RELEASE);
  466                   // Need this if ALT is released before the accelerator
  467                   inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ALT, 0, true), RELEASE);
  468                   label.requestFocus();
  469               }
  470           }
  471   
  472           private void doRelease(JLabel label) {
  473               Component labelFor = label.getLabelFor();
  474               if (labelFor != null && labelFor.isEnabled()) {
  475                   InputMap inputMap = SwingUtilities.getUIInputMap(label, JComponent.WHEN_FOCUSED);
  476                   if (inputMap != null) {
  477                       // inputMap should never be null.
  478                       inputMap.remove(KeyStroke.getKeyStroke(label.getDisplayedMnemonic(), ActionEvent.ALT_MASK, true));
  479                       inputMap.remove(KeyStroke.getKeyStroke(KeyEvent.VK_ALT, 0, true));
  480                   }
  481                   if (labelFor instanceof Container &&
  482                           ((Container) labelFor).isFocusCycleRoot()) {
  483                       labelFor.requestFocus();
  484                   } else {
  485                       SwingUtilities2.compositeRequestFocus(labelFor);
  486                   }
  487               }
  488           }
  489       }
  490   }

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