001: /*
002: * @(#)MediaTracker.java 1.37 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package java.awt;
029:
030: import java.awt.Component;
031: import java.awt.Image;
032: import java.awt.Graphics;
033: import java.awt.image.ImageObserver;
034:
035: /**
036: * The <code>MediaTracker</code> class is a utility class to track
037: * the status of a number of media objects. Media objects could
038: * include audio clips as well as images, though currently only
039: * images are supported.
040: * <p>
041: * To use a media tracker, create an instance of
042: * <code>MediaTracker</code> and call its <code>addImage</code>
043: * method for each image to be tracked. In addition, each image can
044: * be assigned a unique identifier. This identifier controls the
045: * priority order in which the images are fetched. It can also be used
046: * to identify unique subsets of the images that can be waited on
047: * independently. Images with a lower ID are loaded in preference to
048: * those with a higher ID number.
049: * <p>
050: * Here is an example:
051: * <p>
052: * <hr><blockquote><pre>
053: * import java.applet.Applet;
054: * import java.awt.Color;
055: * import java.awt.Image;
056: * import java.awt.Graphics;
057: * import java.awt.MediaTracker;
058: *
059: * public class ImageBlaster extends Applet implements Runnable {
060: * MediaTracker tracker;
061: * Image bg;
062: * Image anim[] = new Image[5];
063: * int index;
064: * Thread animator;
065: *
066: * // Get the images for the background (id == 0)
067: * // and the animation frames (id == 1)
068: * // and add them to the MediaTracker
069: * public void init() {
070: * tracker = new MediaTracker(this);
071: * bg = getImage(getDocumentBase(),
072: * "images/background.gif");
073: * tracker.addImage(bg, 0);
074: * for (int i = 0; i < 5; i++) {
075: * anim[i] = getImage(getDocumentBase(),
076: * "images/anim"+i+".gif");
077: * tracker.addImage(anim[i], 1);
078: * }
079: * }
080: *
081: * // Start the animation thread.
082: * public void start() {
083: * animator = new Thread(this);
084: * animator.start();
085: * }
086: *
087: * // Stop the animation thread.
088: * public void stop() {
089: * animator.stop();
090: * animator = null;
091: * }
092: *
093: * // Run the animation thread.
094: * // First wait for the background image to fully load
095: * // and paint. Then wait for all of the animation
096: * // frames to finish loading. Finally, loop and
097: * // increment the animation frame index.
098: * public void run() {
099: * try {
100: * tracker.waitForID(0);
101: * tracker.waitForID(1);
102: * } catch (InterruptedException e) {
103: * return;
104: * }
105: * Thread me = Thread.currentThread();
106: * while (animator == me) {
107: * try {
108: * Thread.sleep(100);
109: * } catch (InterruptedException e) {
110: * break;
111: * }
112: * synchronized (this) {
113: * index++;
114: * if (index >= anim.length) {
115: * index = 0;
116: * }
117: * }
118: * repaint();
119: * }
120: * }
121: *
122: * // The background image fills the frame so we
123: * // don't need to clear the applet on repaints.
124: * // Just call the paint method.
125: * public void update(Graphics g) {
126: * paint(g);
127: * }
128: *
129: * // Paint a large red rectangle if there are any errors
130: * // loading the images. Otherwise always paint the
131: * // background so that it appears incrementally as it
132: * // is loading. Finally, only paint the current animation
133: * // frame if all of the frames (id == 1) are done loading,
134: * // so that we don't get partial animations.
135: * public void paint(Graphics g) {
136: * if ((tracker.statusAll(false) & MediaTracker.ERRORED) != 0) {
137: * g.setColor(Color.red);
138: * g.fillRect(0, 0, size().width, size().height);
139: * return;
140: * }
141: * g.drawImage(bg, 0, 0, this);
142: * if (tracker.statusID(1, false) == MediaTracker.COMPLETE) {
143: * g.drawImage(anim[index], 10, 10, this);
144: * }
145: * }
146: * }
147: * </pre></blockquote><hr>
148: * <p>
149: * @version 1.32, 08/19/02
150: * @author Jim Graham
151: * @since JDK1.0
152: */
153: public class MediaTracker implements java.io.Serializable {
154: Component target;
155: transient MediaEntry head;
156: /*
157: * JDK 1.1 serialVersionUID
158: */
159: private static final long serialVersionUID = -483174189758638095L;
160:
161: /**
162: * Creates a media tracker to track images for a given component.
163: * @param comp the component on which the images
164: * will eventually be drawn.
165: * @since JDK1.0
166: */
167: public MediaTracker(Component comp) {
168: target = comp;
169: }
170:
171: /**
172: * Adds an image to the list of images being tracked by this media
173: * tracker. The image will eventually be rendered at its default
174: * (unscaled) size.
175: * @param image the image to be tracked.
176: * @param id an identifier used to track this image.
177: * @since JDK1.0
178: */
179: public void addImage(Image image, int id) {
180: addImage(image, id, -1, -1);
181: }
182:
183: /**
184: * Adds a scaled image to the list of images being tracked
185: * by this media tracker. The image will eventually be
186: * rendered at the indicated width and height.
187: * @param image the image to be tracked.
188: * @param id an identifier that can be used to track this image.
189: * @param w the width at which the image is rendered.
190: * @param h the height at which the image is rendered.
191: * @since JDK1.0
192: */
193: public synchronized void addImage(Image image, int id, int w, int h) {
194: head = MediaEntry.insert(head, new ImageMediaEntry(this , image,
195: id, w, h));
196: }
197:
198: /**
199: * Flag indicating some media is currently being loaded.
200: * @see java.awt.MediaTracker#statusAll
201: * @see java.awt.MediaTracker#statusID
202: * @since JDK1.0
203: */
204: public static final int LOADING = 1;
205: /**
206: * Flag indicating that the downloading of some media was aborted.
207: * @see java.awt.MediaTracker#statusAll
208: * @see java.awt.MediaTracker#statusID
209: * @since JDK1.0
210: */
211: public static final int ABORTED = 2;
212: /**
213: * Flag indicating that the downloading of some media encountered
214: * an error.
215: * @see java.awt.MediaTracker#statusAll
216: * @see java.awt.MediaTracker#statusID
217: * @since JDK1.0
218: */
219: public static final int ERRORED = 4;
220: /**
221: * Flag indicating that the downloading of media was completed
222: * successfully.
223: * @see java.awt.MediaTracker#statusAll
224: * @see java.awt.MediaTracker#statusID
225: * @since JDK1.0
226: */
227: public static final int COMPLETE = 8;
228: static final int DONE = (ABORTED | ERRORED | COMPLETE);
229:
230: /**
231: * Checks to see if all images being tracked by this media tracker
232: * have finished loading.
233: * <p>
234: * This method does not start loading the images if they are not
235: * already loading.
236: * <p>
237: * If there is an error while loading or scaling an image, then that
238: * image is considered to have finished loading. Use the
239: * <code>isErrorAny</code> or <code>isErrorID</code> methods to
240: * check for errors.
241: * @return <code>true</code> if all images have finished loading,
242: * have been aborted, or have encountered
243: * an error; <code>false</code> otherwise.
244: * @see java.awt.MediaTracker#checkAll(boolean)
245: * @see java.awt.MediaTracker#checkID
246: * @see java.awt.MediaTracker#isErrorAny
247: * @see java.awt.MediaTracker#isErrorID
248: * @since JDK1.0
249: */
250: public boolean checkAll() {
251: return checkAll(false, true);
252: }
253:
254: /**
255: * Checks to see if all images being tracked by this media tracker
256: * have finished loading.
257: * <p>
258: * If the value of the <code>load</code> flag is <code>true</code>,
259: * then this method starts loading any images that are not yet
260: * being loaded.
261: * <p>
262: * If there is an error while loading or scaling an image, that
263: * image is considered to have finished loading. Use the
264: * <code>isErrorAny</code> and <code>isErrorID</code> methods to
265: * check for errors.
266: * @param load if <code>true</code>, start loading any
267: * images that are not yet being loaded.
268: * @return <code>true</code> if all images have finished loading,
269: * have been aborted, or have encountered
270: * an error; <code>false</code> otherwise.
271: * @see java.awt.MediaTracker#checkID
272: * @see java.awt.MediaTracker#checkAll()
273: * @see java.awt.MediaTracker#isErrorAny()
274: * @see java.awt.MediaTracker#isErrorID(int)
275: * @since JDK1.0
276: */
277: public boolean checkAll(boolean load) {
278: return checkAll(load, true);
279: }
280:
281: private synchronized boolean checkAll(boolean load, boolean verify) {
282: MediaEntry cur = head;
283: boolean done = true;
284: while (cur != null) {
285: if ((cur.getStatus(load, verify) & DONE) == 0) {
286: done = false;
287: }
288: cur = cur.next;
289: }
290: return done;
291: }
292:
293: /**
294: * Checks the error status of all of the images.
295: * @return <code>true</code> if any of the images tracked
296: * by this media tracker had an error during
297: * loading; <code>false</code> otherwise.
298: * @see java.awt.MediaTracker#isErrorID
299: * @see java.awt.MediaTracker#getErrorsAny
300: * @since JDK1.0
301: */
302: public synchronized boolean isErrorAny() {
303: MediaEntry cur = head;
304: while (cur != null) {
305: if ((cur.getStatus(false, true) & ERRORED) != 0) {
306: return true;
307: }
308: cur = cur.next;
309: }
310: return false;
311: }
312:
313: /**
314: * Returns a list of all media that have encountered an error.
315: * @return an array of media objects tracked by this
316: * media tracker that have encountered
317: * an error, or <code>null</code> if
318: * there are none with errors.
319: * @see java.awt.MediaTracker#isErrorAny
320: * @see java.awt.MediaTracker#getErrorsID
321: * @since JDK1.0
322: */
323: public synchronized Object[] getErrorsAny() {
324: MediaEntry cur = head;
325: int numerrors = 0;
326: while (cur != null) {
327: if ((cur.getStatus(false, true) & ERRORED) != 0) {
328: numerrors++;
329: }
330: cur = cur.next;
331: }
332: if (numerrors == 0) {
333: return null;
334: }
335: Object errors[] = new Object[numerrors];
336: cur = head;
337: numerrors = 0;
338: while (cur != null) {
339: if ((cur.getStatus(false, false) & ERRORED) != 0) {
340: errors[numerrors++] = cur.getMedia();
341: }
342: cur = cur.next;
343: }
344: return errors;
345: }
346:
347: /**
348: * Starts loading all images tracked by this media tracker. This
349: * method waits until all the images being tracked have finished
350: * loading.
351: * <p>
352: * If there is an error while loading or scaling an image, then that
353: * image is considered to have finished loading. Use the
354: * <code>isErrorAny</code> or <code>isErrorID</code> methods to
355: * check for errors.
356: * @see java.awt.MediaTracker#waitForID(int)
357: * @see java.awt.MediaTracker#waitForAll(long)
358: * @see java.awt.MediaTracker#isErrorAny
359: * @see java.awt.MediaTracker#isErrorID
360: * @exception InterruptedException if another thread has
361: * interrupted this thread.
362: * @since JDK1.0
363: */
364: public void waitForAll() throws InterruptedException {
365: waitForAll(0);
366: }
367:
368: /**
369: * Starts loading all images tracked by this media tracker. This
370: * method waits until all the images being tracked have finished
371: * loading, or until the length of time specified in milliseconds
372: * by the <code>ms</code> argument has passed.
373: * <p>
374: * If there is an error while loading or scaling an image, then
375: * that image is considered to have finished loading. Use the
376: * <code>isErrorAny</code> or <code>isErrorID</code> methods to
377: * check for errors.
378: * @param ms the number of milliseconds to wait
379: * for the loading to complete.
380: * @return <code>true</code> if all images were successfully
381: * loaded; <code>false</code> otherwise.
382: * @see java.awt.MediaTracker#waitForID(int)
383: * @see java.awt.MediaTracker#waitForAll(long)
384: * @see java.awt.MediaTracker#isErrorAny
385: * @see java.awt.MediaTracker#isErrorID
386: * @exception InterruptedException if another thread has
387: * interrupted this thread.
388: * @since JDK1.0
389: */
390: public synchronized boolean waitForAll(long ms)
391: throws InterruptedException {
392: long end = System.currentTimeMillis() + ms;
393: boolean first = true;
394: while (true) {
395: int status = statusAll(first, first);
396: if ((status & LOADING) == 0) {
397: return (status == COMPLETE);
398: }
399: first = false;
400: long timeout;
401: if (ms == 0) {
402: timeout = 0;
403: } else {
404: timeout = end - System.currentTimeMillis();
405: if (timeout <= 0) {
406: return false;
407: }
408: }
409: wait(timeout);
410: }
411: }
412:
413: /**
414: * Calculates and returns the bitwise inclusive <b>OR</b> of the
415: * status of all media that are tracked by this media tracker.
416: * <p>
417: * Possible flags defined by the
418: * <code>MediaTracker</code> class are <code>LOADING</code>,
419: * <code>ABORTED</code>, <code>ERRORED</code>, and
420: * <code>COMPLETE</code>. An image that hasn't started
421: * loading has zero as its status.
422: * <p>
423: * If the value of <code>load</code> is <code>true</code>, then
424: * this method starts loading any images that are not yet being loaded.
425: * @param load if <code>true</code>, start loading
426: * any images that are not yet being loaded.
427: * @return the bitwise inclusive <b>OR</b> of the status of
428: * all of the media being tracked.
429: * @see java.awt.MediaTracker#statusID(int, boolean)
430: * @see java.awt.MediaTracker#LOADING
431: * @see java.awt.MediaTracker#ABORTED
432: * @see java.awt.MediaTracker#ERRORED
433: * @see java.awt.MediaTracker#COMPLETE
434: * @since JDK1.0
435: */
436: public int statusAll(boolean load) {
437: return statusAll(load, true);
438: }
439:
440: private synchronized int statusAll(boolean load, boolean verify) {
441: MediaEntry cur = head;
442: int status = 0;
443: while (cur != null) {
444: status = status | cur.getStatus(load, verify);
445: cur = cur.next;
446: }
447: return status;
448: }
449:
450: /**
451: * Checks to see if all images tracked by this media tracker that
452: * are tagged with the specified identifier have finished loading.
453: * <p>
454: * This method does not start loading the images if they are not
455: * already loading.
456: * <p>
457: * If there is an error while loading or scaling an image, then that
458: * image is considered to have finished loading. Use the
459: * <code>isErrorAny</code> or <code>isErrorID</code> methods to
460: * check for errors.
461: * @param id the identifier of the images to check.
462: * @return <code>true</code> if all images have finished loading,
463: * have been aborted, or have encountered
464: * an error; <code>false</code> otherwise.
465: * @see java.awt.MediaTracker#checkID(int, boolean)
466: * @see java.awt.MediaTracker#checkAll()
467: * @see java.awt.MediaTracker#isErrorAny()
468: * @see java.awt.MediaTracker#isErrorID(int)
469: * @since JDK1.0
470: */
471: public boolean checkID(int id) {
472: return checkID(id, false, true);
473: }
474:
475: /**
476: * Checks to see if all images tracked by this media tracker that
477: * are tagged with the specified identifier have finished loading.
478: * <p>
479: * If the value of the <code>load</code> flag is <code>true</code>,
480: * then this method starts loading any images that are not yet
481: * being loaded.
482: * <p>
483: * If there is an error while loading or scaling an image, then that
484: * image is considered to have finished loading. Use the
485: * <code>isErrorAny</code> or <code>isErrorID</code> methods to
486: * check for errors.
487: * @param id the identifier of the images to check.
488: * @param load if <code>true</code>, start loading any
489: * images that are not yet being loaded.
490: * @return <code>true</code> if all images have finished loading,
491: * have been aborted, or have encountered
492: * an error; <code>false</code> otherwise.
493: * @see java.awt.MediaTracker#checkID(int, boolean)
494: * @see java.awt.MediaTracker#checkAll()
495: * @see java.awt.MediaTracker#isErrorAny()
496: * @see java.awt.MediaTracker#isErrorID(int)
497: * @since JDK1.0
498: */
499: public boolean checkID(int id, boolean load) {
500: return checkID(id, load, true);
501: }
502:
503: private synchronized boolean checkID(int id, boolean load,
504: boolean verify) {
505: MediaEntry cur = head;
506: boolean done = true;
507: while (cur != null) {
508: if (cur.getID() == id
509: && (cur.getStatus(load, verify) & DONE) == 0) {
510: done = false;
511: }
512: cur = cur.next;
513: }
514: return done;
515: }
516:
517: /**
518: * Checks the error status of all of the images tracked by this
519: * media tracker with the specified identifier.
520: * @param id the identifier of the images to check.
521: * @return <code>true</code> if any of the images with the
522: * specified identifier had an error during
523: * loading; <code>false</code> otherwise.
524: * @see java.awt.MediaTracker#isErrorAny
525: * @see java.awt.MediaTracker#getErrorsID
526: * @since JDK1.0
527: */
528: public synchronized boolean isErrorID(int id) {
529: MediaEntry cur = head;
530: while (cur != null) {
531: if (cur.getID() == id
532: && (cur.getStatus(false, true) & ERRORED) != 0) {
533: return true;
534: }
535: cur = cur.next;
536: }
537: return false;
538: }
539:
540: /**
541: * Returns a list of media with the specified ID that
542: * have encountered an error.
543: * @param id the identifier of the images to check.
544: * @return an array of media objects tracked by this media
545: * tracker with the specified identifier
546: * that have encountered an error, or
547: * <code>null</code> if there are none with errors.
548: * @see java.awt.MediaTracker#isErrorID
549: * @see java.awt.MediaTracker#isErrorAny
550: * @see java.awt.MediaTracker#getErrorsAny
551: * @since JDK1.0
552: */
553: public synchronized Object[] getErrorsID(int id) {
554: MediaEntry cur = head;
555: int numerrors = 0;
556: while (cur != null) {
557: if (cur.getID() == id
558: && (cur.getStatus(false, true) & ERRORED) != 0) {
559: numerrors++;
560: }
561: cur = cur.next;
562: }
563: if (numerrors == 0) {
564: return null;
565: }
566: Object errors[] = new Object[numerrors];
567: cur = head;
568: numerrors = 0;
569: while (cur != null) {
570: if (cur.getID() == id
571: && (cur.getStatus(false, false) & ERRORED) != 0) {
572: errors[numerrors++] = cur.getMedia();
573: }
574: cur = cur.next;
575: }
576: return errors;
577: }
578:
579: /**
580: * Starts loading all images tracked by this media tracker with the
581: * specified identifier. This method waits until all the images with
582: * the specified identifier have finished loading.
583: * <p>
584: * If there is an error while loading or scaling an image, then that
585: * image is considered to have finished loading. Use the
586: * <code>isErrorAny</code> and <code>isErrorID</code> methods to
587: * check for errors.
588: * @param id the identifier of the images to check.
589: * @see java.awt.MediaTracker#waitForAll
590: * @see java.awt.MediaTracker#isErrorAny()
591: * @see java.awt.MediaTracker#isErrorID(int)
592: * @exception InterruptedException if another thread has
593: * interrupted this thread.
594: * @since JDK1.0
595: */
596: public void waitForID(int id) throws InterruptedException {
597: waitForID(id, 0);
598: }
599:
600: /**
601: * Starts loading all images tracked by this media tracker with the
602: * specified identifier. This method waits until all the images with
603: * the specified identifier have finished loading, or until the
604: * length of time specified in milliseconds by the <code>ms</code>
605: * argument has passed.
606: * <p>
607: * If there is an error while loading or scaling an image, then that
608: * image is considered to have finished loading. Use the
609: * <code>statusID</code>, <code>isErrorID</code>, and
610: * <code>isErrorAny</code> methods to check for errors.
611: * @param id the identifier of the images to check.
612: * @param ms the length of time, in milliseconds, to wait
613: * for the loading to complete.
614: * @see java.awt.MediaTracker#waitForAll
615: * @see java.awt.MediaTracker#waitForID(int)
616: * @see java.awt.MediaTracker#statusID
617: * @see java.awt.MediaTracker#isErrorAny()
618: * @see java.awt.MediaTracker#isErrorID(int)
619: * @exception InterruptedException if another thread has
620: * interrupted this thread.
621: * @since JDK1.0
622: */
623: public synchronized boolean waitForID(int id, long ms)
624: throws InterruptedException {
625: long end = System.currentTimeMillis() + ms;
626: boolean first = true;
627: while (true) {
628: int status = statusID(id, first, first);
629: if ((status & LOADING) == 0) {
630: return (status == COMPLETE);
631: }
632: first = false;
633: long timeout;
634: if (ms == 0) {
635: timeout = 0;
636: } else {
637: timeout = end - System.currentTimeMillis();
638: if (timeout <= 0) {
639: return false;
640: }
641: }
642: wait(timeout);
643: }
644: }
645:
646: /**
647: * Calculates and returns the bitwise inclusive <b>OR</b> of the
648: * status of all media with the specified identifier that are
649: * tracked by this media tracker.
650: * <p>
651: * Possible flags defined by the
652: * <code>MediaTracker</code> class are <code>LOADING</code>,
653: * <code>ABORTED</code>, <code>ERRORED</code>, and
654: * <code>COMPLETE</code>. An image that hasn't started
655: * loading has zero as its status.
656: * <p>
657: * If the value of <code>load</code> is <code>true</code>, then
658: * this method starts loading any images that are not yet being loaded.
659: * @param id the identifier of the images to check.
660: * @param load if <code>true</code>, start loading
661: * any images that are not yet being loaded.
662: * @return the bitwise inclusive <b>OR</b> of the status of
663: * all of the media with the specified
664: * identifier that are being tracked.
665: * @see java.awt.MediaTracker#statusAll(boolean)
666: * @see java.awt.MediaTracker#LOADING
667: * @see java.awt.MediaTracker#ABORTED
668: * @see java.awt.MediaTracker#ERRORED
669: * @see java.awt.MediaTracker#COMPLETE
670: * @since JDK1.0
671: */
672: public int statusID(int id, boolean load) {
673: return statusID(id, load, true);
674: }
675:
676: private synchronized int statusID(int id, boolean load,
677: boolean verify) {
678: MediaEntry cur = head;
679: int status = 0;
680: while (cur != null) {
681: if (cur.getID() == id) {
682: status = status | cur.getStatus(load, verify);
683: }
684: cur = cur.next;
685: }
686: return status;
687: }
688:
689: /**
690: * Remove the specified image from this media tracker.
691: * All instances of the specified image are removed,
692: * regardless of scale or ID.
693: * @param image the image to be removed
694: * @see java.awt.MediaTracker#removeImage(java.awt.Image, int)
695: * @see java.awt.MediaTracker#removeImage(java.awt.Image, int, int, int)
696: * @since JDK1.1
697: */
698: public synchronized void removeImage(Image image) {
699: MediaEntry cur = head;
700: MediaEntry prev = null;
701: while (cur != null) {
702: MediaEntry next = cur.next;
703: if (cur.getMedia() == image) {
704: if (prev == null) {
705: head = next;
706: } else {
707: prev.next = next;
708: }
709: cur.cancel();
710: } else {
711: prev = cur;
712: }
713: cur = next;
714: }
715: notifyAll(); // Notify in case remaining images are "done".
716: }
717:
718: /**
719: * Remove the specified image from the specified tracking
720: * ID of this media tracker.
721: * All instances of <code>Image</code> being tracked
722: * under the specified ID are removed regardless of scale.
723: * @param image the image to be removed.
724: * @param id the tracking ID frrom which to remove the image.
725: * @see java.awt.MediaTracker#removeImage(java.awt.Image)
726: * @see java.awt.MediaTracker#removeImage(java.awt.Image, int, int, int)
727: * @since JDK1.1
728: */
729: public synchronized void removeImage(Image image, int id) {
730: MediaEntry cur = head;
731: MediaEntry prev = null;
732: while (cur != null) {
733: MediaEntry next = cur.next;
734: if (cur.getID() == id && cur.getMedia() == image) {
735: if (prev == null) {
736: head = next;
737: } else {
738: prev.next = next;
739: }
740: cur.cancel();
741: } else {
742: prev = cur;
743: }
744: cur = next;
745: }
746: notifyAll(); // Notify in case remaining images are "done".
747: }
748:
749: /**
750: * Remove the specified image with the specified
751: * width, height, and ID from this media tracker.
752: * Only the specified instance (with any duplicates) is removed.
753: * @param image the image to be removed
754: * @param id the tracking ID from which to remove the image.
755: * @param width the width to remove (-1 for unscaled).
756: * @param height the height to remove (-1 for unscaled).
757: * @see java.awt.MediaTracker#removeImage(java.awt.Image)
758: * @see java.awt.MediaTracker#removeImage(java.awt.Image, int)
759: * @since JDK1.1
760: */
761: public synchronized void removeImage(Image image, int id,
762: int width, int height) {
763: MediaEntry cur = head;
764: MediaEntry prev = null;
765: while (cur != null) {
766: MediaEntry next = cur.next;
767: if (cur.getID() == id
768: && cur instanceof ImageMediaEntry
769: && ((ImageMediaEntry) cur).matches(image, width,
770: height)) {
771: if (prev == null) {
772: head = next;
773: } else {
774: prev.next = next;
775: }
776: cur.cancel();
777: } else {
778: prev = cur;
779: }
780: cur = next;
781: }
782: notifyAll(); // Notify in case remaining images are "done".
783: }
784:
785: synchronized void setDone() {
786: notifyAll();
787: }
788: }
789:
790: abstract class MediaEntry {
791: MediaTracker tracker;
792: int ID;
793: MediaEntry next;
794: int status;
795: boolean cancelled;
796: /*
797: * JDK 1.1 serialVersionUID
798: */
799: private static final long serialVersionUID = -2924957284304726459L;
800:
801: MediaEntry(MediaTracker mt, int id) {
802: tracker = mt;
803: ID = id;
804: }
805:
806: abstract Object getMedia();
807:
808: static MediaEntry insert(MediaEntry head, MediaEntry me) {
809: MediaEntry cur = head;
810: MediaEntry prev = null;
811: while (cur != null) {
812: if (cur.ID > me.ID) {
813: break;
814: }
815: prev = cur;
816: cur = cur.next;
817: }
818: me.next = cur;
819: if (prev == null) {
820: head = me;
821: } else {
822: prev.next = me;
823: }
824: return head;
825: }
826:
827: int getID() {
828: return ID;
829: }
830:
831: abstract void startLoad();
832:
833: void cancel() {
834: cancelled = true;
835: }
836:
837: static final int LOADING = MediaTracker.LOADING;
838: static final int ABORTED = MediaTracker.ABORTED;
839: static final int ERRORED = MediaTracker.ERRORED;
840: static final int COMPLETE = MediaTracker.COMPLETE;
841: static final int LOADSTARTED = (LOADING | ERRORED | COMPLETE);
842: static final int DONE = (ABORTED | ERRORED | COMPLETE);
843:
844: synchronized int getStatus(boolean doLoad, boolean doVerify) {
845: if (doLoad && ((status & LOADSTARTED) == 0)) {
846: status = (status & ~ABORTED) | LOADING;
847: startLoad();
848: }
849: return status;
850: }
851:
852: void setStatus(int flag) {
853: synchronized (this ) {
854: status = flag;
855: }
856: tracker.setDone();
857: }
858: }
859:
860: class ImageMediaEntry extends MediaEntry implements ImageObserver,
861: java.io.Serializable {
862: Image image;
863: int width;
864: int height;
865:
866: ImageMediaEntry(MediaTracker mt, Image img, int c, int w, int h) {
867: super (mt, c);
868: image = img;
869: width = w;
870: height = h;
871: }
872:
873: boolean matches(Image img, int w, int h) {
874: return (image == img && width == w && height == h);
875: }
876:
877: Object getMedia() {
878: return image;
879: }
880:
881: int getStatus(boolean doLoad, boolean doVerify) {
882: if (doVerify) {
883: int flags = tracker.target.checkImage(image, width, height,
884: null);
885: int s = parseflags(flags);
886: if (s == 0) {
887: if ((status & (ERRORED | COMPLETE)) != 0) {
888: setStatus(ABORTED);
889: }
890: } else if (s != status) {
891: setStatus(s);
892: }
893: }
894: return super .getStatus(doLoad, doVerify);
895: }
896:
897: void startLoad() {
898: if (tracker.target.prepareImage(image, width, height, this )) {
899: setStatus(COMPLETE);
900: }
901: }
902:
903: int parseflags(int infoflags) {
904: if ((infoflags & ERROR) != 0) {
905: return ERRORED;
906: } else if ((infoflags & ABORT) != 0) {
907: return ABORTED;
908: } else if ((infoflags & (ALLBITS | FRAMEBITS)) != 0) {
909: return COMPLETE;
910: }
911: return 0;
912: }
913:
914: public boolean imageUpdate(Image img, int infoflags, int x, int y,
915: int w, int h) {
916: if (cancelled) {
917: return false;
918: }
919: int s = parseflags(infoflags);
920: if (s != 0 && s != status) {
921: setStatus(s);
922: }
923: return ((status & LOADING) != 0);
924: }
925: }
|