jdk/src/share/classes/javax/swing/JLabel.java
changeset 2 90ce3da70b43
child 466 6acd5ec503a8
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     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;
       
    27 
       
    28 import java.awt.Component;
       
    29 import java.awt.Font;
       
    30 import java.awt.Image;
       
    31 import java.awt.*;
       
    32 import java.text.*;
       
    33 import java.awt.geom.*;
       
    34 
       
    35 import java.io.ObjectOutputStream;
       
    36 import java.io.ObjectInputStream;
       
    37 import java.io.IOException;
       
    38 
       
    39 import javax.swing.plaf.LabelUI;
       
    40 import javax.accessibility.*;
       
    41 import javax.swing.text.*;
       
    42 import javax.swing.text.html.*;
       
    43 import javax.swing.plaf.basic.*;
       
    44 import java.util.*;
       
    45 
       
    46 
       
    47 /**
       
    48  * A display area for a short text string or an image,
       
    49  * or both.
       
    50  * A label does not react to input events.
       
    51  * As a result, it cannot get the keyboard focus.
       
    52  * A label can, however, display a keyboard alternative
       
    53  * as a convenience for a nearby component
       
    54  * that has a keyboard alternative but can't display it.
       
    55  * <p>
       
    56  * A <code>JLabel</code> object can display
       
    57  * either text, an image, or both.
       
    58  * You can specify where in the label's display area
       
    59  * the label's contents are aligned
       
    60  * by setting the vertical and horizontal alignment.
       
    61  * By default, labels are vertically centered
       
    62  * in their display area.
       
    63  * Text-only labels are leading edge aligned, by default;
       
    64  * image-only labels are horizontally centered, by default.
       
    65  * <p>
       
    66  * You can also specify the position of the text
       
    67  * relative to the image.
       
    68  * By default, text is on the trailing edge of the image,
       
    69  * with the text and image vertically aligned.
       
    70  * <p>
       
    71  * A label's leading and trailing edge are determined from the value of its
       
    72  * {@link java.awt.ComponentOrientation} property.  At present, the default
       
    73  * ComponentOrientation setting maps the leading edge to left and the trailing
       
    74  * edge to right.
       
    75  *
       
    76  * <p>
       
    77  * Finally, you can use the <code>setIconTextGap</code> method
       
    78  * to specify how many pixels
       
    79  * should appear between the text and the image.
       
    80  * The default is 4 pixels.
       
    81  * <p>
       
    82  * See <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/label.html">How to Use Labels</a>
       
    83  * in <em>The Java Tutorial</em>
       
    84  * for further documentation.
       
    85  * <p>
       
    86  * <strong>Warning:</strong> Swing is not thread safe. For more
       
    87  * information see <a
       
    88  * href="package-summary.html#threading">Swing's Threading
       
    89  * Policy</a>.
       
    90  * <p>
       
    91  * <strong>Warning:</strong>
       
    92  * Serialized objects of this class will not be compatible with
       
    93  * future Swing releases. The current serialization support is
       
    94  * appropriate for short term storage or RMI between applications running
       
    95  * the same version of Swing.  As of 1.4, support for long term storage
       
    96  * of all JavaBeans<sup><font size="-2">TM</font></sup>
       
    97  * has been added to the <code>java.beans</code> package.
       
    98  * Please see {@link java.beans.XMLEncoder}.
       
    99  *
       
   100  * @beaninfo
       
   101  *   attribute: isContainer false
       
   102  * description: A component that displays a short string and an icon.
       
   103  *
       
   104  * @author Hans Muller
       
   105  */
       
   106 public class JLabel extends JComponent implements SwingConstants, Accessible
       
   107 {
       
   108     /**
       
   109      * @see #getUIClassID
       
   110      * @see #readObject
       
   111      */
       
   112     private static final String uiClassID = "LabelUI";
       
   113 
       
   114     private int mnemonic = '\0';
       
   115     private int mnemonicIndex = -1;
       
   116 
       
   117     private String text = "";         // "" rather than null, for BeanBox
       
   118     private Icon defaultIcon = null;
       
   119     private Icon disabledIcon = null;
       
   120     private boolean disabledIconSet = false;
       
   121 
       
   122     private int verticalAlignment = CENTER;
       
   123     private int horizontalAlignment = LEADING;
       
   124     private int verticalTextPosition = CENTER;
       
   125     private int horizontalTextPosition = TRAILING;
       
   126     private int iconTextGap = 4;
       
   127 
       
   128     protected Component labelFor = null;
       
   129 
       
   130     /**
       
   131      * Client property key used to determine what label is labeling the
       
   132      * component.  This is generally not used by labels, but is instead
       
   133      * used by components such as text areas that are being labeled by
       
   134      * labels.  When the labelFor property of a label is set, it will
       
   135      * automatically set the LABELED_BY_PROPERTY of the component being
       
   136      * labelled.
       
   137      *
       
   138      * @see #setLabelFor
       
   139      */
       
   140     static final String LABELED_BY_PROPERTY = "labeledBy";
       
   141 
       
   142     /**
       
   143      * Creates a <code>JLabel</code> instance with the specified
       
   144      * text, image, and horizontal alignment.
       
   145      * The label is centered vertically in its display area.
       
   146      * The text is on the trailing edge of the image.
       
   147      *
       
   148      * @param text  The text to be displayed by the label.
       
   149      * @param icon  The image to be displayed by the label.
       
   150      * @param horizontalAlignment  One of the following constants
       
   151      *           defined in <code>SwingConstants</code>:
       
   152      *           <code>LEFT</code>,
       
   153      *           <code>CENTER</code>,
       
   154      *           <code>RIGHT</code>,
       
   155      *           <code>LEADING</code> or
       
   156      *           <code>TRAILING</code>.
       
   157      */
       
   158     public JLabel(String text, Icon icon, int horizontalAlignment) {
       
   159         setText(text);
       
   160         setIcon(icon);
       
   161         setHorizontalAlignment(horizontalAlignment);
       
   162         updateUI();
       
   163         setAlignmentX(LEFT_ALIGNMENT);
       
   164     }
       
   165 
       
   166     /**
       
   167      * Creates a <code>JLabel</code> instance with the specified
       
   168      * text and horizontal alignment.
       
   169      * The label is centered vertically in its display area.
       
   170      *
       
   171      * @param text  The text to be displayed by the label.
       
   172      * @param horizontalAlignment  One of the following constants
       
   173      *           defined in <code>SwingConstants</code>:
       
   174      *           <code>LEFT</code>,
       
   175      *           <code>CENTER</code>,
       
   176      *           <code>RIGHT</code>,
       
   177      *           <code>LEADING</code> or
       
   178      *           <code>TRAILING</code>.
       
   179      */
       
   180     public JLabel(String text, int horizontalAlignment) {
       
   181         this(text, null, horizontalAlignment);
       
   182     }
       
   183 
       
   184     /**
       
   185      * Creates a <code>JLabel</code> instance with the specified text.
       
   186      * The label is aligned against the leading edge of its display area,
       
   187      * and centered vertically.
       
   188      *
       
   189      * @param text  The text to be displayed by the label.
       
   190      */
       
   191     public JLabel(String text) {
       
   192         this(text, null, LEADING);
       
   193     }
       
   194 
       
   195     /**
       
   196      * Creates a <code>JLabel</code> instance with the specified
       
   197      * image and horizontal alignment.
       
   198      * The label is centered vertically in its display area.
       
   199      *
       
   200      * @param image  The image to be displayed by the label.
       
   201      * @param horizontalAlignment  One of the following constants
       
   202      *           defined in <code>SwingConstants</code>:
       
   203      *           <code>LEFT</code>,
       
   204      *           <code>CENTER</code>,
       
   205      *           <code>RIGHT</code>,
       
   206      *           <code>LEADING</code> or
       
   207      *           <code>TRAILING</code>.
       
   208      */
       
   209     public JLabel(Icon image, int horizontalAlignment) {
       
   210         this(null, image, horizontalAlignment);
       
   211     }
       
   212 
       
   213     /**
       
   214      * Creates a <code>JLabel</code> instance with the specified image.
       
   215      * The label is centered vertically and horizontally
       
   216      * in its display area.
       
   217      *
       
   218      * @param image  The image to be displayed by the label.
       
   219      */
       
   220     public JLabel(Icon image) {
       
   221         this(null, image, CENTER);
       
   222     }
       
   223 
       
   224     /**
       
   225      * Creates a <code>JLabel</code> instance with
       
   226      * no image and with an empty string for the title.
       
   227      * The label is centered vertically
       
   228      * in its display area.
       
   229      * The label's contents, once set, will be displayed on the leading edge
       
   230      * of the label's display area.
       
   231      */
       
   232     public JLabel() {
       
   233         this("", null, LEADING);
       
   234     }
       
   235 
       
   236 
       
   237     /**
       
   238      * Returns the L&F object that renders this component.
       
   239      *
       
   240      * @return LabelUI object
       
   241      */
       
   242     public LabelUI getUI() {
       
   243         return (LabelUI)ui;
       
   244     }
       
   245 
       
   246 
       
   247     /**
       
   248      * Sets the L&F object that renders this component.
       
   249      *
       
   250      * @param ui  the LabelUI L&F object
       
   251      * @see UIDefaults#getUI
       
   252      * @beaninfo
       
   253      *        bound: true
       
   254      *       hidden: true
       
   255      *    attribute: visualUpdate true
       
   256      *  description: The UI object that implements the Component's LookAndFeel.
       
   257      */
       
   258     public void setUI(LabelUI ui) {
       
   259         super.setUI(ui);
       
   260         // disabled icon is generated by LF so it should be unset here
       
   261         if (!disabledIconSet && disabledIcon != null) {
       
   262             setDisabledIcon(null);
       
   263         }
       
   264     }
       
   265 
       
   266 
       
   267     /**
       
   268      * Resets the UI property to a value from the current look and feel.
       
   269      *
       
   270      * @see JComponent#updateUI
       
   271      */
       
   272     public void updateUI() {
       
   273         setUI((LabelUI)UIManager.getUI(this));
       
   274     }
       
   275 
       
   276 
       
   277     /**
       
   278      * Returns a string that specifies the name of the l&f class
       
   279      * that renders this component.
       
   280      *
       
   281      * @return String "LabelUI"
       
   282      *
       
   283      * @see JComponent#getUIClassID
       
   284      * @see UIDefaults#getUI
       
   285      */
       
   286     public String getUIClassID() {
       
   287         return uiClassID;
       
   288     }
       
   289 
       
   290 
       
   291     /**
       
   292      * Returns the text string that the label displays.
       
   293      *
       
   294      * @return a String
       
   295      * @see #setText
       
   296      */
       
   297     public String getText() {
       
   298         return text;
       
   299     }
       
   300 
       
   301 
       
   302     /**
       
   303      * Defines the single line of text this component will display.  If
       
   304      * the value of text is null or empty string, nothing is displayed.
       
   305      * <p>
       
   306      * The default value of this property is null.
       
   307      * <p>
       
   308      * This is a JavaBeans bound property.
       
   309      *
       
   310      * @see #setVerticalTextPosition
       
   311      * @see #setHorizontalTextPosition
       
   312      * @see #setIcon
       
   313      * @beaninfo
       
   314      *    preferred: true
       
   315      *        bound: true
       
   316      *    attribute: visualUpdate true
       
   317      *  description: Defines the single line of text this component will display.
       
   318      */
       
   319     public void setText(String text) {
       
   320 
       
   321         String oldAccessibleName = null;
       
   322         if (accessibleContext != null) {
       
   323             oldAccessibleName = accessibleContext.getAccessibleName();
       
   324         }
       
   325 
       
   326         String oldValue = this.text;
       
   327         this.text = text;
       
   328         firePropertyChange("text", oldValue, text);
       
   329 
       
   330         setDisplayedMnemonicIndex(
       
   331                       SwingUtilities.findDisplayedMnemonicIndex(
       
   332                                           text, getDisplayedMnemonic()));
       
   333 
       
   334         if ((accessibleContext != null)
       
   335             && (accessibleContext.getAccessibleName() != oldAccessibleName)) {
       
   336                 accessibleContext.firePropertyChange(
       
   337                         AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
       
   338                         oldAccessibleName,
       
   339                         accessibleContext.getAccessibleName());
       
   340         }
       
   341         if (text == null || oldValue == null || !text.equals(oldValue)) {
       
   342             revalidate();
       
   343             repaint();
       
   344         }
       
   345     }
       
   346 
       
   347 
       
   348     /**
       
   349      * Returns the graphic image (glyph, icon) that the label displays.
       
   350      *
       
   351      * @return an Icon
       
   352      * @see #setIcon
       
   353      */
       
   354     public Icon getIcon() {
       
   355         return defaultIcon;
       
   356     }
       
   357 
       
   358     /**
       
   359      * Defines the icon this component will display.  If
       
   360      * the value of icon is null, nothing is displayed.
       
   361      * <p>
       
   362      * The default value of this property is null.
       
   363      * <p>
       
   364      * This is a JavaBeans bound property.
       
   365      *
       
   366      * @see #setVerticalTextPosition
       
   367      * @see #setHorizontalTextPosition
       
   368      * @see #getIcon
       
   369      * @beaninfo
       
   370      *    preferred: true
       
   371      *        bound: true
       
   372      *    attribute: visualUpdate true
       
   373      *  description: The icon this component will display.
       
   374      */
       
   375     public void setIcon(Icon icon) {
       
   376         Icon oldValue = defaultIcon;
       
   377         defaultIcon = icon;
       
   378 
       
   379         /* If the default icon has really changed and we had
       
   380          * generated the disabled icon for this component
       
   381          * (in other words, setDisabledIcon() was never called), then
       
   382          * clear the disabledIcon field.
       
   383          */
       
   384         if ((defaultIcon != oldValue) && !disabledIconSet) {
       
   385             disabledIcon = null;
       
   386         }
       
   387 
       
   388         firePropertyChange("icon", oldValue, defaultIcon);
       
   389 
       
   390         if ((accessibleContext != null) && (oldValue != defaultIcon)) {
       
   391                 accessibleContext.firePropertyChange(
       
   392                         AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
       
   393                         oldValue, defaultIcon);
       
   394         }
       
   395 
       
   396         /* If the default icon has changed and the new one is
       
   397          * a different size, then revalidate.   Repaint if the
       
   398          * default icon has changed.
       
   399          */
       
   400         if (defaultIcon != oldValue) {
       
   401             if ((defaultIcon == null) ||
       
   402                 (oldValue == null) ||
       
   403                 (defaultIcon.getIconWidth() != oldValue.getIconWidth()) ||
       
   404                 (defaultIcon.getIconHeight() != oldValue.getIconHeight())) {
       
   405                 revalidate();
       
   406             }
       
   407             repaint();
       
   408         }
       
   409     }
       
   410 
       
   411 
       
   412     /**
       
   413      * Returns the icon used by the label when it's disabled.
       
   414      * If no disabled icon has been set this will forward the call to
       
   415      * the look and feel to construct an appropriate disabled Icon.
       
   416      * <p>
       
   417      * Some look and feels might not render the disabled Icon, in which
       
   418      * case they will ignore this.
       
   419      *
       
   420      * @return the <code>disabledIcon</code> property
       
   421      * @see #setDisabledIcon
       
   422      * @see javax.swing.LookAndFeel#getDisabledIcon
       
   423      * @see ImageIcon
       
   424      */
       
   425     public Icon getDisabledIcon() {
       
   426         if (!disabledIconSet && disabledIcon == null && defaultIcon != null) {
       
   427             disabledIcon = UIManager.getLookAndFeel().getDisabledIcon(this, defaultIcon);
       
   428             if (disabledIcon != null) {
       
   429                 firePropertyChange("disabledIcon", null, disabledIcon);
       
   430             }
       
   431         }
       
   432         return disabledIcon;
       
   433     }
       
   434 
       
   435 
       
   436     /**
       
   437      * Set the icon to be displayed if this JLabel is "disabled"
       
   438      * (JLabel.setEnabled(false)).
       
   439      * <p>
       
   440      * The default value of this property is null.
       
   441      *
       
   442      * @param disabledIcon the Icon to display when the component is disabled
       
   443      * @see #getDisabledIcon
       
   444      * @see #setEnabled
       
   445      * @beaninfo
       
   446      *        bound: true
       
   447      *    attribute: visualUpdate true
       
   448      *  description: The icon to display if the label is disabled.
       
   449      */
       
   450     public void setDisabledIcon(Icon disabledIcon) {
       
   451         Icon oldValue = this.disabledIcon;
       
   452         this.disabledIcon = disabledIcon;
       
   453         disabledIconSet = (disabledIcon != null);
       
   454         firePropertyChange("disabledIcon", oldValue, disabledIcon);
       
   455         if (disabledIcon != oldValue) {
       
   456             if (disabledIcon == null || oldValue == null ||
       
   457                 disabledIcon.getIconWidth() != oldValue.getIconWidth() ||
       
   458                 disabledIcon.getIconHeight() != oldValue.getIconHeight()) {
       
   459                 revalidate();
       
   460             }
       
   461             if (!isEnabled()) {
       
   462                 repaint();
       
   463             }
       
   464         }
       
   465     }
       
   466 
       
   467 
       
   468     /**
       
   469      * Specify a keycode that indicates a mnemonic key.
       
   470      * This property is used when the label is part of a larger component.
       
   471      * If the labelFor property of the label is not null, the label will
       
   472      * call the requestFocus method of the component specified by the
       
   473      * labelFor property when the mnemonic is activated.
       
   474      *
       
   475      * @see #getLabelFor
       
   476      * @see #setLabelFor
       
   477      * @beaninfo
       
   478      *        bound: true
       
   479      *    attribute: visualUpdate true
       
   480      *  description: The mnemonic keycode.
       
   481      */
       
   482     public void setDisplayedMnemonic(int key) {
       
   483         int oldKey = mnemonic;
       
   484         mnemonic = key;
       
   485         firePropertyChange("displayedMnemonic", oldKey, mnemonic);
       
   486 
       
   487         setDisplayedMnemonicIndex(
       
   488             SwingUtilities.findDisplayedMnemonicIndex(getText(), mnemonic));
       
   489 
       
   490         if (key != oldKey) {
       
   491             revalidate();
       
   492             repaint();
       
   493         }
       
   494     }
       
   495 
       
   496 
       
   497     /**
       
   498      * Specifies the displayedMnemonic as a char value.
       
   499      *
       
   500      * @param aChar  a char specifying the mnemonic to display
       
   501      * @see #setDisplayedMnemonic(int)
       
   502      */
       
   503     public void setDisplayedMnemonic(char aChar) {
       
   504         int vk = (int) aChar;
       
   505         if(vk >= 'a' && vk <='z')
       
   506             vk -= ('a' - 'A');
       
   507         setDisplayedMnemonic(vk);
       
   508     }
       
   509 
       
   510 
       
   511     /**
       
   512      * Return the keycode that indicates a mnemonic key.
       
   513      * This property is used when the label is part of a larger component.
       
   514      * If the labelFor property of the label is not null, the label will
       
   515      * call the requestFocus method of the component specified by the
       
   516      * labelFor property when the mnemonic is activated.
       
   517      *
       
   518      * @return int value for the mnemonic key
       
   519      *
       
   520      * @see #getLabelFor
       
   521      * @see #setLabelFor
       
   522      */
       
   523     public int getDisplayedMnemonic() {
       
   524         return mnemonic;
       
   525     }
       
   526 
       
   527     /**
       
   528      * Provides a hint to the look and feel as to which character in the
       
   529      * text should be decorated to represent the mnemonic. Not all look and
       
   530      * feels may support this. A value of -1 indicates either there is no
       
   531      * mnemonic, the mnemonic character is not contained in the string, or
       
   532      * the developer does not wish the mnemonic to be displayed.
       
   533      * <p>
       
   534      * The value of this is updated as the properties relating to the
       
   535      * mnemonic change (such as the mnemonic itself, the text...).
       
   536      * You should only ever have to call this if
       
   537      * you do not wish the default character to be underlined. For example, if
       
   538      * the text was 'Save As', with a mnemonic of 'a', and you wanted the 'A'
       
   539      * to be decorated, as 'Save <u>A</u>s', you would have to invoke
       
   540      * <code>setDisplayedMnemonicIndex(5)</code> after invoking
       
   541      * <code>setDisplayedMnemonic(KeyEvent.VK_A)</code>.
       
   542      *
       
   543      * @since 1.4
       
   544      * @param index Index into the String to underline
       
   545      * @exception IllegalArgumentException will be thrown if <code>index</code
       
   546      *            is >= length of the text, or < -1
       
   547      *
       
   548      * @beaninfo
       
   549      *        bound: true
       
   550      *    attribute: visualUpdate true
       
   551      *  description: the index into the String to draw the keyboard character
       
   552      *               mnemonic at
       
   553      */
       
   554     public void setDisplayedMnemonicIndex(int index)
       
   555                                              throws IllegalArgumentException {
       
   556         int oldValue = mnemonicIndex;
       
   557         if (index == -1) {
       
   558             mnemonicIndex = -1;
       
   559         } else {
       
   560             String text = getText();
       
   561             int textLength = (text == null) ? 0 : text.length();
       
   562             if (index < -1 || index >= textLength) {  // index out of range
       
   563                 throw new IllegalArgumentException("index == " + index);
       
   564             }
       
   565         }
       
   566         mnemonicIndex = index;
       
   567         firePropertyChange("displayedMnemonicIndex", oldValue, index);
       
   568         if (index != oldValue) {
       
   569             revalidate();
       
   570             repaint();
       
   571         }
       
   572     }
       
   573 
       
   574     /**
       
   575      * Returns the character, as an index, that the look and feel should
       
   576      * provide decoration for as representing the mnemonic character.
       
   577      *
       
   578      * @since 1.4
       
   579      * @return index representing mnemonic character
       
   580      * @see #setDisplayedMnemonicIndex
       
   581      */
       
   582     public int getDisplayedMnemonicIndex() {
       
   583         return mnemonicIndex;
       
   584     }
       
   585 
       
   586     /**
       
   587      * Verify that key is a legal value for the horizontalAlignment properties.
       
   588      *
       
   589      * @param key the property value to check
       
   590      * @param message the IllegalArgumentException detail message
       
   591      * @exception IllegalArgumentException if key isn't LEFT, CENTER, RIGHT,
       
   592      * LEADING or TRAILING.
       
   593      * @see #setHorizontalTextPosition
       
   594      * @see #setHorizontalAlignment
       
   595      */
       
   596     protected int checkHorizontalKey(int key, String message) {
       
   597         if ((key == LEFT) ||
       
   598             (key == CENTER) ||
       
   599             (key == RIGHT) ||
       
   600             (key == LEADING) ||
       
   601             (key == TRAILING)) {
       
   602             return key;
       
   603         }
       
   604         else {
       
   605             throw new IllegalArgumentException(message);
       
   606         }
       
   607     }
       
   608 
       
   609 
       
   610     /**
       
   611      * Verify that key is a legal value for the
       
   612      * verticalAlignment or verticalTextPosition properties.
       
   613      *
       
   614      * @param key the property value to check
       
   615      * @param message the IllegalArgumentException detail message
       
   616      * @exception IllegalArgumentException if key isn't TOP, CENTER, or BOTTOM.
       
   617      * @see #setVerticalAlignment
       
   618      * @see #setVerticalTextPosition
       
   619      */
       
   620     protected int checkVerticalKey(int key, String message) {
       
   621         if ((key == TOP) || (key == CENTER) || (key == BOTTOM)) {
       
   622             return key;
       
   623         }
       
   624         else {
       
   625             throw new IllegalArgumentException(message);
       
   626         }
       
   627     }
       
   628 
       
   629 
       
   630     /**
       
   631      * Returns the amount of space between the text and the icon
       
   632      * displayed in this label.
       
   633      *
       
   634      * @return an int equal to the number of pixels between the text
       
   635      *         and the icon.
       
   636      * @see #setIconTextGap
       
   637      */
       
   638     public int getIconTextGap() {
       
   639         return iconTextGap;
       
   640     }
       
   641 
       
   642 
       
   643     /**
       
   644      * If both the icon and text properties are set, this property
       
   645      * defines the space between them.
       
   646      * <p>
       
   647      * The default value of this property is 4 pixels.
       
   648      * <p>
       
   649      * This is a JavaBeans bound property.
       
   650      *
       
   651      * @see #getIconTextGap
       
   652      * @beaninfo
       
   653      *        bound: true
       
   654      *    attribute: visualUpdate true
       
   655      *  description: If both the icon and text properties are set, this
       
   656      *               property defines the space between them.
       
   657      */
       
   658     public void setIconTextGap(int iconTextGap) {
       
   659         int oldValue = this.iconTextGap;
       
   660         this.iconTextGap = iconTextGap;
       
   661         firePropertyChange("iconTextGap", oldValue, iconTextGap);
       
   662         if (iconTextGap != oldValue) {
       
   663             revalidate();
       
   664             repaint();
       
   665         }
       
   666     }
       
   667 
       
   668 
       
   669 
       
   670     /**
       
   671      * Returns the alignment of the label's contents along the Y axis.
       
   672      *
       
   673      * @return   The value of the verticalAlignment property, one of the
       
   674      *           following constants defined in <code>SwingConstants</code>:
       
   675      *           <code>TOP</code>,
       
   676      *           <code>CENTER</code>, or
       
   677      *           <code>BOTTOM</code>.
       
   678      *
       
   679      * @see SwingConstants
       
   680      * @see #setVerticalAlignment
       
   681      */
       
   682     public int getVerticalAlignment() {
       
   683         return verticalAlignment;
       
   684     }
       
   685 
       
   686 
       
   687     /**
       
   688      * Sets the alignment of the label's contents along the Y axis.
       
   689      * <p>
       
   690      * The default value of this property is CENTER.
       
   691      *
       
   692      * @param alignment One of the following constants
       
   693      *           defined in <code>SwingConstants</code>:
       
   694      *           <code>TOP</code>,
       
   695      *           <code>CENTER</code> (the default), or
       
   696      *           <code>BOTTOM</code>.
       
   697      *
       
   698      * @see SwingConstants
       
   699      * @see #getVerticalAlignment
       
   700      * @beaninfo
       
   701      *        bound: true
       
   702      *         enum: TOP    SwingConstants.TOP
       
   703      *               CENTER SwingConstants.CENTER
       
   704      *               BOTTOM SwingConstants.BOTTOM
       
   705      *    attribute: visualUpdate true
       
   706      *  description: The alignment of the label's contents along the Y axis.
       
   707      */
       
   708     public void setVerticalAlignment(int alignment) {
       
   709         if (alignment == verticalAlignment) return;
       
   710         int oldValue = verticalAlignment;
       
   711         verticalAlignment = checkVerticalKey(alignment, "verticalAlignment");
       
   712         firePropertyChange("verticalAlignment", oldValue, verticalAlignment);
       
   713         repaint();
       
   714     }
       
   715 
       
   716 
       
   717     /**
       
   718      * Returns the alignment of the label's contents along the X axis.
       
   719      *
       
   720      * @return   The value of the horizontalAlignment property, one of the
       
   721      *           following constants defined in <code>SwingConstants</code>:
       
   722      *           <code>LEFT</code>,
       
   723      *           <code>CENTER</code>,
       
   724      *           <code>RIGHT</code>,
       
   725      *           <code>LEADING</code> or
       
   726      *           <code>TRAILING</code>.
       
   727      *
       
   728      * @see #setHorizontalAlignment
       
   729      * @see SwingConstants
       
   730      */
       
   731     public int getHorizontalAlignment() {
       
   732         return horizontalAlignment;
       
   733     }
       
   734 
       
   735     /**
       
   736      * Sets the alignment of the label's contents along the X axis.
       
   737      * <p>
       
   738      * This is a JavaBeans bound property.
       
   739      *
       
   740      * @param alignment  One of the following constants
       
   741      *           defined in <code>SwingConstants</code>:
       
   742      *           <code>LEFT</code>,
       
   743      *           <code>CENTER</code> (the default for image-only labels),
       
   744      *           <code>RIGHT</code>,
       
   745      *           <code>LEADING</code> (the default for text-only labels) or
       
   746      *           <code>TRAILING</code>.
       
   747      *
       
   748      * @see SwingConstants
       
   749      * @see #getHorizontalAlignment
       
   750      * @beaninfo
       
   751      *        bound: true
       
   752      *         enum: LEFT     SwingConstants.LEFT
       
   753      *               CENTER   SwingConstants.CENTER
       
   754      *               RIGHT    SwingConstants.RIGHT
       
   755      *               LEADING  SwingConstants.LEADING
       
   756      *               TRAILING SwingConstants.TRAILING
       
   757      *    attribute: visualUpdate true
       
   758      *  description: The alignment of the label's content along the X axis.
       
   759      */
       
   760     public void setHorizontalAlignment(int alignment) {
       
   761         if (alignment == horizontalAlignment) return;
       
   762         int oldValue = horizontalAlignment;
       
   763         horizontalAlignment = checkHorizontalKey(alignment,
       
   764                                                  "horizontalAlignment");
       
   765         firePropertyChange("horizontalAlignment",
       
   766                            oldValue, horizontalAlignment);
       
   767         repaint();
       
   768     }
       
   769 
       
   770 
       
   771     /**
       
   772      * Returns the vertical position of the label's text,
       
   773      * relative to its image.
       
   774      *
       
   775      * @return   One of the following constants
       
   776      *           defined in <code>SwingConstants</code>:
       
   777      *           <code>TOP</code>,
       
   778      *           <code>CENTER</code>, or
       
   779      *           <code>BOTTOM</code>.
       
   780      *
       
   781      * @see #setVerticalTextPosition
       
   782      * @see SwingConstants
       
   783      */
       
   784     public int getVerticalTextPosition() {
       
   785         return verticalTextPosition;
       
   786     }
       
   787 
       
   788 
       
   789     /**
       
   790      * Sets the vertical position of the label's text,
       
   791      * relative to its image.
       
   792      * <p>
       
   793      * The default value of this property is CENTER.
       
   794      * <p>
       
   795      * This is a JavaBeans bound property.
       
   796      *
       
   797      * @param textPosition  One of the following constants
       
   798      *           defined in <code>SwingConstants</code>:
       
   799      *           <code>TOP</code>,
       
   800      *           <code>CENTER</code> (the default), or
       
   801      *           <code>BOTTOM</code>.
       
   802      *
       
   803      * @see SwingConstants
       
   804      * @see #getVerticalTextPosition
       
   805      * @beaninfo
       
   806      *        bound: true
       
   807      *         enum: TOP    SwingConstants.TOP
       
   808      *               CENTER SwingConstants.CENTER
       
   809      *               BOTTOM SwingConstants.BOTTOM
       
   810      *       expert: true
       
   811      *    attribute: visualUpdate true
       
   812      *  description: The vertical position of the text relative to it's image.
       
   813      */
       
   814     public void setVerticalTextPosition(int textPosition) {
       
   815         if (textPosition == verticalTextPosition) return;
       
   816         int old = verticalTextPosition;
       
   817         verticalTextPosition = checkVerticalKey(textPosition,
       
   818                                                 "verticalTextPosition");
       
   819         firePropertyChange("verticalTextPosition", old, verticalTextPosition);
       
   820         revalidate();
       
   821         repaint();
       
   822     }
       
   823 
       
   824 
       
   825     /**
       
   826      * Returns the horizontal position of the label's text,
       
   827      * relative to its image.
       
   828      *
       
   829      * @return   One of the following constants
       
   830      *           defined in <code>SwingConstants</code>:
       
   831      *           <code>LEFT</code>,
       
   832      *           <code>CENTER</code>,
       
   833      *           <code>RIGHT</code>,
       
   834      *           <code>LEADING</code> or
       
   835      *           <code>TRAILING</code>.
       
   836      *
       
   837      * @see SwingConstants
       
   838      */
       
   839     public int getHorizontalTextPosition() {
       
   840         return horizontalTextPosition;
       
   841     }
       
   842 
       
   843 
       
   844     /**
       
   845      * Sets the horizontal position of the label's text,
       
   846      * relative to its image.
       
   847      *
       
   848      * @param textPosition  One of the following constants
       
   849      *           defined in <code>SwingConstants</code>:
       
   850      *           <code>LEFT</code>,
       
   851      *           <code>CENTER</code>,
       
   852      *           <code>RIGHT</code>,
       
   853      *           <code>LEADING</code>, or
       
   854      *           <code>TRAILING</code> (the default).
       
   855      * @exception IllegalArgumentException
       
   856      *
       
   857      * @see SwingConstants
       
   858      * @beaninfo
       
   859      *       expert: true
       
   860      *        bound: true
       
   861      *         enum: LEFT     SwingConstants.LEFT
       
   862      *               CENTER   SwingConstants.CENTER
       
   863      *               RIGHT    SwingConstants.RIGHT
       
   864      *               LEADING  SwingConstants.LEADING
       
   865      *               TRAILING SwingConstants.TRAILING
       
   866      *    attribute: visualUpdate true
       
   867      *  description: The horizontal position of the label's text,
       
   868      *               relative to its image.
       
   869      */
       
   870     public void setHorizontalTextPosition(int textPosition) {
       
   871         int old = horizontalTextPosition;
       
   872         this.horizontalTextPosition = checkHorizontalKey(textPosition,
       
   873                                                 "horizontalTextPosition");
       
   874         firePropertyChange("horizontalTextPosition",
       
   875                            old, horizontalTextPosition);
       
   876         revalidate();
       
   877         repaint();
       
   878     }
       
   879 
       
   880 
       
   881     /**
       
   882      * This is overridden to return false if the current Icon's Image is
       
   883      * not equal to the passed in Image <code>img</code>.
       
   884      *
       
   885      * @see     java.awt.image.ImageObserver
       
   886      * @see     java.awt.Component#imageUpdate(java.awt.Image, int, int, int, int, int)
       
   887      */
       
   888     public boolean imageUpdate(Image img, int infoflags,
       
   889                                int x, int y, int w, int h) {
       
   890         // Don't use getDisabledIcon, will trigger creation of icon if icon
       
   891         // not set.
       
   892         if (!isShowing() ||
       
   893             !SwingUtilities.doesIconReferenceImage(getIcon(), img) &&
       
   894             !SwingUtilities.doesIconReferenceImage(disabledIcon, img)) {
       
   895 
       
   896             return false;
       
   897         }
       
   898         return super.imageUpdate(img, infoflags, x, y, w, h);
       
   899     }
       
   900 
       
   901 
       
   902     /**
       
   903      * See readObject() and writeObject() in JComponent for more
       
   904      * information about serialization in Swing.
       
   905      */
       
   906     private void writeObject(ObjectOutputStream s) throws IOException {
       
   907         s.defaultWriteObject();
       
   908         if (getUIClassID().equals(uiClassID)) {
       
   909             byte count = JComponent.getWriteObjCounter(this);
       
   910             JComponent.setWriteObjCounter(this, --count);
       
   911             if (count == 0 && ui != null) {
       
   912                 ui.installUI(this);
       
   913             }
       
   914         }
       
   915     }
       
   916 
       
   917 
       
   918     /**
       
   919      * Returns a string representation of this JLabel. This method
       
   920      * is intended to be used only for debugging purposes, and the
       
   921      * content and format of the returned string may vary between
       
   922      * implementations. The returned string may be empty but may not
       
   923      * be <code>null</code>.
       
   924      *
       
   925      * @return  a string representation of this JLabel.
       
   926      */
       
   927     protected String paramString() {
       
   928         String textString = (text != null ?
       
   929                              text : "");
       
   930         String defaultIconString = ((defaultIcon != null)
       
   931                                     && (defaultIcon != this)  ?
       
   932                                     defaultIcon.toString() : "");
       
   933         String disabledIconString = ((disabledIcon != null)
       
   934                                      && (disabledIcon != this) ?
       
   935                                      disabledIcon.toString() : "");
       
   936         String labelForString = (labelFor  != null ?
       
   937                                  labelFor.toString() : "");
       
   938         String verticalAlignmentString;
       
   939         if (verticalAlignment == TOP) {
       
   940             verticalAlignmentString = "TOP";
       
   941         } else if (verticalAlignment == CENTER) {
       
   942             verticalAlignmentString = "CENTER";
       
   943         } else if (verticalAlignment == BOTTOM) {
       
   944             verticalAlignmentString = "BOTTOM";
       
   945         } else verticalAlignmentString = "";
       
   946         String horizontalAlignmentString;
       
   947         if (horizontalAlignment == LEFT) {
       
   948             horizontalAlignmentString = "LEFT";
       
   949         } else if (horizontalAlignment == CENTER) {
       
   950             horizontalAlignmentString = "CENTER";
       
   951         } else if (horizontalAlignment == RIGHT) {
       
   952             horizontalAlignmentString = "RIGHT";
       
   953         } else if (horizontalAlignment == LEADING) {
       
   954             horizontalAlignmentString = "LEADING";
       
   955         } else if (horizontalAlignment == TRAILING) {
       
   956             horizontalAlignmentString = "TRAILING";
       
   957         } else horizontalAlignmentString = "";
       
   958         String verticalTextPositionString;
       
   959         if (verticalTextPosition == TOP) {
       
   960             verticalTextPositionString = "TOP";
       
   961         } else if (verticalTextPosition == CENTER) {
       
   962             verticalTextPositionString = "CENTER";
       
   963         } else if (verticalTextPosition == BOTTOM) {
       
   964             verticalTextPositionString = "BOTTOM";
       
   965         } else verticalTextPositionString = "";
       
   966         String horizontalTextPositionString;
       
   967         if (horizontalTextPosition == LEFT) {
       
   968             horizontalTextPositionString = "LEFT";
       
   969         } else if (horizontalTextPosition == CENTER) {
       
   970             horizontalTextPositionString = "CENTER";
       
   971         } else if (horizontalTextPosition == RIGHT) {
       
   972             horizontalTextPositionString = "RIGHT";
       
   973         } else if (horizontalTextPosition == LEADING) {
       
   974             horizontalTextPositionString = "LEADING";
       
   975         } else if (horizontalTextPosition == TRAILING) {
       
   976             horizontalTextPositionString = "TRAILING";
       
   977         } else horizontalTextPositionString = "";
       
   978 
       
   979         return super.paramString() +
       
   980         ",defaultIcon=" + defaultIconString +
       
   981         ",disabledIcon=" + disabledIconString +
       
   982         ",horizontalAlignment=" + horizontalAlignmentString +
       
   983         ",horizontalTextPosition=" + horizontalTextPositionString +
       
   984         ",iconTextGap=" + iconTextGap +
       
   985         ",labelFor=" + labelForString +
       
   986         ",text=" + textString +
       
   987         ",verticalAlignment=" + verticalAlignmentString +
       
   988         ",verticalTextPosition=" + verticalTextPositionString;
       
   989     }
       
   990 
       
   991     /**
       
   992      * --- Accessibility Support ---
       
   993      */
       
   994 
       
   995     /**
       
   996      * Get the component this is labelling.
       
   997      *
       
   998      * @return the Component this is labelling.  Can be null if this
       
   999      * does not label a Component.  If the displayedMnemonic
       
  1000      * property is set and the labelFor property is also set, the label
       
  1001      * will call the requestFocus method of the component specified by the
       
  1002      * labelFor property when the mnemonic is activated.
       
  1003      *
       
  1004      * @see #getDisplayedMnemonic
       
  1005      * @see #setDisplayedMnemonic
       
  1006      */
       
  1007     public Component getLabelFor() {
       
  1008         return labelFor;
       
  1009     }
       
  1010 
       
  1011     /**
       
  1012      * Set the component this is labelling.  Can be null if this does not
       
  1013      * label a Component.  If the displayedMnemonic property is set
       
  1014      * and the labelFor property is also set, the label will
       
  1015      * call the requestFocus method of the component specified by the
       
  1016      * labelFor property when the mnemonic is activated.
       
  1017      *
       
  1018      * @param c  the Component this label is for, or null if the label is
       
  1019      *           not the label for a component
       
  1020      *
       
  1021      * @see #getDisplayedMnemonic
       
  1022      * @see #setDisplayedMnemonic
       
  1023      *
       
  1024      * @beaninfo
       
  1025      *        bound: true
       
  1026      *  description: The component this is labelling.
       
  1027      */
       
  1028     public void setLabelFor(Component c) {
       
  1029         Component oldC = labelFor;
       
  1030         labelFor = c;
       
  1031         firePropertyChange("labelFor", oldC, c);
       
  1032 
       
  1033         if (oldC instanceof JComponent) {
       
  1034             ((JComponent)oldC).putClientProperty(LABELED_BY_PROPERTY, null);
       
  1035         }
       
  1036         if (c instanceof JComponent) {
       
  1037             ((JComponent)c).putClientProperty(LABELED_BY_PROPERTY, this);
       
  1038         }
       
  1039     }
       
  1040 
       
  1041     /**
       
  1042      * Get the AccessibleContext of this object
       
  1043      *
       
  1044      * @return the AccessibleContext of this object
       
  1045      * @beaninfo
       
  1046      *       expert: true
       
  1047      *  description: The AccessibleContext associated with this Label.
       
  1048      */
       
  1049     public AccessibleContext getAccessibleContext() {
       
  1050         if (accessibleContext == null) {
       
  1051             accessibleContext = new AccessibleJLabel();
       
  1052         }
       
  1053         return accessibleContext;
       
  1054     }
       
  1055 
       
  1056     /**
       
  1057      * The class used to obtain the accessible role for this object.
       
  1058      * <p>
       
  1059      * <strong>Warning:</strong>
       
  1060      * Serialized objects of this class will not be compatible with
       
  1061      * future Swing releases. The current serialization support is
       
  1062      * appropriate for short term storage or RMI between applications running
       
  1063      * the same version of Swing.  As of 1.4, support for long term storage
       
  1064      * of all JavaBeans<sup><font size="-2">TM</font></sup>
       
  1065      * has been added to the <code>java.beans</code> package.
       
  1066      * Please see {@link java.beans.XMLEncoder}.
       
  1067      */
       
  1068     protected class AccessibleJLabel extends AccessibleJComponent
       
  1069         implements AccessibleText, AccessibleExtendedComponent {
       
  1070 
       
  1071         /**
       
  1072          * Get the accessible name of this object.
       
  1073          *
       
  1074          * @return the localized name of the object -- can be null if this
       
  1075          * object does not have a name
       
  1076          * @see AccessibleContext#setAccessibleName
       
  1077          */
       
  1078         public String getAccessibleName() {
       
  1079             String name = accessibleName;
       
  1080 
       
  1081             if (name == null) {
       
  1082                 name = (String)getClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY);
       
  1083             }
       
  1084             if (name == null) {
       
  1085                 name = JLabel.this.getText();
       
  1086             }
       
  1087             if (name == null) {
       
  1088                 name = super.getAccessibleName();
       
  1089             }
       
  1090             return name;
       
  1091         }
       
  1092 
       
  1093         /**
       
  1094          * Get the role of this object.
       
  1095          *
       
  1096          * @return an instance of AccessibleRole describing the role of the
       
  1097          * object
       
  1098          * @see AccessibleRole
       
  1099          */
       
  1100         public AccessibleRole getAccessibleRole() {
       
  1101             return AccessibleRole.LABEL;
       
  1102         }
       
  1103 
       
  1104         /**
       
  1105          * Get the AccessibleIcons associated with this object if one
       
  1106          * or more exist.  Otherwise return null.
       
  1107          * @since 1.3
       
  1108          */
       
  1109         public AccessibleIcon [] getAccessibleIcon() {
       
  1110             Icon icon = getIcon();
       
  1111             if (icon instanceof Accessible) {
       
  1112                 AccessibleContext ac =
       
  1113                 ((Accessible)icon).getAccessibleContext();
       
  1114                 if (ac != null && ac instanceof AccessibleIcon) {
       
  1115                     return new AccessibleIcon[] { (AccessibleIcon)ac };
       
  1116                 }
       
  1117             }
       
  1118             return null;
       
  1119         }
       
  1120 
       
  1121         /**
       
  1122          * Get the AccessibleRelationSet associated with this object if one
       
  1123          * exists.  Otherwise return null.
       
  1124          * @see AccessibleRelation
       
  1125          * @since 1.3
       
  1126          */
       
  1127         public AccessibleRelationSet getAccessibleRelationSet() {
       
  1128             // Check where the AccessibleContext's relation
       
  1129             // set already contains a LABEL_FOR relation.
       
  1130             AccessibleRelationSet relationSet
       
  1131                 = super.getAccessibleRelationSet();
       
  1132 
       
  1133             if (!relationSet.contains(AccessibleRelation.LABEL_FOR)) {
       
  1134                 Component c = JLabel.this.getLabelFor();
       
  1135                 if (c != null) {
       
  1136                     AccessibleRelation relation
       
  1137                         = new AccessibleRelation(AccessibleRelation.LABEL_FOR);
       
  1138                     relation.setTarget(c);
       
  1139                     relationSet.add(relation);
       
  1140                 }
       
  1141             }
       
  1142             return relationSet;
       
  1143         }
       
  1144 
       
  1145 
       
  1146         /* AccessibleText ---------- */
       
  1147 
       
  1148         public AccessibleText getAccessibleText() {
       
  1149             View view = (View)JLabel.this.getClientProperty("html");
       
  1150             if (view != null) {
       
  1151                 return this;
       
  1152             } else {
       
  1153                 return null;
       
  1154             }
       
  1155         }
       
  1156 
       
  1157         /**
       
  1158          * Given a point in local coordinates, return the zero-based index
       
  1159          * of the character under that Point.  If the point is invalid,
       
  1160          * this method returns -1.
       
  1161          *
       
  1162          * @param p the Point in local coordinates
       
  1163          * @return the zero-based index of the character under Point p; if
       
  1164          * Point is invalid returns -1.
       
  1165          * @since 1.3
       
  1166          */
       
  1167         public int getIndexAtPoint(Point p) {
       
  1168             View view = (View) JLabel.this.getClientProperty("html");
       
  1169             if (view != null) {
       
  1170                 Rectangle r = getTextRectangle();
       
  1171                 if (r == null) {
       
  1172                     return -1;
       
  1173                 }
       
  1174                 Rectangle2D.Float shape =
       
  1175                     new Rectangle2D.Float(r.x, r.y, r.width, r.height);
       
  1176                 Position.Bias bias[] = new Position.Bias[1];
       
  1177                 return view.viewToModel(p.x, p.y, shape, bias);
       
  1178             } else {
       
  1179                 return -1;
       
  1180             }
       
  1181         }
       
  1182 
       
  1183         /**
       
  1184          * Determine the bounding box of the character at the given
       
  1185          * index into the string.  The bounds are returned in local
       
  1186          * coordinates.  If the index is invalid an empty rectangle is
       
  1187          * returned.
       
  1188          *
       
  1189          * @param i the index into the String
       
  1190          * @return the screen coordinates of the character's the bounding box,
       
  1191          * if index is invalid returns an empty rectangle.
       
  1192          * @since 1.3
       
  1193          */
       
  1194         public Rectangle getCharacterBounds(int i) {
       
  1195             View view = (View) JLabel.this.getClientProperty("html");
       
  1196             if (view != null) {
       
  1197                 Rectangle r = getTextRectangle();
       
  1198         if (r == null) {
       
  1199             return null;
       
  1200         }
       
  1201                 Rectangle2D.Float shape =
       
  1202                     new Rectangle2D.Float(r.x, r.y, r.width, r.height);
       
  1203                 try {
       
  1204                     Shape charShape =
       
  1205                         view.modelToView(i, shape, Position.Bias.Forward);
       
  1206                     return charShape.getBounds();
       
  1207                 } catch (BadLocationException e) {
       
  1208                     return null;
       
  1209                 }
       
  1210             } else {
       
  1211                 return null;
       
  1212             }
       
  1213         }
       
  1214 
       
  1215         /**
       
  1216          * Return the number of characters (valid indicies)
       
  1217          *
       
  1218          * @return the number of characters
       
  1219          * @since 1.3
       
  1220          */
       
  1221         public int getCharCount() {
       
  1222             View view = (View) JLabel.this.getClientProperty("html");
       
  1223             if (view != null) {
       
  1224                 Document d = view.getDocument();
       
  1225                 if (d instanceof StyledDocument) {
       
  1226                     StyledDocument doc = (StyledDocument)d;
       
  1227                     return doc.getLength();
       
  1228                 }
       
  1229             }
       
  1230             return accessibleContext.getAccessibleName().length();
       
  1231         }
       
  1232 
       
  1233         /**
       
  1234          * Return the zero-based offset of the caret.
       
  1235          *
       
  1236          * Note: That to the right of the caret will have the same index
       
  1237          * value as the offset (the caret is between two characters).
       
  1238          * @return the zero-based offset of the caret.
       
  1239          * @since 1.3
       
  1240          */
       
  1241         public int getCaretPosition() {
       
  1242             // There is no caret.
       
  1243             return -1;
       
  1244         }
       
  1245 
       
  1246         /**
       
  1247          * Returns the String at a given index.
       
  1248          *
       
  1249          * @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
       
  1250          * or AccessibleText.SENTENCE to retrieve
       
  1251          * @param index an index within the text >= 0
       
  1252          * @return the letter, word, or sentence,
       
  1253          *   null for an invalid index or part
       
  1254          * @since 1.3
       
  1255          */
       
  1256         public String getAtIndex(int part, int index) {
       
  1257             if (index < 0 || index >= getCharCount()) {
       
  1258                 return null;
       
  1259             }
       
  1260             switch (part) {
       
  1261             case AccessibleText.CHARACTER:
       
  1262                 try {
       
  1263                     return getText(index, 1);
       
  1264                 } catch (BadLocationException e) {
       
  1265                     return null;
       
  1266                 }
       
  1267             case AccessibleText.WORD:
       
  1268                 try {
       
  1269                     String s = getText(0, getCharCount());
       
  1270                     BreakIterator words = BreakIterator.getWordInstance(getLocale());
       
  1271                     words.setText(s);
       
  1272                     int end = words.following(index);
       
  1273                     return s.substring(words.previous(), end);
       
  1274                 } catch (BadLocationException e) {
       
  1275                     return null;
       
  1276                 }
       
  1277             case AccessibleText.SENTENCE:
       
  1278                 try {
       
  1279                     String s = getText(0, getCharCount());
       
  1280                     BreakIterator sentence =
       
  1281                         BreakIterator.getSentenceInstance(getLocale());
       
  1282                     sentence.setText(s);
       
  1283                     int end = sentence.following(index);
       
  1284                     return s.substring(sentence.previous(), end);
       
  1285                 } catch (BadLocationException e) {
       
  1286                     return null;
       
  1287                 }
       
  1288             default:
       
  1289                 return null;
       
  1290             }
       
  1291         }
       
  1292 
       
  1293         /**
       
  1294          * Returns the String after a given index.
       
  1295          *
       
  1296          * @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
       
  1297          * or AccessibleText.SENTENCE to retrieve
       
  1298          * @param index an index within the text >= 0
       
  1299          * @return the letter, word, or sentence, null for an invalid
       
  1300          *  index or part
       
  1301          * @since 1.3
       
  1302          */
       
  1303         public String getAfterIndex(int part, int index) {
       
  1304             if (index < 0 || index >= getCharCount()) {
       
  1305                 return null;
       
  1306             }
       
  1307             switch (part) {
       
  1308             case AccessibleText.CHARACTER:
       
  1309                 if (index+1 >= getCharCount()) {
       
  1310                    return null;
       
  1311                 }
       
  1312                 try {
       
  1313                     return getText(index+1, 1);
       
  1314                 } catch (BadLocationException e) {
       
  1315                     return null;
       
  1316                 }
       
  1317             case AccessibleText.WORD:
       
  1318                 try {
       
  1319                     String s = getText(0, getCharCount());
       
  1320                     BreakIterator words = BreakIterator.getWordInstance(getLocale());
       
  1321                     words.setText(s);
       
  1322                     int start = words.following(index);
       
  1323                     if (start == BreakIterator.DONE || start >= s.length()) {
       
  1324                         return null;
       
  1325                     }
       
  1326                     int end = words.following(start);
       
  1327                     if (end == BreakIterator.DONE || end >= s.length()) {
       
  1328                         return null;
       
  1329                     }
       
  1330                     return s.substring(start, end);
       
  1331                 } catch (BadLocationException e) {
       
  1332                     return null;
       
  1333                 }
       
  1334             case AccessibleText.SENTENCE:
       
  1335                 try {
       
  1336                     String s = getText(0, getCharCount());
       
  1337                     BreakIterator sentence =
       
  1338                         BreakIterator.getSentenceInstance(getLocale());
       
  1339                     sentence.setText(s);
       
  1340                     int start = sentence.following(index);
       
  1341                     if (start == BreakIterator.DONE || start > s.length()) {
       
  1342                         return null;
       
  1343                     }
       
  1344                     int end = sentence.following(start);
       
  1345                     if (end == BreakIterator.DONE || end > s.length()) {
       
  1346                         return null;
       
  1347                     }
       
  1348                     return s.substring(start, end);
       
  1349                 } catch (BadLocationException e) {
       
  1350                     return null;
       
  1351                 }
       
  1352             default:
       
  1353                 return null;
       
  1354             }
       
  1355         }
       
  1356 
       
  1357         /**
       
  1358          * Returns the String before a given index.
       
  1359          *
       
  1360          * @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
       
  1361          *   or AccessibleText.SENTENCE to retrieve
       
  1362          * @param index an index within the text >= 0
       
  1363          * @return the letter, word, or sentence, null for an invalid index
       
  1364          *  or part
       
  1365          * @since 1.3
       
  1366          */
       
  1367         public String getBeforeIndex(int part, int index) {
       
  1368             if (index < 0 || index > getCharCount()-1) {
       
  1369                 return null;
       
  1370             }
       
  1371             switch (part) {
       
  1372             case AccessibleText.CHARACTER:
       
  1373                 if (index == 0) {
       
  1374                     return null;
       
  1375                 }
       
  1376                 try {
       
  1377                     return getText(index-1, 1);
       
  1378                 } catch (BadLocationException e) {
       
  1379                     return null;
       
  1380                 }
       
  1381             case AccessibleText.WORD:
       
  1382                 try {
       
  1383                     String s = getText(0, getCharCount());
       
  1384                     BreakIterator words = BreakIterator.getWordInstance(getLocale());
       
  1385                     words.setText(s);
       
  1386                     int end = words.following(index);
       
  1387                     end = words.previous();
       
  1388                     int start = words.previous();
       
  1389                     if (start == BreakIterator.DONE) {
       
  1390                         return null;
       
  1391                     }
       
  1392                     return s.substring(start, end);
       
  1393                 } catch (BadLocationException e) {
       
  1394                     return null;
       
  1395                 }
       
  1396             case AccessibleText.SENTENCE:
       
  1397                 try {
       
  1398                     String s = getText(0, getCharCount());
       
  1399                     BreakIterator sentence =
       
  1400                         BreakIterator.getSentenceInstance(getLocale());
       
  1401                     sentence.setText(s);
       
  1402                     int end = sentence.following(index);
       
  1403                     end = sentence.previous();
       
  1404                     int start = sentence.previous();
       
  1405                     if (start == BreakIterator.DONE) {
       
  1406                         return null;
       
  1407                     }
       
  1408                     return s.substring(start, end);
       
  1409                 } catch (BadLocationException e) {
       
  1410                     return null;
       
  1411                 }
       
  1412             default:
       
  1413                 return null;
       
  1414             }
       
  1415         }
       
  1416 
       
  1417         /**
       
  1418          * Return the AttributeSet for a given character at a given index
       
  1419          *
       
  1420          * @param i the zero-based index into the text
       
  1421          * @return the AttributeSet of the character
       
  1422          * @since 1.3
       
  1423          */
       
  1424         public AttributeSet getCharacterAttribute(int i) {
       
  1425             View view = (View) JLabel.this.getClientProperty("html");
       
  1426             if (view != null) {
       
  1427                 Document d = view.getDocument();
       
  1428                 if (d instanceof StyledDocument) {
       
  1429                     StyledDocument doc = (StyledDocument)d;
       
  1430                     Element elem = doc.getCharacterElement(i);
       
  1431                     if (elem != null) {
       
  1432                         return elem.getAttributes();
       
  1433                     }
       
  1434                 }
       
  1435             }
       
  1436             return null;
       
  1437         }
       
  1438 
       
  1439         /**
       
  1440          * Returns the start offset within the selected text.
       
  1441          * If there is no selection, but there is
       
  1442          * a caret, the start and end offsets will be the same.
       
  1443          *
       
  1444          * @return the index into the text of the start of the selection
       
  1445          * @since 1.3
       
  1446          */
       
  1447         public int getSelectionStart() {
       
  1448             // Text cannot be selected.
       
  1449             return -1;
       
  1450         }
       
  1451 
       
  1452         /**
       
  1453          * Returns the end offset within the selected text.
       
  1454          * If there is no selection, but there is
       
  1455          * a caret, the start and end offsets will be the same.
       
  1456          *
       
  1457          * @return the index into teh text of the end of the selection
       
  1458          * @since 1.3
       
  1459          */
       
  1460         public int getSelectionEnd() {
       
  1461             // Text cannot be selected.
       
  1462             return -1;
       
  1463         }
       
  1464 
       
  1465         /**
       
  1466          * Returns the portion of the text that is selected.
       
  1467          *
       
  1468          * @return the String portion of the text that is selected
       
  1469          * @since 1.3
       
  1470          */
       
  1471         public String getSelectedText() {
       
  1472             // Text cannot be selected.
       
  1473             return null;
       
  1474         }
       
  1475 
       
  1476         /*
       
  1477          * Returns the text substring starting at the specified
       
  1478          * offset with the specified length.
       
  1479          */
       
  1480         private String getText(int offset, int length)
       
  1481             throws BadLocationException {
       
  1482 
       
  1483             View view = (View) JLabel.this.getClientProperty("html");
       
  1484             if (view != null) {
       
  1485                 Document d = view.getDocument();
       
  1486                 if (d instanceof StyledDocument) {
       
  1487                     StyledDocument doc = (StyledDocument)d;
       
  1488                     return doc.getText(offset, length);
       
  1489                 }
       
  1490             }
       
  1491             return null;
       
  1492         }
       
  1493 
       
  1494         /*
       
  1495          * Returns the bounding rectangle for the component text.
       
  1496          */
       
  1497         private Rectangle getTextRectangle() {
       
  1498 
       
  1499             String text = JLabel.this.getText();
       
  1500             Icon icon = (JLabel.this.isEnabled()) ? JLabel.this.getIcon() : JLabel.this.getDisabledIcon();
       
  1501 
       
  1502             if ((icon == null) && (text == null)) {
       
  1503                 return null;
       
  1504             }
       
  1505 
       
  1506             Rectangle paintIconR = new Rectangle();
       
  1507             Rectangle paintTextR = new Rectangle();
       
  1508             Rectangle paintViewR = new Rectangle();
       
  1509             Insets paintViewInsets = new Insets(0, 0, 0, 0);
       
  1510 
       
  1511             paintViewInsets = JLabel.this.getInsets(paintViewInsets);
       
  1512             paintViewR.x = paintViewInsets.left;
       
  1513             paintViewR.y = paintViewInsets.top;
       
  1514             paintViewR.width = JLabel.this.getWidth() - (paintViewInsets.left + paintViewInsets.right);
       
  1515             paintViewR.height = JLabel.this.getHeight() - (paintViewInsets.top + paintViewInsets.bottom);
       
  1516 
       
  1517             String clippedText = SwingUtilities.layoutCompoundLabel(
       
  1518                 (JComponent)JLabel.this,
       
  1519                 getFontMetrics(getFont()),
       
  1520                 text,
       
  1521                 icon,
       
  1522                 JLabel.this.getVerticalAlignment(),
       
  1523                 JLabel.this.getHorizontalAlignment(),
       
  1524                 JLabel.this.getVerticalTextPosition(),
       
  1525                 JLabel.this.getHorizontalTextPosition(),
       
  1526                 paintViewR,
       
  1527                 paintIconR,
       
  1528                 paintTextR,
       
  1529                 JLabel.this.getIconTextGap());
       
  1530 
       
  1531             return paintTextR;
       
  1532         }
       
  1533 
       
  1534         // ----- AccessibleExtendedComponent
       
  1535 
       
  1536         /**
       
  1537          * Returns the AccessibleExtendedComponent
       
  1538          *
       
  1539          * @return the AccessibleExtendedComponent
       
  1540          */
       
  1541         AccessibleExtendedComponent getAccessibleExtendedComponent() {
       
  1542             return this;
       
  1543         }
       
  1544 
       
  1545         /**
       
  1546          * Returns the tool tip text
       
  1547          *
       
  1548          * @return the tool tip text, if supported, of the object;
       
  1549          * otherwise, null
       
  1550          * @since 1.4
       
  1551          */
       
  1552         public String getToolTipText() {
       
  1553             return JLabel.this.getToolTipText();
       
  1554         }
       
  1555 
       
  1556         /**
       
  1557          * Returns the titled border text
       
  1558          *
       
  1559          * @return the titled border text, if supported, of the object;
       
  1560          * otherwise, null
       
  1561          * @since 1.4
       
  1562          */
       
  1563         public String getTitledBorderText() {
       
  1564             return super.getTitledBorderText();
       
  1565         }
       
  1566 
       
  1567         /**
       
  1568          * Returns key bindings associated with this object
       
  1569          *
       
  1570          * @return the key bindings, if supported, of the object;
       
  1571          * otherwise, null
       
  1572          * @see AccessibleKeyBinding
       
  1573          * @since 1.4
       
  1574          */
       
  1575         public AccessibleKeyBinding getAccessibleKeyBinding() {
       
  1576             int mnemonic = JLabel.this.getDisplayedMnemonic();
       
  1577             if (mnemonic == 0) {
       
  1578                 return null;
       
  1579             }
       
  1580             return new LabelKeyBinding(mnemonic);
       
  1581         }
       
  1582 
       
  1583         class LabelKeyBinding implements AccessibleKeyBinding {
       
  1584             int mnemonic;
       
  1585 
       
  1586             LabelKeyBinding(int mnemonic) {
       
  1587                 this.mnemonic = mnemonic;
       
  1588             }
       
  1589 
       
  1590             /**
       
  1591              * Returns the number of key bindings for this object
       
  1592              *
       
  1593              * @return the zero-based number of key bindings for this object
       
  1594              */
       
  1595             public int getAccessibleKeyBindingCount() {
       
  1596                 return 1;
       
  1597             }
       
  1598 
       
  1599             /**
       
  1600              * Returns a key binding for this object.  The value returned is an
       
  1601              * java.lang.Object which must be cast to appropriate type depending
       
  1602              * on the underlying implementation of the key.  For example, if the
       
  1603              * Object returned is a javax.swing.KeyStroke, the user of this
       
  1604              * method should do the following:
       
  1605              * <nf><code>
       
  1606              * Component c = <get the component that has the key bindings>
       
  1607              * AccessibleContext ac = c.getAccessibleContext();
       
  1608              * AccessibleKeyBinding akb = ac.getAccessibleKeyBinding();
       
  1609              * for (int i = 0; i < akb.getAccessibleKeyBindingCount(); i++) {
       
  1610              *     Object o = akb.getAccessibleKeyBinding(i);
       
  1611              *     if (o instanceof javax.swing.KeyStroke) {
       
  1612              *         javax.swing.KeyStroke keyStroke = (javax.swing.KeyStroke)o;
       
  1613              *         <do something with the key binding>
       
  1614              *     }
       
  1615              * }
       
  1616              * </code></nf>
       
  1617              *
       
  1618              * @param i zero-based index of the key bindings
       
  1619              * @return a javax.lang.Object which specifies the key binding
       
  1620              * @exception IllegalArgumentException if the index is
       
  1621              * out of bounds
       
  1622              * @see #getAccessibleKeyBindingCount
       
  1623              */
       
  1624             public java.lang.Object getAccessibleKeyBinding(int i) {
       
  1625                 if (i != 0) {
       
  1626                     throw new IllegalArgumentException();
       
  1627                 }
       
  1628                 return KeyStroke.getKeyStroke(mnemonic, 0);
       
  1629             }
       
  1630         }
       
  1631 
       
  1632     }  // AccessibleJComponent
       
  1633 }