1. /*
  2. * @(#)JLabel.java 1.100 00/02/02
  3. *
  4. * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package javax.swing;
  11. import java.awt.Component;
  12. import java.awt.Font;
  13. import java.awt.Image;
  14. import java.awt.*;
  15. import java.text.*;
  16. import java.awt.geom.*;
  17. import java.io.ObjectOutputStream;
  18. import java.io.ObjectInputStream;
  19. import java.io.IOException;
  20. import javax.swing.plaf.LabelUI;
  21. import javax.accessibility.*;
  22. import javax.swing.text.*;
  23. import javax.swing.text.html.*;
  24. import javax.swing.plaf.basic.*;
  25. import java.util.*;
  26. /**
  27. * A display area for a short text string or an image,
  28. * or both.
  29. * A label does not react to input events.
  30. * As a result, it cannot get the keyboard focus.
  31. * A label can, however, display a keyboard alternative
  32. * as a convenience for a nearby component
  33. * that has a keyboard alternative but can't display it.
  34. * <p>
  35. * A <code>JLabel</code> object can display
  36. * either text, an image, or both.
  37. * You can specify where in the label's display area
  38. * the label's contents are aligned
  39. * by setting the vertical and horizontal alignment.
  40. * By default, labels are vertically centered
  41. * in their display area.
  42. * Text-only labels are leading edge aligned, by default;
  43. * image-only labels are horizontally centered, by default.
  44. * <p>
  45. * You can also specify the position of the text
  46. * relative to the image.
  47. * By default, text is on the trailing edge of the image,
  48. * with the text and image vertically aligned.
  49. * <p>
  50. * A label's leading and trailing edge are determined from the value of its
  51. * {@link java.awt.ComponentOrientation} property. At present, the default
  52. * ComponentOrientation setting maps the leading edge to left and the trailing
  53. * edge to right.
  54. *
  55. * <p>
  56. * Finally, you can use the <code>setIconTextGap</code> method
  57. * to specify how many pixels
  58. * should appear between the text and the image.
  59. * The default is 4 pixels.
  60. * <p>
  61. * See <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/label.html">How to Use Labels</a>
  62. * in <em>The Java Tutorial</em>
  63. * for further documentation.
  64. * <p>
  65. * <strong>Warning:</strong>
  66. * Serialized objects of this class will not be compatible with
  67. * future Swing releases. The current serialization support is appropriate
  68. * for short term storage or RMI between applications running the same
  69. * version of Swing. A future release of Swing will provide support for
  70. * long term persistence.
  71. *
  72. * @beaninfo
  73. * attribute: isContainer false
  74. * description: A component that displays a short string and an icon.
  75. *
  76. * @version 1.100 02/02/00
  77. * @author Hans Muller
  78. */
  79. public class JLabel extends JComponent implements SwingConstants, Accessible
  80. {
  81. /**
  82. * @see #getUIClassID
  83. * @see #readObject
  84. */
  85. private static final String uiClassID = "LabelUI";
  86. private int mnemonic = '\0';
  87. private String text = ""; // "" rather than null, for BeanBox
  88. private Icon defaultIcon = null;
  89. private Icon disabledIcon = null;
  90. private boolean disabledIconSet = false;
  91. private int verticalAlignment = CENTER;
  92. private int horizontalAlignment = LEADING;
  93. private int verticalTextPosition = CENTER;
  94. private int horizontalTextPosition = TRAILING;
  95. private int iconTextGap = 4;
  96. protected Component labelFor = null;
  97. private AccessibleIcon accessibleIcon = null;
  98. /**
  99. * Client property key used to determine what label is labeling the
  100. * component. This is generally not used by labels, but is instead
  101. * used by components such as text areas that are being labeled by
  102. * labels. When the labelFor property of a label is set, it will
  103. * automatically set the LABELED_BY_PROPERTY of the component being
  104. * labelled.
  105. *
  106. * @see #setLabelFor
  107. */
  108. static final String LABELED_BY_PROPERTY = "labeledBy";
  109. /**
  110. * Creates a <code>JLabel</code> instance with the specified
  111. * text, image, and horizontal alignment.
  112. * The label is centered vertically in its display area.
  113. * The text is on the trailing edge of the image.
  114. *
  115. * @param text The text to be displayed by the label.
  116. * @param icon The image to be displayed by the label.
  117. * @param horizontalAlignment One of the following constants
  118. * defined in <code>SwingConstants</code>:
  119. * <code>LEFT</code>,
  120. * <code>CENTER</code>,
  121. * <code>RIGHT</code>,
  122. * <code>LEADING</code> or
  123. * <code>TRAILING</code>.
  124. */
  125. public JLabel(String text, Icon icon, int horizontalAlignment) {
  126. setText(text);
  127. setIcon(icon);
  128. setHorizontalAlignment(horizontalAlignment);
  129. updateUI();
  130. setAlignmentX(LEFT_ALIGNMENT);
  131. }
  132. /**
  133. * Creates a <code>JLabel</code> instance with the specified
  134. * text and horizontal alignment.
  135. * The label is centered vertically in its display area.
  136. *
  137. * @param text The text to be displayed by the label.
  138. * @param horizontalAlignment One of the following constants
  139. * defined in <code>SwingConstants</code>:
  140. * <code>LEFT</code>,
  141. * <code>CENTER</code>,
  142. * <code>RIGHT</code>,
  143. * <code>LEADING</code> or
  144. * <code>TRAILING</code>.
  145. */
  146. public JLabel(String text, int horizontalAlignment) {
  147. this(text, null, horizontalAlignment);
  148. }
  149. /**
  150. * Creates a <code>JLabel</code> instance with the specified text.
  151. * The label is aligned against the leading edge of its display area,
  152. * and centered vertically.
  153. *
  154. * @param text The text to be displayed by the label.
  155. */
  156. public JLabel(String text) {
  157. this(text, null, LEADING);
  158. }
  159. /**
  160. * Creates a <code>JLabel</code> instance with the specified
  161. * image and horizontal alignment.
  162. * The label is centered vertically in its display area.
  163. *
  164. * @param icon The image to be displayed by the label.
  165. * @param horizontalAlignment One of the following constants
  166. * defined in <code>SwingConstants</code>:
  167. * <code>LEFT</code>,
  168. * <code>CENTER</code>,
  169. * <code>RIGHT</code>,
  170. * <code>LEADING</code> or
  171. * <code>TRAILING</code>.
  172. */
  173. public JLabel(Icon image, int horizontalAlignment) {
  174. this(null, image, horizontalAlignment);
  175. }
  176. /**
  177. * Creates a <code>JLabel</code> instance with the specified image.
  178. * The label is centered vertically and horizontally
  179. * in its display area.
  180. *
  181. * @param icon The image to be displayed by the label.
  182. */
  183. public JLabel(Icon image) {
  184. this(null, image, CENTER);
  185. }
  186. /**
  187. * Creates a <code>JLabel</code> instance with
  188. * no image and with an empty string for the title.
  189. * The label is centered vertically
  190. * in its display area.
  191. * The label's contents, once set, will be displayed on the leading edge
  192. * of the label's display area.
  193. */
  194. public JLabel() {
  195. this("", null, LEADING);
  196. }
  197. /**
  198. * Returns the L&F object that renders this component.
  199. *
  200. * @return LabelUI object
  201. */
  202. public LabelUI getUI() {
  203. return (LabelUI)ui;
  204. }
  205. /**
  206. * Sets the L&F object that renders this component.
  207. *
  208. * @param ui the LabelUI L&F object
  209. * @see UIDefaults#getUI
  210. * @beaninfo
  211. * expert: true
  212. * description: The L&F object that renders this component.
  213. */
  214. public void setUI(LabelUI ui) {
  215. super.setUI(ui);
  216. }
  217. /**
  218. * Notification from the UIFactory that the L&F
  219. * has changed.
  220. *
  221. * @see JComponent#updateUI
  222. */
  223. public void updateUI() {
  224. setUI((LabelUI)UIManager.getUI(this));
  225. }
  226. /**
  227. * Returns a string that specifies the name of the l&f class
  228. * that renders this component.
  229. *
  230. * @return String "LabelUI"
  231. *
  232. * @see JComponent#getUIClassID
  233. * @see UIDefaults#getUI
  234. */
  235. public String getUIClassID() {
  236. return uiClassID;
  237. }
  238. /**
  239. * Returns the text string that the label displays.
  240. *
  241. * @return a String
  242. * @see #setText
  243. */
  244. public String getText() {
  245. return text;
  246. }
  247. /**
  248. * Defines the single line of text this component will display. If
  249. * the value of text is null or empty string, nothing is displayed.
  250. * <p>
  251. * The default value of this property is null.
  252. * <p>
  253. * This is a JavaBeans bound property.
  254. *
  255. * @see #setVerticalTextPosition
  256. * @see #setHorizontalTextPosition
  257. * @see #setIcon
  258. * @beaninfo
  259. * preferred: true
  260. * bound: true
  261. * attribute: visualUpdate true
  262. * description: Defines the single line of text this component will display.
  263. */
  264. public void setText(String text) {
  265. String oldAccessibleName = null;
  266. if (accessibleContext != null) {
  267. oldAccessibleName = accessibleContext.getAccessibleName();
  268. }
  269. String oldValue = this.text;
  270. this.text = text;
  271. firePropertyChange("text", oldValue, text);
  272. if ((accessibleContext != null)
  273. && (accessibleContext.getAccessibleName() != oldAccessibleName)) {
  274. accessibleContext.firePropertyChange(
  275. AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  276. oldAccessibleName,
  277. accessibleContext.getAccessibleName());
  278. }
  279. if (text == null || oldValue == null || !text.equals(oldValue)) {
  280. revalidate();
  281. repaint();
  282. }
  283. }
  284. /**
  285. * Returns the graphic image (glyph, icon) that the label displays.
  286. *
  287. * @return an Icon
  288. * @see #setIcon
  289. */
  290. public Icon getIcon() {
  291. return defaultIcon;
  292. }
  293. /**
  294. * Defines the icon this component will display. If
  295. * the value of icon is null, nothing is displayed.
  296. * <p>
  297. * The default value of this property is null.
  298. * <p>
  299. * This is a JavaBeans bound property.
  300. *
  301. * @see #setVerticalTextPosition
  302. * @see #setHorizontalTextPosition
  303. * @see #getIcon
  304. * @beaninfo
  305. * preferred: true
  306. * bound: true
  307. * attribute: visualUpdate true
  308. * description: The icon this component will display.
  309. */
  310. public void setIcon(Icon icon) {
  311. Icon oldValue = defaultIcon;
  312. defaultIcon = icon;
  313. /* If the default icon has really changed and we had
  314. * generated the disabled icon for this component
  315. * (in other words, setDisabledIcon() was never called), then
  316. * clear the disabledIcon field.
  317. */
  318. if ((defaultIcon != oldValue) && !disabledIconSet) {
  319. disabledIcon = null;
  320. }
  321. firePropertyChange("icon", oldValue, defaultIcon);
  322. if ((accessibleContext != null) && (oldValue != defaultIcon)) {
  323. accessibleContext.firePropertyChange(
  324. AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  325. oldValue, defaultIcon);
  326. }
  327. /* If the default icon has changed and the new one is
  328. * a different size, then revalidate. Repaint if the
  329. * default icon has changed.
  330. */
  331. if (defaultIcon != oldValue) {
  332. if ((defaultIcon == null) ||
  333. (oldValue == null) ||
  334. (defaultIcon.getIconWidth() != oldValue.getIconWidth()) ||
  335. (defaultIcon.getIconHeight() != oldValue.getIconHeight())) {
  336. revalidate();
  337. }
  338. repaint();
  339. }
  340. // set the accessible icon
  341. accessibleIcon = null;
  342. if (defaultIcon instanceof Accessible) {
  343. AccessibleContext ac =
  344. ((Accessible)defaultIcon).getAccessibleContext();
  345. if (ac != null && ac instanceof AccessibleIcon) {
  346. accessibleIcon = (AccessibleIcon)ac;
  347. }
  348. }
  349. }
  350. /**
  351. * Returns the value of the disabledIcon property if it's been set,
  352. * If it hasn't been set and the value of the icon property is
  353. * an ImageIcon, we compute a "grayed out" version of the icon and
  354. * update the disabledIcon property with that.
  355. *
  356. * @return The value of the disabledIcon property.
  357. * @see #setDisabledIcon
  358. * @see ImageIcon
  359. */
  360. public Icon getDisabledIcon()
  361. {
  362. if(!disabledIconSet &&
  363. (disabledIcon == null) &&
  364. (defaultIcon != null) &&
  365. (defaultIcon instanceof ImageIcon)) {
  366. Image grayImage = GrayFilter.createDisabledImage(((ImageIcon)defaultIcon).getImage());
  367. disabledIcon = new ImageIcon(grayImage);
  368. firePropertyChange("disabledIcon", null, disabledIcon);
  369. }
  370. return disabledIcon;
  371. }
  372. /**
  373. * Set the icon to be displayed if this JLabel is "disabled"
  374. * (JLabel.setEnabled(false)).
  375. * <p>
  376. * The default value of this property is null.
  377. *
  378. * @param disabledIcon the Icon to display when the component is disabled
  379. * @see #getDisabledIcon
  380. * @see #setEnabled
  381. * @beaninfo
  382. * bound: true
  383. * attribute: visualUpdate true
  384. * description: The icon to display if the label is disabled.
  385. */
  386. public void setDisabledIcon(Icon disabledIcon) {
  387. Icon oldValue = this.disabledIcon;
  388. this.disabledIcon = disabledIcon;
  389. disabledIconSet = true;
  390. firePropertyChange("disabledIcon", oldValue, disabledIcon);
  391. if (disabledIcon != oldValue) {
  392. if (disabledIcon == null || oldValue == null ||
  393. disabledIcon.getIconWidth() != oldValue.getIconWidth() ||
  394. disabledIcon.getIconHeight() != oldValue.getIconHeight()) {
  395. revalidate();
  396. }
  397. if (!isEnabled()) {
  398. repaint();
  399. }
  400. }
  401. }
  402. /**
  403. * Specify a keycode that indicates a mnemonic key.
  404. * This property is used when the label is part of a larger component.
  405. * If the labelFor property of the label is not null, the label will
  406. * call the requestFocus method of the component specified by the
  407. * labelFor property when the mnemonic is activated.
  408. *
  409. * @see #getLabelFor
  410. * @see #setLabelFor
  411. * @beaninfo
  412. * bound: true
  413. * attribute: visualUpdate true
  414. * description: The mnemonic keycode.
  415. */
  416. public void setDisplayedMnemonic(int key) {
  417. int oldKey = mnemonic;
  418. mnemonic = key;
  419. firePropertyChange("displayedMnemonic", oldKey, mnemonic);
  420. if (key != oldKey) {
  421. revalidate();
  422. repaint();
  423. }
  424. }
  425. /**
  426. * Specifies the displayedMnemonic as a char value.
  427. *
  428. * @param aChar a char specifying the mnemonic to display
  429. * @see #setDisplayedMnemonic(int)
  430. */
  431. public void setDisplayedMnemonic(char aChar) {
  432. int vk = (int) aChar;
  433. if(vk >= 'a' && vk <='z')
  434. vk -= ('a' - 'A');
  435. setDisplayedMnemonic(vk);
  436. }
  437. /**
  438. * Return the keycode that indicates a mnemonic key.
  439. * This property is used when the label is part of a larger component.
  440. * If the labelFor property of the label is not null, the label will
  441. * call the requestFocus method of the component specified by the
  442. * labelFor property when the mnemonic is activated.
  443. *
  444. * @return int value for the mnemonic key
  445. *
  446. * @see #getLabelFor
  447. * @see #setLabelFor
  448. */
  449. public int getDisplayedMnemonic() {
  450. return mnemonic;
  451. }
  452. /**
  453. * Verify that key is a legal value for the horizontalAlignment properties.
  454. *
  455. * @param key the property value to check
  456. * @param message the IllegalArgumentException detail message
  457. * @exception IllegalArgumentException if key isn't LEFT, CENTER, RIGHT,
  458. * LEADING or TRAILING.
  459. * @see #setHorizontalTextPosition
  460. * @see #setHorizontalAlignment
  461. */
  462. protected int checkHorizontalKey(int key, String message) {
  463. if ((key == LEFT) ||
  464. (key == CENTER) ||
  465. (key == RIGHT) ||
  466. (key == LEADING) ||
  467. (key == TRAILING)) {
  468. return key;
  469. }
  470. else {
  471. throw new IllegalArgumentException(message);
  472. }
  473. }
  474. /**
  475. * Verify that key is a legal value for the
  476. * verticalAlignment or verticalTextPosition properties.
  477. *
  478. * @param key the property value to check
  479. * @param message the IllegalArgumentException detail message
  480. * @exception IllegalArgumentException if key isn't TOP, CENTER, or BOTTOM.
  481. * @see #setVerticalAlignment
  482. * @see #setVerticalTextPosition
  483. */
  484. protected int checkVerticalKey(int key, String message) {
  485. if ((key == TOP) || (key == CENTER) || (key == BOTTOM)) {
  486. return key;
  487. }
  488. else {
  489. throw new IllegalArgumentException(message);
  490. }
  491. }
  492. /**
  493. * Returns the amount of space between the text and the icon
  494. * displayed in this label.
  495. *
  496. * @return an int equal to the number of pixels between the text
  497. * and the icon.
  498. * @see #setIconTextGap
  499. */
  500. public int getIconTextGap() {
  501. return iconTextGap;
  502. }
  503. /**
  504. * If both the icon and text properties are set, this property
  505. * defines the space between them.
  506. * <p>
  507. * The default value of this property is 4 pixels.
  508. * <p>
  509. * This is a JavaBeans bound property.
  510. *
  511. * @see #getIconTextGap
  512. * @beaninfo
  513. * bound: true
  514. * attribute: visualUpdate true
  515. * description: If both the icon and text properties are set, this
  516. * property defines the space between them.
  517. */
  518. public void setIconTextGap(int iconTextGap) {
  519. int oldValue = this.iconTextGap;
  520. this.iconTextGap = iconTextGap;
  521. firePropertyChange("iconTextGap", oldValue, iconTextGap);
  522. if (iconTextGap != oldValue) {
  523. revalidate();
  524. repaint();
  525. }
  526. }
  527. /**
  528. * Returns the alignment of the label's contents along the Y axis.
  529. *
  530. * @return The value of the verticalAlignment property, one of the
  531. * following constants defined in <code>SwingConstants</code>:
  532. * <code>TOP</code>,
  533. * <code>CENTER</code>, or
  534. * <code>BOTTOM</code>.
  535. *
  536. * @see SwingConstants
  537. * @see #setVerticalAlignment
  538. */
  539. public int getVerticalAlignment() {
  540. return verticalAlignment;
  541. }
  542. /**
  543. * Sets the alignment of the label's contents along the Y axis.
  544. * <p>
  545. * The default value of this property is CENTER.
  546. *
  547. * @param alignment One of the following constants
  548. * defined in <code>SwingConstants</code>:
  549. * <code>TOP</code>,
  550. * <code>CENTER</code> (the default), or
  551. * <code>BOTTOM</code>.
  552. *
  553. * @see SwingConstants
  554. * @see #getVerticalAlignment
  555. * @beaninfo
  556. * bound: true
  557. * enum: TOP SwingConstants.TOP
  558. * CENTER SwingConstants.CENTER
  559. * BOTTOM SwingConstants.BOTTOM
  560. * attribute: visualUpdate true
  561. * description: The alignment of the label's contents along the Y axis.
  562. */
  563. public void setVerticalAlignment(int alignment) {
  564. if (alignment == verticalAlignment) return;
  565. int oldValue = verticalAlignment;
  566. verticalAlignment = checkVerticalKey(alignment, "verticalAlignment");
  567. firePropertyChange("verticalAlignment", oldValue, verticalAlignment);
  568. repaint();
  569. }
  570. /**
  571. * Returns the alignment of the label's contents along the X axis.
  572. *
  573. * @return The value of the horizontalAlignment property, one of the
  574. * following constants defined in <code>SwingConstants</code>:
  575. * <code>LEFT</code>,
  576. * <code>CENTER</code>,
  577. * <code>RIGHT</code>,
  578. * <code>LEADING</code> or
  579. * <code>TRAILING</code>.
  580. *
  581. * @see #setHorizontalAlignment
  582. * @see SwingConstants
  583. */
  584. public int getHorizontalAlignment() {
  585. return horizontalAlignment;
  586. }
  587. /**
  588. * Sets the alignment of the label's contents along the X axis.
  589. * <p>
  590. * This is a JavaBeans bound property.
  591. *
  592. * @param alignment One of the following constants
  593. * defined in <code>SwingConstants</code>:
  594. * <code>LEFT</code>,
  595. * <code>CENTER</code> (the default for image-only labels),
  596. * <code>RIGHT</code>,
  597. * <code>LEADING</code> (the default for text-only labels) or
  598. * <code>TRAILING</code>.
  599. *
  600. * @see SwingConstants
  601. * @see #getHorizontalAlignment
  602. * @beaninfo
  603. * bound: true
  604. * enum: LEFT SwingConstants.LEFT
  605. * CENTER SwingConstants.CENTER
  606. * RIGHT SwingConstants.RIGHT
  607. * LEADING SwingConstants.LEADING
  608. * TRAILING SwingConstants.TRAILING
  609. * attribute: visualUpdate true
  610. * description: The alignment of the label's content along the X axis.
  611. */
  612. public void setHorizontalAlignment(int alignment) {
  613. if (alignment == horizontalAlignment) return;
  614. int oldValue = horizontalAlignment;
  615. horizontalAlignment = checkHorizontalKey(alignment,
  616. "horizontalAlignment");
  617. firePropertyChange("horizontalAlignment",
  618. oldValue, horizontalAlignment);
  619. repaint();
  620. }
  621. /**
  622. * Returns the vertical position of the label's text,
  623. * relative to its image.
  624. *
  625. * @return One of the following constants
  626. * defined in <code>SwingConstants</code>:
  627. * <code>TOP</code>,
  628. * <code>CENTER</code>, or
  629. * <code>BOTTOM</code>.
  630. *
  631. * @see #setVerticalTextPosition
  632. * @see SwingConstants
  633. */
  634. public int getVerticalTextPosition() {
  635. return verticalTextPosition;
  636. }
  637. /**
  638. * Sets the vertical position of the label's text,
  639. * relative to its image.
  640. * <p>
  641. * The default value of this property is CENTER.
  642. * <p>
  643. * This is a JavaBeans bound property.
  644. *
  645. * @param textPosition One of the following constants
  646. * defined in <code>SwingConstants</code>:
  647. * <code>TOP</code>,
  648. * <code>CENTER</code> (the default), or
  649. * <code>BOTTOM</code>.
  650. *
  651. * @see SwingConstants
  652. * @see #getVerticalTextPosition
  653. * @beaninfo
  654. * bound: true
  655. * enum: TOP SwingConstants.TOP
  656. * CENTER SwingConstants.CENTER
  657. * BOTTOM SwingConstants.BOTTOM
  658. * expert: true
  659. * attribute: visualUpdate true
  660. * description: The vertical position of the text relative to it's image.
  661. */
  662. public void setVerticalTextPosition(int textPosition) {
  663. if (textPosition == verticalTextPosition) return;
  664. int old = verticalTextPosition;
  665. verticalTextPosition = checkVerticalKey(textPosition,
  666. "verticalTextPosition");
  667. firePropertyChange("verticalTextPosition", old, verticalTextPosition);
  668. repaint();
  669. }
  670. /**
  671. * Returns the horizontal position of the label's text,
  672. * relative to its image.
  673. *
  674. * @return One of the following constants
  675. * defined in <code>SwingConstants</code>:
  676. * <code>LEFT</code>,
  677. * <code>CENTER</code>,
  678. * <code>RIGHT</code>,
  679. * <code>LEADING</code> or
  680. * <code>TRAILING</code>.
  681. *
  682. * @see SwingConstants
  683. */
  684. public int getHorizontalTextPosition() {
  685. return horizontalTextPosition;
  686. }
  687. /**
  688. * Sets the horizontal position of the label's text,
  689. * relative to its image.
  690. *
  691. * @param x One of the following constants
  692. * defined in <code>SwingConstants</code>:
  693. * <code>LEFT</code>,
  694. * <code>CENTER</code>,
  695. * <code>RIGHT</code>,
  696. * <code>LEADING</code>, or
  697. * <code>TRAILING</code> (the default).
  698. * @exception IllegalArgumentException
  699. *
  700. * @see SwingConstants
  701. * @beaninfo
  702. * expert: true
  703. * bound: true
  704. * enum: LEFT SwingConstants.LEFT
  705. * CENTER SwingConstants.CENTER
  706. * RIGHT SwingConstants.RIGHT
  707. * LEADING SwingConstants.LEADING
  708. * TRAILING SwingConstants.TRAILING
  709. * attribute: visualUpdate true
  710. * description: The horizontal position of the label's text,
  711. * relative to its image.
  712. */
  713. public void setHorizontalTextPosition(int textPosition) {
  714. int old = horizontalTextPosition;
  715. this.horizontalTextPosition = checkHorizontalKey(textPosition,
  716. "horizontalTextPosition");
  717. firePropertyChange("horizontalTextPosition",
  718. old, horizontalTextPosition);
  719. repaint();
  720. }
  721. /**
  722. * This is overriden to return false if the current Icon's Image is
  723. * not equal to the passed in Image <code>img</code>.
  724. *
  725. * @see java.awt.image.ImageObserver
  726. * @see java.awt.Component#imageUpdate(java.awt.Image, int, int, int, int, int)
  727. */
  728. public boolean imageUpdate(Image img, int infoflags,
  729. int x, int y, int w, int h) {
  730. if (!SwingUtilities.doesIconReferenceImage(getIcon(), img) &&
  731. !SwingUtilities.doesIconReferenceImage(getDisabledIcon(), img)) {
  732. return false;
  733. }
  734. return super.imageUpdate(img, infoflags, x, y, w, h);
  735. }
  736. /**
  737. * See readObject() and writeObject() in JComponent for more
  738. * information about serialization in Swing.
  739. */
  740. private void writeObject(ObjectOutputStream s) throws IOException {
  741. s.defaultWriteObject();
  742. if ((ui != null) && (getUIClassID().equals(uiClassID))) {
  743. ui.installUI(this);
  744. }
  745. }
  746. /**
  747. * Returns a string representation of this JLabel. This method
  748. * is intended to be used only for debugging purposes, and the
  749. * content and format of the returned string may vary between
  750. * implementations. The returned string may be empty but may not
  751. * be <code>null</code>.
  752. *
  753. * @return a string representation of this JLabel.
  754. */
  755. protected String paramString() {
  756. String textString = (text != null ?
  757. text : "");
  758. String defaultIconString = ((defaultIcon != null)
  759. && (defaultIcon != this) ?
  760. defaultIcon.toString() : "");
  761. String disabledIconString = ((disabledIcon != null)
  762. && (disabledIcon != this) ?
  763. disabledIcon.toString() : "");
  764. String labelForString = (labelFor != null ?
  765. labelFor.toString() : "");
  766. String verticalAlignmentString;
  767. if (verticalAlignment == TOP) {
  768. verticalAlignmentString = "TOP";
  769. } else if (verticalAlignment == CENTER) {
  770. verticalAlignmentString = "CENTER";
  771. } else if (verticalAlignment == BOTTOM) {
  772. verticalAlignmentString = "BOTTOM";
  773. } else verticalAlignmentString = "";
  774. String horizontalAlignmentString;
  775. if (horizontalAlignment == LEFT) {
  776. horizontalAlignmentString = "LEFT";
  777. } else if (horizontalAlignment == CENTER) {
  778. horizontalAlignmentString = "CENTER";
  779. } else if (horizontalAlignment == RIGHT) {
  780. horizontalAlignmentString = "RIGHT";
  781. } else horizontalAlignmentString = "";
  782. String verticalTextPositionString;
  783. if (verticalTextPosition == TOP) {
  784. verticalTextPositionString = "TOP";
  785. } else if (verticalTextPosition == CENTER) {
  786. verticalTextPositionString = "CENTER";
  787. } else if (verticalTextPosition == BOTTOM) {
  788. verticalTextPositionString = "BOTTOM";
  789. } else verticalTextPositionString = "";
  790. String horizontalTextPositionString;
  791. if (horizontalTextPosition == LEFT) {
  792. horizontalTextPositionString = "LEFT";
  793. } else if (horizontalTextPosition == CENTER) {
  794. horizontalTextPositionString = "CENTER";
  795. } else if (horizontalTextPosition == RIGHT) {
  796. horizontalTextPositionString = "RIGHT";
  797. } else horizontalTextPositionString = "";
  798. return super.paramString() +
  799. ",defaultIcon=" + defaultIconString +
  800. ",disabledIcon=" + disabledIconString +
  801. ",horizontalAlignment=" + horizontalAlignmentString +
  802. ",horizontalTextPosition=" + horizontalTextPositionString +
  803. ",iconTextGap=" + iconTextGap +
  804. ",labelFor=" + labelForString +
  805. ",text=" + textString +
  806. ",verticalAlignment=" + verticalAlignmentString +
  807. ",verticalTextPosition=" + verticalTextPositionString;
  808. }
  809. /**
  810. * --- Accessibility Support ---
  811. */
  812. /**
  813. * Get the component this is labelling.
  814. *
  815. * @return the Component this is labelling. Can be null if this
  816. * does not label a Component. If the displayedMnemonic
  817. * property is set and the labelFor property is also set, the label
  818. * will call the requestFocus method of the component specified by the
  819. * labelFor property when the mnemonic is activated.
  820. *
  821. * @see #getDisplayedMnemonic
  822. * @see #setDisplayedMnemonic
  823. */
  824. public Component getLabelFor() {
  825. return labelFor;
  826. }
  827. /**
  828. * Set the component this is labelling. Can be null if this does not
  829. * label a Component. If the displayedMnemonic property is set
  830. * and the labelFor property is also set, the label will
  831. * call the requestFocus method of the component specified by the
  832. * labelFor property when the mnemonic is activated.
  833. *
  834. * @param c the Component this label is for, or null if the label is
  835. * not the label for a component
  836. *
  837. * @see #getDisplayedMnemonic
  838. * @see #setDisplayedMnemonic
  839. *
  840. * @beaninfo
  841. * bound: true
  842. * description: The component this is labelling.
  843. */
  844. public void setLabelFor(Component c) {
  845. Component oldC = labelFor;
  846. labelFor = c;
  847. firePropertyChange("labelFor", oldC, c);
  848. if (oldC instanceof JComponent) {
  849. ((JComponent)oldC).putClientProperty(LABELED_BY_PROPERTY, null);
  850. }
  851. if (c instanceof JComponent) {
  852. ((JComponent)c).putClientProperty(LABELED_BY_PROPERTY, this);
  853. }
  854. }
  855. /**
  856. * Get the AccessibleContext of this object
  857. *
  858. * @return the AccessibleContext of this object
  859. * @beaninfo
  860. * expert: true
  861. * description: The AccessibleContext associated with this Label.
  862. */
  863. public AccessibleContext getAccessibleContext() {
  864. if (accessibleContext == null) {
  865. accessibleContext = new AccessibleJLabel();
  866. }
  867. return accessibleContext;
  868. }
  869. /**
  870. * The class used to obtain the accessible role for this object.
  871. * <p>
  872. * <strong>Warning:</strong>
  873. * Serialized objects of this class will not be compatible with
  874. * future Swing releases. The current serialization support is appropriate
  875. * for short term storage or RMI between applications running the same
  876. * version of Swing. A future release of Swing will provide support for
  877. * long term persistence.
  878. */
  879. protected class AccessibleJLabel extends AccessibleJComponent
  880. implements AccessibleText {
  881. /**
  882. * Get the accessible name of this object.
  883. *
  884. * @return the localized name of the object -- can be null if this
  885. * object does not have a name
  886. * @see AccessibleContext#setAccessibleName
  887. */
  888. public String getAccessibleName() {
  889. if (accessibleName != null) {
  890. return accessibleName;
  891. } else {
  892. if (JLabel.this.getText() == null) {
  893. return super.getAccessibleName();
  894. } else {
  895. return JLabel.this.getText();
  896. }
  897. }
  898. }
  899. /**
  900. * Get the role of this object.
  901. *
  902. * @return an instance of AccessibleRole describing the role of the
  903. * object
  904. * @see AccessibleRole
  905. */
  906. public AccessibleRole getAccessibleRole() {
  907. return AccessibleRole.LABEL;
  908. }
  909. /**
  910. * Get the AccessibleIcons associated with this object if one
  911. * or more exist. Otherwise return null.
  912. */
  913. public AccessibleIcon [] getAccessibleIcon() {
  914. if (JLabel.this.accessibleIcon == null) {
  915. return null;
  916. } else {
  917. AccessibleIcon [] ac = new AccessibleIcon[1];
  918. ac[0] = JLabel.this.accessibleIcon;
  919. return ac;
  920. }
  921. }
  922. /**
  923. * Get the AccessibleRelationSet associated with this object if one
  924. * exists. Otherwise return null.
  925. * @see AccessibleRelation
  926. */
  927. public AccessibleRelationSet getAccessibleRelationSet() {
  928. // Check where the AccessibleContext's relation
  929. // set already contains a LABEL_FOR relation.
  930. AccessibleRelationSet relationSet
  931. = super.getAccessibleRelationSet();
  932. if (!relationSet.contains(AccessibleRelation.LABEL_FOR)) {
  933. Component c = JLabel.this.getLabelFor();
  934. if (c != null) {
  935. AccessibleRelation relation
  936. = new AccessibleRelation(AccessibleRelation.LABEL_FOR);
  937. relation.setTarget(c);
  938. relationSet.add(relation);
  939. }
  940. }
  941. return relationSet;
  942. }
  943. /* AccessibleText ---------- */
  944. public AccessibleText getAccessibleText() {
  945. View view = (View)JLabel.this.getClientProperty("html");
  946. if (view != null) {
  947. return this;
  948. } else {
  949. return null;
  950. }
  951. }
  952. /**
  953. * Given a point in local coordinates, return the zero-based index
  954. * of the character under that Point. If the point is invalid,
  955. * this method returns -1.
  956. *
  957. * @param p the Point in local coordinates
  958. * @return the zero-based index of the character under Point p; if
  959. * Point is invalid returns -1.
  960. */
  961. public int getIndexAtPoint(Point p) {
  962. View view = (View) JLabel.this.getClientProperty("html");
  963. if (view != null) {
  964. Rectangle r = getTextRectangle();
  965. if (r == null) {
  966. return -1;
  967. }
  968. Rectangle2D.Float shape =
  969. new Rectangle2D.Float(r.x, r.y, r.width, r.height);
  970. Position.Bias bias[] = new Position.Bias[1];
  971. return view.viewToModel(p.x, p.y, shape, bias);
  972. } else {
  973. return -1;
  974. }
  975. }
  976. /**
  977. * Determine the bounding box of the character at the given
  978. * index into the string. The bounds are returned in local
  979. * coordinates. If the index is invalid an empty rectangle is
  980. * returned.
  981. *
  982. * @param i the index into the String
  983. * @return the screen coordinates of the character's the bounding box,
  984. * if index is invalid returns an empty rectangle.
  985. */
  986. public Rectangle getCharacterBounds(int i) {
  987. View view = (View) JLabel.this.getClientProperty("html");
  988. if (view != null) {
  989. Rectangle r = getTextRectangle();
  990. if (r == null) {
  991. return null;
  992. }
  993. Rectangle2D.Float shape =
  994. new Rectangle2D.Float(r.x, r.y, r.width, r.height);
  995. try {
  996. Shape charShape =
  997. view.modelToView(i, shape, Position.Bias.Forward);
  998. return charShape.getBounds();
  999. } catch (BadLocationException e) {
  1000. return null;
  1001. }
  1002. } else {
  1003. return null;
  1004. }
  1005. }
  1006. /**
  1007. * Return the number of characters (valid indicies)
  1008. *
  1009. * @return the number of characters
  1010. */
  1011. public int getCharCount() {
  1012. View view = (View) JLabel.this.getClientProperty("html");
  1013. if (view != null) {
  1014. Document d = view.getDocument();
  1015. if (d instanceof StyledDocument) {
  1016. StyledDocument doc = (StyledDocument)d;
  1017. return doc.getLength();
  1018. }
  1019. }
  1020. return accessibleContext.getAccessibleName().length();
  1021. }
  1022. /**
  1023. * Return the zero-based offset of the caret.
  1024. *
  1025. * Note: That to the right of the caret will have the same index
  1026. * value as the offset (the caret is between two characters).
  1027. * @return the zero-based offset of the caret.
  1028. */
  1029. public int getCaretPosition() {
  1030. // There is no caret.
  1031. return -1;
  1032. }
  1033. /**
  1034. * Returns the String at a given index.
  1035. *
  1036. * @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
  1037. * or AccessibleText.SENTENCE to retrieve
  1038. * @param index an index within the text >= 0
  1039. * @return the letter, word, or sentence,
  1040. * null for an invalid index or part
  1041. */
  1042. public String getAtIndex(int part, int index) {
  1043. if (index < 0 || index >= getCharCount()) {
  1044. return null;
  1045. }
  1046. switch (part) {
  1047. case AccessibleText.CHARACTER:
  1048. try {
  1049. return getText(index, 1);
  1050. } catch (BadLocationException e) {
  1051. return null;
  1052. }
  1053. case AccessibleText.WORD:
  1054. try {
  1055. String s = getText(0, getCharCount());
  1056. BreakIterator words = BreakIterator.getWordInstance();
  1057. words.setText(s);
  1058. int end = words.following(index);
  1059. return s.substring(words.previous(), end);
  1060. } catch (BadLocationException e) {
  1061. return null;
  1062. }
  1063. case AccessibleText.SENTENCE:
  1064. try {
  1065. String s = getText(0, getCharCount());
  1066. BreakIterator sentence =
  1067. BreakIterator.getSentenceInstance();
  1068. sentence.setText(s);
  1069. int end = sentence.following(index);
  1070. return s.substring(sentence.previous(), end);
  1071. } catch (BadLocationException e) {
  1072. return null;
  1073. }
  1074. default:
  1075. return null;
  1076. }
  1077. }
  1078. /**
  1079. * Returns the String after a given index.
  1080. *
  1081. * @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
  1082. * or AccessibleText.SENTENCE to retrieve
  1083. * @param index an index within the text >= 0
  1084. * @return the letter, word, or sentence, null for an invalid
  1085. * index or part
  1086. */
  1087. public String getAfterIndex(int part, int index) {
  1088. if (index < 0 || index >= getCharCount()) {
  1089. return null;
  1090. }
  1091. switch (part) {
  1092. case AccessibleText.CHARACTER:
  1093. if (index+1 >= getCharCount()) {
  1094. return null;
  1095. }
  1096. try {
  1097. return getText(index+1, 1);
  1098. } catch (BadLocationException e) {
  1099. return null;
  1100. }
  1101. case AccessibleText.WORD:
  1102. try {
  1103. String s = getText(0, getCharCount());
  1104. BreakIterator words = BreakIterator.getWordInstance();
  1105. words.setText(s);
  1106. int start = words.following(index);
  1107. if (start == BreakIterator.DONE || start >= s.length()) {
  1108. return null;
  1109. }
  1110. int end = words.following(start);
  1111. if (end == BreakIterator.DONE || end >= s.length()) {
  1112. return null;
  1113. }
  1114. return s.substring(start, end);
  1115. } catch (BadLocationException e) {
  1116. return null;
  1117. }
  1118. case AccessibleText.SENTENCE:
  1119. try {
  1120. String s = getText(0, getCharCount());
  1121. BreakIterator sentence =
  1122. BreakIterator.getSentenceInstance();
  1123. sentence.setText(s);
  1124. int start = sentence.following(index);
  1125. if (start == BreakIterator.DONE || start >= s.length()) {
  1126. return null;
  1127. }
  1128. int end = sentence.following(start);
  1129. if (end == BreakIterator.DONE || end >= s.length()) {
  1130. return null;
  1131. }
  1132. return s.substring(start, end);
  1133. } catch (BadLocationException e) {
  1134. return null;
  1135. }
  1136. default:
  1137. return null;
  1138. }
  1139. }
  1140. /**
  1141. * Returns the String before a given index.
  1142. *
  1143. * @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
  1144. * or AccessibleText.SENTENCE to retrieve
  1145. * @param index an index within the text >= 0
  1146. * @return the letter, word, or sentence, null for an invalid index
  1147. * or part
  1148. */
  1149. public String getBeforeIndex(int part, int index) {
  1150. if (index < 0 || index > getCharCount()-1) {
  1151. return null;
  1152. }
  1153. switch (part) {
  1154. case AccessibleText.CHARACTER:
  1155. if (index == 0) {
  1156. return null;
  1157. }
  1158. try {
  1159. return getText(index-1, 1);
  1160. } catch (BadLocationException e) {
  1161. return null;
  1162. }
  1163. case AccessibleText.WORD:
  1164. try {
  1165. String s = getText(0, getCharCount());
  1166. BreakIterator words = BreakIterator.getWordInstance();
  1167. words.setText(s);
  1168. int end = words.following(index);
  1169. end = words.previous();
  1170. int start = words.previous();
  1171. if (start == BreakIterator.DONE) {
  1172. return null;
  1173. }
  1174. return s.substring(start, end);
  1175. } catch (BadLocationException e) {
  1176. return null;
  1177. }
  1178. case AccessibleText.SENTENCE:
  1179. try {
  1180. String s = getText(0, getCharCount());
  1181. BreakIterator sentence =
  1182. BreakIterator.getSentenceInstance();
  1183. sentence.setText(s);
  1184. int end = sentence.following(index);
  1185. end = sentence.previous();
  1186. int start = sentence.previous();
  1187. if (start == BreakIterator.DONE) {
  1188. return null;
  1189. }
  1190. return s.substring(start, end);
  1191. } catch (BadLocationException e) {
  1192. return null;
  1193. }
  1194. default:
  1195. return null;
  1196. }
  1197. }
  1198. /**
  1199. * Return the AttributeSet for a given character at a given index
  1200. *
  1201. * @param i the zero-based index into the text
  1202. * @return the AttributeSet of the character
  1203. */
  1204. public AttributeSet getCharacterAttribute(int i) {
  1205. View view = (View) JLabel.this.getClientProperty("html");
  1206. if (view != null) {
  1207. Document d = view.getDocument();
  1208. if (d instanceof StyledDocument) {
  1209. StyledDocument doc = (StyledDocument)d;
  1210. Element elem = doc.getCharacterElement(i);
  1211. if (elem != null) {
  1212. return elem.getAttributes();
  1213. }
  1214. }
  1215. }
  1216. return null;
  1217. }
  1218. /**
  1219. * Returns the start offset within the selected text.
  1220. * If there is no selection, but there is
  1221. * a caret, the start and end offsets will be the same.
  1222. *
  1223. * @return the index into the text of the start of the selection
  1224. */
  1225. public int getSelectionStart() {
  1226. // Text cannot be selected.
  1227. return -1;
  1228. }
  1229. /**
  1230. * Returns the end offset within the selected text.
  1231. * If there is no selection, but there is
  1232. * a caret, the start and end offsets will be the same.
  1233. *
  1234. * @return the index into teh text of the end of the selection
  1235. */
  1236. public int getSelectionEnd() {
  1237. // Text cannot be selected.
  1238. return -1;
  1239. }
  1240. /**
  1241. * Returns the portion of the text that is selected.
  1242. *
  1243. * @return the String portion of the text that is selected
  1244. */
  1245. public String getSelectedText() {
  1246. // Text cannot be selected.
  1247. return null;
  1248. }
  1249. /*
  1250. * Returns the text substring starting at the specified
  1251. * offset with the specified length.
  1252. */
  1253. private String getText(int offset, int length)
  1254. throws BadLocationException {
  1255. View view = (View) JLabel.this.getClientProperty("html");
  1256. if (view != null) {
  1257. Document d = view.getDocument();
  1258. if (d instanceof StyledDocument) {
  1259. StyledDocument doc = (StyledDocument)d;
  1260. return doc.getText(offset, length);
  1261. }
  1262. }
  1263. return null;
  1264. }
  1265. /*
  1266. * Returns the bounding rectangle for the component text.
  1267. */
  1268. private Rectangle getTextRectangle() {
  1269. String text = JLabel.this.getText();
  1270. Icon icon = (JLabel.this.isEnabled()) ? JLabel.this.getIcon() : JLabel.this.getDisabledIcon();
  1271. if ((icon == null) && (text == null)) {
  1272. return null;
  1273. }
  1274. Rectangle paintIconR = new Rectangle();
  1275. Rectangle paintTextR = new Rectangle();
  1276. Rectangle paintViewR = new Rectangle();
  1277. Insets paintViewInsets = new Insets(0, 0, 0, 0);
  1278. paintViewInsets = JLabel.this.getInsets(paintViewInsets);
  1279. paintViewR.x = paintViewInsets.left;
  1280. paintViewR.y = paintViewInsets.top;
  1281. paintViewR.width = JLabel.this.getWidth() - (paintViewInsets.left + paintViewInsets.right);
  1282. paintViewR.height = JLabel.this.getHeight() - (paintViewInsets.top + paintViewInsets.bottom);
  1283. Graphics g = JLabel.this.getGraphics();
  1284. if (g == null) {
  1285. return null;
  1286. }
  1287. String clippedText = SwingUtilities.layoutCompoundLabel(
  1288. (JComponent)JLabel.this,
  1289. g.getFontMetrics(),
  1290. text,
  1291. icon,
  1292. JLabel.this.getVerticalAlignment(),
  1293. JLabel.this.getHorizontalAlignment(),
  1294. JLabel.this.getVerticalTextPosition(),
  1295. JLabel.this.getHorizontalTextPosition(),
  1296. paintViewR,
  1297. paintIconR,
  1298. paintTextR,
  1299. JLabel.this.getIconTextGap());
  1300. return paintTextR;
  1301. }
  1302. } // AccessibleJComponent
  1303. }