home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 November / Chip_1998-11_cd.bin / tema / Cafe / main.bin / MediaTracker.java < prev    next >
Text File  |  1997-10-01  |  31KB  |  932 lines

  1. /*
  2.  * @(#)MediaTracker.java    1.26 97/06/17
  3.  * 
  4.  * Copyright (c) 1995, 1996 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  * CopyrightVersion 1.1_beta
  20.  * 
  21.  */
  22.  
  23. package java.awt;
  24.  
  25. import java.awt.Component;
  26. import java.awt.Image;
  27. import java.awt.Graphics;
  28. import java.awt.image.ImageObserver;
  29.  
  30. /**
  31.  * The <code>MediaTracker</code> class is a utility class to track 
  32.  * the status of a number of media objects. Media objects could 
  33.  * include audio clips as well as images, though currently only 
  34.  * images are supported. 
  35.  * <p>
  36.  * To use a media tracker, create an instance of  
  37.  * <code>MediaTracker</code> and call its <code>addImage</code>  
  38.  * method for each image to be tracked. In addition, each image can 
  39.  * be assigned a unique identifier. This identifier controls the 
  40.  * priority order in which the images are fetched. It can also be used 
  41.  * to identify unique subsets of the images that can be waited on 
  42.  * independently. Images with a lower ID are loaded in preference to 
  43.  * those with a higher ID number. 
  44.  * <p>
  45.  * Here is an example: 
  46.  * <p>
  47.  * <hr><blockquote><pre>
  48.  * import java.applet.Applet;
  49.  * import java.awt.Color;
  50.  * import java.awt.Image;
  51.  * import java.awt.Graphics;
  52.  * import java.awt.MediaTracker;
  53.  *
  54.  * public class ImageBlaster extends Applet implements Runnable {
  55.  *    MediaTracker tracker;
  56.  *    Image bg;
  57.  *    Image anim[] = new Image[5];
  58.  *    int index;
  59.  *    Thread animator;
  60.  *
  61.  *    // Get the images for the background (id == 0) 
  62.  *    // and the animation frames (id == 1) 
  63.  *      // and add them to the MediaTracker
  64.  *    public void init() {
  65.  *        tracker = new MediaTracker(this);
  66.  *        bg = getImage(getDocumentBase(), 
  67.  *                  "images/background.gif");
  68.  *        tracker.addImage(bg, 0);
  69.  *        for (int i = 0; i < 5; i++) {
  70.  *        anim[i] = getImage(getDocumentBase(), 
  71.  *                      "images/anim"+i+".gif");
  72.  *        tracker.addImage(anim[i], 1);
  73.  *        }
  74.  *    }
  75.  *
  76.  *    // Start the animation thread.
  77.  *    public void start() {
  78.  *        animator = new Thread(this);
  79.  *        animator.start();
  80.  *    }
  81.  *
  82.  *    // Stop the animation thread.
  83.  *    public void stop() {
  84.  *        animator.stop();
  85.  *        animator = null;
  86.  *    }
  87.  *
  88.  *    // Run the animation thread.
  89.  *    // First wait for the background image to fully load 
  90.  *      // and paint.  Then wait for all of the animation 
  91.  *    // frames to finish loading. Finally, loop and 
  92.  *    // increment the animation frame index.
  93.  *    public void run() {
  94.  *        try {
  95.  *        tracker.waitForID(0);
  96.  *        tracker.waitForID(1);
  97.  *        } catch (InterruptedException e) {
  98.  *        return;
  99.  *        }
  100.  *        Thread me = Thread.currentThread();
  101.  *        while (animator == me) {
  102.  *        try {
  103.  *            Thread.sleep(100);
  104.  *        } catch (InterruptedException e) {
  105.  *            break;
  106.  *        }
  107.  *        synchronized (this) {
  108.  *            index++;
  109.  *            if (index >= anim.length) {
  110.  *            index = 0;
  111.  *            }
  112.  *        }
  113.  *        repaint();
  114.  *        }
  115.  *    }
  116.  *
  117.  *    // The background image fills the frame so we 
  118.  *    // don't need to clear the applet on repaints. 
  119.  *      // Just call the paint method.
  120.  *    public void update(Graphics g) {
  121.  *        paint(g);
  122.  *    }
  123.  *
  124.  *    // Paint a large red rectangle if there are any errors 
  125.  *    // loading the images.  Otherwise always paint the 
  126.  *    // background so that it appears incrementally as it 
  127.  *      // is loading.  Finally, only paint the current animation 
  128.  *    // frame if all of the frames (id == 1) are done loading,
  129.  *    // so that we don't get partial animations.
  130.  *    public void paint(Graphics g) {
  131.  *        if ((tracker.statusAll(false) & MediaTracker.ERRORED) != 0) {
  132.  *        g.setColor(Color.red);
  133.  *        g.fillRect(0, 0, size().width, size().height);
  134.  *        return;
  135.  *        }
  136.  *        g.drawImage(bg, 0, 0, this);
  137.  *        if (tracker.statusID(1, false) == MediaTracker.COMPLETE) {
  138.  *        g.drawImage(anim[index], 10, 10, this);
  139.  *        }
  140.  *    }
  141.  * }
  142.  * </pre></blockquote><hr>
  143.  * <p>
  144.  * @version     1.26, 06/17/97
  145.  * @author     Jim Graham
  146.  * @since       JDK1.0
  147.  */
  148. public class MediaTracker implements java.io.Serializable {
  149.     Component target;
  150.     MediaEntry head;
  151.  
  152.     /*
  153.      * JDK 1.1 serialVersionUID 
  154.      */
  155.     private static final long serialVersionUID = -483174189758638095L;
  156.  
  157.     /**
  158.      * Creates a media tracker to track images for a given component.
  159.      * @param     comp the component on which the images 
  160.      *                     will eventually be drawn.
  161.      * @since     JDK1.0
  162.      */
  163.     public MediaTracker(Component comp) {
  164.     target = comp;
  165.     }
  166.  
  167.     /**
  168.      * Adds an image to the list of images being tracked by this media 
  169.      * tracker. The image will eventually be rendered at its default 
  170.      * (unscaled) size. 
  171.      * @param     image   the image to be tracked.
  172.      * @param     id      an identifier used to track this image.
  173.      * @since     JDK1.0
  174.      */
  175.     public void addImage(Image image, int id) {
  176.     addImage(image, id, -1, -1);
  177.     }
  178.  
  179.     /**
  180.      * Adds a scaled image to the list of images being tracked  
  181.      * by this media tracker. The image will eventually be 
  182.      * rendered at the indicated width and height.
  183.      * @param     image   the image to be tracked.
  184.      * @param     id   an identifier that can be used to track this image.
  185.      * @param     w    the width at which the image is rendered.
  186.      * @param     h    the height at which the image is rendered.
  187.      * @since     JDK1.0
  188.      */
  189.     public synchronized void addImage(Image image, int id, int w, int h) {
  190.     head = MediaEntry.insert(head,
  191.                  new ImageMediaEntry(this, image, id, w, h));
  192.     }
  193.  
  194.     /**
  195.      * Flag indicating some media is currently being loaded.
  196.      * @see         java.awt.MediaTracker#statusAll
  197.      * @see         java.awt.MediaTracker#statusID
  198.      * @since       JDK1.0
  199.      */
  200.     public static final int LOADING = 1;
  201.  
  202.     /**
  203.      * Flag indicating that the downloading of some media was aborted.
  204.      * @see         java.awt.MediaTracker#statusAll
  205.      * @see         java.awt.MediaTracker#statusID
  206.      * @since       JDK1.0
  207.      */
  208.     public static final int ABORTED = 2;
  209.  
  210.     /**
  211.      * Flag indicating that the downloading of some media encountered 
  212.      * an error.
  213.      * @see         java.awt.MediaTracker#statusAll
  214.      * @see         java.awt.MediaTracker#statusID
  215.      * @since       JDK1.0
  216.      */
  217.     public static final int ERRORED = 4;
  218.  
  219.     /**
  220.      * Flag indicating that the downloading of media was completed 
  221.      * successfully.
  222.      * @see         java.awt.MediaTracker#statusAll
  223.      * @see         java.awt.MediaTracker#statusID
  224.      * @since       JDK1.0
  225.      */
  226.     public static final int COMPLETE = 8;
  227.  
  228.     static final int DONE = (ABORTED | ERRORED | COMPLETE);
  229.  
  230.     /**
  231.      * Checks to see if all images being tracked by this media tracker 
  232.      * have finished loading. 
  233.      * <p>
  234.      * This method does not start loading the images if they are not 
  235.      * already loading. 
  236.      * <p>
  237.      * If there is an error while loading or scaling an image, then that 
  238.      * image is considered to have finished loading. Use the 
  239.      * <code>isErrorAny</code> or <code>isErrorID</code> methods to 
  240.      * check for errors. 
  241.      * @return      <code>true</code> if all images have finished loading, 
  242.      *                       have been aborted, or have encountered 
  243.      *                       an error; <code>false</code> otherwise.
  244.      * @see         java.awt.MediaTracker#checkAll(boolean)
  245.      * @see         java.awt.MediaTracker#checkID
  246.      * @see         java.awt.MediaTracker#isErrorAny
  247.      * @see         java.awt.MediaTracker#isErrorID
  248.      * @since       JDK1.0
  249.      */
  250.     public boolean checkAll() {
  251.     return checkAll(false, true);
  252.     }
  253.  
  254.     /**
  255.      * Checks to see if all images being tracked by this media tracker 
  256.      * have finished loading. 
  257.      * <p>
  258.      * If the value of the <code>load</code> flag is <code>true</code>, 
  259.      * then this method starts loading any images that are not yet 
  260.      * being loaded. 
  261.      * <p>
  262.      * If there is an error while loading or scaling an image, that 
  263.      * image is considered to have finished loading. Use the 
  264.      * <code>isErrorAny</code> and <code>isErrorID</code> methods to 
  265.      * check for errors. 
  266.      * @param       load   if <code>true</code>, start loading any 
  267.      *                       images that are not yet being loaded.
  268.      * @return      <code>true</code> if all images have finished loading, 
  269.      *                       have been aborted, or have encountered 
  270.      *                       an error; <code>false</code> otherwise.
  271.      * @see         java.awt.MediaTracker#checkID
  272.      * @see         java.awt.MediaTracker#checkAll()
  273.      * @see         java.awt.MediaTracker#isErrorAny()
  274.      * @see         java.awt.MediaTracker#isErrorID(int)
  275.      * @since       JDK1.0
  276.      */
  277.     public boolean checkAll(boolean load) {
  278.     return checkAll(load, true);
  279.     }
  280.  
  281.     private synchronized boolean checkAll(boolean load, boolean verify) {
  282.     MediaEntry cur = head;
  283.     boolean done = true;
  284.     while (cur != null) {
  285.         if ((cur.getStatus(load, verify) & DONE) == 0) {
  286.         done = false;
  287.         }
  288.         cur = cur.next;
  289.     }
  290.     return done;
  291.     }
  292.  
  293.     /**
  294.      * Checks the error status of all of the images.
  295.      * @return   <code>true</code> if any of the images tracked
  296.      *                  by this media tracker had an error during 
  297.      *                  loading; <code>false</code> otherwise.
  298.      * @see      java.awt.MediaTracker#isErrorID
  299.      * @see      java.awt.MediaTracker#getErrorsAny
  300.      * @since    JDK1.0
  301.      */
  302.     public synchronized boolean isErrorAny() {
  303.     MediaEntry cur = head;
  304.     while (cur != null) {
  305.         if ((cur.getStatus(false, true) & ERRORED) != 0) {
  306.         return true;
  307.         }
  308.         cur = cur.next;
  309.     }
  310.     return false;
  311.     }
  312.  
  313.     /**
  314.      * Returns a list of all media that have encountered an error.
  315.      * @return       an array of media objects tracked by this 
  316.      *                        media tracker that have encountered 
  317.      *                        an error, or <code>null</code> if 
  318.      *                        there are none with errors.
  319.      * @see          java.awt.MediaTracker#isErrorAny
  320.      * @see          java.awt.MediaTracker#getErrorsID
  321.      * @since        JDK1.0
  322.      */
  323.     public synchronized Object[] getErrorsAny() {
  324.     MediaEntry cur = head;
  325.     int numerrors = 0;
  326.     while (cur != null) {
  327.         if ((cur.getStatus(false, true) & ERRORED) != 0) {
  328.         numerrors++;
  329.         }
  330.         cur = cur.next;
  331.     }
  332.     if (numerrors == 0) {
  333.         return null;
  334.     }
  335.     Object errors[] = new Object[numerrors];
  336.     cur = head;
  337.     numerrors = 0;
  338.     while (cur != null) {
  339.         if ((cur.getStatus(false, false) & ERRORED) != 0) {
  340.         errors[numerrors++] = cur.getMedia();
  341.         }
  342.         cur = cur.next;
  343.     }
  344.     return errors;
  345.     }
  346.  
  347.     /**
  348.      * Starts loading all images tracked by this media tracker. This 
  349.      * method waits until all the images being tracked have finished 
  350.      * loading. 
  351.      * <p>
  352.      * If there is an error while loading or scaling an image, then that 
  353.      * image is considered to have finished loading. Use the 
  354.      * <code>isErrorAny</code> or <code>isErrorID</code> methods to 
  355.      * check for errors. 
  356.      * @see         java.awt.MediaTracker#waitForID(int)
  357.      * @see         java.awt.MediaTracker#waitForAll(long)
  358.      * @see         java.awt.MediaTracker#isErrorAny
  359.      * @see         java.awt.MediaTracker#isErrorID
  360.      * @exception   InterruptedException  if another thread has 
  361.      *                                     interrupted this thread.
  362.      * @since       JDK1.0
  363.      */
  364.     public void waitForAll() throws InterruptedException {
  365.     waitForAll(0);
  366.     }
  367.  
  368.     /**
  369.      * Starts loading all images tracked by this media tracker. This 
  370.      * method waits until all the images being tracked have finished 
  371.      * loading, or until the length of time specified in milliseconds  
  372.      * by the <code>ms</code> argument has passed. 
  373.      * <p>
  374.      * If there is an error while loading or scaling an image, then  
  375.      * that image is considered to have finished loading. Use the 
  376.      * <code>isErrorAny</code> or <code>isErrorID</code> methods to 
  377.      * check for errors. 
  378.      * @param       ms       the number of milliseconds to wait 
  379.      *                       for the loading to complete.
  380.      * @return      <code>true</code> if all images were successfully 
  381.      *                       loaded; <code>false</code> otherwise.
  382.      * @see         java.awt.MediaTracker#waitForID(int)
  383.      * @see         java.awt.MediaTracker#waitForAll(long)
  384.      * @see         java.awt.MediaTracker#isErrorAny
  385.      * @see         java.awt.MediaTracker#isErrorID
  386.      * @exception   InterruptedException  if another thread has 
  387.      *                                     interrupted this thread.
  388.      * @since       JDK1.0
  389.      */
  390.     public synchronized boolean waitForAll(long ms)
  391.     throws InterruptedException
  392.     {
  393.     long end = System.currentTimeMillis() + ms;
  394.     boolean first = true;
  395.     while (true) {
  396.         int status = statusAll(first, first);
  397.         if ((status & LOADING) == 0) {
  398.         return (status == COMPLETE);
  399.         }
  400.         first = false;
  401.         long timeout;
  402.         if (ms == 0) {
  403.         timeout = 0;
  404.         } else {
  405.         timeout = end - System.currentTimeMillis();
  406.         if (timeout <= 0) {
  407.             return false;
  408.         }
  409.         }
  410.         wait(timeout);
  411.     }
  412.     }
  413.  
  414.     /**
  415.      * Calculates and returns the bitwise inclusive <b>OR</b> of the 
  416.      * status of all media that are tracked by this media tracker. 
  417.      * <p>
  418.      * Possible flags defined by the 
  419.      * <code>MediaTracker</code> class are <code>LOADING</code>, 
  420.      * <code>ABORTED</code>, <code>ERRORED</code>, and 
  421.      * <code>COMPLETE</code>. An image that hasn't started 
  422.      * loading has zero as its status. 
  423.      * <p>
  424.      * If the value of <code>load</code> is <code>true</code>, then
  425.      * this method starts loading any images that are not yet being loaded. 
  426.      * @param        load   if <code>true</code>, start loading 
  427.      *                            any images that are not yet being loaded.
  428.      * @return       the bitwise inclusive <b>OR</b> of the status of 
  429.      *                            all of the media being tracked.
  430.      * @see          java.awt.MediaTracker#statusID(int, boolean)
  431.      * @see          java.awt.MediaTracker#LOADING
  432.      * @see          java.awt.MediaTracker#ABORTED
  433.      * @see          java.awt.MediaTracker#ERRORED
  434.      * @see          java.awt.MediaTracker#COMPLETE
  435.      * @since        JDK1.0
  436.      */
  437.     public int statusAll(boolean load) {
  438.     return statusAll(load, true);
  439.     }
  440.  
  441.     private synchronized int statusAll(boolean load, boolean verify) {
  442.     MediaEntry cur = head;
  443.     int status = 0;
  444.     while (cur != null) {
  445.         status = status | cur.getStatus(load, verify);
  446.         cur = cur.next;
  447.     }
  448.     return status;
  449.     }
  450.  
  451.     /**
  452.      * Checks to see if all images tracked by this media tracker that 
  453.      * are tagged with the specified identifier have finished loading. 
  454.      * <p>
  455.      * This method does not start loading the images if they are not 
  456.      * already loading. 
  457.      * <p>
  458.      * If there is an error while loading or scaling an image, then that 
  459.      * image is considered to have finished loading. Use the 
  460.      * <code>isErrorAny</code> or <code>isErrorID</code> methods to 
  461.      * check for errors. 
  462.      * @param       id   the identifier of the images to check.
  463.      * @return      <code>true</code> if all images have finished loading, 
  464.      *                       have been aborted, or have encountered 
  465.      *                       an error; <code>false</code> otherwise.
  466.      * @see         java.awt.MediaTracker#checkID(int, boolean)
  467.      * @see         java.awt.MediaTracker#checkAll()
  468.      * @see         java.awt.MediaTracker#isErrorAny()
  469.      * @see         java.awt.MediaTracker#isErrorID(int)
  470.      * @since       JDK1.0
  471.      */
  472.     public boolean checkID(int id) {
  473.     return checkID(id, false, true);
  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.      * If the value of the <code>load</code> flag is <code>true</code>, 
  481.      * then this method starts loading any images that are not yet 
  482.      * being loaded. 
  483.      * <p>
  484.      * If there is an error while loading or scaling an image, then that 
  485.      * image is considered to have finished loading. Use the 
  486.      * <code>isErrorAny</code> or <code>isErrorID</code> methods to 
  487.      * check for errors. 
  488.      * @param       id       the identifier of the images to check.
  489.      * @param       load     if <code>true</code>, start loading any 
  490.      *                       images that are not yet being loaded.
  491.      * @return      <code>true</code> if all images have finished loading, 
  492.      *                       have been aborted, or have encountered 
  493.      *                       an error; <code>false</code> otherwise.
  494.      * @see         java.awt.MediaTracker#checkID(int, boolean)
  495.      * @see         java.awt.MediaTracker#checkAll()
  496.      * @see         java.awt.MediaTracker#isErrorAny()
  497.      * @see         java.awt.MediaTracker#isErrorID(int)
  498.      * @since       JDK1.0
  499.      */
  500.     public boolean checkID(int id, boolean load) {
  501.     return checkID(id, load, true);
  502.     }
  503.  
  504.     private synchronized boolean checkID(int id, boolean load, boolean verify)
  505.     {
  506.     MediaEntry cur = head;
  507.     boolean done = true;
  508.     while (cur != null) {
  509.         if (cur.getID() == id
  510.         && (cur.getStatus(load, verify) & DONE) == 0)
  511.         {
  512.         done = false;
  513.         }
  514.         cur = cur.next;
  515.     }
  516.     return done;
  517.     }
  518.  
  519.     /**
  520.      * Checks the error status of all of the images tracked by this 
  521.      * media tracker with the specified identifier. 
  522.      * @param        id   the identifier of the images to check.
  523.      * @return       <code>true</code> if any of the images with the 
  524.      *                          specified identifier had an error during 
  525.      *                          loading; <code>false</code> otherwise.
  526.      * @see          java.awt.MediaTracker#isErrorAny
  527.      * @see          java.awt.MediaTracker#getErrorsID
  528.      * @since        JDK1.0
  529.      */
  530.     public synchronized boolean isErrorID(int id) {
  531.     MediaEntry cur = head;
  532.     while (cur != null) {
  533.         if (cur.getID() == id
  534.         && (cur.getStatus(false, true) & ERRORED) != 0)
  535.         {
  536.         return true;
  537.         }
  538.         cur = cur.next;
  539.     }
  540.     return false;
  541.     }
  542.  
  543.     /**
  544.      * Returns a list of media with the specified ID that 
  545.      * have encountered an error.
  546.      * @param       id   the identifier of the images to check.
  547.      * @return      an array of media objects tracked by this media 
  548.      *                       tracker with the specified identifier 
  549.      *                       that have encountered an error, or 
  550.      *                       <code>null</code> if there are none with errors.
  551.      * @see         java.awt.MediaTracker#isErrorID
  552.      * @see         java.awt.MediaTracker#isErrorAny
  553.      * @see         java.awt.MediaTracker#getErrorsAny
  554.      * @since       JDK1.0
  555.      */
  556.     public synchronized Object[] getErrorsID(int id) {
  557.     MediaEntry cur = head;
  558.     int numerrors = 0;
  559.     while (cur != null) {
  560.         if (cur.getID() == id
  561.         && (cur.getStatus(false, true) & ERRORED) != 0)
  562.         {
  563.         numerrors++;
  564.         }
  565.         cur = cur.next;
  566.     }
  567.     if (numerrors == 0) {
  568.         return null;
  569.     }
  570.     Object errors[] = new Object[numerrors];
  571.     cur = head;
  572.     numerrors = 0;
  573.     while (cur != null) {
  574.         if (cur.getID() == id
  575.         && (cur.getStatus(false, false) & ERRORED) != 0)
  576.         {
  577.         errors[numerrors++] = cur.getMedia();
  578.         }
  579.         cur = cur.next;
  580.     }
  581.     return errors;
  582.     }
  583.  
  584.     /**
  585.      * Starts loading all images tracked by this media tracker with the 
  586.      * specified identifier. This method waits until all the images with 
  587.      * the specified identifier have finished loading. 
  588.      * <p>
  589.      * If there is an error while loading or scaling an image, then that 
  590.      * image is considered to have finished loading. Use the 
  591.      * <code>isErrorAny</code> and <code>isErrorID</code> methods to 
  592.      * check for errors. 
  593.      * @param         id   the identifier of the images to check.
  594.      * @see           java.awt.MediaTracker#waitForAll
  595.      * @see           java.awt.MediaTracker#isErrorAny()
  596.      * @see           java.awt.MediaTracker#isErrorID(int)
  597.      * @exception     InterruptedException  if another thread has 
  598.      *                          interrupted this thread.
  599.      * @since         JDK1.0
  600.      */
  601.     public void waitForID(int id) throws InterruptedException {
  602.     waitForID(id, 0);
  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, or until the 
  609.      * length of time specified in milliseconds by the <code>ms</code> 
  610.      * argument has passed. 
  611.      * <p>
  612.      * If there is an error while loading or scaling an image, then that 
  613.      * image is considered to have finished loading. Use the 
  614.      * <code>statusID</code>, <code>isErrorID</code>, and
  615.      * <code>isErrorAny</code> methods to check for errors. 
  616.      * @param         id   the identifier of the images to check.
  617.      * @param         ms   the length of time, in milliseconds, to wait 
  618.      *                           for the loading to complete.
  619.      * @see           java.awt.MediaTracker#waitForAll
  620.      * @see           java.awt.MediaTracker#waitForID(int)
  621.      * @see           java.awt.MediaTracker#statusID
  622.      * @see           java.awt.MediaTracker#isErrorAny()
  623.      * @see           java.awt.MediaTracker#isErrorID(int)
  624.      * @exception     InterruptedException  if another thread has 
  625.      *                          interrupted this thread.
  626.      * @since         JDK1.0 
  627.      */
  628.     public synchronized boolean waitForID(int id, long ms)
  629.     throws InterruptedException
  630.     {
  631.     long end = System.currentTimeMillis() + ms;
  632.     boolean first = true;
  633.     while (true) {
  634.         int status = statusID(id, first, first);
  635.         if ((status & LOADING) == 0) {
  636.         return (status == COMPLETE);
  637.         }
  638.         first = false;
  639.         long timeout;
  640.         if (ms == 0) {
  641.         timeout = 0;
  642.         } else {
  643.         timeout = end - System.currentTimeMillis();
  644.         if (timeout <= 0) {
  645.             return false;
  646.         }
  647.         }
  648.         wait(timeout);
  649.     }
  650.     }
  651.  
  652.     /**
  653.      * Calculates and returns the bitwise inclusive <b>OR</b> of the 
  654.      * status of all media with the specified identifier that are 
  655.      * tracked by this media tracker. 
  656.      * <p>
  657.      * Possible flags defined by the 
  658.      * <code>MediaTracker</code> class are <code>LOADING</code>, 
  659.      * <code>ABORTED</code>, <code>ERRORED</code>, and 
  660.      * <code>COMPLETE</code>. An image that hasn't started 
  661.      * loading has zero as its status. 
  662.      * <p>
  663.      * If the value of <code>load</code> is <code>true</code>, then
  664.      * this method starts loading any images that are not yet being loaded. 
  665.      * @param        id   the identifier of the images to check.
  666.      * @param        load   if <code>true</code>, start loading 
  667.      *                            any images that are not yet being loaded.
  668.      * @return       the bitwise inclusive <b>OR</b> of the status of 
  669.      *                            all of the media with the specified
  670.      *                            identifier that are being tracked.
  671.      * @see          java.awt.MediaTracker#statusAll(boolean)
  672.      * @see          java.awt.MediaTracker#LOADING
  673.      * @see          java.awt.MediaTracker#ABORTED
  674.      * @see          java.awt.MediaTracker#ERRORED
  675.      * @see          java.awt.MediaTracker#COMPLETE
  676.      * @since        JDK1.0
  677.      */
  678.     public int statusID(int id, boolean load) {
  679.     return statusID(id, load, true);
  680.     }
  681.  
  682.     private synchronized int statusID(int id, boolean load, boolean verify) {
  683.     MediaEntry cur = head;
  684.     int status = 0;
  685.     while (cur != null) {
  686.         if (cur.getID() == id) {
  687.         status = status | cur.getStatus(load, verify);
  688.         }
  689.         cur = cur.next;
  690.     }
  691.     return status;
  692.     }
  693.  
  694.     /**
  695.      * Remove the specified image from this media tracker.
  696.      * All instances of the specified image are removed, 
  697.      * regardless of scale or ID.
  698.      * @param   image     the image to be removed
  699.      * @see     java.awt.MediaTracker#removeImage(java.awt.Image, int)
  700.      * @see     java.awt.MediaTracker#removeImage(java.awt.Image, int, int, int)
  701.      * @since   JDK1.1
  702.      */
  703.     public synchronized void removeImage(Image image) {
  704.     MediaEntry cur = head;
  705.     MediaEntry prev = null;
  706.     while (cur != null) {
  707.         MediaEntry next = cur.next;
  708.         if (cur.getMedia() == image) {
  709.         if (prev == null) {
  710.             head = next;
  711.         } else {
  712.             prev.next = next;
  713.         }
  714.         cur.cancel();
  715.         } else {
  716.         prev = cur;
  717.         }
  718.         cur = next;
  719.     }
  720.     notifyAll();    // Notify in case remaining images are "done".
  721.     }
  722.  
  723.     /**
  724.      * Remove the specified image from the specified tracking 
  725.      * ID of this media tracker.
  726.      * All instances of <code>Image</code> being tracked 
  727.      * under the specified ID are removed regardless of scale.
  728.      * @param      image the image to be removed.
  729.      * @param      id the tracking ID frrom which to remove the image.
  730.      * @see        java.awt.MediaTracker#removeImage(java.awt.Image)
  731.      * @see        java.awt.MediaTracker#removeImage(java.awt.Image, int, int, int)
  732.      * @since      JDK1.1
  733.      */
  734.     public synchronized void removeImage(Image image, int id) {
  735.     MediaEntry cur = head;
  736.     MediaEntry prev = null;
  737.     while (cur != null) {
  738.         MediaEntry next = cur.next;
  739.         if (cur.getID() == id && cur.getMedia() == image) {
  740.         if (prev == null) {
  741.             head = next;
  742.         } else {
  743.             prev.next = next;
  744.         }
  745.         cur.cancel();
  746.         } else {
  747.         prev = cur;
  748.         }
  749.         cur = next;
  750.     }
  751.     notifyAll();    // Notify in case remaining images are "done".
  752.     }
  753.  
  754.     /**
  755.      * Remove the specified image with the specified 
  756.      * width, height, and ID from this media tracker.
  757.      * Only the specified instance (with any duplicates) is removed.
  758.      * @param   image the image to be removed
  759.      * @param   id the tracking ID from which to remove the image.
  760.      * @param   width the width to remove (-1 for unscaled).
  761.      * @param   height the height to remove (-1 for unscaled).
  762.      * @see     java.awt.MediaTracker#removeImage(java.awt.Image)
  763.      * @see     java.awt.MediaTracker#removeImage(java.awt.Image, int)
  764.      * @since   JDK1.1
  765.      */
  766.     public synchronized void removeImage(Image image, int id,
  767.                      int width, int height) {
  768.     MediaEntry cur = head;
  769.     MediaEntry prev = null;
  770.     while (cur != null) {
  771.         MediaEntry next = cur.next;
  772.         if (cur.getID() == id && cur instanceof ImageMediaEntry
  773.         && ((ImageMediaEntry) cur).matches(image, width, height))
  774.         {
  775.         if (prev == null) {
  776.             head = next;
  777.         } else {
  778.             prev.next = next;
  779.         }
  780.         cur.cancel();
  781.         } else {
  782.         prev = cur;
  783.         }
  784.         cur = next;
  785.     }
  786.     notifyAll();    // Notify in case remaining images are "done".
  787.     }
  788.  
  789.     synchronized void setDone() {
  790.     notifyAll();
  791.     }
  792. }
  793.  
  794. abstract class MediaEntry {
  795.     MediaTracker tracker;
  796.     int ID;
  797.     MediaEntry next;
  798.  
  799.     int status;
  800.     boolean cancelled;
  801.  
  802.     /*
  803.      * JDK 1.1 serialVersionUID 
  804.      */
  805.     private static final long serialVersionUID = -2924957284304726459L;
  806.  
  807.     MediaEntry(MediaTracker mt, int id) {
  808.     tracker = mt;
  809.     ID = id;
  810.     }
  811.  
  812.     abstract Object getMedia();
  813.  
  814.     static MediaEntry insert(MediaEntry head, MediaEntry me) {
  815.     MediaEntry cur = head;
  816.     MediaEntry prev = null;
  817.     while (cur != null) {
  818.         if (cur.ID > me.ID) {
  819.         break;
  820.         }
  821.         prev = cur;
  822.         cur = cur.next;
  823.     }
  824.     me.next = cur;
  825.     if (prev == null) {
  826.         head = me;
  827.     } else {
  828.         prev.next = me;
  829.     }
  830.     return head;
  831.     }
  832.  
  833.     int getID() {
  834.     return ID;
  835.     }
  836.  
  837.     abstract void startLoad();
  838.  
  839.     void cancel() {
  840.     cancelled = true;
  841.     }
  842.  
  843.     static final int LOADING = MediaTracker.LOADING;
  844.     static final int ABORTED = MediaTracker.ABORTED;
  845.     static final int ERRORED = MediaTracker.ERRORED;
  846.     static final int COMPLETE = MediaTracker.COMPLETE;
  847.  
  848.     static final int LOADSTARTED = (LOADING | ERRORED | COMPLETE);
  849.     static final int DONE = (ABORTED | ERRORED | COMPLETE);
  850.  
  851.     synchronized int getStatus(boolean doLoad, boolean doVerify) {
  852.     if (doLoad && ((status & LOADSTARTED) == 0)) {
  853.         status = (status & ~ABORTED) | LOADING;
  854.         startLoad();
  855.     }
  856.     return status;
  857.     }
  858.  
  859.     void setStatus(int flag) {
  860.     synchronized (this) {
  861.         status = flag;
  862.     }
  863.     tracker.setDone();
  864.     }
  865. }
  866.  
  867. class ImageMediaEntry extends MediaEntry implements ImageObserver, 
  868. java.io.Serializable {
  869.     Image image;
  870.     int width;
  871.     int height;
  872.  
  873.     ImageMediaEntry(MediaTracker mt, Image img, int c, int w, int h) {
  874.     super(mt, c);
  875.     image = img;
  876.     width = w;
  877.     height = h;
  878.     }
  879.  
  880.     boolean matches(Image img, int w, int h) {
  881.     return (image == img && width == w && height == h);
  882.     }
  883.  
  884.     Object getMedia() {
  885.     return image;
  886.     }
  887.  
  888.     int getStatus(boolean doLoad, boolean doVerify) {
  889.     if (doVerify) {
  890.         int flags = tracker.target.checkImage(image, width, height, this);
  891.         int s = parseflags(flags);
  892.         if (s == 0) {
  893.         if ((status & (ERRORED | COMPLETE)) != 0) {
  894.             setStatus(ABORTED);
  895.         }
  896.         } else if (s != status) {
  897.         setStatus(s);
  898.         }
  899.     }
  900.     return super.getStatus(doLoad, doVerify);
  901.     }
  902.  
  903.     void startLoad() {
  904.     if (tracker.target.prepareImage(image, width, height, this)) {
  905.         setStatus(COMPLETE);
  906.     }
  907.     }
  908.  
  909.     int parseflags(int infoflags) {
  910.     if ((infoflags & ERROR) != 0) {
  911.         return ERRORED;
  912.     } else if ((infoflags & ABORT) != 0) {
  913.         return ABORTED;
  914.     } else if ((infoflags & (ALLBITS | FRAMEBITS)) != 0) {
  915.         return COMPLETE;
  916.     }
  917.     return 0;
  918.     }
  919.  
  920.     public boolean imageUpdate(Image img, int infoflags,
  921.                    int x, int y, int w, int h) {
  922.     if (cancelled) {
  923.         return false;
  924.     }
  925.     int s = parseflags(infoflags);
  926.     if (s != 0 && s != status) {
  927.         setStatus(s);
  928.     }
  929.     return ((status & LOADING) != 0);
  930.     }
  931. }
  932.