1 /* 2 * Copyright (c) 1995, 2007, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 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 32 /** 33 * The <code>MediaTracker</code> class is a utility class to track 34 * the status of a number of media objects. Media objects could 35 * include audio clips as well as images, though currently only 36 * images are supported. 37 * <p> 38 * To use a media tracker, create an instance of 39 * <code>MediaTracker</code> and call its <code>addImage</code> 40 * method for each image to be tracked. In addition, each image can 41 * be assigned a unique identifier. This identifier controls the 42 * priority order in which the images are fetched. It can also be used 43 * to identify unique subsets of the images that can be waited on 44 * independently. Images with a lower ID are loaded in preference to 45 * those with a higher ID number. 46 * 47 * <p> 48 * 49 * Tracking an animated image 50 * might not always be useful 51 * due to the multi-part nature of animated image 52 * loading and painting, 53 * but it is supported. 54 * <code>MediaTracker</code> treats an animated image 55 * as completely loaded 56 * when the first frame is completely loaded. 57 * At that point, the <code>MediaTracker</code> 58 * signals any waiters 59 * that the image is completely loaded. 60 * If no <code>ImageObserver</code>s are observing the image 61 * when the first frame has finished loading, 62 * the image might flush itself 63 * to conserve resources 64 * (see {@link Image#flush()}). 65 * 66 * <p> 67 * Here is an example of using <code>MediaTracker</code>: 68 * <p> 69 * <hr><blockquote><pre>{@code 70 * import java.applet.Applet; 71 * import java.awt.Color; 72 * import java.awt.Image; 73 * import java.awt.Graphics; 74 * import java.awt.MediaTracker; 75 * 76 * public class ImageBlaster extends Applet implements Runnable { 77 * MediaTracker tracker; 78 * Image bg; 79 * Image anim[] = new Image[5]; 80 * int index; 81 * Thread animator; 82 * 83 * // Get the images for the background (id == 0) 84 * // and the animation frames (id == 1) 85 * // and add them to the MediaTracker 86 * public void init() { 87 * tracker = new MediaTracker(this); 88 * bg = getImage(getDocumentBase(), 89 * "images/background.gif"); 90 * tracker.addImage(bg, 0); 91 * for (int i = 0; i < 5; i++) { 92 * anim[i] = getImage(getDocumentBase(), 93 * "images/anim"+i+".gif"); 94 * tracker.addImage(anim[i], 1); 95 * } 96 * } 97 * 98 * // Start the animation thread. 99 * 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 * @author Jim Graham 166 * @since JDK1.0 167 */ 168 public class MediaTracker implements java.io.Serializable { 169 170 /** 171 * A given <code>Component</code> that will be 172 * tracked by a media tracker where the image will 173 * eventually be drawn. 174 * 175 * @serial 176 * @see #MediaTracker(Component) 177 */ 178 Component target; 179 /** 180 * The head of the list of <code>Images</code> that is being 181 * tracked by the <code>MediaTracker</code>. 182 * 183 * @serial 184 * @see #addImage(Image, int) 185 * @see #removeImage(Image) 186 */ 187 MediaEntry head; 188 189 /* 190 * JDK 1.1 serialVersionUID 191 */ 192 private static final long serialVersionUID = -483174189758638095L; 193 194 /** 195 * Creates a media tracker to track images for a given component. 196 * @param comp the component on which the images 197 * will eventually be drawn 198 */ 199 public MediaTracker(Component comp) { 200 target = comp; 201 } 202 203 /** 204 * Adds an image to the list of images being tracked by this media 205 * tracker. The image will eventually be rendered at its default 206 * (unscaled) size. 207 * @param image the image to be tracked 208 * @param id an identifier used to track this image 209 */ 210 public void addImage(Image image, int id) { 211 addImage(image, id, -1, -1); 212 } 213 214 /** 215 * Adds a scaled image to the list of images being tracked 216 * by this media tracker. The image will eventually be 217 * rendered at the indicated width and height. 218 * 219 * @param image the image to be tracked 220 * @param id an identifier that can be used to track this image 221 * @param w the width at which the image is rendered 222 * @param h the height at which the image is rendered 223 */ 224 public synchronized void addImage(Image image, int id, int w, int h) { 225 head = MediaEntry.insert(head, 226 new ImageMediaEntry(this, image, id, w, h)); 227 } 228 229 /** 230 * Flag indicating that media is currently being loaded. 231 * @see java.awt.MediaTracker#statusAll 232 * @see java.awt.MediaTracker#statusID 233 */ 234 public static final int LOADING = 1; 235 236 /** 237 * Flag indicating that the downloading of media was aborted. 238 * @see java.awt.MediaTracker#statusAll 239 * @see java.awt.MediaTracker#statusID 240 */ 241 public static final int ABORTED = 2; 242 243 /** 244 * Flag indicating that the downloading of media encountered 245 * an error. 246 * @see java.awt.MediaTracker#statusAll 247 * @see java.awt.MediaTracker#statusID 248 */ 249 public static final int ERRORED = 4; 250 251 /** 252 * Flag indicating that the downloading of media was completed 253 * successfully. 254 * @see java.awt.MediaTracker#statusAll 255 * @see java.awt.MediaTracker#statusID 256 */ 257 public static final int COMPLETE = 8; 258 259 static final int DONE = (ABORTED | ERRORED | COMPLETE); 260 261 /** 262 * Checks to see if all images being tracked by this media tracker 263 * have finished loading. 264 * <p> 265 * This method does not start loading the images if they are not 266 * already loading. 267 * <p> 268 * If there is an error while loading or scaling an image, then that 269 * image is considered to have finished loading. Use the 270 * <code>isErrorAny</code> or <code>isErrorID</code> methods to 271 * check for errors. 272 * @return <code>true</code> if all images have finished loading, 273 * have been aborted, or have encountered 274 * an error; <code>false</code> otherwise 275 * @see java.awt.MediaTracker#checkAll(boolean) 276 * @see java.awt.MediaTracker#checkID 277 * @see java.awt.MediaTracker#isErrorAny 278 * @see java.awt.MediaTracker#isErrorID 279 */ 280 public boolean checkAll() { 281 return checkAll(false, true); 282 } 283 284 /** 285 * Checks to see if all images being tracked by this media tracker 286 * have finished loading. 287 * <p> 288 * If the value of the <code>load</code> flag is <code>true</code>, 289 * then this method starts loading any images that are not yet 290 * being loaded. 291 * <p> 292 * If there is an error while loading or scaling an image, that 293 * image is considered to have finished loading. Use the 294 * <code>isErrorAny</code> and <code>isErrorID</code> methods to 295 * check for errors. 296 * @param load if <code>true</code>, start loading any 297 * images that are not yet being loaded 298 * @return <code>true</code> if all images have finished loading, 299 * have been aborted, or have encountered 300 * an error; <code>false</code> otherwise 301 * @see java.awt.MediaTracker#checkID 302 * @see java.awt.MediaTracker#checkAll() 303 * @see java.awt.MediaTracker#isErrorAny() 304 * @see java.awt.MediaTracker#isErrorID(int) 305 */ 306 public boolean checkAll(boolean load) { 307 return checkAll(load, true); 308 } 309 310 private synchronized boolean checkAll(boolean load, boolean verify) { 311 MediaEntry cur = head; 312 boolean done = true; 313 while (cur != null) { 314 if ((cur.getStatus(load, verify) & DONE) == 0) { 315 done = false; 316 } 317 cur = cur.next; 318 } 319 return done; 320 } 321 322 /** 323 * Checks the error status of all of the images. 324 * @return <code>true</code> if any of the images tracked 325 * by this media tracker had an error during 326 * loading; <code>false</code> otherwise 327 * @see java.awt.MediaTracker#isErrorID 328 * @see java.awt.MediaTracker#getErrorsAny 329 */ 330 public synchronized boolean isErrorAny() { 331 MediaEntry cur = head; 332 while (cur != null) { 333 if ((cur.getStatus(false, true) & ERRORED) != 0) { 334 return true; 335 } 336 cur = cur.next; 337 } 338 return false; 339 } 340 341 /** 342 * Returns a list of all media that have encountered an error. 343 * @return an array of media objects tracked by this 344 * media tracker that have encountered 345 * an error, or <code>null</code> if 346 * there are none with errors 347 * @see java.awt.MediaTracker#isErrorAny 348 * @see java.awt.MediaTracker#getErrorsID 349 */ 350 public synchronized Object[] getErrorsAny() { 351 MediaEntry cur = head; 352 int numerrors = 0; 353 while (cur != null) { 354 if ((cur.getStatus(false, true) & ERRORED) != 0) { 355 numerrors++; 356 } 357 cur = cur.next; 358 } 359 if (numerrors == 0) { 360 return null; 361 } 362 Object errors[] = new Object[numerrors]; 363 cur = head; 364 numerrors = 0; 365 while (cur != null) { 366 if ((cur.getStatus(false, false) & ERRORED) != 0) { 367 errors[numerrors++] = cur.getMedia(); 368 } 369 cur = cur.next; 370 } 371 return errors; 372 } 373 374 /** 375 * Starts loading all images tracked by this media tracker. This 376 * method waits until all the images being tracked have finished 377 * loading. 378 * <p> 379 * If there is an error while loading or scaling an image, then that 380 * image is considered to have finished loading. Use the 381 * <code>isErrorAny</code> or <code>isErrorID</code> methods to 382 * check for errors. 383 * @see java.awt.MediaTracker#waitForID(int) 384 * @see java.awt.MediaTracker#waitForAll(long) 385 * @see java.awt.MediaTracker#isErrorAny 386 * @see java.awt.MediaTracker#isErrorID 387 * @exception InterruptedException if any thread has 388 * interrupted this thread 389 */ 390 public void waitForAll() throws InterruptedException { 391 waitForAll(0); 392 } 393 394 /** 395 * Starts loading all images tracked by this media tracker. This 396 * method waits until all the images being tracked have finished 397 * loading, or until the length of time specified in milliseconds 398 * by the <code>ms</code> argument has passed. 399 * <p> 400 * If there is an error while loading or scaling an image, then 401 * that image is considered to have finished loading. Use the 402 * <code>isErrorAny</code> or <code>isErrorID</code> methods to 403 * check for errors. 404 * @param ms the number of milliseconds to wait 405 * for the loading to complete 406 * @return <code>true</code> if all images were successfully 407 * loaded; <code>false</code> otherwise 408 * @see java.awt.MediaTracker#waitForID(int) 409 * @see java.awt.MediaTracker#waitForAll(long) 410 * @see java.awt.MediaTracker#isErrorAny 411 * @see java.awt.MediaTracker#isErrorID 412 * @exception InterruptedException if any thread has 413 * interrupted this thread. 414 */ 415 public synchronized boolean waitForAll(long ms) 416 throws InterruptedException 417 { 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, boolean verify) 528 { 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 { 535 done = false; 536 } 537 cur = cur.next; 538 } 539 return done; 540 } 541 542 /** 543 * Checks the error status of all of the images tracked by this 544 * media tracker with the specified identifier. 545 * @param id the identifier of the images to check 546 * @return <code>true</code> if any of the images with the 547 * specified identifier had an error during 548 * loading; <code>false</code> otherwise 549 * @see java.awt.MediaTracker#isErrorAny 550 * @see java.awt.MediaTracker#getErrorsID 551 */ 552 public synchronized boolean isErrorID(int id) { 553 MediaEntry cur = head; 554 while (cur != null) { 555 if (cur.getID() == id 556 && (cur.getStatus(false, true) & ERRORED) != 0) 557 { 558 return true; 559 } 560 cur = cur.next; 561 } 562 return false; 563 } 564 565 /** 566 * Returns a list of media with the specified ID that 567 * have encountered an error. 568 * @param id the identifier of the images to check 569 * @return an array of media objects tracked by this media 570 * tracker with the specified identifier 571 * that have encountered an error, or 572 * <code>null</code> if there are none with errors 573 * @see java.awt.MediaTracker#isErrorID 574 * @see java.awt.MediaTracker#isErrorAny 575 * @see java.awt.MediaTracker#getErrorsAny 576 */ 577 public synchronized Object[] getErrorsID(int id) { 578 MediaEntry cur = head; 579 int numerrors = 0; 580 while (cur != null) { 581 if (cur.getID() == id 582 && (cur.getStatus(false, true) & ERRORED) != 0) 583 { 584 numerrors++; 585 } 586 cur = cur.next; 587 } 588 if (numerrors == 0) { 589 return null; 590 } 591 Object errors[] = new Object[numerrors]; 592 cur = head; 593 numerrors = 0; 594 while (cur != null) { 595 if (cur.getID() == id 596 && (cur.getStatus(false, false) & ERRORED) != 0) 597 { 598 errors[numerrors++] = cur.getMedia(); 599 } 600 cur = cur.next; 601 } 602 return errors; 603 } 604 605 /** 606 * Starts loading all images tracked by this media tracker with the 607 * specified identifier. This method waits until all the images with 608 * the specified identifier have finished loading. 609 * <p> 610 * If there is an error while loading or scaling an image, then that 611 * image is considered to have finished loading. Use the 612 * <code>isErrorAny</code> and <code>isErrorID</code> methods to 613 * check for errors. 614 * @param id the identifier of the images to check 615 * @see java.awt.MediaTracker#waitForAll 616 * @see java.awt.MediaTracker#isErrorAny() 617 * @see java.awt.MediaTracker#isErrorID(int) 618 * @exception InterruptedException if any thread has 619 * interrupted this thread. 620 */ 621 public void waitForID(int id) throws InterruptedException { 622 waitForID(id, 0); 623 } 624 625 /** 626 * Starts loading all images tracked by this media tracker with the 627 * specified identifier. This method waits until all the images with 628 * the specified identifier have finished loading, or until the 629 * length of time specified in milliseconds by the <code>ms</code> 630 * argument has passed. 631 * <p> 632 * If there is an error while loading or scaling an image, then that 633 * image is considered to have finished loading. Use the 634 * <code>statusID</code>, <code>isErrorID</code>, and 635 * <code>isErrorAny</code> methods to check for errors. 636 * @param id the identifier of the images to check 637 * @param ms the length of time, in milliseconds, to wait 638 * for the loading to complete 639 * @see java.awt.MediaTracker#waitForAll 640 * @see java.awt.MediaTracker#waitForID(int) 641 * @see java.awt.MediaTracker#statusID 642 * @see java.awt.MediaTracker#isErrorAny() 643 * @see java.awt.MediaTracker#isErrorID(int) 644 * @exception InterruptedException if any thread has 645 * interrupted this thread. 646 */ 647 public synchronized boolean waitForID(int id, long ms) 648 throws InterruptedException 649 { 650 long end = System.currentTimeMillis() + ms; 651 boolean first = true; 652 while (true) { 653 int status = statusID(id, first, first); 654 if ((status & LOADING) == 0) { 655 return (status == COMPLETE); 656 } 657 first = false; 658 long timeout; 659 if (ms == 0) { 660 timeout = 0; 661 } else { 662 timeout = end - System.currentTimeMillis(); 663 if (timeout <= 0) { 664 return false; 665 } 666 } 667 wait(timeout); 668 } 669 } 670 671 /** 672 * Calculates and returns the bitwise inclusive <b>OR</b> of the 673 * status of all media with the specified identifier that are 674 * tracked by this media tracker. 675 * <p> 676 * Possible flags defined by the 677 * <code>MediaTracker</code> class are <code>LOADING</code>, 678 * <code>ABORTED</code>, <code>ERRORED</code>, and 679 * <code>COMPLETE</code>. An image that hasn't started 680 * loading has zero as its status. 681 * <p> 682 * If the value of <code>load</code> is <code>true</code>, then 683 * this method starts loading any images that are not yet being loaded. 684 * @param id the identifier of the images to check 685 * @param load if <code>true</code>, start loading 686 * any images that are not yet being loaded 687 * @return the bitwise inclusive <b>OR</b> of the status of 688 * all of the media with the specified 689 * identifier that are being tracked 690 * @see java.awt.MediaTracker#statusAll(boolean) 691 * @see java.awt.MediaTracker#LOADING 692 * @see java.awt.MediaTracker#ABORTED 693 * @see java.awt.MediaTracker#ERRORED 694 * @see java.awt.MediaTracker#COMPLETE 695 */ 696 public int statusID(int id, boolean load) { 697 return statusID(id, load, true); 698 } 699 700 private synchronized int statusID(int id, boolean load, boolean verify) { 701 MediaEntry cur = head; 702 int status = 0; 703 while (cur != null) { 704 if (cur.getID() == id) { 705 status = status | cur.getStatus(load, verify); 706 } 707 cur = cur.next; 708 } 709 return status; 710 } 711 712 /** 713 * Removes the specified image from this media tracker. 714 * All instances of the specified image are removed, 715 * regardless of scale or ID. 716 * @param image the image to be removed 717 * @see java.awt.MediaTracker#removeImage(java.awt.Image, int) 718 * @see java.awt.MediaTracker#removeImage(java.awt.Image, int, int, int) 719 * @since JDK1.1 720 */ 721 public synchronized void removeImage(Image image) { 722 MediaEntry cur = head; 723 MediaEntry prev = null; 724 while (cur != null) { 725 MediaEntry next = cur.next; 726 if (cur.getMedia() == image) { 727 if (prev == null) { 728 head = next; 729 } else { 730 prev.next = next; 731 } 732 cur.cancel(); 733 } else { 734 prev = cur; 735 } 736 cur = next; 737 } 738 notifyAll(); // Notify in case remaining images are "done". 739 } 740 741 /** 742 * Removes the specified image from the specified tracking 743 * ID of this media tracker. 744 * All instances of <code>Image</code> being tracked 745 * under the specified ID are removed regardless of scale. 746 * @param image the image to be removed 747 * @param id the tracking ID from which to remove the image 748 * @see java.awt.MediaTracker#removeImage(java.awt.Image) 749 * @see java.awt.MediaTracker#removeImage(java.awt.Image, int, int, int) 750 * @since JDK1.1 751 */ 752 public synchronized void removeImage(Image image, int id) { 753 MediaEntry cur = head; 754 MediaEntry prev = null; 755 while (cur != null) { 756 MediaEntry next = cur.next; 757 if (cur.getID() == id && cur.getMedia() == image) { 758 if (prev == null) { 759 head = next; 760 } else { 761 prev.next = next; 762 } 763 cur.cancel(); 764 } else { 765 prev = cur; 766 } 767 cur = next; 768 } 769 notifyAll(); // Notify in case remaining images are "done". 770 } 771 772 /** 773 * Removes the specified image with the specified 774 * width, height, and ID from this media tracker. 775 * Only the specified instance (with any duplicates) is removed. 776 * @param image the image to be removed 777 * @param id the tracking ID from which to remove the image 778 * @param width the width to remove (-1 for unscaled) 779 * @param height the height to remove (-1 for unscaled) 780 * @see java.awt.MediaTracker#removeImage(java.awt.Image) 781 * @see java.awt.MediaTracker#removeImage(java.awt.Image, int) 782 * @since JDK1.1 783 */ 784 public synchronized void removeImage(Image image, int id, 785 int width, int height) { 786 MediaEntry cur = head; 787 MediaEntry prev = null; 788 while (cur != null) { 789 MediaEntry next = cur.next; 790 if (cur.getID() == id && cur instanceof ImageMediaEntry 791 && ((ImageMediaEntry) cur).matches(image, width, height)) 792 { 793 if (prev == null) { 794 head = next; 795 } else { 796 prev.next = next; 797 } 798 cur.cancel(); 799 } else { 800 prev = cur; 801 } 802 cur = next; 803 } 804 notifyAll(); // Notify in case remaining images are "done". 805 } 806 807 synchronized void setDone() { 808 notifyAll(); 809 } 810 } 811 812 abstract class MediaEntry { 813 MediaTracker tracker; 814 int ID; 815 MediaEntry next; 816 817 int status; 818 boolean cancelled; 819 820 MediaEntry(MediaTracker mt, int id) { 821 tracker = mt; 822 ID = id; 823 } 824 825 abstract Object getMedia(); 826 827 static MediaEntry insert(MediaEntry head, MediaEntry me) { 828 MediaEntry cur = head; 829 MediaEntry prev = null; 830 while (cur != null) { 831 if (cur.ID > me.ID) { 832 break; 833 } 834 prev = cur; 835 cur = cur.next; 836 } 837 me.next = cur; 838 if (prev == null) { 839 head = me; 840 } else { 841 prev.next = me; 842 } 843 return head; 844 } 845 846 int getID() { 847 return ID; 848 } 849 850 abstract void startLoad(); 851 852 void cancel() { 853 cancelled = true; 854 } 855 856 static final int LOADING = MediaTracker.LOADING; 857 static final int ABORTED = MediaTracker.ABORTED; 858 static final int ERRORED = MediaTracker.ERRORED; 859 static final int COMPLETE = MediaTracker.COMPLETE; 860 861 static final int LOADSTARTED = (LOADING | ERRORED | COMPLETE); 862 static final int DONE = (ABORTED | ERRORED | COMPLETE); 863 864 synchronized int getStatus(boolean doLoad, boolean doVerify) { 865 if (doLoad && ((status & LOADSTARTED) == 0)) { 866 status = (status & ~ABORTED) | LOADING; 867 startLoad(); 868 } 869 return status; 870 } 871 872 void setStatus(int flag) { 873 synchronized (this) { 874 status = flag; 875 } 876 tracker.setDone(); 877 } 878 } 879 880 class ImageMediaEntry extends MediaEntry implements ImageObserver, 881 java.io.Serializable { 882 Image image; 883 int width; 884 int height; 885 886 /* 887 * JDK 1.1 serialVersionUID 888 */ 889 private static final long serialVersionUID = 4739377000350280650L; 890 891 ImageMediaEntry(MediaTracker mt, Image img, int c, int w, int h) { 892 super(mt, c); 893 image = img; 894 width = w; 895 height = h; 896 } 897 898 boolean matches(Image img, int w, int h) { 899 return (image == img && width == w && height == h); 900 } 901 902 Object getMedia() { 903 return image; 904 } 905 906 synchronized int getStatus(boolean doLoad, boolean doVerify) { 907 if (doVerify) { 908 int flags = tracker.target.checkImage(image, width, height, null); 909 int s = parseflags(flags); 910 if (s == 0) { 911 if ((status & (ERRORED | COMPLETE)) != 0) { 912 setStatus(ABORTED); 913 } 914 } else if (s != status) { 915 setStatus(s); 916 } 917 } 918 return super.getStatus(doLoad, doVerify); 919 } 920 921 void startLoad() { 922 if (tracker.target.prepareImage(image, width, height, this)) { 923 setStatus(COMPLETE); 924 } 925 } 926 927 int parseflags(int infoflags) { 928 if ((infoflags & ERROR) != 0) { 929 return ERRORED; 930 } else if ((infoflags & ABORT) != 0) { 931 return ABORTED; 932 } else if ((infoflags & (ALLBITS | FRAMEBITS)) != 0) { 933 return COMPLETE; 934 } 935 return 0; 936 } 937 938 public boolean imageUpdate(Image img, int infoflags, 939 int x, int y, int w, int h) { 940 if (cancelled) { 941 return false; 942 } 943 int s = parseflags(infoflags); 944 if (s != 0 && s != status) { 945 setStatus(s); 946 } 947 return ((status & LOADING) != 0); 948 } 949 }