1. /*
  2. * @(#)MediaTracker.java 1.34 01/11/29
  3. *
  4. * Copyright 2002 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.34, 11/29/01
  126. * @author Jim Graham
  127. * @since JDK1.0
  128. */
  129. public class MediaTracker implements java.io.Serializable {
  130. /**
  131. * A given Component that will be
  132. * tracked by a media tracker where the image will
  133. * eventually be drawn.
  134. *
  135. * @serial
  136. * @see MediaTracker()
  137. */
  138. Component target;
  139. /**
  140. * The head of the list of Images that is being
  141. * tracked by the MediaTracker.
  142. *
  143. * @serial
  144. * @see addImage()
  145. * @see removeImage()
  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. * @param image the image to be tracked.
  175. * @param id an identifier that can be used to track this image.
  176. * @param w the width at which the image is rendered.
  177. * @param h the height at which the image is rendered.
  178. */
  179. public synchronized void addImage(Image image, int id, int w, int h) {
  180. head = MediaEntry.insert(head,
  181. new ImageMediaEntry(this, image, id, w, h));
  182. }
  183. /**
  184. * Flag indicating some media is currently being loaded.
  185. * @see java.awt.MediaTracker#statusAll
  186. * @see java.awt.MediaTracker#statusID
  187. */
  188. public static final int LOADING = 1;
  189. /**
  190. * Flag indicating that the downloading of some media was aborted.
  191. * @see java.awt.MediaTracker#statusAll
  192. * @see java.awt.MediaTracker#statusID
  193. */
  194. public static final int ABORTED = 2;
  195. /**
  196. * Flag indicating that the downloading of some media encountered
  197. * an error.
  198. * @see java.awt.MediaTracker#statusAll
  199. * @see java.awt.MediaTracker#statusID
  200. */
  201. public static final int ERRORED = 4;
  202. /**
  203. * Flag indicating that the downloading of media was completed
  204. * successfully.
  205. * @see java.awt.MediaTracker#statusAll
  206. * @see java.awt.MediaTracker#statusID
  207. */
  208. public static final int COMPLETE = 8;
  209. static final int DONE = (ABORTED | ERRORED | COMPLETE);
  210. /**
  211. * Checks to see if all images being tracked by this media tracker
  212. * have finished loading.
  213. * <p>
  214. * This method does not start loading the images if they are not
  215. * already loading.
  216. * <p>
  217. * If there is an error while loading or scaling an image, then that
  218. * image is considered to have finished loading. Use the
  219. * <code>isErrorAny</code> or <code>isErrorID</code> methods to
  220. * check for errors.
  221. * @return <code>true</code> if all images have finished loading,
  222. * have been aborted, or have encountered
  223. * an error; <code>false</code> otherwise.
  224. * @see java.awt.MediaTracker#checkAll(boolean)
  225. * @see java.awt.MediaTracker#checkID
  226. * @see java.awt.MediaTracker#isErrorAny
  227. * @see java.awt.MediaTracker#isErrorID
  228. */
  229. public boolean checkAll() {
  230. return checkAll(false, true);
  231. }
  232. /**
  233. * Checks to see if all images being tracked by this media tracker
  234. * have finished loading.
  235. * <p>
  236. * If the value of the <code>load</code> flag is <code>true</code>,
  237. * then this method starts loading any images that are not yet
  238. * being loaded.
  239. * <p>
  240. * If there is an error while loading or scaling an image, that
  241. * image is considered to have finished loading. Use the
  242. * <code>isErrorAny</code> and <code>isErrorID</code> methods to
  243. * check for errors.
  244. * @param load if <code>true</code>, start loading any
  245. * images that are not yet being loaded.
  246. * @return <code>true</code> if all images have finished loading,
  247. * have been aborted, or have encountered
  248. * an error; <code>false</code> otherwise.
  249. * @see java.awt.MediaTracker#checkID
  250. * @see java.awt.MediaTracker#checkAll()
  251. * @see java.awt.MediaTracker#isErrorAny()
  252. * @see java.awt.MediaTracker#isErrorID(int)
  253. */
  254. public boolean checkAll(boolean load) {
  255. return checkAll(load, true);
  256. }
  257. private synchronized boolean checkAll(boolean load, boolean verify) {
  258. MediaEntry cur = head;
  259. boolean done = true;
  260. while (cur != null) {
  261. if ((cur.getStatus(load, verify) & DONE) == 0) {
  262. done = false;
  263. }
  264. cur = cur.next;
  265. }
  266. return done;
  267. }
  268. /**
  269. * Checks the error status of all of the images.
  270. * @return <code>true</code> if any of the images tracked
  271. * by this media tracker had an error during
  272. * loading; <code>false</code> otherwise.
  273. * @see java.awt.MediaTracker#isErrorID
  274. * @see java.awt.MediaTracker#getErrorsAny
  275. */
  276. public synchronized boolean isErrorAny() {
  277. MediaEntry cur = head;
  278. while (cur != null) {
  279. if ((cur.getStatus(false, true) & ERRORED) != 0) {
  280. return true;
  281. }
  282. cur = cur.next;
  283. }
  284. return false;
  285. }
  286. /**
  287. * Returns a list of all media that have encountered an error.
  288. * @return an array of media objects tracked by this
  289. * media tracker that have encountered
  290. * an error, or <code>null</code> if
  291. * there are none with errors.
  292. * @see java.awt.MediaTracker#isErrorAny
  293. * @see java.awt.MediaTracker#getErrorsID
  294. */
  295. public synchronized Object[] getErrorsAny() {
  296. MediaEntry cur = head;
  297. int numerrors = 0;
  298. while (cur != null) {
  299. if ((cur.getStatus(false, true) & ERRORED) != 0) {
  300. numerrors++;
  301. }
  302. cur = cur.next;
  303. }
  304. if (numerrors == 0) {
  305. return null;
  306. }
  307. Object errors[] = new Object[numerrors];
  308. cur = head;
  309. numerrors = 0;
  310. while (cur != null) {
  311. if ((cur.getStatus(false, false) & ERRORED) != 0) {
  312. errors[numerrors++] = cur.getMedia();
  313. }
  314. cur = cur.next;
  315. }
  316. return errors;
  317. }
  318. /**
  319. * Starts loading all images tracked by this media tracker. This
  320. * method waits until all the images being tracked have finished
  321. * loading.
  322. * <p>
  323. * If there is an error while loading or scaling an image, then that
  324. * image is considered to have finished loading. Use the
  325. * <code>isErrorAny</code> or <code>isErrorID</code> methods to
  326. * check for errors.
  327. * @see java.awt.MediaTracker#waitForID(int)
  328. * @see java.awt.MediaTracker#waitForAll(long)
  329. * @see java.awt.MediaTracker#isErrorAny
  330. * @see java.awt.MediaTracker#isErrorID
  331. * @exception InterruptedException if another thread has
  332. * interrupted this thread.
  333. */
  334. public void waitForAll() throws InterruptedException {
  335. waitForAll(0);
  336. }
  337. /**
  338. * Starts loading all images tracked by this media tracker. This
  339. * method waits until all the images being tracked have finished
  340. * loading, or until the length of time specified in milliseconds
  341. * by the <code>ms</code> argument has passed.
  342. * <p>
  343. * If there is an error while loading or scaling an image, then
  344. * that image is considered to have finished loading. Use the
  345. * <code>isErrorAny</code> or <code>isErrorID</code> methods to
  346. * check for errors.
  347. * @param ms the number of milliseconds to wait
  348. * for the loading to complete.
  349. * @return <code>true</code> if all images were successfully
  350. * loaded; <code>false</code> otherwise.
  351. * @see java.awt.MediaTracker#waitForID(int)
  352. * @see java.awt.MediaTracker#waitForAll(long)
  353. * @see java.awt.MediaTracker#isErrorAny
  354. * @see java.awt.MediaTracker#isErrorID
  355. * @exception InterruptedException if another thread has
  356. * interrupted this thread.
  357. */
  358. public synchronized boolean waitForAll(long ms)
  359. throws InterruptedException
  360. {
  361. long end = System.currentTimeMillis() + ms;
  362. boolean first = true;
  363. while (true) {
  364. int status = statusAll(first, first);
  365. if ((status & LOADING) == 0) {
  366. return (status == COMPLETE);
  367. }
  368. first = false;
  369. long timeout;
  370. if (ms == 0) {
  371. timeout = 0;
  372. } else {
  373. timeout = end - System.currentTimeMillis();
  374. if (timeout <= 0) {
  375. return false;
  376. }
  377. }
  378. wait(timeout);
  379. }
  380. }
  381. /**
  382. * Calculates and returns the bitwise inclusive <b>OR</b> of the
  383. * status of all media that are tracked by this media tracker.
  384. * <p>
  385. * Possible flags defined by the
  386. * <code>MediaTracker</code> class are <code>LOADING</code>,
  387. * <code>ABORTED</code>, <code>ERRORED</code>, and
  388. * <code>COMPLETE</code>. An image that hasn't started
  389. * loading has zero as its status.
  390. * <p>
  391. * If the value of <code>load</code> is <code>true</code>, then
  392. * this method starts loading any images that are not yet being loaded.
  393. * @param load if <code>true</code>, start loading
  394. * any images that are not yet being loaded.
  395. * @return the bitwise inclusive <b>OR</b> of the status of
  396. * all of the media being tracked.
  397. * @see java.awt.MediaTracker#statusID(int, boolean)
  398. * @see java.awt.MediaTracker#LOADING
  399. * @see java.awt.MediaTracker#ABORTED
  400. * @see java.awt.MediaTracker#ERRORED
  401. * @see java.awt.MediaTracker#COMPLETE
  402. */
  403. public int statusAll(boolean load) {
  404. return statusAll(load, true);
  405. }
  406. private synchronized int statusAll(boolean load, boolean verify) {
  407. MediaEntry cur = head;
  408. int status = 0;
  409. while (cur != null) {
  410. status = status | cur.getStatus(load, verify);
  411. cur = cur.next;
  412. }
  413. return status;
  414. }
  415. /**
  416. * Checks to see if all images tracked by this media tracker that
  417. * are tagged with the specified identifier have finished loading.
  418. * <p>
  419. * This method does not start loading the images if they are not
  420. * already loading.
  421. * <p>
  422. * If there is an error while loading or scaling an image, then that
  423. * image is considered to have finished loading. Use the
  424. * <code>isErrorAny</code> or <code>isErrorID</code> methods to
  425. * check for errors.
  426. * @param id the identifier of the images to check.
  427. * @return <code>true</code> if all images have finished loading,
  428. * have been aborted, or have encountered
  429. * an error; <code>false</code> otherwise.
  430. * @see java.awt.MediaTracker#checkID(int, boolean)
  431. * @see java.awt.MediaTracker#checkAll()
  432. * @see java.awt.MediaTracker#isErrorAny()
  433. * @see java.awt.MediaTracker#isErrorID(int)
  434. */
  435. public boolean checkID(int id) {
  436. return checkID(id, false, true);
  437. }
  438. /**
  439. * Checks to see if all images tracked by this media tracker that
  440. * are tagged with the specified identifier have finished loading.
  441. * <p>
  442. * If the value of the <code>load</code> flag is <code>true</code>,
  443. * then this method starts loading any images that are not yet
  444. * being loaded.
  445. * <p>
  446. * If there is an error while loading or scaling an image, then that
  447. * image is considered to have finished loading. Use the
  448. * <code>isErrorAny</code> or <code>isErrorID</code> methods to
  449. * check for errors.
  450. * @param id the identifier of the images to check.
  451. * @param load if <code>true</code>, start loading any
  452. * images that are not yet being loaded.
  453. * @return <code>true</code> if all images have finished loading,
  454. * have been aborted, or have encountered
  455. * an error; <code>false</code> otherwise.
  456. * @see java.awt.MediaTracker#checkID(int, boolean)
  457. * @see java.awt.MediaTracker#checkAll()
  458. * @see java.awt.MediaTracker#isErrorAny()
  459. * @see java.awt.MediaTracker#isErrorID(int)
  460. */
  461. public boolean checkID(int id, boolean load) {
  462. return checkID(id, load, true);
  463. }
  464. private synchronized boolean checkID(int id, boolean load, boolean verify)
  465. {
  466. MediaEntry cur = head;
  467. boolean done = true;
  468. while (cur != null) {
  469. if (cur.getID() == id
  470. && (cur.getStatus(load, verify) & DONE) == 0)
  471. {
  472. done = false;
  473. }
  474. cur = cur.next;
  475. }
  476. return done;
  477. }
  478. /**
  479. * Checks the error status of all of the images tracked by this
  480. * media tracker with the specified identifier.
  481. * @param id the identifier of the images to check.
  482. * @return <code>true</code> if any of the images with the
  483. * specified identifier had an error during
  484. * loading; <code>false</code> otherwise.
  485. * @see java.awt.MediaTracker#isErrorAny
  486. * @see java.awt.MediaTracker#getErrorsID
  487. */
  488. public synchronized boolean isErrorID(int id) {
  489. MediaEntry cur = head;
  490. while (cur != null) {
  491. if (cur.getID() == id
  492. && (cur.getStatus(false, true) & ERRORED) != 0)
  493. {
  494. return true;
  495. }
  496. cur = cur.next;
  497. }
  498. return false;
  499. }
  500. /**
  501. * Returns a list of media with the specified ID that
  502. * have encountered an error.
  503. * @param id the identifier of the images to check.
  504. * @return an array of media objects tracked by this media
  505. * tracker with the specified identifier
  506. * that have encountered an error, or
  507. * <code>null</code> if there are none with errors.
  508. * @see java.awt.MediaTracker#isErrorID
  509. * @see java.awt.MediaTracker#isErrorAny
  510. * @see java.awt.MediaTracker#getErrorsAny
  511. */
  512. public synchronized Object[] getErrorsID(int id) {
  513. MediaEntry cur = head;
  514. int numerrors = 0;
  515. while (cur != null) {
  516. if (cur.getID() == id
  517. && (cur.getStatus(false, true) & ERRORED) != 0)
  518. {
  519. numerrors++;
  520. }
  521. cur = cur.next;
  522. }
  523. if (numerrors == 0) {
  524. return null;
  525. }
  526. Object errors[] = new Object[numerrors];
  527. cur = head;
  528. numerrors = 0;
  529. while (cur != null) {
  530. if (cur.getID() == id
  531. && (cur.getStatus(false, false) & ERRORED) != 0)
  532. {
  533. errors[numerrors++] = cur.getMedia();
  534. }
  535. cur = cur.next;
  536. }
  537. return errors;
  538. }
  539. /**
  540. * Starts loading all images tracked by this media tracker with the
  541. * specified identifier. This method waits until all the images with
  542. * the specified identifier have finished loading.
  543. * <p>
  544. * If there is an error while loading or scaling an image, then that
  545. * image is considered to have finished loading. Use the
  546. * <code>isErrorAny</code> and <code>isErrorID</code> methods to
  547. * check for errors.
  548. * @param id the identifier of the images to check.
  549. * @see java.awt.MediaTracker#waitForAll
  550. * @see java.awt.MediaTracker#isErrorAny()
  551. * @see java.awt.MediaTracker#isErrorID(int)
  552. * @exception InterruptedException if another thread has
  553. * interrupted this thread.
  554. */
  555. public void waitForID(int id) throws InterruptedException {
  556. waitForID(id, 0);
  557. }
  558. /**
  559. * Starts loading all images tracked by this media tracker with the
  560. * specified identifier. This method waits until all the images with
  561. * the specified identifier have finished loading, or until the
  562. * length of time specified in milliseconds by the <code>ms</code>
  563. * argument has passed.
  564. * <p>
  565. * If there is an error while loading or scaling an image, then that
  566. * image is considered to have finished loading. Use the
  567. * <code>statusID</code>, <code>isErrorID</code>, and
  568. * <code>isErrorAny</code> methods to check for errors.
  569. * @param id the identifier of the images to check.
  570. * @param ms the length of time, in milliseconds, to wait
  571. * for the loading to complete.
  572. * @see java.awt.MediaTracker#waitForAll
  573. * @see java.awt.MediaTracker#waitForID(int)
  574. * @see java.awt.MediaTracker#statusID
  575. * @see java.awt.MediaTracker#isErrorAny()
  576. * @see java.awt.MediaTracker#isErrorID(int)
  577. * @exception InterruptedException if another thread has
  578. * interrupted this thread.
  579. */
  580. public synchronized boolean waitForID(int id, long ms)
  581. throws InterruptedException
  582. {
  583. long end = System.currentTimeMillis() + ms;
  584. boolean first = true;
  585. while (true) {
  586. int status = statusID(id, first, first);
  587. if ((status & LOADING) == 0) {
  588. return (status == COMPLETE);
  589. }
  590. first = false;
  591. long timeout;
  592. if (ms == 0) {
  593. timeout = 0;
  594. } else {
  595. timeout = end - System.currentTimeMillis();
  596. if (timeout <= 0) {
  597. return false;
  598. }
  599. }
  600. wait(timeout);
  601. }
  602. }
  603. /**
  604. * Calculates and returns the bitwise inclusive <b>OR</b> of the
  605. * status of all media with the specified identifier that are
  606. * tracked by this media tracker.
  607. * <p>
  608. * Possible flags defined by the
  609. * <code>MediaTracker</code> class are <code>LOADING</code>,
  610. * <code>ABORTED</code>, <code>ERRORED</code>, and
  611. * <code>COMPLETE</code>. An image that hasn't started
  612. * loading has zero as its status.
  613. * <p>
  614. * If the value of <code>load</code> is <code>true</code>, then
  615. * this method starts loading any images that are not yet being loaded.
  616. * @param id the identifier of the images to check.
  617. * @param load if <code>true</code>, start loading
  618. * any images that are not yet being loaded.
  619. * @return the bitwise inclusive <b>OR</b> of the status of
  620. * all of the media with the specified
  621. * identifier that are being tracked.
  622. * @see java.awt.MediaTracker#statusAll(boolean)
  623. * @see java.awt.MediaTracker#LOADING
  624. * @see java.awt.MediaTracker#ABORTED
  625. * @see java.awt.MediaTracker#ERRORED
  626. * @see java.awt.MediaTracker#COMPLETE
  627. */
  628. public int statusID(int id, boolean load) {
  629. return statusID(id, load, true);
  630. }
  631. private synchronized int statusID(int id, boolean load, boolean verify) {
  632. MediaEntry cur = head;
  633. int status = 0;
  634. while (cur != null) {
  635. if (cur.getID() == id) {
  636. status = status | cur.getStatus(load, verify);
  637. }
  638. cur = cur.next;
  639. }
  640. return status;
  641. }
  642. /**
  643. * Remove the specified image from this media tracker.
  644. * All instances of the specified image are removed,
  645. * regardless of scale or ID.
  646. * @param image the image to be removed
  647. * @see java.awt.MediaTracker#removeImage(java.awt.Image, int)
  648. * @see java.awt.MediaTracker#removeImage(java.awt.Image, int, int, int)
  649. * @since JDK1.1
  650. */
  651. public synchronized void removeImage(Image image) {
  652. MediaEntry cur = head;
  653. MediaEntry prev = null;
  654. while (cur != null) {
  655. MediaEntry next = cur.next;
  656. if (cur.getMedia() == image) {
  657. if (prev == null) {
  658. head = next;
  659. } else {
  660. prev.next = next;
  661. }
  662. cur.cancel();
  663. } else {
  664. prev = cur;
  665. }
  666. cur = next;
  667. }
  668. notifyAll(); // Notify in case remaining images are "done".
  669. }
  670. /**
  671. * Remove the specified image from the specified tracking
  672. * ID of this media tracker.
  673. * All instances of <code>Image</code> being tracked
  674. * under the specified ID are removed regardless of scale.
  675. * @param image the image to be removed.
  676. * @param id the tracking ID frrom which to remove the image.
  677. * @see java.awt.MediaTracker#removeImage(java.awt.Image)
  678. * @see java.awt.MediaTracker#removeImage(java.awt.Image, int, int, int)
  679. * @since JDK1.1
  680. */
  681. public synchronized void removeImage(Image image, int id) {
  682. MediaEntry cur = head;
  683. MediaEntry prev = null;
  684. while (cur != null) {
  685. MediaEntry next = cur.next;
  686. if (cur.getID() == id && cur.getMedia() == image) {
  687. if (prev == null) {
  688. head = next;
  689. } else {
  690. prev.next = next;
  691. }
  692. cur.cancel();
  693. } else {
  694. prev = cur;
  695. }
  696. cur = next;
  697. }
  698. notifyAll(); // Notify in case remaining images are "done".
  699. }
  700. /**
  701. * Remove the specified image with the specified
  702. * width, height, and ID from this media tracker.
  703. * Only the specified instance (with any duplicates) is removed.
  704. * @param image the image to be removed
  705. * @param id the tracking ID from which to remove the image.
  706. * @param width the width to remove (-1 for unscaled).
  707. * @param height the height to remove (-1 for unscaled).
  708. * @see java.awt.MediaTracker#removeImage(java.awt.Image)
  709. * @see java.awt.MediaTracker#removeImage(java.awt.Image, int)
  710. * @since JDK1.1
  711. */
  712. public synchronized void removeImage(Image image, int id,
  713. int width, int height) {
  714. MediaEntry cur = head;
  715. MediaEntry prev = null;
  716. while (cur != null) {
  717. MediaEntry next = cur.next;
  718. if (cur.getID() == id && cur instanceof ImageMediaEntry
  719. && ((ImageMediaEntry) cur).matches(image, width, height))
  720. {
  721. if (prev == null) {
  722. head = next;
  723. } else {
  724. prev.next = next;
  725. }
  726. cur.cancel();
  727. } else {
  728. prev = cur;
  729. }
  730. cur = next;
  731. }
  732. notifyAll(); // Notify in case remaining images are "done".
  733. }
  734. synchronized void setDone() {
  735. notifyAll();
  736. }
  737. }
  738. abstract class MediaEntry {
  739. MediaTracker tracker;
  740. int ID;
  741. MediaEntry next;
  742. int status;
  743. boolean cancelled;
  744. /*
  745. * JDK 1.1 serialVersionUID
  746. */
  747. private static final long serialVersionUID = -2924957284304726459L;
  748. MediaEntry(MediaTracker mt, int id) {
  749. tracker = mt;
  750. ID = id;
  751. }
  752. abstract Object getMedia();
  753. static MediaEntry insert(MediaEntry head, MediaEntry me) {
  754. MediaEntry cur = head;
  755. MediaEntry prev = null;
  756. while (cur != null) {
  757. if (cur.ID > me.ID) {
  758. break;
  759. }
  760. prev = cur;
  761. cur = cur.next;
  762. }
  763. me.next = cur;
  764. if (prev == null) {
  765. head = me;
  766. } else {
  767. prev.next = me;
  768. }
  769. return head;
  770. }
  771. int getID() {
  772. return ID;
  773. }
  774. abstract void startLoad();
  775. void cancel() {
  776. cancelled = true;
  777. }
  778. static final int LOADING = MediaTracker.LOADING;
  779. static final int ABORTED = MediaTracker.ABORTED;
  780. static final int ERRORED = MediaTracker.ERRORED;
  781. static final int COMPLETE = MediaTracker.COMPLETE;
  782. static final int LOADSTARTED = (LOADING | ERRORED | COMPLETE);
  783. static final int DONE = (ABORTED | ERRORED | COMPLETE);
  784. synchronized int getStatus(boolean doLoad, boolean doVerify) {
  785. if (doLoad && ((status & LOADSTARTED) == 0)) {
  786. status = (status & ~ABORTED) | LOADING;
  787. startLoad();
  788. }
  789. return status;
  790. }
  791. void setStatus(int flag) {
  792. synchronized (this) {
  793. status = flag;
  794. }
  795. tracker.setDone();
  796. }
  797. }
  798. class ImageMediaEntry extends MediaEntry implements ImageObserver,
  799. java.io.Serializable {
  800. Image image;
  801. int width;
  802. int height;
  803. ImageMediaEntry(MediaTracker mt, Image img, int c, int w, int h) {
  804. super(mt, c);
  805. image = img;
  806. width = w;
  807. height = h;
  808. }
  809. boolean matches(Image img, int w, int h) {
  810. return (image == img && width == w && height == h);
  811. }
  812. Object getMedia() {
  813. return image;
  814. }
  815. int getStatus(boolean doLoad, boolean doVerify) {
  816. if (doVerify) {
  817. int flags = tracker.target.checkImage(image, width, height, null);
  818. int s = parseflags(flags);
  819. if (s == 0) {
  820. if ((status & (ERRORED | COMPLETE)) != 0) {
  821. setStatus(ABORTED);
  822. }
  823. } else if (s != status) {
  824. setStatus(s);
  825. }
  826. }
  827. return super.getStatus(doLoad, doVerify);
  828. }
  829. void startLoad() {
  830. if (tracker.target.prepareImage(image, width, height, this)) {
  831. setStatus(COMPLETE);
  832. }
  833. }
  834. int parseflags(int infoflags) {
  835. if ((infoflags & ERROR) != 0) {
  836. return ERRORED;
  837. } else if ((infoflags & ABORT) != 0) {
  838. return ABORTED;
  839. } else if ((infoflags & (ALLBITS | FRAMEBITS)) != 0) {
  840. return COMPLETE;
  841. }
  842. return 0;
  843. }
  844. public boolean imageUpdate(Image img, int infoflags,
  845. int x, int y, int w, int h) {
  846. if (cancelled) {
  847. return false;
  848. }
  849. int s = parseflags(infoflags);
  850. if (s != 0 && s != status) {
  851. setStatus(s);
  852. }
  853. return ((status & LOADING) != 0);
  854. }
  855. }