1. /*
  2. * @(#)MediaTracker.java 1.39 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 java.awt;
  8. import java.awt.Component;
  9. import java.awt.Image;
  10. import java.awt.Graphics;
  11. import java.awt.image.ImageObserver;
  12. /**
  13. * The <code>MediaTracker</code> class is a utility class to track
  14. * the status of a number of media objects. Media objects could
  15. * include audio clips as well as images, though currently only
  16. * images are supported.
  17. * <p>
  18. * To use a media tracker, create an instance of
  19. * <code>MediaTracker</code> and call its <code>addImage</code>
  20. * method for each image to be tracked. In addition, each image can
  21. * be assigned a unique identifier. This identifier controls the
  22. * priority order in which the images are fetched. It can also be used
  23. * to identify unique subsets of the images that can be waited on
  24. * independently. Images with a lower ID are loaded in preference to
  25. * those with a higher ID number.
  26. * <p>
  27. * Here is an example:
  28. * <p>
  29. * <hr><blockquote><pre>
  30. * import java.applet.Applet;
  31. * import java.awt.Color;
  32. * import java.awt.Image;
  33. * import java.awt.Graphics;
  34. * import java.awt.MediaTracker;
  35. *
  36. * public class ImageBlaster extends Applet implements Runnable {
  37. * MediaTracker tracker;
  38. * Image bg;
  39. * Image anim[] = new Image[5];
  40. * int index;
  41. * Thread animator;
  42. *
  43. * // Get the images for the background (id == 0)
  44. * // and the animation frames (id == 1)
  45. * // and add them to the MediaTracker
  46. * public void init() {
  47. * tracker = new MediaTracker(this);
  48. * bg = getImage(getDocumentBase(),
  49. * "images/background.gif");
  50. * tracker.addImage(bg, 0);
  51. * for (int i = 0; i < 5; i++) {
  52. * anim[i] = getImage(getDocumentBase(),
  53. * "images/anim"+i+".gif");
  54. * tracker.addImage(anim[i], 1);
  55. * }
  56. * }
  57. *
  58. * // Start the animation thread.
  59. * public void start() {
  60. * animator = new Thread(this);
  61. * animator.start();
  62. * }
  63. *
  64. * // Stop the animation thread.
  65. * public void stop() {
  66. * animator = null;
  67. * }
  68. *
  69. * // Run the animation thread.
  70. * // First wait for the background image to fully load
  71. * // and paint. Then wait for all of the animation
  72. * // frames to finish loading. Finally, loop and
  73. * // increment the animation frame index.
  74. * public void run() {
  75. * try {
  76. * tracker.waitForID(0);
  77. * tracker.waitForID(1);
  78. * } catch (InterruptedException e) {
  79. * return;
  80. * }
  81. * Thread me = Thread.currentThread();
  82. * while (animator == me) {
  83. * try {
  84. * Thread.sleep(100);
  85. * } catch (InterruptedException e) {
  86. * break;
  87. * }
  88. * synchronized (this) {
  89. * index++;
  90. * if (index >= anim.length) {
  91. * index = 0;
  92. * }
  93. * }
  94. * repaint();
  95. * }
  96. * }
  97. *
  98. * // The background image fills the frame so we
  99. * // don't need to clear the applet on repaints.
  100. * // Just call the paint method.
  101. * public void update(Graphics g) {
  102. * paint(g);
  103. * }
  104. *
  105. * // Paint a large red rectangle if there are any errors
  106. * // loading the images. Otherwise always paint the
  107. * // background so that it appears incrementally as it
  108. * // is loading. Finally, only paint the current animation
  109. * // frame if all of the frames (id == 1) are done loading,
  110. * // so that we don't get partial animations.
  111. * public void paint(Graphics g) {
  112. * if ((tracker.statusAll(false) & MediaTracker.ERRORED) != 0) {
  113. * g.setColor(Color.red);
  114. * g.fillRect(0, 0, size().width, size().height);
  115. * return;
  116. * }
  117. * g.drawImage(bg, 0, 0, this);
  118. * if (tracker.statusID(1, false) == MediaTracker.COMPLETE) {
  119. * g.drawImage(anim[index], 10, 10, this);
  120. * }
  121. * }
  122. * }
  123. * </pre></blockquote><hr>
  124. * <p>
  125. * @version 1.39, 01/23/03
  126. * @author Jim Graham
  127. * @since JDK1.0
  128. */
  129. public class MediaTracker implements java.io.Serializable {
  130. /**
  131. * A given <code>Component</code> that will be
  132. * tracked by a media tracker where the image will
  133. * eventually be drawn.
  134. *
  135. * @serial
  136. * @see #MediaTracker(Component)
  137. */
  138. Component target;
  139. /**
  140. * The head of the list of <code>Images</code> that is being
  141. * tracked by the <code>MediaTracker</code>.
  142. *
  143. * @serial
  144. * @see #addImage(Image, int)
  145. * @see #removeImage(Image)
  146. */
  147. MediaEntry head;
  148. /*
  149. * JDK 1.1 serialVersionUID
  150. */
  151. private static final long serialVersionUID = -483174189758638095L;
  152. /**
  153. * Creates a media tracker to track images for a given component.
  154. * @param comp the component on which the images
  155. * will eventually be drawn
  156. */
  157. public MediaTracker(Component comp) {
  158. target = comp;
  159. }
  160. /**
  161. * Adds an image to the list of images being tracked by this media
  162. * tracker. The image will eventually be rendered at its default
  163. * (unscaled) size.
  164. * @param image the image to be tracked
  165. * @param id an identifier used to track this image
  166. */
  167. public void addImage(Image image, int id) {
  168. addImage(image, id, -1, -1);
  169. }
  170. /**
  171. * Adds a scaled image to the list of images being tracked
  172. * by this media tracker. The image will eventually be
  173. * rendered at the indicated width and height.
  174. *
  175. * @param image the image to be tracked
  176. * @param id an identifier that can be used to track this image
  177. * @param w the width at which the image is rendered
  178. * @param h the height at which the image is rendered
  179. */
  180. public synchronized void addImage(Image image, int id, int w, int h) {
  181. head = MediaEntry.insert(head,
  182. new ImageMediaEntry(this, image, id, w, h));
  183. }
  184. /**
  185. * Flag indicating that media is currently being loaded.
  186. * @see java.awt.MediaTracker#statusAll
  187. * @see java.awt.MediaTracker#statusID
  188. */
  189. public static final int LOADING = 1;
  190. /**
  191. * Flag indicating that the downloading of media was aborted.
  192. * @see java.awt.MediaTracker#statusAll
  193. * @see java.awt.MediaTracker#statusID
  194. */
  195. public static final int ABORTED = 2;
  196. /**
  197. * Flag indicating that the downloading of media encountered
  198. * an error.
  199. * @see java.awt.MediaTracker#statusAll
  200. * @see java.awt.MediaTracker#statusID
  201. */
  202. public static final int ERRORED = 4;
  203. /**
  204. * Flag indicating that the downloading of media was completed
  205. * successfully.
  206. * @see java.awt.MediaTracker#statusAll
  207. * @see java.awt.MediaTracker#statusID
  208. */
  209. public static final int COMPLETE = 8;
  210. static final int DONE = (ABORTED | ERRORED | COMPLETE);
  211. /**
  212. * Checks to see if all images being tracked by this media tracker
  213. * have finished loading.
  214. * <p>
  215. * This method does not start loading the images if they are not
  216. * already loading.
  217. * <p>
  218. * If there is an error while loading or scaling an image, then that
  219. * image is considered to have finished loading. Use the
  220. * <code>isErrorAny</code> or <code>isErrorID</code> methods to
  221. * check for errors.
  222. * @return <code>true</code> if all images have finished loading,
  223. * have been aborted, or have encountered
  224. * an error; <code>false</code> otherwise
  225. * @see java.awt.MediaTracker#checkAll(boolean)
  226. * @see java.awt.MediaTracker#checkID
  227. * @see java.awt.MediaTracker#isErrorAny
  228. * @see java.awt.MediaTracker#isErrorID
  229. */
  230. public boolean checkAll() {
  231. return checkAll(false, true);
  232. }
  233. /**
  234. * Checks to see if all images being tracked by this media tracker
  235. * have finished loading.
  236. * <p>
  237. * If the value of the <code>load</code> flag is <code>true</code>,
  238. * then this method starts loading any images that are not yet
  239. * being loaded.
  240. * <p>
  241. * If there is an error while loading or scaling an image, that
  242. * image is considered to have finished loading. Use the
  243. * <code>isErrorAny</code> and <code>isErrorID</code> methods to
  244. * check for errors.
  245. * @param load if <code>true</code>, start loading any
  246. * images that are not yet being loaded
  247. * @return <code>true</code> if all images have finished loading,
  248. * have been aborted, or have encountered
  249. * an error; <code>false</code> otherwise
  250. * @see java.awt.MediaTracker#checkID
  251. * @see java.awt.MediaTracker#checkAll()
  252. * @see java.awt.MediaTracker#isErrorAny()
  253. * @see java.awt.MediaTracker#isErrorID(int)
  254. */
  255. public boolean checkAll(boolean load) {
  256. return checkAll(load, true);
  257. }
  258. private synchronized boolean checkAll(boolean load, boolean verify) {
  259. MediaEntry cur = head;
  260. boolean done = true;
  261. while (cur != null) {
  262. if ((cur.getStatus(load, verify) & DONE) == 0) {
  263. done = false;
  264. }
  265. cur = cur.next;
  266. }
  267. return done;
  268. }
  269. /**
  270. * Checks the error status of all of the images.
  271. * @return <code>true</code> if any of the images tracked
  272. * by this media tracker had an error during
  273. * loading; <code>false</code> otherwise
  274. * @see java.awt.MediaTracker#isErrorID
  275. * @see java.awt.MediaTracker#getErrorsAny
  276. */
  277. public synchronized boolean isErrorAny() {
  278. MediaEntry cur = head;
  279. while (cur != null) {
  280. if ((cur.getStatus(false, true) & ERRORED) != 0) {
  281. return true;
  282. }
  283. cur = cur.next;
  284. }
  285. return false;
  286. }
  287. /**
  288. * Returns a list of all media that have encountered an error.
  289. * @return an array of media objects tracked by this
  290. * media tracker that have encountered
  291. * an error, or <code>null</code> if
  292. * there are none with errors
  293. * @see java.awt.MediaTracker#isErrorAny
  294. * @see java.awt.MediaTracker#getErrorsID
  295. */
  296. public synchronized Object[] getErrorsAny() {
  297. MediaEntry cur = head;
  298. int numerrors = 0;
  299. while (cur != null) {
  300. if ((cur.getStatus(false, true) & ERRORED) != 0) {
  301. numerrors++;
  302. }
  303. cur = cur.next;
  304. }
  305. if (numerrors == 0) {
  306. return null;
  307. }
  308. Object errors[] = new Object[numerrors];
  309. cur = head;
  310. numerrors = 0;
  311. while (cur != null) {
  312. if ((cur.getStatus(false, false) & ERRORED) != 0) {
  313. errors[numerrors++] = cur.getMedia();
  314. }
  315. cur = cur.next;
  316. }
  317. return errors;
  318. }
  319. /**
  320. * Starts loading all images tracked by this media tracker. This
  321. * method waits until all the images being tracked have finished
  322. * loading.
  323. * <p>
  324. * If there is an error while loading or scaling an image, then that
  325. * image is considered to have finished loading. Use the
  326. * <code>isErrorAny</code> or <code>isErrorID</code> methods to
  327. * check for errors.
  328. * @see java.awt.MediaTracker#waitForID(int)
  329. * @see java.awt.MediaTracker#waitForAll(long)
  330. * @see java.awt.MediaTracker#isErrorAny
  331. * @see java.awt.MediaTracker#isErrorID
  332. * @exception InterruptedException if another thread has
  333. * interrupted this thread
  334. */
  335. public void waitForAll() throws InterruptedException {
  336. waitForAll(0);
  337. }
  338. /**
  339. * Starts loading all images tracked by this media tracker. This
  340. * method waits until all the images being tracked have finished
  341. * loading, or until the length of time specified in milliseconds
  342. * by the <code>ms</code> argument has passed.
  343. * <p>
  344. * If there is an error while loading or scaling an image, then
  345. * that image is considered to have finished loading. Use the
  346. * <code>isErrorAny</code> or <code>isErrorID</code> methods to
  347. * check for errors.
  348. * @param ms the number of milliseconds to wait
  349. * for the loading to complete
  350. * @return <code>true</code> if all images were successfully
  351. * loaded; <code>false</code> otherwise
  352. * @see java.awt.MediaTracker#waitForID(int)
  353. * @see java.awt.MediaTracker#waitForAll(long)
  354. * @see java.awt.MediaTracker#isErrorAny
  355. * @see java.awt.MediaTracker#isErrorID
  356. * @exception InterruptedException if another thread has
  357. * interrupted this thread.
  358. */
  359. public synchronized boolean waitForAll(long ms)
  360. throws InterruptedException
  361. {
  362. long end = System.currentTimeMillis() + ms;
  363. boolean first = true;
  364. while (true) {
  365. int status = statusAll(first, first);
  366. if ((status & LOADING) == 0) {
  367. return (status == COMPLETE);
  368. }
  369. first = false;
  370. long timeout;
  371. if (ms == 0) {
  372. timeout = 0;
  373. } else {
  374. timeout = end - System.currentTimeMillis();
  375. if (timeout <= 0) {
  376. return false;
  377. }
  378. }
  379. wait(timeout);
  380. }
  381. }
  382. /**
  383. * Calculates and returns the bitwise inclusive <b>OR</b> of the
  384. * status of all media that are tracked by this media tracker.
  385. * <p>
  386. * Possible flags defined by the
  387. * <code>MediaTracker</code> class are <code>LOADING</code>,
  388. * <code>ABORTED</code>, <code>ERRORED</code>, and
  389. * <code>COMPLETE</code>. An image that hasn't started
  390. * loading has zero as its status.
  391. * <p>
  392. * If the value of <code>load</code> is <code>true</code>, then
  393. * this method starts loading any images that are not yet being loaded.
  394. *
  395. * @param load if <code>true</code>, start loading
  396. * any images that are not yet being loaded
  397. * @return the bitwise inclusive <b>OR</b> of the status of
  398. * all of the media being tracked
  399. * @see java.awt.MediaTracker#statusID(int, boolean)
  400. * @see java.awt.MediaTracker#LOADING
  401. * @see java.awt.MediaTracker#ABORTED
  402. * @see java.awt.MediaTracker#ERRORED
  403. * @see java.awt.MediaTracker#COMPLETE
  404. */
  405. public int statusAll(boolean load) {
  406. return statusAll(load, true);
  407. }
  408. private synchronized int statusAll(boolean load, boolean verify) {
  409. MediaEntry cur = head;
  410. int status = 0;
  411. while (cur != null) {
  412. status = status | cur.getStatus(load, verify);
  413. cur = cur.next;
  414. }
  415. return status;
  416. }
  417. /**
  418. * Checks to see if all images tracked by this media tracker that
  419. * are tagged with the specified identifier have finished loading.
  420. * <p>
  421. * This method does not start loading the images if they are not
  422. * already loading.
  423. * <p>
  424. * If there is an error while loading or scaling an image, then that
  425. * image is considered to have finished loading. Use the
  426. * <code>isErrorAny</code> or <code>isErrorID</code> methods to
  427. * check for errors.
  428. * @param id the identifier of the images to check
  429. * @return <code>true</code> if all images have finished loading,
  430. * have been aborted, or have encountered
  431. * an error; <code>false</code> otherwise
  432. * @see java.awt.MediaTracker#checkID(int, boolean)
  433. * @see java.awt.MediaTracker#checkAll()
  434. * @see java.awt.MediaTracker#isErrorAny()
  435. * @see java.awt.MediaTracker#isErrorID(int)
  436. */
  437. public boolean checkID(int id) {
  438. return checkID(id, false, true);
  439. }
  440. /**
  441. * Checks to see if all images tracked by this media tracker that
  442. * are tagged with the specified identifier have finished loading.
  443. * <p>
  444. * If the value of the <code>load</code> flag is <code>true</code>,
  445. * then this method starts loading any images that are not yet
  446. * being loaded.
  447. * <p>
  448. * If there is an error while loading or scaling an image, then that
  449. * image is considered to have finished loading. Use the
  450. * <code>isErrorAny</code> or <code>isErrorID</code> methods to
  451. * check for errors.
  452. * @param id the identifier of the images to check
  453. * @param load if <code>true</code>, start loading any
  454. * images that are not yet being loaded
  455. * @return <code>true</code> if all images have finished loading,
  456. * have been aborted, or have encountered
  457. * an error; <code>false</code> otherwise
  458. * @see java.awt.MediaTracker#checkID(int, boolean)
  459. * @see java.awt.MediaTracker#checkAll()
  460. * @see java.awt.MediaTracker#isErrorAny()
  461. * @see java.awt.MediaTracker#isErrorID(int)
  462. */
  463. public boolean checkID(int id, boolean load) {
  464. return checkID(id, load, true);
  465. }
  466. private synchronized boolean checkID(int id, boolean load, boolean verify)
  467. {
  468. MediaEntry cur = head;
  469. boolean done = true;
  470. while (cur != null) {
  471. if (cur.getID() == id
  472. && (cur.getStatus(load, verify) & DONE) == 0)
  473. {
  474. done = false;
  475. }
  476. cur = cur.next;
  477. }
  478. return done;
  479. }
  480. /**
  481. * Checks the error status of all of the images tracked by this
  482. * media tracker with the specified identifier.
  483. * @param id the identifier of the images to check
  484. * @return <code>true</code> if any of the images with the
  485. * specified identifier had an error during
  486. * loading; <code>false</code> otherwise
  487. * @see java.awt.MediaTracker#isErrorAny
  488. * @see java.awt.MediaTracker#getErrorsID
  489. */
  490. public synchronized boolean isErrorID(int id) {
  491. MediaEntry cur = head;
  492. while (cur != null) {
  493. if (cur.getID() == id
  494. && (cur.getStatus(false, true) & ERRORED) != 0)
  495. {
  496. return true;
  497. }
  498. cur = cur.next;
  499. }
  500. return false;
  501. }
  502. /**
  503. * Returns a list of media with the specified ID that
  504. * have encountered an error.
  505. * @param id the identifier of the images to check
  506. * @return an array of media objects tracked by this media
  507. * tracker with the specified identifier
  508. * that have encountered an error, or
  509. * <code>null</code> if there are none with errors
  510. * @see java.awt.MediaTracker#isErrorID
  511. * @see java.awt.MediaTracker#isErrorAny
  512. * @see java.awt.MediaTracker#getErrorsAny
  513. */
  514. public synchronized Object[] getErrorsID(int id) {
  515. MediaEntry cur = head;
  516. int numerrors = 0;
  517. while (cur != null) {
  518. if (cur.getID() == id
  519. && (cur.getStatus(false, true) & ERRORED) != 0)
  520. {
  521. numerrors++;
  522. }
  523. cur = cur.next;
  524. }
  525. if (numerrors == 0) {
  526. return null;
  527. }
  528. Object errors[] = new Object[numerrors];
  529. cur = head;
  530. numerrors = 0;
  531. while (cur != null) {
  532. if (cur.getID() == id
  533. && (cur.getStatus(false, false) & ERRORED) != 0)
  534. {
  535. errors[numerrors++] = cur.getMedia();
  536. }
  537. cur = cur.next;
  538. }
  539. return errors;
  540. }
  541. /**
  542. * Starts loading all images tracked by this media tracker with the
  543. * specified identifier. This method waits until all the images with
  544. * the specified identifier have finished loading.
  545. * <p>
  546. * If there is an error while loading or scaling an image, then that
  547. * image is considered to have finished loading. Use the
  548. * <code>isErrorAny</code> and <code>isErrorID</code> methods to
  549. * check for errors.
  550. * @param id the identifier of the images to check
  551. * @see java.awt.MediaTracker#waitForAll
  552. * @see java.awt.MediaTracker#isErrorAny()
  553. * @see java.awt.MediaTracker#isErrorID(int)
  554. * @exception InterruptedException if another thread has
  555. * interrupted this thread.
  556. */
  557. public void waitForID(int id) throws InterruptedException {
  558. waitForID(id, 0);
  559. }
  560. /**
  561. * Starts loading all images tracked by this media tracker with the
  562. * specified identifier. This method waits until all the images with
  563. * the specified identifier have finished loading, or until the
  564. * length of time specified in milliseconds by the <code>ms</code>
  565. * argument has passed.
  566. * <p>
  567. * If there is an error while loading or scaling an image, then that
  568. * image is considered to have finished loading. Use the
  569. * <code>statusID</code>, <code>isErrorID</code>, and
  570. * <code>isErrorAny</code> methods to check for errors.
  571. * @param id the identifier of the images to check
  572. * @param ms the length of time, in milliseconds, to wait
  573. * for the loading to complete
  574. * @see java.awt.MediaTracker#waitForAll
  575. * @see java.awt.MediaTracker#waitForID(int)
  576. * @see java.awt.MediaTracker#statusID
  577. * @see java.awt.MediaTracker#isErrorAny()
  578. * @see java.awt.MediaTracker#isErrorID(int)
  579. * @exception InterruptedException if another thread has
  580. * interrupted this thread.
  581. */
  582. public synchronized boolean waitForID(int id, long ms)
  583. throws InterruptedException
  584. {
  585. long end = System.currentTimeMillis() + ms;
  586. boolean first = true;
  587. while (true) {
  588. int status = statusID(id, first, first);
  589. if ((status & LOADING) == 0) {
  590. return (status == COMPLETE);
  591. }
  592. first = false;
  593. long timeout;
  594. if (ms == 0) {
  595. timeout = 0;
  596. } else {
  597. timeout = end - System.currentTimeMillis();
  598. if (timeout <= 0) {
  599. return false;
  600. }
  601. }
  602. wait(timeout);
  603. }
  604. }
  605. /**
  606. * Calculates and returns the bitwise inclusive <b>OR</b> of the
  607. * status of all media with the specified identifier that are
  608. * tracked by this media tracker.
  609. * <p>
  610. * Possible flags defined by the
  611. * <code>MediaTracker</code> class are <code>LOADING</code>,
  612. * <code>ABORTED</code>, <code>ERRORED</code>, and
  613. * <code>COMPLETE</code>. An image that hasn't started
  614. * loading has zero as its status.
  615. * <p>
  616. * If the value of <code>load</code> is <code>true</code>, then
  617. * this method starts loading any images that are not yet being loaded.
  618. * @param id the identifier of the images to check
  619. * @param load if <code>true</code>, start loading
  620. * any images that are not yet being loaded
  621. * @return the bitwise inclusive <b>OR</b> of the status of
  622. * all of the media with the specified
  623. * identifier that are being tracked
  624. * @see java.awt.MediaTracker#statusAll(boolean)
  625. * @see java.awt.MediaTracker#LOADING
  626. * @see java.awt.MediaTracker#ABORTED
  627. * @see java.awt.MediaTracker#ERRORED
  628. * @see java.awt.MediaTracker#COMPLETE
  629. */
  630. public int statusID(int id, boolean load) {
  631. return statusID(id, load, true);
  632. }
  633. private synchronized int statusID(int id, boolean load, boolean verify) {
  634. MediaEntry cur = head;
  635. int status = 0;
  636. while (cur != null) {
  637. if (cur.getID() == id) {
  638. status = status | cur.getStatus(load, verify);
  639. }
  640. cur = cur.next;
  641. }
  642. return status;
  643. }
  644. /**
  645. * Removes the specified image from this media tracker.
  646. * All instances of the specified image are removed,
  647. * regardless of scale or ID.
  648. * @param image the image to be removed
  649. * @see java.awt.MediaTracker#removeImage(java.awt.Image, int)
  650. * @see java.awt.MediaTracker#removeImage(java.awt.Image, int, int, int)
  651. * @since JDK1.1
  652. */
  653. public synchronized void removeImage(Image image) {
  654. MediaEntry cur = head;
  655. MediaEntry prev = null;
  656. while (cur != null) {
  657. MediaEntry next = cur.next;
  658. if (cur.getMedia() == image) {
  659. if (prev == null) {
  660. head = next;
  661. } else {
  662. prev.next = next;
  663. }
  664. cur.cancel();
  665. } else {
  666. prev = cur;
  667. }
  668. cur = next;
  669. }
  670. notifyAll(); // Notify in case remaining images are "done".
  671. }
  672. /**
  673. * Removes the specified image from the specified tracking
  674. * ID of this media tracker.
  675. * All instances of <code>Image</code> being tracked
  676. * under the specified ID are removed regardless of scale.
  677. * @param image the image to be removed
  678. * @param id the tracking ID frrom which to remove the image
  679. * @see java.awt.MediaTracker#removeImage(java.awt.Image)
  680. * @see java.awt.MediaTracker#removeImage(java.awt.Image, int, int, int)
  681. * @since JDK1.1
  682. */
  683. public synchronized void removeImage(Image image, int id) {
  684. MediaEntry cur = head;
  685. MediaEntry prev = null;
  686. while (cur != null) {
  687. MediaEntry next = cur.next;
  688. if (cur.getID() == id && cur.getMedia() == image) {
  689. if (prev == null) {
  690. head = next;
  691. } else {
  692. prev.next = next;
  693. }
  694. cur.cancel();
  695. } else {
  696. prev = cur;
  697. }
  698. cur = next;
  699. }
  700. notifyAll(); // Notify in case remaining images are "done".
  701. }
  702. /**
  703. * Removes the specified image with the specified
  704. * width, height, and ID from this media tracker.
  705. * Only the specified instance (with any duplicates) is removed.
  706. * @param image the image to be removed
  707. * @param id the tracking ID from which to remove the image
  708. * @param width the width to remove (-1 for unscaled)
  709. * @param height the height to remove (-1 for unscaled)
  710. * @see java.awt.MediaTracker#removeImage(java.awt.Image)
  711. * @see java.awt.MediaTracker#removeImage(java.awt.Image, int)
  712. * @since JDK1.1
  713. */
  714. public synchronized void removeImage(Image image, int id,
  715. int width, int height) {
  716. MediaEntry cur = head;
  717. MediaEntry prev = null;
  718. while (cur != null) {
  719. MediaEntry next = cur.next;
  720. if (cur.getID() == id && cur instanceof ImageMediaEntry
  721. && ((ImageMediaEntry) cur).matches(image, width, height))
  722. {
  723. if (prev == null) {
  724. head = next;
  725. } else {
  726. prev.next = next;
  727. }
  728. cur.cancel();
  729. } else {
  730. prev = cur;
  731. }
  732. cur = next;
  733. }
  734. notifyAll(); // Notify in case remaining images are "done".
  735. }
  736. synchronized void setDone() {
  737. notifyAll();
  738. }
  739. }
  740. abstract class MediaEntry {
  741. MediaTracker tracker;
  742. int ID;
  743. MediaEntry next;
  744. int status;
  745. boolean cancelled;
  746. MediaEntry(MediaTracker mt, int id) {
  747. tracker = mt;
  748. ID = id;
  749. }
  750. abstract Object getMedia();
  751. static MediaEntry insert(MediaEntry head, MediaEntry me) {
  752. MediaEntry cur = head;
  753. MediaEntry prev = null;
  754. while (cur != null) {
  755. if (cur.ID > me.ID) {
  756. break;
  757. }
  758. prev = cur;
  759. cur = cur.next;
  760. }
  761. me.next = cur;
  762. if (prev == null) {
  763. head = me;
  764. } else {
  765. prev.next = me;
  766. }
  767. return head;
  768. }
  769. int getID() {
  770. return ID;
  771. }
  772. abstract void startLoad();
  773. void cancel() {
  774. cancelled = true;
  775. }
  776. static final int LOADING = MediaTracker.LOADING;
  777. static final int ABORTED = MediaTracker.ABORTED;
  778. static final int ERRORED = MediaTracker.ERRORED;
  779. static final int COMPLETE = MediaTracker.COMPLETE;
  780. static final int LOADSTARTED = (LOADING | ERRORED | COMPLETE);
  781. static final int DONE = (ABORTED | ERRORED | COMPLETE);
  782. synchronized int getStatus(boolean doLoad, boolean doVerify) {
  783. if (doLoad && ((status & LOADSTARTED) == 0)) {
  784. status = (status & ~ABORTED) | LOADING;
  785. startLoad();
  786. }
  787. return status;
  788. }
  789. void setStatus(int flag) {
  790. synchronized (this) {
  791. status = flag;
  792. }
  793. tracker.setDone();
  794. }
  795. }
  796. class ImageMediaEntry extends MediaEntry implements ImageObserver,
  797. java.io.Serializable {
  798. Image image;
  799. int width;
  800. int height;
  801. /*
  802. * JDK 1.1 serialVersionUID
  803. */
  804. private static final long serialVersionUID = 4739377000350280650L;
  805. ImageMediaEntry(MediaTracker mt, Image img, int c, int w, int h) {
  806. super(mt, c);
  807. image = img;
  808. width = w;
  809. height = h;
  810. }
  811. boolean matches(Image img, int w, int h) {
  812. return (image == img && width == w && height == h);
  813. }
  814. Object getMedia() {
  815. return image;
  816. }
  817. int getStatus(boolean doLoad, boolean doVerify) {
  818. if (doVerify) {
  819. int flags = tracker.target.checkImage(image, width, height, null);
  820. int s = parseflags(flags);
  821. if (s == 0) {
  822. if ((status & (ERRORED | COMPLETE)) != 0) {
  823. setStatus(ABORTED);
  824. }
  825. } else if (s != status) {
  826. setStatus(s);
  827. }
  828. }
  829. return super.getStatus(doLoad, doVerify);
  830. }
  831. void startLoad() {
  832. if (tracker.target.prepareImage(image, width, height, this)) {
  833. setStatus(COMPLETE);
  834. }
  835. }
  836. int parseflags(int infoflags) {
  837. if ((infoflags & ERROR) != 0) {
  838. return ERRORED;
  839. } else if ((infoflags & ABORT) != 0) {
  840. return ABORTED;
  841. } else if ((infoflags & (ALLBITS | FRAMEBITS)) != 0) {
  842. return COMPLETE;
  843. }
  844. return 0;
  845. }
  846. public boolean imageUpdate(Image img, int infoflags,
  847. int x, int y, int w, int h) {
  848. if (cancelled) {
  849. return false;
  850. }
  851. int s = parseflags(infoflags);
  852. if (s != 0 && s != status) {
  853. setStatus(s);
  854. }
  855. return ((status & LOADING) != 0);
  856. }
  857. }