1. /*
  2. * @(#)ImageIcon.java 1.50 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing;
  8. import java.awt.*;
  9. import java.awt.image.*;
  10. import java.net.URL;
  11. import java.io.Serializable;
  12. import java.io.ObjectOutputStream;
  13. import java.io.ObjectInputStream;
  14. import java.io.IOException;
  15. import java.util.Locale;
  16. import javax.accessibility.*;
  17. /**
  18. * An implementation of the Icon interface that paints Icons
  19. * from Images. Images that are created from a URL or filename
  20. * are preloaded using MediaTracker to monitor the loaded state
  21. * of the image.
  22. *
  23. * <p>
  24. * For further information and examples of using image icons, see
  25. * <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/icon.html">How to Use Icons</a>
  26. * in <em>The Java Tutorial.</em>
  27. *
  28. * <p>
  29. * <strong>Warning:</strong>
  30. * Serialized objects of this class will not be compatible with
  31. * future Swing releases. The current serialization support is
  32. * appropriate for short term storage or RMI between applications running
  33. * the same version of Swing. As of 1.4, support for long term storage
  34. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  35. * has been added to the <code>java.beans</code> package.
  36. * Please see {@link java.beans.XMLEncoder}.
  37. *
  38. * @version 1.50 01/23/03
  39. * @author Jeff Dinkins
  40. * @author Lynn Monsanto
  41. */
  42. public class ImageIcon implements Icon, Serializable, Accessible {
  43. /* Keep references to the filename and location so that
  44. * alternate persistence schemes have the option to archive
  45. * images symbolically rather than including the image data
  46. * in the archive.
  47. */
  48. transient private String filename;
  49. transient private URL location;
  50. transient Image image;
  51. transient int loadStatus = 0;
  52. ImageObserver imageObserver;
  53. String description = null;
  54. protected final static Component component = new Component() {};
  55. protected final static MediaTracker tracker = new MediaTracker(component);
  56. /**
  57. * Id used in loading images from MediaTracker.
  58. */
  59. private static int mediaTrackerID;
  60. int width = -1;
  61. int height = -1;
  62. /**
  63. * Creates an ImageIcon from the specified file. The image will
  64. * be preloaded by using MediaTracker to monitor the loading state
  65. * of the image.
  66. * @param filename the name of the file containing the image
  67. * @param description a brief textual description of the image
  68. * @see #ImageIcon(String)
  69. */
  70. public ImageIcon(String filename, String description) {
  71. image = Toolkit.getDefaultToolkit().getImage(filename);
  72. if (image == null) {
  73. return;
  74. }
  75. this.filename = filename;
  76. this.description = description;
  77. loadImage(image);
  78. }
  79. /**
  80. * Creates an ImageIcon from the specified file. The image will
  81. * be preloaded by using MediaTracker to monitor the loading state
  82. * of the image. The specified String can be a file name or a
  83. * file path. When specifying a path, use the Internet-standard
  84. * forward-slash ("/") as a separator.
  85. * (The string is converted to an URL, so the forward-slash works
  86. * on all systems.)
  87. * For example, specify:
  88. * <pre>
  89. * new ImageIcon("images/myImage.gif") </pre>
  90. * The description is initialized to the <code>filename</code> string.
  91. *
  92. * @param filename a String specifying a filename or path
  93. * @see #getDescription
  94. */
  95. public ImageIcon (String filename) {
  96. this(filename, filename);
  97. }
  98. /**
  99. * Creates an ImageIcon from the specified URL. The image will
  100. * be preloaded by using MediaTracker to monitor the loaded state
  101. * of the image.
  102. * @param location the URL for the image
  103. * @param description a brief textual description of the image
  104. * @see #ImageIcon(String)
  105. */
  106. public ImageIcon(URL location, String description) {
  107. image = Toolkit.getDefaultToolkit().getImage(location);
  108. if (image == null) {
  109. return;
  110. }
  111. this.location = location;
  112. this.description = description;
  113. loadImage(image);
  114. }
  115. /**
  116. * Creates an ImageIcon from the specified URL. The image will
  117. * be preloaded by using MediaTracker to monitor the loaded state
  118. * of the image.
  119. * The icon's description is initialized to be
  120. * a string representation of the URL.
  121. * @param location the URL for the image
  122. * @see #getDescription
  123. */
  124. public ImageIcon (URL location) {
  125. this(location, location.toExternalForm());
  126. }
  127. /**
  128. * Creates an ImageIcon from the image.
  129. * @param image the image
  130. * @param description a brief textual description of the image
  131. */
  132. public ImageIcon(Image image, String description) {
  133. this(image);
  134. this.description = description;
  135. }
  136. /**
  137. * Creates an ImageIcon from an image object.
  138. * If the image has a "comment" property that is a string,
  139. * then the string is used as the description of this icon.
  140. * @param image the image
  141. * @see #getDescription
  142. * @see java.awt.Image#getProperty
  143. */
  144. public ImageIcon (Image image) {
  145. this.image = image;
  146. Object o = image.getProperty("comment", imageObserver);
  147. if (o instanceof String) {
  148. description = (String) o;
  149. }
  150. loadImage(image);
  151. }
  152. /**
  153. * Creates an ImageIcon from an array of bytes which were
  154. * read from an image file containing a supported image format,
  155. * such as GIF or JPEG. Normally this array is created
  156. * by reading an image using Class.getResourceAsStream(), but
  157. * the byte array may also be statically stored in a class.
  158. *
  159. * @param imageData an array of pixels in an image format supported
  160. * by the AWT Toolkit, such as GIF or JPEG.
  161. * @param description a brief textual description of the image
  162. * @see java.awt.Toolkit#createImage
  163. */
  164. public ImageIcon (byte[] imageData, String description) {
  165. this.image = Toolkit.getDefaultToolkit().createImage(imageData);
  166. if (image == null) {
  167. return;
  168. }
  169. this.description = description;
  170. loadImage(image);
  171. }
  172. /**
  173. * Creates an ImageIcon from an array of bytes which were
  174. * read from an image file containing a supported image format,
  175. * such as GIF or JPEG. Normally this array is created
  176. * by reading an image using Class.getResourceAsStream(), but
  177. * the byte array may also be statically stored in a class.
  178. * If the resulting image has a "comment" property that is a string,
  179. * then the string is used as the description of this icon.
  180. *
  181. * @param imageData an array of pixels in an image format supported by
  182. * the AWT Toolkit, such as GIF or JPEG
  183. * @see java.awt.Toolkit#createImage
  184. * @see #getDescription
  185. * @see java.awt.Image#getProperty
  186. */
  187. public ImageIcon (byte[] imageData) {
  188. this.image = Toolkit.getDefaultToolkit().createImage(imageData);
  189. if (image == null) {
  190. return;
  191. }
  192. Object o = image.getProperty("comment", imageObserver);
  193. if (o instanceof String) {
  194. description = (String) o;
  195. }
  196. loadImage(image);
  197. }
  198. /**
  199. * Creates an uninitialized image icon.
  200. */
  201. public ImageIcon() {
  202. }
  203. /**
  204. * Loads the image, returning only when the image is loaded.
  205. * @param image the image
  206. */
  207. protected void loadImage(Image image) {
  208. synchronized(tracker) {
  209. int id = getNextID();
  210. tracker.addImage(image, id);
  211. try {
  212. tracker.waitForID(id, 0);
  213. } catch (InterruptedException e) {
  214. System.out.println("INTERRUPTED while loading Image");
  215. }
  216. loadStatus = tracker.statusID(id, false);
  217. tracker.removeImage(image, id);
  218. width = image.getWidth(imageObserver);
  219. height = image.getHeight(imageObserver);
  220. }
  221. }
  222. /**
  223. * Returns an ID to use with the MediaTracker in loading an image.
  224. */
  225. private int getNextID() {
  226. synchronized(tracker) {
  227. return ++mediaTrackerID;
  228. }
  229. }
  230. /**
  231. * Returns the status of the image loading operation.
  232. * @return the loading status as defined by java.awt.MediaTracker
  233. * @see java.awt.MediaTracker#ABORTED
  234. * @see java.awt.MediaTracker#ERRORED
  235. * @see java.awt.MediaTracker#COMPLETE
  236. */
  237. public int getImageLoadStatus() {
  238. return loadStatus;
  239. }
  240. /**
  241. * Returns this icon's <code>Image</code>.
  242. * @return the <code>Image</code> object for this <code>ImageIcon</code>
  243. */
  244. public Image getImage() {
  245. return image;
  246. }
  247. /**
  248. * Sets the image displayed by this icon.
  249. * @param image the image
  250. */
  251. public void setImage(Image image) {
  252. this.image = image;
  253. loadImage(image);
  254. }
  255. /**
  256. * Gets the description of the image. This is meant to be a brief
  257. * textual description of the object. For example, it might be
  258. * presented to a blind user to give an indication of the purpose
  259. * of the image.
  260. * The description may be null.
  261. *
  262. * @return a brief textual description of the image
  263. */
  264. public String getDescription() {
  265. return description;
  266. }
  267. /**
  268. * Sets the description of the image. This is meant to be a brief
  269. * textual description of the object. For example, it might be
  270. * presented to a blind user to give an indication of the purpose
  271. * of the image.
  272. * @param description a brief textual description of the image
  273. */
  274. public void setDescription(String description) {
  275. this.description = description;
  276. }
  277. /**
  278. * Paints the icon.
  279. * The top-left corner of the icon is drawn at
  280. * the point (<code>x</code>, <code>y</code>)
  281. * in the coordinate space of the graphics context <code>g</code>.
  282. * If this icon has no image observer,
  283. * this method uses the <code>c</code> component
  284. * as the observer.
  285. *
  286. * @param c the component to be used as the observer
  287. * if this icon has no image observer
  288. * @param g the graphics context
  289. * @param x the X coordinate of the icon's top-left corner
  290. * @param y the Y coordinate of the icon's top-left corner
  291. */
  292. public synchronized void paintIcon(Component c, Graphics g, int x, int y) {
  293. if(imageObserver == null) {
  294. g.drawImage(image, x, y, c);
  295. } else {
  296. g.drawImage(image, x, y, imageObserver);
  297. }
  298. }
  299. /**
  300. * Gets the width of the icon.
  301. *
  302. * @return the width in pixels of this icon
  303. */
  304. public int getIconWidth() {
  305. return width;
  306. }
  307. /**
  308. * Gets the height of the icon.
  309. *
  310. * @return the height in pixels of this icon
  311. */
  312. public int getIconHeight() {
  313. return height;
  314. }
  315. /**
  316. * Sets the image observer for the image. Set this
  317. * property if the ImageIcon contains an animated GIF, so
  318. * the observer is notified to update its display.
  319. * For example:
  320. * <pre>
  321. * icon = new ImageIcon(...)
  322. * button.setIcon(icon);
  323. * icon.setImageObserver(button);
  324. * </pre>
  325. *
  326. * @param observer the image observer
  327. */
  328. public void setImageObserver(ImageObserver observer) {
  329. imageObserver = observer;
  330. }
  331. /**
  332. * Returns the image observer for the image.
  333. *
  334. * @return the image observer, which may be null
  335. */
  336. public ImageObserver getImageObserver() {
  337. return imageObserver;
  338. }
  339. /**
  340. * Returns a string representation of this image.
  341. *
  342. * @return a string representing this image
  343. */
  344. public String toString() {
  345. if (description != null) {
  346. return description;
  347. }
  348. return super.toString();
  349. }
  350. private void readObject(ObjectInputStream s)
  351. throws ClassNotFoundException, IOException
  352. {
  353. s.defaultReadObject();
  354. int w = s.readInt();
  355. int h = s.readInt();
  356. int[] pixels = (int[])(s.readObject());
  357. if (pixels != null) {
  358. Toolkit tk = Toolkit.getDefaultToolkit();
  359. ColorModel cm = ColorModel.getRGBdefault();
  360. image = tk.createImage(new MemoryImageSource(w, h, cm, pixels, 0, w));
  361. }
  362. }
  363. private void writeObject(ObjectOutputStream s)
  364. throws IOException
  365. {
  366. s.defaultWriteObject();
  367. int w = getIconWidth();
  368. int h = getIconHeight();
  369. int[] pixels = image != null? new int[w * h] : null;
  370. if (image != null) {
  371. try {
  372. PixelGrabber pg = new PixelGrabber(image, 0, 0, w, h, pixels, 0, w);
  373. pg.grabPixels();
  374. if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
  375. throw new IOException("failed to load image contents");
  376. }
  377. }
  378. catch (InterruptedException e) {
  379. throw new IOException("image load interrupted");
  380. }
  381. }
  382. s.writeInt(w);
  383. s.writeInt(h);
  384. s.writeObject(pixels);
  385. }
  386. /**
  387. * --- Accessibility Support ---
  388. */
  389. private AccessibleImageIcon accessibleContext = null;
  390. /**
  391. * Gets the AccessibleContext associated with this ImageIcon.
  392. * For image icons, the AccessibleContext takes the form of an
  393. * AccessibleImageIcon.
  394. * A new AccessibleImageIcon instance is created if necessary.
  395. *
  396. * @return an AccessibleImageIcon that serves as the
  397. * AccessibleContext of this ImageIcon
  398. * @beaninfo
  399. * expert: true
  400. * description: The AccessibleContext associated with this ImageIcon.
  401. */
  402. public AccessibleContext getAccessibleContext() {
  403. if (accessibleContext == null) {
  404. accessibleContext = new AccessibleImageIcon();
  405. }
  406. return accessibleContext;
  407. }
  408. /**
  409. * This class implements accessibility support for the
  410. * <code>ImageIcon</code> class. It provides an implementation of the
  411. * Java Accessibility API appropriate to image icon user-interface
  412. * elements.
  413. * <p>
  414. * <strong>Warning:</strong>
  415. * Serialized objects of this class will not be compatible with
  416. * future Swing releases. The current serialization support is
  417. * appropriate for short term storage or RMI between applications running
  418. * the same version of Swing. As of 1.4, support for long term storage
  419. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  420. * has been added to the <code>java.beans</code> package.
  421. * Please see {@link java.beans.XMLEncoder}.
  422. */
  423. protected class AccessibleImageIcon extends AccessibleContext
  424. implements AccessibleIcon, Serializable {
  425. /*
  426. * AccessibleContest implementation -----------------
  427. */
  428. /**
  429. * Gets the role of this object.
  430. *
  431. * @return an instance of AccessibleRole describing the role of the
  432. * object
  433. * @see AccessibleRole
  434. */
  435. public AccessibleRole getAccessibleRole() {
  436. return AccessibleRole.ICON;
  437. }
  438. /**
  439. * Gets the state of this object.
  440. *
  441. * @return an instance of AccessibleStateSet containing the current
  442. * state set of the object
  443. * @see AccessibleState
  444. */
  445. public AccessibleStateSet getAccessibleStateSet() {
  446. return null;
  447. }
  448. /**
  449. * Gets the Accessible parent of this object. If the parent of this
  450. * object implements Accessible, this method should simply return
  451. * getParent().
  452. *
  453. * @return the Accessible parent of this object -- can be null if this
  454. * object does not have an Accessible parent
  455. */
  456. public Accessible getAccessibleParent() {
  457. return null;
  458. }
  459. /**
  460. * Gets the index of this object in its accessible parent.
  461. *
  462. * @return the index of this object in its parent; -1 if this
  463. * object does not have an accessible parent.
  464. * @see #getAccessibleParent
  465. */
  466. public int getAccessibleIndexInParent() {
  467. return -1;
  468. }
  469. /**
  470. * Returns the number of accessible children in the object. If all
  471. * of the children of this object implement Accessible, than this
  472. * method should return the number of children of this object.
  473. *
  474. * @return the number of accessible children in the object.
  475. */
  476. public int getAccessibleChildrenCount() {
  477. return 0;
  478. }
  479. /**
  480. * Returns the nth Accessible child of the object.
  481. *
  482. * @param i zero-based index of child
  483. * @return the nth Accessible child of the object
  484. */
  485. public Accessible getAccessibleChild(int i) {
  486. return null;
  487. }
  488. /**
  489. * Returns the locale of this object.
  490. *
  491. * @return the locale of this object
  492. */
  493. public Locale getLocale() throws IllegalComponentStateException {
  494. return null;
  495. }
  496. /*
  497. * AccessibleIcon implementation -----------------
  498. */
  499. /**
  500. * Gets the description of the icon. This is meant to be a brief
  501. * textual description of the object. For example, it might be
  502. * presented to a blind user to give an indication of the purpose
  503. * of the icon.
  504. *
  505. * @return the description of the icon
  506. */
  507. public String getAccessibleIconDescription() {
  508. return ImageIcon.this.getDescription();
  509. }
  510. /**
  511. * Sets the description of the icon. This is meant to be a brief
  512. * textual description of the object. For example, it might be
  513. * presented to a blind user to give an indication of the purpose
  514. * of the icon.
  515. *
  516. * @param description the description of the icon
  517. */
  518. public void setAccessibleIconDescription(String description) {
  519. ImageIcon.this.setDescription(description);
  520. }
  521. /**
  522. * Gets the height of the icon.
  523. *
  524. * @return the height of the icon
  525. */
  526. public int getAccessibleIconHeight() {
  527. return ImageIcon.this.height;
  528. }
  529. /**
  530. * Gets the width of the icon.
  531. *
  532. * @return the width of the icon
  533. */
  534. public int getAccessibleIconWidth() {
  535. return ImageIcon.this.width;
  536. }
  537. private void readObject(ObjectInputStream s)
  538. throws ClassNotFoundException, IOException
  539. {
  540. s.defaultReadObject();
  541. }
  542. private void writeObject(ObjectOutputStream s)
  543. throws IOException
  544. {
  545. s.defaultWriteObject();
  546. }
  547. } // AccessibleImageIcon
  548. }