14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.awt;
27
28 import java.awt.Component;
29 import java.awt.Image;
30 import java.awt.image.ImageObserver;
31 import sun.awt.image.MultiResolutionToolkitImage;
32
33 /**
34 * The <code>MediaTracker</code> class is a utility class to track
35 * the status of a number of media objects. Media objects could
36 * include audio clips as well as images, though currently only
37 * images are supported.
38 * <p>
39 * To use a media tracker, create an instance of
40 * <code>MediaTracker</code> and call its <code>addImage</code>
41 * method for each image to be tracked. In addition, each image can
42 * be assigned a unique identifier. This identifier controls the
43 * priority order in which the images are fetched. It can also be used
44 * to identify unique subsets of the images that can be waited on
45 * independently. Images with a lower ID are loaded in preference to
46 * those with a higher ID number.
47 *
48 * <p>
49 *
50 * Tracking an animated image
51 * might not always be useful
52 * due to the multi-part nature of animated image
53 * loading and painting,
54 * but it is supported.
55 * <code>MediaTracker</code> treats an animated image
56 * as completely loaded
57 * when the first frame is completely loaded.
58 * At that point, the <code>MediaTracker</code>
59 * signals any waiters
60 * that the image is completely loaded.
61 * If no <code>ImageObserver</code>s are observing the image
62 * when the first frame has finished loading,
63 * the image might flush itself
64 * to conserve resources
65 * (see {@link Image#flush()}).
66 *
67 * <p>
68 * Here is an example of using <code>MediaTracker</code>:
69 *
70 * <hr><blockquote><pre>{@code
71 * import java.applet.Applet;
72 * import java.awt.Color;
73 * import java.awt.Image;
74 * import java.awt.Graphics;
75 * import java.awt.MediaTracker;
76 *
77 * public class ImageBlaster extends Applet implements Runnable {
78 * MediaTracker tracker;
79 * Image bg;
80 * Image anim[] = new Image[5];
81 * int index;
82 * Thread animator;
83 *
84 * // Get the images for the background (id == 0)
85 * // and the animation frames (id == 1)
86 * // and add them to the MediaTracker
87 * public void init() {
88 * tracker = new MediaTracker(this);
152 * public void paint(Graphics g) {
153 * if ((tracker.statusAll(false) & MediaTracker.ERRORED) != 0) {
154 * g.setColor(Color.red);
155 * g.fillRect(0, 0, size().width, size().height);
156 * return;
157 * }
158 * g.drawImage(bg, 0, 0, this);
159 * if (tracker.statusID(1, false) == MediaTracker.COMPLETE) {
160 * g.drawImage(anim[index], 10, 10, this);
161 * }
162 * }
163 * }
164 * } </pre></blockquote><hr>
165 *
166 * @author Jim Graham
167 * @since 1.0
168 */
169 public class MediaTracker implements java.io.Serializable {
170
171 /**
172 * A given <code>Component</code> that will be
173 * tracked by a media tracker where the image will
174 * eventually be drawn.
175 *
176 * @serial
177 * @see #MediaTracker(Component)
178 */
179 Component target;
180 /**
181 * The head of the list of <code>Images</code> that is being
182 * tracked by the <code>MediaTracker</code>.
183 *
184 * @serial
185 * @see #addImage(Image, int)
186 * @see #removeImage(Image)
187 */
188 MediaEntry head;
189
190 /*
191 * JDK 1.1 serialVersionUID
192 */
193 private static final long serialVersionUID = -483174189758638095L;
194
195 /**
196 * Creates a media tracker to track images for a given component.
197 * @param comp the component on which the images
198 * will eventually be drawn
199 */
200 public MediaTracker(Component comp) {
201 target = comp;
202 }
260
261 /**
262 * Flag indicating that the downloading of media was completed
263 * successfully.
264 * @see java.awt.MediaTracker#statusAll
265 * @see java.awt.MediaTracker#statusID
266 */
267 public static final int COMPLETE = 8;
268
269 static final int DONE = (ABORTED | ERRORED | COMPLETE);
270
271 /**
272 * Checks to see if all images being tracked by this media tracker
273 * have finished loading.
274 * <p>
275 * This method does not start loading the images if they are not
276 * already loading.
277 * <p>
278 * If there is an error while loading or scaling an image, then that
279 * image is considered to have finished loading. Use the
280 * <code>isErrorAny</code> or <code>isErrorID</code> methods to
281 * check for errors.
282 * @return <code>true</code> if all images have finished loading,
283 * have been aborted, or have encountered
284 * an error; <code>false</code> otherwise
285 * @see java.awt.MediaTracker#checkAll(boolean)
286 * @see java.awt.MediaTracker#checkID
287 * @see java.awt.MediaTracker#isErrorAny
288 * @see java.awt.MediaTracker#isErrorID
289 */
290 public boolean checkAll() {
291 return checkAll(false, true);
292 }
293
294 /**
295 * Checks to see if all images being tracked by this media tracker
296 * have finished loading.
297 * <p>
298 * If the value of the <code>load</code> flag is <code>true</code>,
299 * then this method starts loading any images that are not yet
300 * being loaded.
301 * <p>
302 * If there is an error while loading or scaling an image, that
303 * image is considered to have finished loading. Use the
304 * <code>isErrorAny</code> and <code>isErrorID</code> methods to
305 * check for errors.
306 * @param load if <code>true</code>, start loading any
307 * images that are not yet being loaded
308 * @return <code>true</code> if all images have finished loading,
309 * have been aborted, or have encountered
310 * an error; <code>false</code> otherwise
311 * @see java.awt.MediaTracker#checkID
312 * @see java.awt.MediaTracker#checkAll()
313 * @see java.awt.MediaTracker#isErrorAny()
314 * @see java.awt.MediaTracker#isErrorID(int)
315 */
316 public boolean checkAll(boolean load) {
317 return checkAll(load, true);
318 }
319
320 private synchronized boolean checkAll(boolean load, boolean verify) {
321 MediaEntry cur = head;
322 boolean done = true;
323 while (cur != null) {
324 if ((cur.getStatus(load, verify) & DONE) == 0) {
325 done = false;
326 }
327 cur = cur.next;
328 }
329 return done;
330 }
331
332 /**
333 * Checks the error status of all of the images.
334 * @return <code>true</code> if any of the images tracked
335 * by this media tracker had an error during
336 * loading; <code>false</code> otherwise
337 * @see java.awt.MediaTracker#isErrorID
338 * @see java.awt.MediaTracker#getErrorsAny
339 */
340 public synchronized boolean isErrorAny() {
341 MediaEntry cur = head;
342 while (cur != null) {
343 if ((cur.getStatus(false, true) & ERRORED) != 0) {
344 return true;
345 }
346 cur = cur.next;
347 }
348 return false;
349 }
350
351 /**
352 * Returns a list of all media that have encountered an error.
353 * @return an array of media objects tracked by this
354 * media tracker that have encountered
355 * an error, or <code>null</code> if
356 * there are none with errors
357 * @see java.awt.MediaTracker#isErrorAny
358 * @see java.awt.MediaTracker#getErrorsID
359 */
360 public synchronized Object[] getErrorsAny() {
361 MediaEntry cur = head;
362 int numerrors = 0;
363 while (cur != null) {
364 if ((cur.getStatus(false, true) & ERRORED) != 0) {
365 numerrors++;
366 }
367 cur = cur.next;
368 }
369 if (numerrors == 0) {
370 return null;
371 }
372 Object errors[] = new Object[numerrors];
373 cur = head;
374 numerrors = 0;
375 while (cur != null) {
376 if ((cur.getStatus(false, false) & ERRORED) != 0) {
377 errors[numerrors++] = cur.getMedia();
378 }
379 cur = cur.next;
380 }
381 return errors;
382 }
383
384 /**
385 * Starts loading all images tracked by this media tracker. This
386 * method waits until all the images being tracked have finished
387 * loading.
388 * <p>
389 * If there is an error while loading or scaling an image, then that
390 * image is considered to have finished loading. Use the
391 * <code>isErrorAny</code> or <code>isErrorID</code> methods to
392 * check for errors.
393 * @see java.awt.MediaTracker#waitForID(int)
394 * @see java.awt.MediaTracker#waitForAll(long)
395 * @see java.awt.MediaTracker#isErrorAny
396 * @see java.awt.MediaTracker#isErrorID
397 * @exception InterruptedException if any thread has
398 * interrupted this thread
399 */
400 public void waitForAll() throws InterruptedException {
401 waitForAll(0);
402 }
403
404 /**
405 * Starts loading all images tracked by this media tracker. This
406 * method waits until all the images being tracked have finished
407 * loading, or until the length of time specified in milliseconds
408 * by the <code>ms</code> argument has passed.
409 * <p>
410 * If there is an error while loading or scaling an image, then
411 * that image is considered to have finished loading. Use the
412 * <code>isErrorAny</code> or <code>isErrorID</code> methods to
413 * check for errors.
414 * @param ms the number of milliseconds to wait
415 * for the loading to complete
416 * @return <code>true</code> if all images were successfully
417 * loaded; <code>false</code> otherwise
418 * @see java.awt.MediaTracker#waitForID(int)
419 * @see java.awt.MediaTracker#waitForAll(long)
420 * @see java.awt.MediaTracker#isErrorAny
421 * @see java.awt.MediaTracker#isErrorID
422 * @exception InterruptedException if any thread has
423 * interrupted this thread.
424 */
425 public synchronized boolean waitForAll(long ms)
426 throws InterruptedException
427 {
428 long end = System.currentTimeMillis() + ms;
429 boolean first = true;
430 while (true) {
431 int status = statusAll(first, first);
432 if ((status & LOADING) == 0) {
433 return (status == COMPLETE);
434 }
435 first = false;
436 long timeout;
437 if (ms == 0) {
438 timeout = 0;
439 } else {
440 timeout = end - System.currentTimeMillis();
441 if (timeout <= 0) {
442 return false;
443 }
444 }
445 wait(timeout);
446 }
447 }
448
449 /**
450 * Calculates and returns the bitwise inclusive <b>OR</b> of the
451 * status of all media that are tracked by this media tracker.
452 * <p>
453 * Possible flags defined by the
454 * <code>MediaTracker</code> class are <code>LOADING</code>,
455 * <code>ABORTED</code>, <code>ERRORED</code>, and
456 * <code>COMPLETE</code>. An image that hasn't started
457 * loading has zero as its status.
458 * <p>
459 * If the value of <code>load</code> is <code>true</code>, then
460 * this method starts loading any images that are not yet being loaded.
461 *
462 * @param load if <code>true</code>, start loading
463 * any images that are not yet being loaded
464 * @return the bitwise inclusive <b>OR</b> of the status of
465 * all of the media being tracked
466 * @see java.awt.MediaTracker#statusID(int, boolean)
467 * @see java.awt.MediaTracker#LOADING
468 * @see java.awt.MediaTracker#ABORTED
469 * @see java.awt.MediaTracker#ERRORED
470 * @see java.awt.MediaTracker#COMPLETE
471 */
472 public int statusAll(boolean load) {
473 return statusAll(load, true);
474 }
475
476 private synchronized int statusAll(boolean load, boolean verify) {
477 MediaEntry cur = head;
478 int status = 0;
479 while (cur != null) {
480 status = status | cur.getStatus(load, verify);
481 cur = cur.next;
482 }
483 return status;
484 }
485
486 /**
487 * Checks to see if all images tracked by this media tracker that
488 * are tagged with the specified identifier have finished loading.
489 * <p>
490 * This method does not start loading the images if they are not
491 * already loading.
492 * <p>
493 * If there is an error while loading or scaling an image, then that
494 * image is considered to have finished loading. Use the
495 * <code>isErrorAny</code> or <code>isErrorID</code> methods to
496 * check for errors.
497 * @param id the identifier of the images to check
498 * @return <code>true</code> if all images have finished loading,
499 * have been aborted, or have encountered
500 * an error; <code>false</code> otherwise
501 * @see java.awt.MediaTracker#checkID(int, boolean)
502 * @see java.awt.MediaTracker#checkAll()
503 * @see java.awt.MediaTracker#isErrorAny()
504 * @see java.awt.MediaTracker#isErrorID(int)
505 */
506 public boolean checkID(int id) {
507 return checkID(id, false, true);
508 }
509
510 /**
511 * Checks to see if all images tracked by this media tracker that
512 * are tagged with the specified identifier have finished loading.
513 * <p>
514 * If the value of the <code>load</code> flag is <code>true</code>,
515 * then this method starts loading any images that are not yet
516 * being loaded.
517 * <p>
518 * If there is an error while loading or scaling an image, then that
519 * image is considered to have finished loading. Use the
520 * <code>isErrorAny</code> or <code>isErrorID</code> methods to
521 * check for errors.
522 * @param id the identifier of the images to check
523 * @param load if <code>true</code>, start loading any
524 * images that are not yet being loaded
525 * @return <code>true</code> if all images have finished loading,
526 * have been aborted, or have encountered
527 * an error; <code>false</code> otherwise
528 * @see java.awt.MediaTracker#checkID(int, boolean)
529 * @see java.awt.MediaTracker#checkAll()
530 * @see java.awt.MediaTracker#isErrorAny()
531 * @see java.awt.MediaTracker#isErrorID(int)
532 */
533 public boolean checkID(int id, boolean load) {
534 return checkID(id, load, true);
535 }
536
537 private synchronized boolean checkID(int id, boolean load, boolean verify)
538 {
539 MediaEntry cur = head;
540 boolean done = true;
541 while (cur != null) {
542 if (cur.getID() == id
543 && (cur.getStatus(load, verify) & DONE) == 0)
544 {
545 done = false;
546 }
547 cur = cur.next;
548 }
549 return done;
550 }
551
552 /**
553 * Checks the error status of all of the images tracked by this
554 * media tracker with the specified identifier.
555 * @param id the identifier of the images to check
556 * @return <code>true</code> if any of the images with the
557 * specified identifier had an error during
558 * loading; <code>false</code> otherwise
559 * @see java.awt.MediaTracker#isErrorAny
560 * @see java.awt.MediaTracker#getErrorsID
561 */
562 public synchronized boolean isErrorID(int id) {
563 MediaEntry cur = head;
564 while (cur != null) {
565 if (cur.getID() == id
566 && (cur.getStatus(false, true) & ERRORED) != 0)
567 {
568 return true;
569 }
570 cur = cur.next;
571 }
572 return false;
573 }
574
575 /**
576 * Returns a list of media with the specified ID that
577 * have encountered an error.
578 * @param id the identifier of the images to check
579 * @return an array of media objects tracked by this media
580 * tracker with the specified identifier
581 * that have encountered an error, or
582 * <code>null</code> if there are none with errors
583 * @see java.awt.MediaTracker#isErrorID
584 * @see java.awt.MediaTracker#isErrorAny
585 * @see java.awt.MediaTracker#getErrorsAny
586 */
587 public synchronized Object[] getErrorsID(int id) {
588 MediaEntry cur = head;
589 int numerrors = 0;
590 while (cur != null) {
591 if (cur.getID() == id
592 && (cur.getStatus(false, true) & ERRORED) != 0)
593 {
594 numerrors++;
595 }
596 cur = cur.next;
597 }
598 if (numerrors == 0) {
599 return null;
600 }
601 Object errors[] = new Object[numerrors];
602 cur = head;
603 numerrors = 0;
604 while (cur != null) {
605 if (cur.getID() == id
606 && (cur.getStatus(false, false) & ERRORED) != 0)
607 {
608 errors[numerrors++] = cur.getMedia();
609 }
610 cur = cur.next;
611 }
612 return errors;
613 }
614
615 /**
616 * Starts loading all images tracked by this media tracker with the
617 * specified identifier. This method waits until all the images with
618 * the specified identifier have finished loading.
619 * <p>
620 * If there is an error while loading or scaling an image, then that
621 * image is considered to have finished loading. Use the
622 * <code>isErrorAny</code> and <code>isErrorID</code> methods to
623 * check for errors.
624 * @param id the identifier of the images to check
625 * @see java.awt.MediaTracker#waitForAll
626 * @see java.awt.MediaTracker#isErrorAny()
627 * @see java.awt.MediaTracker#isErrorID(int)
628 * @exception InterruptedException if any thread has
629 * interrupted this thread.
630 */
631 public void waitForID(int id) throws InterruptedException {
632 waitForID(id, 0);
633 }
634
635 /**
636 * Starts loading all images tracked by this media tracker with the
637 * specified identifier. This method waits until all the images with
638 * the specified identifier have finished loading, or until the
639 * length of time specified in milliseconds by the <code>ms</code>
640 * argument has passed.
641 * <p>
642 * If there is an error while loading or scaling an image, then that
643 * image is considered to have finished loading. Use the
644 * <code>statusID</code>, <code>isErrorID</code>, and
645 * <code>isErrorAny</code> methods to check for errors.
646 * @param id the identifier of the images to check
647 * @param ms the length of time, in milliseconds, to wait
648 * for the loading to complete
649 * @return {@code true} if the loading completed in time;
650 * otherwise {@code false}
651 * @see java.awt.MediaTracker#waitForAll
652 * @see java.awt.MediaTracker#waitForID(int)
653 * @see java.awt.MediaTracker#statusID
654 * @see java.awt.MediaTracker#isErrorAny()
655 * @see java.awt.MediaTracker#isErrorID(int)
656 * @exception InterruptedException if any thread has
657 * interrupted this thread.
658 */
659 public synchronized boolean waitForID(int id, long ms)
660 throws InterruptedException
661 {
662 long end = System.currentTimeMillis() + ms;
663 boolean first = true;
664 while (true) {
665 int status = statusID(id, first, first);
669 first = false;
670 long timeout;
671 if (ms == 0) {
672 timeout = 0;
673 } else {
674 timeout = end - System.currentTimeMillis();
675 if (timeout <= 0) {
676 return false;
677 }
678 }
679 wait(timeout);
680 }
681 }
682
683 /**
684 * Calculates and returns the bitwise inclusive <b>OR</b> of the
685 * status of all media with the specified identifier that are
686 * tracked by this media tracker.
687 * <p>
688 * Possible flags defined by the
689 * <code>MediaTracker</code> class are <code>LOADING</code>,
690 * <code>ABORTED</code>, <code>ERRORED</code>, and
691 * <code>COMPLETE</code>. An image that hasn't started
692 * loading has zero as its status.
693 * <p>
694 * If the value of <code>load</code> is <code>true</code>, then
695 * this method starts loading any images that are not yet being loaded.
696 * @param id the identifier of the images to check
697 * @param load if <code>true</code>, start loading
698 * any images that are not yet being loaded
699 * @return the bitwise inclusive <b>OR</b> of the status of
700 * all of the media with the specified
701 * identifier that are being tracked
702 * @see java.awt.MediaTracker#statusAll(boolean)
703 * @see java.awt.MediaTracker#LOADING
704 * @see java.awt.MediaTracker#ABORTED
705 * @see java.awt.MediaTracker#ERRORED
706 * @see java.awt.MediaTracker#COMPLETE
707 */
708 public int statusID(int id, boolean load) {
709 return statusID(id, load, true);
710 }
711
712 private synchronized int statusID(int id, boolean load, boolean verify) {
713 MediaEntry cur = head;
714 int status = 0;
715 while (cur != null) {
716 if (cur.getID() == id) {
717 status = status | cur.getStatus(load, verify);
744 MediaEntry prev = null;
745 while (cur != null) {
746 MediaEntry next = cur.next;
747 if (cur.getMedia() == image) {
748 if (prev == null) {
749 head = next;
750 } else {
751 prev.next = next;
752 }
753 cur.cancel();
754 } else {
755 prev = cur;
756 }
757 cur = next;
758 }
759 }
760
761 /**
762 * Removes the specified image from the specified tracking
763 * ID of this media tracker.
764 * All instances of <code>Image</code> being tracked
765 * under the specified ID are removed regardless of scale.
766 * @param image the image to be removed
767 * @param id the tracking ID from which to remove the image
768 * @see java.awt.MediaTracker#removeImage(java.awt.Image)
769 * @see java.awt.MediaTracker#removeImage(java.awt.Image, int, int, int)
770 * @since 1.1
771 */
772 public synchronized void removeImage(Image image, int id) {
773 removeImageImpl(image, id);
774 Image rvImage = getResolutionVariant(image);
775 if (rvImage != null) {
776 removeImageImpl(rvImage, id);
777 }
778 notifyAll(); // Notify in case remaining images are "done".
779 }
780
781 private void removeImageImpl(Image image, int id) {
782 MediaEntry cur = head;
783 MediaEntry prev = null;
784 while (cur != null) {
|
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.awt;
27
28 import java.awt.Component;
29 import java.awt.Image;
30 import java.awt.image.ImageObserver;
31 import sun.awt.image.MultiResolutionToolkitImage;
32
33 /**
34 * The {@code MediaTracker} class is a utility class to track
35 * the status of a number of media objects. Media objects could
36 * include audio clips as well as images, though currently only
37 * images are supported.
38 * <p>
39 * To use a media tracker, create an instance of
40 * {@code MediaTracker} and call its {@code addImage}
41 * method for each image to be tracked. In addition, each image can
42 * be assigned a unique identifier. This identifier controls the
43 * priority order in which the images are fetched. It can also be used
44 * to identify unique subsets of the images that can be waited on
45 * independently. Images with a lower ID are loaded in preference to
46 * those with a higher ID number.
47 *
48 * <p>
49 *
50 * Tracking an animated image
51 * might not always be useful
52 * due to the multi-part nature of animated image
53 * loading and painting,
54 * but it is supported.
55 * {@code MediaTracker} treats an animated image
56 * as completely loaded
57 * when the first frame is completely loaded.
58 * At that point, the {@code MediaTracker}
59 * signals any waiters
60 * that the image is completely loaded.
61 * If no {@code ImageObserver}s are observing the image
62 * when the first frame has finished loading,
63 * the image might flush itself
64 * to conserve resources
65 * (see {@link Image#flush()}).
66 *
67 * <p>
68 * Here is an example of using {@code MediaTracker}:
69 *
70 * <hr><blockquote><pre>{@code
71 * import java.applet.Applet;
72 * import java.awt.Color;
73 * import java.awt.Image;
74 * import java.awt.Graphics;
75 * import java.awt.MediaTracker;
76 *
77 * public class ImageBlaster extends Applet implements Runnable {
78 * MediaTracker tracker;
79 * Image bg;
80 * Image anim[] = new Image[5];
81 * int index;
82 * Thread animator;
83 *
84 * // Get the images for the background (id == 0)
85 * // and the animation frames (id == 1)
86 * // and add them to the MediaTracker
87 * public void init() {
88 * tracker = new MediaTracker(this);
152 * public void paint(Graphics g) {
153 * if ((tracker.statusAll(false) & MediaTracker.ERRORED) != 0) {
154 * g.setColor(Color.red);
155 * g.fillRect(0, 0, size().width, size().height);
156 * return;
157 * }
158 * g.drawImage(bg, 0, 0, this);
159 * if (tracker.statusID(1, false) == MediaTracker.COMPLETE) {
160 * g.drawImage(anim[index], 10, 10, this);
161 * }
162 * }
163 * }
164 * } </pre></blockquote><hr>
165 *
166 * @author Jim Graham
167 * @since 1.0
168 */
169 public class MediaTracker implements java.io.Serializable {
170
171 /**
172 * A given {@code Component} that will be
173 * tracked by a media tracker where the image will
174 * eventually be drawn.
175 *
176 * @serial
177 * @see #MediaTracker(Component)
178 */
179 Component target;
180 /**
181 * The head of the list of {@code Images} that is being
182 * tracked by the {@code MediaTracker}.
183 *
184 * @serial
185 * @see #addImage(Image, int)
186 * @see #removeImage(Image)
187 */
188 MediaEntry head;
189
190 /*
191 * JDK 1.1 serialVersionUID
192 */
193 private static final long serialVersionUID = -483174189758638095L;
194
195 /**
196 * Creates a media tracker to track images for a given component.
197 * @param comp the component on which the images
198 * will eventually be drawn
199 */
200 public MediaTracker(Component comp) {
201 target = comp;
202 }
260
261 /**
262 * Flag indicating that the downloading of media was completed
263 * successfully.
264 * @see java.awt.MediaTracker#statusAll
265 * @see java.awt.MediaTracker#statusID
266 */
267 public static final int COMPLETE = 8;
268
269 static final int DONE = (ABORTED | ERRORED | COMPLETE);
270
271 /**
272 * Checks to see if all images being tracked by this media tracker
273 * have finished loading.
274 * <p>
275 * This method does not start loading the images if they are not
276 * already loading.
277 * <p>
278 * If there is an error while loading or scaling an image, then that
279 * image is considered to have finished loading. Use the
280 * {@code isErrorAny} or {@code isErrorID} methods to
281 * check for errors.
282 * @return {@code true} if all images have finished loading,
283 * have been aborted, or have encountered
284 * an error; {@code false} otherwise
285 * @see java.awt.MediaTracker#checkAll(boolean)
286 * @see java.awt.MediaTracker#checkID
287 * @see java.awt.MediaTracker#isErrorAny
288 * @see java.awt.MediaTracker#isErrorID
289 */
290 public boolean checkAll() {
291 return checkAll(false, true);
292 }
293
294 /**
295 * Checks to see if all images being tracked by this media tracker
296 * have finished loading.
297 * <p>
298 * If the value of the {@code load} flag is {@code true},
299 * then this method starts loading any images that are not yet
300 * being loaded.
301 * <p>
302 * If there is an error while loading or scaling an image, that
303 * image is considered to have finished loading. Use the
304 * {@code isErrorAny} and {@code isErrorID} methods to
305 * check for errors.
306 * @param load if {@code true}, start loading any
307 * images that are not yet being loaded
308 * @return {@code true} if all images have finished loading,
309 * have been aborted, or have encountered
310 * an error; {@code false} otherwise
311 * @see java.awt.MediaTracker#checkID
312 * @see java.awt.MediaTracker#checkAll()
313 * @see java.awt.MediaTracker#isErrorAny()
314 * @see java.awt.MediaTracker#isErrorID(int)
315 */
316 public boolean checkAll(boolean load) {
317 return checkAll(load, true);
318 }
319
320 private synchronized boolean checkAll(boolean load, boolean verify) {
321 MediaEntry cur = head;
322 boolean done = true;
323 while (cur != null) {
324 if ((cur.getStatus(load, verify) & DONE) == 0) {
325 done = false;
326 }
327 cur = cur.next;
328 }
329 return done;
330 }
331
332 /**
333 * Checks the error status of all of the images.
334 * @return {@code true} if any of the images tracked
335 * by this media tracker had an error during
336 * loading; {@code false} otherwise
337 * @see java.awt.MediaTracker#isErrorID
338 * @see java.awt.MediaTracker#getErrorsAny
339 */
340 public synchronized boolean isErrorAny() {
341 MediaEntry cur = head;
342 while (cur != null) {
343 if ((cur.getStatus(false, true) & ERRORED) != 0) {
344 return true;
345 }
346 cur = cur.next;
347 }
348 return false;
349 }
350
351 /**
352 * Returns a list of all media that have encountered an error.
353 * @return an array of media objects tracked by this
354 * media tracker that have encountered
355 * an error, or {@code null} if
356 * there are none with errors
357 * @see java.awt.MediaTracker#isErrorAny
358 * @see java.awt.MediaTracker#getErrorsID
359 */
360 public synchronized Object[] getErrorsAny() {
361 MediaEntry cur = head;
362 int numerrors = 0;
363 while (cur != null) {
364 if ((cur.getStatus(false, true) & ERRORED) != 0) {
365 numerrors++;
366 }
367 cur = cur.next;
368 }
369 if (numerrors == 0) {
370 return null;
371 }
372 Object errors[] = new Object[numerrors];
373 cur = head;
374 numerrors = 0;
375 while (cur != null) {
376 if ((cur.getStatus(false, false) & ERRORED) != 0) {
377 errors[numerrors++] = cur.getMedia();
378 }
379 cur = cur.next;
380 }
381 return errors;
382 }
383
384 /**
385 * Starts loading all images tracked by this media tracker. This
386 * method waits until all the images being tracked have finished
387 * loading.
388 * <p>
389 * If there is an error while loading or scaling an image, then that
390 * image is considered to have finished loading. Use the
391 * {@code isErrorAny} or {@code isErrorID} methods to
392 * check for errors.
393 * @see java.awt.MediaTracker#waitForID(int)
394 * @see java.awt.MediaTracker#waitForAll(long)
395 * @see java.awt.MediaTracker#isErrorAny
396 * @see java.awt.MediaTracker#isErrorID
397 * @exception InterruptedException if any thread has
398 * interrupted this thread
399 */
400 public void waitForAll() throws InterruptedException {
401 waitForAll(0);
402 }
403
404 /**
405 * Starts loading all images tracked by this media tracker. This
406 * method waits until all the images being tracked have finished
407 * loading, or until the length of time specified in milliseconds
408 * by the {@code ms} argument has passed.
409 * <p>
410 * If there is an error while loading or scaling an image, then
411 * that image is considered to have finished loading. Use the
412 * {@code isErrorAny} or {@code isErrorID} methods to
413 * check for errors.
414 * @param ms the number of milliseconds to wait
415 * for the loading to complete
416 * @return {@code true} if all images were successfully
417 * loaded; {@code false} otherwise
418 * @see java.awt.MediaTracker#waitForID(int)
419 * @see java.awt.MediaTracker#waitForAll(long)
420 * @see java.awt.MediaTracker#isErrorAny
421 * @see java.awt.MediaTracker#isErrorID
422 * @exception InterruptedException if any thread has
423 * interrupted this thread.
424 */
425 public synchronized boolean waitForAll(long ms)
426 throws InterruptedException
427 {
428 long end = System.currentTimeMillis() + ms;
429 boolean first = true;
430 while (true) {
431 int status = statusAll(first, first);
432 if ((status & LOADING) == 0) {
433 return (status == COMPLETE);
434 }
435 first = false;
436 long timeout;
437 if (ms == 0) {
438 timeout = 0;
439 } else {
440 timeout = end - System.currentTimeMillis();
441 if (timeout <= 0) {
442 return false;
443 }
444 }
445 wait(timeout);
446 }
447 }
448
449 /**
450 * Calculates and returns the bitwise inclusive <b>OR</b> of the
451 * status of all media that are tracked by this media tracker.
452 * <p>
453 * Possible flags defined by the
454 * {@code MediaTracker} class are {@code LOADING},
455 * {@code ABORTED}, {@code ERRORED}, and
456 * {@code COMPLETE}. An image that hasn't started
457 * loading has zero as its status.
458 * <p>
459 * If the value of {@code load} is {@code true}, then
460 * this method starts loading any images that are not yet being loaded.
461 *
462 * @param load if {@code true}, start loading
463 * any images that are not yet being loaded
464 * @return the bitwise inclusive <b>OR</b> of the status of
465 * all of the media being tracked
466 * @see java.awt.MediaTracker#statusID(int, boolean)
467 * @see java.awt.MediaTracker#LOADING
468 * @see java.awt.MediaTracker#ABORTED
469 * @see java.awt.MediaTracker#ERRORED
470 * @see java.awt.MediaTracker#COMPLETE
471 */
472 public int statusAll(boolean load) {
473 return statusAll(load, true);
474 }
475
476 private synchronized int statusAll(boolean load, boolean verify) {
477 MediaEntry cur = head;
478 int status = 0;
479 while (cur != null) {
480 status = status | cur.getStatus(load, verify);
481 cur = cur.next;
482 }
483 return status;
484 }
485
486 /**
487 * Checks to see if all images tracked by this media tracker that
488 * are tagged with the specified identifier have finished loading.
489 * <p>
490 * This method does not start loading the images if they are not
491 * already loading.
492 * <p>
493 * If there is an error while loading or scaling an image, then that
494 * image is considered to have finished loading. Use the
495 * {@code isErrorAny} or {@code isErrorID} methods to
496 * check for errors.
497 * @param id the identifier of the images to check
498 * @return {@code true} if all images have finished loading,
499 * have been aborted, or have encountered
500 * an error; {@code false} otherwise
501 * @see java.awt.MediaTracker#checkID(int, boolean)
502 * @see java.awt.MediaTracker#checkAll()
503 * @see java.awt.MediaTracker#isErrorAny()
504 * @see java.awt.MediaTracker#isErrorID(int)
505 */
506 public boolean checkID(int id) {
507 return checkID(id, false, true);
508 }
509
510 /**
511 * Checks to see if all images tracked by this media tracker that
512 * are tagged with the specified identifier have finished loading.
513 * <p>
514 * If the value of the {@code load} flag is {@code true},
515 * then this method starts loading any images that are not yet
516 * being loaded.
517 * <p>
518 * If there is an error while loading or scaling an image, then that
519 * image is considered to have finished loading. Use the
520 * {@code isErrorAny} or {@code isErrorID} methods to
521 * check for errors.
522 * @param id the identifier of the images to check
523 * @param load if {@code true}, start loading any
524 * images that are not yet being loaded
525 * @return {@code true} if all images have finished loading,
526 * have been aborted, or have encountered
527 * an error; {@code false} otherwise
528 * @see java.awt.MediaTracker#checkID(int, boolean)
529 * @see java.awt.MediaTracker#checkAll()
530 * @see java.awt.MediaTracker#isErrorAny()
531 * @see java.awt.MediaTracker#isErrorID(int)
532 */
533 public boolean checkID(int id, boolean load) {
534 return checkID(id, load, true);
535 }
536
537 private synchronized boolean checkID(int id, boolean load, boolean verify)
538 {
539 MediaEntry cur = head;
540 boolean done = true;
541 while (cur != null) {
542 if (cur.getID() == id
543 && (cur.getStatus(load, verify) & DONE) == 0)
544 {
545 done = false;
546 }
547 cur = cur.next;
548 }
549 return done;
550 }
551
552 /**
553 * Checks the error status of all of the images tracked by this
554 * media tracker with the specified identifier.
555 * @param id the identifier of the images to check
556 * @return {@code true} if any of the images with the
557 * specified identifier had an error during
558 * loading; {@code false} otherwise
559 * @see java.awt.MediaTracker#isErrorAny
560 * @see java.awt.MediaTracker#getErrorsID
561 */
562 public synchronized boolean isErrorID(int id) {
563 MediaEntry cur = head;
564 while (cur != null) {
565 if (cur.getID() == id
566 && (cur.getStatus(false, true) & ERRORED) != 0)
567 {
568 return true;
569 }
570 cur = cur.next;
571 }
572 return false;
573 }
574
575 /**
576 * Returns a list of media with the specified ID that
577 * have encountered an error.
578 * @param id the identifier of the images to check
579 * @return an array of media objects tracked by this media
580 * tracker with the specified identifier
581 * that have encountered an error, or
582 * {@code null} if there are none with errors
583 * @see java.awt.MediaTracker#isErrorID
584 * @see java.awt.MediaTracker#isErrorAny
585 * @see java.awt.MediaTracker#getErrorsAny
586 */
587 public synchronized Object[] getErrorsID(int id) {
588 MediaEntry cur = head;
589 int numerrors = 0;
590 while (cur != null) {
591 if (cur.getID() == id
592 && (cur.getStatus(false, true) & ERRORED) != 0)
593 {
594 numerrors++;
595 }
596 cur = cur.next;
597 }
598 if (numerrors == 0) {
599 return null;
600 }
601 Object errors[] = new Object[numerrors];
602 cur = head;
603 numerrors = 0;
604 while (cur != null) {
605 if (cur.getID() == id
606 && (cur.getStatus(false, false) & ERRORED) != 0)
607 {
608 errors[numerrors++] = cur.getMedia();
609 }
610 cur = cur.next;
611 }
612 return errors;
613 }
614
615 /**
616 * Starts loading all images tracked by this media tracker with the
617 * specified identifier. This method waits until all the images with
618 * the specified identifier have finished loading.
619 * <p>
620 * If there is an error while loading or scaling an image, then that
621 * image is considered to have finished loading. Use the
622 * {@code isErrorAny} and {@code isErrorID} methods to
623 * check for errors.
624 * @param id the identifier of the images to check
625 * @see java.awt.MediaTracker#waitForAll
626 * @see java.awt.MediaTracker#isErrorAny()
627 * @see java.awt.MediaTracker#isErrorID(int)
628 * @exception InterruptedException if any thread has
629 * interrupted this thread.
630 */
631 public void waitForID(int id) throws InterruptedException {
632 waitForID(id, 0);
633 }
634
635 /**
636 * Starts loading all images tracked by this media tracker with the
637 * specified identifier. This method waits until all the images with
638 * the specified identifier have finished loading, or until the
639 * length of time specified in milliseconds by the {@code ms}
640 * argument has passed.
641 * <p>
642 * If there is an error while loading or scaling an image, then that
643 * image is considered to have finished loading. Use the
644 * {@code statusID}, {@code isErrorID}, and
645 * {@code isErrorAny} methods to check for errors.
646 * @param id the identifier of the images to check
647 * @param ms the length of time, in milliseconds, to wait
648 * for the loading to complete
649 * @return {@code true} if the loading completed in time;
650 * otherwise {@code false}
651 * @see java.awt.MediaTracker#waitForAll
652 * @see java.awt.MediaTracker#waitForID(int)
653 * @see java.awt.MediaTracker#statusID
654 * @see java.awt.MediaTracker#isErrorAny()
655 * @see java.awt.MediaTracker#isErrorID(int)
656 * @exception InterruptedException if any thread has
657 * interrupted this thread.
658 */
659 public synchronized boolean waitForID(int id, long ms)
660 throws InterruptedException
661 {
662 long end = System.currentTimeMillis() + ms;
663 boolean first = true;
664 while (true) {
665 int status = statusID(id, first, first);
669 first = false;
670 long timeout;
671 if (ms == 0) {
672 timeout = 0;
673 } else {
674 timeout = end - System.currentTimeMillis();
675 if (timeout <= 0) {
676 return false;
677 }
678 }
679 wait(timeout);
680 }
681 }
682
683 /**
684 * Calculates and returns the bitwise inclusive <b>OR</b> of the
685 * status of all media with the specified identifier that are
686 * tracked by this media tracker.
687 * <p>
688 * Possible flags defined by the
689 * {@code MediaTracker} class are {@code LOADING},
690 * {@code ABORTED}, {@code ERRORED}, and
691 * {@code COMPLETE}. An image that hasn't started
692 * loading has zero as its status.
693 * <p>
694 * If the value of {@code load} is {@code true}, then
695 * this method starts loading any images that are not yet being loaded.
696 * @param id the identifier of the images to check
697 * @param load if {@code true}, start loading
698 * any images that are not yet being loaded
699 * @return the bitwise inclusive <b>OR</b> of the status of
700 * all of the media with the specified
701 * identifier that are being tracked
702 * @see java.awt.MediaTracker#statusAll(boolean)
703 * @see java.awt.MediaTracker#LOADING
704 * @see java.awt.MediaTracker#ABORTED
705 * @see java.awt.MediaTracker#ERRORED
706 * @see java.awt.MediaTracker#COMPLETE
707 */
708 public int statusID(int id, boolean load) {
709 return statusID(id, load, true);
710 }
711
712 private synchronized int statusID(int id, boolean load, boolean verify) {
713 MediaEntry cur = head;
714 int status = 0;
715 while (cur != null) {
716 if (cur.getID() == id) {
717 status = status | cur.getStatus(load, verify);
744 MediaEntry prev = null;
745 while (cur != null) {
746 MediaEntry next = cur.next;
747 if (cur.getMedia() == image) {
748 if (prev == null) {
749 head = next;
750 } else {
751 prev.next = next;
752 }
753 cur.cancel();
754 } else {
755 prev = cur;
756 }
757 cur = next;
758 }
759 }
760
761 /**
762 * Removes the specified image from the specified tracking
763 * ID of this media tracker.
764 * All instances of {@code Image} being tracked
765 * under the specified ID are removed regardless of scale.
766 * @param image the image to be removed
767 * @param id the tracking ID from which to remove the image
768 * @see java.awt.MediaTracker#removeImage(java.awt.Image)
769 * @see java.awt.MediaTracker#removeImage(java.awt.Image, int, int, int)
770 * @since 1.1
771 */
772 public synchronized void removeImage(Image image, int id) {
773 removeImageImpl(image, id);
774 Image rvImage = getResolutionVariant(image);
775 if (rvImage != null) {
776 removeImageImpl(rvImage, id);
777 }
778 notifyAll(); // Notify in case remaining images are "done".
779 }
780
781 private void removeImageImpl(Image image, int id) {
782 MediaEntry cur = head;
783 MediaEntry prev = null;
784 while (cur != null) {
|