< prev index next >

src/java.desktop/share/classes/java/awt/MediaTracker.java

Print this page




  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) {


< prev index next >