home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / awt / MediaTracker.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  28.7 KB  |  902 lines

  1. /*
  2.  * @(#)MediaTracker.java    1.29 98/03/18
  3.  *
  4.  * Copyright 1995-1997 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.29, 03/18/98
  136.  * @author     Jim Graham
  137.  * @since       JDK1.0
  138.  */
  139. public class MediaTracker implements java.io.Serializable {
  140.     Component target;
  141.     MediaEntry head;
  142.  
  143.     /*
  144.      * JDK 1.1 serialVersionUID 
  145.      */
  146.     private static final long serialVersionUID = -483174189758638095L;
  147.  
  148.     /**
  149.      * Creates a media tracker to track images for a given component.
  150.      * @param     comp the component on which the images 
  151.      *                     will eventually be drawn.
  152.      */
  153.     public MediaTracker(Component comp) {
  154.     target = comp;
  155.     }
  156.  
  157.     /**
  158.      * Adds an image to the list of images being tracked by this media 
  159.      * tracker. The image will eventually be rendered at its default 
  160.      * (unscaled) size. 
  161.      * @param     image   the image to be tracked.
  162.      * @param     id      an identifier used to track this image.
  163.      */
  164.     public void addImage(Image image, int id) {
  165.     addImage(image, id, -1, -1);
  166.     }
  167.  
  168.     /**
  169.      * Adds a scaled image to the list of images being tracked  
  170.      * by this media tracker. The image will eventually be 
  171.      * rendered at the indicated width and height.
  172.      * @param     image   the image to be tracked.
  173.      * @param     id   an identifier that can be used to track this image.
  174.      * @param     w    the width at which the image is rendered.
  175.      * @param     h    the height at which the image is rendered.
  176.      */
  177.     public synchronized void addImage(Image image, int id, int w, int h) {
  178.     head = MediaEntry.insert(head,
  179.                  new ImageMediaEntry(this, image, id, w, h));
  180.     }
  181.  
  182.     /**
  183.      * Flag indicating some media is currently being loaded.
  184.      * @see         java.awt.MediaTracker#statusAll
  185.      * @see         java.awt.MediaTracker#statusID
  186.      */
  187.     public static final int LOADING = 1;
  188.  
  189.     /**
  190.      * Flag indicating that the downloading of some media was aborted.
  191.      * @see         java.awt.MediaTracker#statusAll
  192.      * @see         java.awt.MediaTracker#statusID
  193.      */
  194.     public static final int ABORTED = 2;
  195.  
  196.     /**
  197.      * Flag indicating that the downloading of some media encountered 
  198.      * an error.
  199.      * @see         java.awt.MediaTracker#statusAll
  200.      * @see         java.awt.MediaTracker#statusID
  201.      */
  202.     public static final int ERRORED = 4;
  203.  
  204.     /**
  205.      * Flag indicating that the downloading of media was completed 
  206.      * successfully.
  207.      * @see         java.awt.MediaTracker#statusAll
  208.      * @see         java.awt.MediaTracker#statusID
  209.      */
  210.     public static final int COMPLETE = 8;
  211.  
  212.     static final int DONE = (ABORTED | ERRORED | COMPLETE);
  213.  
  214.     /**
  215.      * Checks to see if all images being tracked by this media tracker 
  216.      * have finished loading. 
  217.      * <p>
  218.      * This method does not start loading the images if they are not 
  219.      * already loading. 
  220.      * <p>
  221.      * If there is an error while loading or scaling an image, then that 
  222.      * image is considered to have finished loading. Use the 
  223.      * <code>isErrorAny</code> or <code>isErrorID</code> methods to 
  224.      * check for errors. 
  225.      * @return      <code>true</code> if all images have finished loading, 
  226.      *                       have been aborted, or have encountered 
  227.      *                       an error; <code>false</code> otherwise.
  228.      * @see         java.awt.MediaTracker#checkAll(boolean)
  229.      * @see         java.awt.MediaTracker#checkID
  230.      * @see         java.awt.MediaTracker#isErrorAny
  231.      * @see         java.awt.MediaTracker#isErrorID
  232.      */
  233.     public boolean checkAll() {
  234.     return checkAll(false, true);
  235.     }
  236.  
  237.     /**
  238.      * Checks to see if all images being tracked by this media tracker 
  239.      * have finished loading. 
  240.      * <p>
  241.      * If the value of the <code>load</code> flag is <code>true</code>, 
  242.      * then this method starts loading any images that are not yet 
  243.      * being loaded. 
  244.      * <p>
  245.      * If there is an error while loading or scaling an image, that 
  246.      * image is considered to have finished loading. Use the 
  247.      * <code>isErrorAny</code> and <code>isErrorID</code> methods to 
  248.      * check for errors. 
  249.      * @param       load   if <code>true</code>, start loading any 
  250.      *                       images that are not yet being loaded.
  251.      * @return      <code>true</code> if all images have finished loading, 
  252.      *                       have been aborted, or have encountered 
  253.      *                       an error; <code>false</code> otherwise.
  254.      * @see         java.awt.MediaTracker#checkID
  255.      * @see         java.awt.MediaTracker#checkAll()
  256.      * @see         java.awt.MediaTracker#isErrorAny()
  257.      * @see         java.awt.MediaTracker#isErrorID(int)
  258.      */
  259.     public boolean checkAll(boolean load) {
  260.     return checkAll(load, true);
  261.     }
  262.  
  263.     private synchronized boolean checkAll(boolean load, boolean verify) {
  264.     MediaEntry cur = head;
  265.     boolean done = true;
  266.     while (cur != null) {
  267.         if ((cur.getStatus(load, verify) & DONE) == 0) {
  268.         done = false;
  269.         }
  270.         cur = cur.next;
  271.     }
  272.     return done;
  273.     }
  274.  
  275.     /**
  276.      * Checks the error status of all of the images.
  277.      * @return   <code>true</code> if any of the images tracked
  278.      *                  by this media tracker had an error during 
  279.      *                  loading; <code>false</code> otherwise.
  280.      * @see      java.awt.MediaTracker#isErrorID
  281.      * @see      java.awt.MediaTracker#getErrorsAny
  282.      */
  283.     public synchronized boolean isErrorAny() {
  284.     MediaEntry cur = head;
  285.     while (cur != null) {
  286.         if ((cur.getStatus(false, true) & ERRORED) != 0) {
  287.         return true;
  288.         }
  289.         cur = cur.next;
  290.     }
  291.     return false;
  292.     }
  293.  
  294.     /**
  295.      * Returns a list of all media that have encountered an error.
  296.      * @return       an array of media objects tracked by this 
  297.      *                        media tracker that have encountered 
  298.      *                        an error, or <code>null</code> if 
  299.      *                        there are none with errors.
  300.      * @see          java.awt.MediaTracker#isErrorAny
  301.      * @see          java.awt.MediaTracker#getErrorsID
  302.      */
  303.     public synchronized Object[] getErrorsAny() {
  304.     MediaEntry cur = head;
  305.     int numerrors = 0;
  306.     while (cur != null) {
  307.         if ((cur.getStatus(false, true) & ERRORED) != 0) {
  308.         numerrors++;
  309.         }
  310.         cur = cur.next;
  311.     }
  312.     if (numerrors == 0) {
  313.         return null;
  314.     }
  315.     Object errors[] = new Object[numerrors];
  316.     cur = head;
  317.     numerrors = 0;
  318.     while (cur != null) {
  319.         if ((cur.getStatus(false, false) & ERRORED) != 0) {
  320.         errors[numerrors++] = cur.getMedia();
  321.         }
  322.         cur = cur.next;
  323.     }
  324.     return errors;
  325.     }
  326.  
  327.     /**
  328.      * Starts loading all images tracked by this media tracker. This 
  329.      * method waits until all the images being tracked have finished 
  330.      * loading. 
  331.      * <p>
  332.      * If there is an error while loading or scaling an image, then that 
  333.      * image is considered to have finished loading. Use the 
  334.      * <code>isErrorAny</code> or <code>isErrorID</code> methods to 
  335.      * check for errors. 
  336.      * @see         java.awt.MediaTracker#waitForID(int)
  337.      * @see         java.awt.MediaTracker#waitForAll(long)
  338.      * @see         java.awt.MediaTracker#isErrorAny
  339.      * @see         java.awt.MediaTracker#isErrorID
  340.      * @exception   InterruptedException  if another thread has 
  341.      *                                     interrupted this thread.
  342.      */
  343.     public void waitForAll() throws InterruptedException {
  344.     waitForAll(0);
  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, or until the length of time specified in milliseconds  
  351.      * by the <code>ms</code> argument has passed. 
  352.      * <p>
  353.      * If there is an error while loading or scaling an image, then  
  354.      * that image is considered to have finished loading. Use the 
  355.      * <code>isErrorAny</code> or <code>isErrorID</code> methods to 
  356.      * check for errors. 
  357.      * @param       ms       the number of milliseconds to wait 
  358.      *                       for the loading to complete.
  359.      * @return      <code>true</code> if all images were successfully 
  360.      *                       loaded; <code>false</code> otherwise.
  361.      * @see         java.awt.MediaTracker#waitForID(int)
  362.      * @see         java.awt.MediaTracker#waitForAll(long)
  363.      * @see         java.awt.MediaTracker#isErrorAny
  364.      * @see         java.awt.MediaTracker#isErrorID
  365.      * @exception   InterruptedException  if another thread has 
  366.      *                                     interrupted this thread.
  367.      */
  368.     public synchronized boolean waitForAll(long ms)
  369.     throws InterruptedException
  370.     {
  371.     long end = System.currentTimeMillis() + ms;
  372.     boolean first = true;
  373.     while (true) {
  374.         int status = statusAll(first, first);
  375.         if ((status & LOADING) == 0) {
  376.         return (status == COMPLETE);
  377.         }
  378.         first = false;
  379.         long timeout;
  380.         if (ms == 0) {
  381.         timeout = 0;
  382.         } else {
  383.         timeout = end - System.currentTimeMillis();
  384.         if (timeout <= 0) {
  385.             return false;
  386.         }
  387.         }
  388.         wait(timeout);
  389.     }
  390.     }
  391.  
  392.     /**
  393.      * Calculates and returns the bitwise inclusive <b>OR</b> of the 
  394.      * status of all media that are tracked by this media tracker. 
  395.      * <p>
  396.      * Possible flags defined by the 
  397.      * <code>MediaTracker</code> class are <code>LOADING</code>, 
  398.      * <code>ABORTED</code>, <code>ERRORED</code>, and 
  399.      * <code>COMPLETE</code>. An image that hasn't started 
  400.      * loading has zero as its status. 
  401.      * <p>
  402.      * If the value of <code>load</code> is <code>true</code>, then
  403.      * this method starts loading any images that are not yet being loaded. 
  404.      * @param        load   if <code>true</code>, start loading 
  405.      *                            any images that are not yet being loaded.
  406.      * @return       the bitwise inclusive <b>OR</b> of the status of 
  407.      *                            all of the media being tracked.
  408.      * @see          java.awt.MediaTracker#statusID(int, boolean)
  409.      * @see          java.awt.MediaTracker#LOADING
  410.      * @see          java.awt.MediaTracker#ABORTED
  411.      * @see          java.awt.MediaTracker#ERRORED
  412.      * @see          java.awt.MediaTracker#COMPLETE
  413.      */
  414.     public int statusAll(boolean load) {
  415.     return statusAll(load, true);
  416.     }
  417.  
  418.     private synchronized int statusAll(boolean load, boolean verify) {
  419.     MediaEntry cur = head;
  420.     int status = 0;
  421.     while (cur != null) {
  422.         status = status | cur.getStatus(load, verify);
  423.         cur = cur.next;
  424.     }
  425.     return status;
  426.     }
  427.  
  428.     /**
  429.      * Checks to see if all images tracked by this media tracker that 
  430.      * are tagged with the specified identifier have finished loading. 
  431.      * <p>
  432.      * This method does not start loading the images if they are not 
  433.      * already loading. 
  434.      * <p>
  435.      * If there is an error while loading or scaling an image, then that 
  436.      * image is considered to have finished loading. Use the 
  437.      * <code>isErrorAny</code> or <code>isErrorID</code> methods to 
  438.      * check for errors. 
  439.      * @param       id   the identifier of the images to check.
  440.      * @return      <code>true</code> if all images have finished loading, 
  441.      *                       have been aborted, or have encountered 
  442.      *                       an error; <code>false</code> otherwise.
  443.      * @see         java.awt.MediaTracker#checkID(int, boolean)
  444.      * @see         java.awt.MediaTracker#checkAll()
  445.      * @see         java.awt.MediaTracker#isErrorAny()
  446.      * @see         java.awt.MediaTracker#isErrorID(int)
  447.      */
  448.     public boolean checkID(int id) {
  449.     return checkID(id, false, true);
  450.     }
  451.  
  452.     /**
  453.      * Checks to see if all images tracked by this media tracker that 
  454.      * are tagged with the specified identifier have finished loading. 
  455.      * <p>
  456.      * If the value of the <code>load</code> flag is <code>true</code>, 
  457.      * then this method starts loading any images that are not yet 
  458.      * being loaded. 
  459.      * <p>
  460.      * If there is an error while loading or scaling an image, then that 
  461.      * image is considered to have finished loading. Use the 
  462.      * <code>isErrorAny</code> or <code>isErrorID</code> methods to 
  463.      * check for errors. 
  464.      * @param       id       the identifier of the images to check.
  465.      * @param       load     if <code>true</code>, start loading any 
  466.      *                       images that are not yet being loaded.
  467.      * @return      <code>true</code> if all images have finished loading, 
  468.      *                       have been aborted, or have encountered 
  469.      *                       an error; <code>false</code> otherwise.
  470.      * @see         java.awt.MediaTracker#checkID(int, boolean)
  471.      * @see         java.awt.MediaTracker#checkAll()
  472.      * @see         java.awt.MediaTracker#isErrorAny()
  473.      * @see         java.awt.MediaTracker#isErrorID(int)
  474.      */
  475.     public boolean checkID(int id, boolean load) {
  476.     return checkID(id, load, true);
  477.     }
  478.  
  479.     private synchronized boolean checkID(int id, boolean load, boolean verify)
  480.     {
  481.     MediaEntry cur = head;
  482.     boolean done = true;
  483.     while (cur != null) {
  484.         if (cur.getID() == id
  485.         && (cur.getStatus(load, verify) & DONE) == 0)
  486.         {
  487.         done = false;
  488.         }
  489.         cur = cur.next;
  490.     }
  491.     return done;
  492.     }
  493.  
  494.     /**
  495.      * Checks the error status of all of the images tracked by this 
  496.      * media tracker with the specified identifier. 
  497.      * @param        id   the identifier of the images to check.
  498.      * @return       <code>true</code> if any of the images with the 
  499.      *                          specified identifier had an error during 
  500.      *                          loading; <code>false</code> otherwise.
  501.      * @see          java.awt.MediaTracker#isErrorAny
  502.      * @see          java.awt.MediaTracker#getErrorsID
  503.      */
  504.     public synchronized boolean isErrorID(int id) {
  505.     MediaEntry cur = head;
  506.     while (cur != null) {
  507.         if (cur.getID() == id
  508.         && (cur.getStatus(false, true) & ERRORED) != 0)
  509.         {
  510.         return true;
  511.         }
  512.         cur = cur.next;
  513.     }
  514.     return false;
  515.     }
  516.  
  517.     /**
  518.      * Returns a list of media with the specified ID that 
  519.      * have encountered an error.
  520.      * @param       id   the identifier of the images to check.
  521.      * @return      an array of media objects tracked by this media 
  522.      *                       tracker with the specified identifier 
  523.      *                       that have encountered an error, or 
  524.      *                       <code>null</code> if there are none with errors.
  525.      * @see         java.awt.MediaTracker#isErrorID
  526.      * @see         java.awt.MediaTracker#isErrorAny
  527.      * @see         java.awt.MediaTracker#getErrorsAny
  528.      */
  529.     public synchronized Object[] getErrorsID(int id) {
  530.     MediaEntry cur = head;
  531.     int numerrors = 0;
  532.     while (cur != null) {
  533.         if (cur.getID() == id
  534.         && (cur.getStatus(false, true) & ERRORED) != 0)
  535.         {
  536.         numerrors++;
  537.         }
  538.         cur = cur.next;
  539.     }
  540.     if (numerrors == 0) {
  541.         return null;
  542.     }
  543.     Object errors[] = new Object[numerrors];
  544.     cur = head;
  545.     numerrors = 0;
  546.     while (cur != null) {
  547.         if (cur.getID() == id
  548.         && (cur.getStatus(false, false) & ERRORED) != 0)
  549.         {
  550.         errors[numerrors++] = cur.getMedia();
  551.         }
  552.         cur = cur.next;
  553.     }
  554.     return errors;
  555.     }
  556.  
  557.     /**
  558.      * Starts loading all images tracked by this media tracker with the 
  559.      * specified identifier. This method waits until all the images with 
  560.      * the specified identifier have finished loading. 
  561.      * <p>
  562.      * If there is an error while loading or scaling an image, then that 
  563.      * image is considered to have finished loading. Use the 
  564.      * <code>isErrorAny</code> and <code>isErrorID</code> methods to 
  565.      * check for errors. 
  566.      * @param         id   the identifier of the images to check.
  567.      * @see           java.awt.MediaTracker#waitForAll
  568.      * @see           java.awt.MediaTracker#isErrorAny()
  569.      * @see           java.awt.MediaTracker#isErrorID(int)
  570.      * @exception     InterruptedException  if another thread has 
  571.      *                          interrupted this thread.
  572.      */
  573.     public void waitForID(int id) throws InterruptedException {
  574.     waitForID(id, 0);
  575.     }
  576.  
  577.     /**
  578.      * Starts loading all images tracked by this media tracker with the 
  579.      * specified identifier. This method waits until all the images with 
  580.      * the specified identifier have finished loading, or until the 
  581.      * length of time specified in milliseconds by the <code>ms</code> 
  582.      * argument has passed. 
  583.      * <p>
  584.      * If there is an error while loading or scaling an image, then that 
  585.      * image is considered to have finished loading. Use the 
  586.      * <code>statusID</code>, <code>isErrorID</code>, and
  587.      * <code>isErrorAny</code> methods to check for errors. 
  588.      * @param         id   the identifier of the images to check.
  589.      * @param         ms   the length of time, in milliseconds, to wait 
  590.      *                           for the loading to complete.
  591.      * @see           java.awt.MediaTracker#waitForAll
  592.      * @see           java.awt.MediaTracker#waitForID(int)
  593.      * @see           java.awt.MediaTracker#statusID
  594.      * @see           java.awt.MediaTracker#isErrorAny()
  595.      * @see           java.awt.MediaTracker#isErrorID(int)
  596.      * @exception     InterruptedException  if another thread has 
  597.      *                          interrupted this thread.
  598.      */
  599.     public synchronized boolean waitForID(int id, long ms)
  600.     throws InterruptedException
  601.     {
  602.     long end = System.currentTimeMillis() + ms;
  603.     boolean first = true;
  604.     while (true) {
  605.         int status = statusID(id, first, first);
  606.         if ((status & LOADING) == 0) {
  607.         return (status == COMPLETE);
  608.         }
  609.         first = false;
  610.         long timeout;
  611.         if (ms == 0) {
  612.         timeout = 0;
  613.         } else {
  614.         timeout = end - System.currentTimeMillis();
  615.         if (timeout <= 0) {
  616.             return false;
  617.         }
  618.         }
  619.         wait(timeout);
  620.     }
  621.     }
  622.  
  623.     /**
  624.      * Calculates and returns the bitwise inclusive <b>OR</b> of the 
  625.      * status of all media with the specified identifier that are 
  626.      * tracked by this media tracker. 
  627.      * <p>
  628.      * Possible flags defined by the 
  629.      * <code>MediaTracker</code> class are <code>LOADING</code>, 
  630.      * <code>ABORTED</code>, <code>ERRORED</code>, and 
  631.      * <code>COMPLETE</code>. An image that hasn't started 
  632.      * loading has zero as its status. 
  633.      * <p>
  634.      * If the value of <code>load</code> is <code>true</code>, then
  635.      * this method starts loading any images that are not yet being loaded. 
  636.      * @param        id   the identifier of the images to check.
  637.      * @param        load   if <code>true</code>, start loading 
  638.      *                            any images that are not yet being loaded.
  639.      * @return       the bitwise inclusive <b>OR</b> of the status of 
  640.      *                            all of the media with the specified
  641.      *                            identifier that are being tracked.
  642.      * @see          java.awt.MediaTracker#statusAll(boolean)
  643.      * @see          java.awt.MediaTracker#LOADING
  644.      * @see          java.awt.MediaTracker#ABORTED
  645.      * @see          java.awt.MediaTracker#ERRORED
  646.      * @see          java.awt.MediaTracker#COMPLETE
  647.      */
  648.     public int statusID(int id, boolean load) {
  649.     return statusID(id, load, true);
  650.     }
  651.  
  652.     private synchronized int statusID(int id, boolean load, boolean verify) {
  653.     MediaEntry cur = head;
  654.     int status = 0;
  655.     while (cur != null) {
  656.         if (cur.getID() == id) {
  657.         status = status | cur.getStatus(load, verify);
  658.         }
  659.         cur = cur.next;
  660.     }
  661.     return status;
  662.     }
  663.  
  664.     /**
  665.      * Remove the specified image from this media tracker.
  666.      * All instances of the specified image are removed, 
  667.      * regardless of scale or ID.
  668.      * @param   image     the image to be removed
  669.      * @see     java.awt.MediaTracker#removeImage(java.awt.Image, int)
  670.      * @see     java.awt.MediaTracker#removeImage(java.awt.Image, int, int, int)
  671.      * @since   JDK1.1
  672.      */
  673.     public synchronized void removeImage(Image image) {
  674.     MediaEntry cur = head;
  675.     MediaEntry prev = null;
  676.     while (cur != null) {
  677.         MediaEntry next = cur.next;
  678.         if (cur.getMedia() == image) {
  679.         if (prev == null) {
  680.             head = next;
  681.         } else {
  682.             prev.next = next;
  683.         }
  684.         cur.cancel();
  685.         } else {
  686.         prev = cur;
  687.         }
  688.         cur = next;
  689.     }
  690.     notifyAll();    // Notify in case remaining images are "done".
  691.     }
  692.  
  693.     /**
  694.      * Remove the specified image from the specified tracking 
  695.      * ID of this media tracker.
  696.      * All instances of <code>Image</code> being tracked 
  697.      * under the specified ID are removed regardless of scale.
  698.      * @param      image the image to be removed.
  699.      * @param      id the tracking ID frrom which to remove the image.
  700.      * @see        java.awt.MediaTracker#removeImage(java.awt.Image)
  701.      * @see        java.awt.MediaTracker#removeImage(java.awt.Image, int, int, int)
  702.      * @since      JDK1.1
  703.      */
  704.     public synchronized void removeImage(Image image, int id) {
  705.     MediaEntry cur = head;
  706.     MediaEntry prev = null;
  707.     while (cur != null) {
  708.         MediaEntry next = cur.next;
  709.         if (cur.getID() == id && cur.getMedia() == image) {
  710.         if (prev == null) {
  711.             head = next;
  712.         } else {
  713.             prev.next = next;
  714.         }
  715.         cur.cancel();
  716.         } else {
  717.         prev = cur;
  718.         }
  719.         cur = next;
  720.     }
  721.     notifyAll();    // Notify in case remaining images are "done".
  722.     }
  723.  
  724.     /**
  725.      * Remove the specified image with the specified 
  726.      * width, height, and ID from this media tracker.
  727.      * Only the specified instance (with any duplicates) is removed.
  728.      * @param   image the image to be removed
  729.      * @param   id the tracking ID from which to remove the image.
  730.      * @param   width the width to remove (-1 for unscaled).
  731.      * @param   height the height to remove (-1 for unscaled).
  732.      * @see     java.awt.MediaTracker#removeImage(java.awt.Image)
  733.      * @see     java.awt.MediaTracker#removeImage(java.awt.Image, int)
  734.      * @since   JDK1.1
  735.      */
  736.     public synchronized void removeImage(Image image, int id,
  737.                      int width, int height) {
  738.     MediaEntry cur = head;
  739.     MediaEntry prev = null;
  740.     while (cur != null) {
  741.         MediaEntry next = cur.next;
  742.         if (cur.getID() == id && cur instanceof ImageMediaEntry
  743.         && ((ImageMediaEntry) cur).matches(image, width, height))
  744.         {
  745.         if (prev == null) {
  746.             head = next;
  747.         } else {
  748.             prev.next = next;
  749.         }
  750.         cur.cancel();
  751.         } else {
  752.         prev = cur;
  753.         }
  754.         cur = next;
  755.     }
  756.     notifyAll();    // Notify in case remaining images are "done".
  757.     }
  758.  
  759.     synchronized void setDone() {
  760.     notifyAll();
  761.     }
  762. }
  763.  
  764. abstract class MediaEntry {
  765.     MediaTracker tracker;
  766.     int ID;
  767.     MediaEntry next;
  768.  
  769.     int status;
  770.     boolean cancelled;
  771.  
  772.     /*
  773.      * JDK 1.1 serialVersionUID 
  774.      */
  775.     private static final long serialVersionUID = -2924957284304726459L;
  776.  
  777.     MediaEntry(MediaTracker mt, int id) {
  778.     tracker = mt;
  779.     ID = id;
  780.     }
  781.  
  782.     abstract Object getMedia();
  783.  
  784.     static MediaEntry insert(MediaEntry head, MediaEntry me) {
  785.     MediaEntry cur = head;
  786.     MediaEntry prev = null;
  787.     while (cur != null) {
  788.         if (cur.ID > me.ID) {
  789.         break;
  790.         }
  791.         prev = cur;
  792.         cur = cur.next;
  793.     }
  794.     me.next = cur;
  795.     if (prev == null) {
  796.         head = me;
  797.     } else {
  798.         prev.next = me;
  799.     }
  800.     return head;
  801.     }
  802.  
  803.     int getID() {
  804.     return ID;
  805.     }
  806.  
  807.     abstract void startLoad();
  808.  
  809.     void cancel() {
  810.     cancelled = true;
  811.     }
  812.  
  813.     static final int LOADING = MediaTracker.LOADING;
  814.     static final int ABORTED = MediaTracker.ABORTED;
  815.     static final int ERRORED = MediaTracker.ERRORED;
  816.     static final int COMPLETE = MediaTracker.COMPLETE;
  817.  
  818.     static final int LOADSTARTED = (LOADING | ERRORED | COMPLETE);
  819.     static final int DONE = (ABORTED | ERRORED | COMPLETE);
  820.  
  821.     synchronized int getStatus(boolean doLoad, boolean doVerify) {
  822.     if (doLoad && ((status & LOADSTARTED) == 0)) {
  823.         status = (status & ~ABORTED) | LOADING;
  824.         startLoad();
  825.     }
  826.     return status;
  827.     }
  828.  
  829.     void setStatus(int flag) {
  830.     synchronized (this) {
  831.         status = flag;
  832.     }
  833.     tracker.setDone();
  834.     }
  835. }
  836.  
  837. class ImageMediaEntry extends MediaEntry implements ImageObserver, 
  838. java.io.Serializable {
  839.     Image image;
  840.     int width;
  841.     int height;
  842.  
  843.     ImageMediaEntry(MediaTracker mt, Image img, int c, int w, int h) {
  844.     super(mt, c);
  845.     image = img;
  846.     width = w;
  847.     height = h;
  848.     }
  849.  
  850.     boolean matches(Image img, int w, int h) {
  851.     return (image == img && width == w && height == h);
  852.     }
  853.  
  854.     Object getMedia() {
  855.     return image;
  856.     }
  857.  
  858.     int getStatus(boolean doLoad, boolean doVerify) {
  859.     if (doVerify) {
  860.         int flags = tracker.target.checkImage(image, width, height, this);
  861.         int s = parseflags(flags);
  862.         if (s == 0) {
  863.         if ((status & (ERRORED | COMPLETE)) != 0) {
  864.             setStatus(ABORTED);
  865.         }
  866.         } else if (s != status) {
  867.         setStatus(s);
  868.         }
  869.     }
  870.     return super.getStatus(doLoad, doVerify);
  871.     }
  872.  
  873.     void startLoad() {
  874.     if (tracker.target.prepareImage(image, width, height, this)) {
  875.         setStatus(COMPLETE);
  876.     }
  877.     }
  878.  
  879.     int parseflags(int infoflags) {
  880.     if ((infoflags & ERROR) != 0) {
  881.         return ERRORED;
  882.     } else if ((infoflags & ABORT) != 0) {
  883.         return ABORTED;
  884.     } else if ((infoflags & (ALLBITS | FRAMEBITS)) != 0) {
  885.         return COMPLETE;
  886.     }
  887.     return 0;
  888.     }
  889.  
  890.     public boolean imageUpdate(Image img, int infoflags,
  891.                    int x, int y, int w, int h) {
  892.     if (cancelled) {
  893.         return false;
  894.     }
  895.     int s = parseflags(infoflags);
  896.     if (s != 0 && s != status) {
  897.         setStatus(s);
  898.     }
  899.     return ((status & LOADING) != 0);
  900.     }
  901. }
  902.