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