home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / Java2 / src / java / awt / MediaTracker.java < prev    next >
Encoding:
Java Source  |  1999-05-28  |  29.1 KB  |  919 lines  |  [TEXT/CWIE]

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