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