home *** CD-ROM | disk | FTP | other *** search
/ Java Programmer's Toolkit / Java Programmer's Toolkit.iso / solaris2 / jdk / src / java / awt / mediatra.jav < prev    next >
Encoding:
Text File  |  1995-10-30  |  11.6 KB  |  428 lines

  1. /*
  2.  * @(#)MediaTracker.java    1.6 95/10/08 Jim Graham
  3.  *
  4.  * Copyright (c) 1995 Sun Microsystems, Inc. All Rights Reserved.
  5.  *
  6.  * Permission to use, copy, modify, and distribute this software
  7.  * and its documentation for NON-COMMERCIAL purposes and without
  8.  * fee is hereby granted provided that this copyright notice
  9.  * appears in all copies. Please refer to the file "copyright.html"
  10.  * for further important copyright and licensing information.
  11.  *
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  13.  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  14.  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  15.  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  16.  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  17.  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  18.  */
  19.  
  20. package java.awt;
  21.  
  22. import java.awt.Component;
  23. import java.awt.Image;
  24. import java.awt.Graphics;
  25. import java.awt.image.ImageObserver;
  26.  
  27. /**
  28.  * A utility class to track the status of a number of media objects.
  29.  * Media objects could include images as well as audio clips, though
  30.  * currently only images are supported.  To use it, simply create an
  31.  * instance and then call addImage() for each image to be tracked.
  32.  * Each image can be assigned a unique ID for indentification purposes.
  33.  * The IDs control the priority order in which the images are fetched
  34.  * as well as identifying unique subsets of the images that can be
  35.  * waited on independently.  Here is an example:
  36.  * <pre>
  37.  *
  38.  * import java.applet.Applet;
  39.  * import java.awt.Color;
  40.  * import java.awt.Image;
  41.  * import java.awt.Graphics;
  42.  * import java.awt.MediaTracker;
  43.  *
  44.  * public class ImageBlaster extends Applet implements Runnable {
  45.  *    MediaTracker tracker;
  46.  *    Image bg;
  47.  *    Image anim[] = new Image[5];
  48.  *    int index;
  49.  *    Thread animator;
  50.  *
  51.  *    // Get the images for the background (id == 0) and the animation
  52.  *    // frames (id == 1) and add them to the MediaTracker
  53.  *    public void init() {
  54.  *        tracker = new MediaTracker(this);
  55.  *        bg = getImage(getDocumentBase(), "images/background.gif");
  56.  *        tracker.addImage(bg, 0);
  57.  *        for (int i = 0; i < 5; i++) {
  58.  *        anim[i] = getImage(getDocumentBase(), "images/anim"+i+".gif");
  59.  *        tracker.addImage(anim[i], 1);
  60.  *        }
  61.  *    }
  62.  *    // Start the animation thread.
  63.  *    public void start() {
  64.  *        animator = new Thread(this);
  65.  *        animator.start();
  66.  *    }
  67.  *    // Stop the animation thread.
  68.  *    public void stop() {
  69.  *        animator.stop();
  70.  *        animator = null;
  71.  *    }
  72.  *    // Run the animation thread.
  73.  *    // First wait for the background image to fully load and paint.
  74.  *    // Then wait for all of the animation frames to finish loading.
  75.  *    // Finally loop and increment the animation frame index.
  76.  *    public void run() {
  77.  *        try {
  78.  *        tracker.waitForID(0);
  79.  *        tracker.waitForID(1);
  80.  *        } catch (InterruptedException e) {
  81.  *        return;
  82.  *        }
  83.  *        Thread me = Thread.currentThread();
  84.  *        while (animator == me) {
  85.  *        try {
  86.  *            Thread.sleep(100);
  87.  *        } catch (InterruptedException e) {
  88.  *            break;
  89.  *        }
  90.  *        synchronized (this) {
  91.  *            index++;
  92.  *            if (index >= anim.length) {
  93.  *            index = 0;
  94.  *            }
  95.  *        }
  96.  *        repaint();
  97.  *        }
  98.  *    }
  99.  *    // The background image fills our frame so we don't need to clear
  100.  *    // the applet on repaints, just call the paint method.
  101.  *    public void update(Graphics g) {
  102.  *        paint(g);
  103.  *    }
  104.  *    // Paint a large red rectangle if there are any errors loading the
  105.  *    // images.  Otherwise always paint the background so that it appears
  106.  *    // incrementally as it is loading.  Finally, only paint the current
  107.  *    // animation frame if all of the frames (id == 1) are done loading
  108.  *    // so that we don't get partial animations.
  109.  *    public void paint(Graphics g) {
  110.  *        if (tracker.isErrorAny()) {
  111.  *        g.setColor(Color.red);
  112.  *        g.fillRect(0, 0, size().width, size().height);
  113.  *        return;
  114.  *        }
  115.  *        g.drawImage(bg, 0, 0, this);
  116.  *        if (tracker.checkID(1)) {
  117.  *        g.drawImage(anim[index], 10, 10, this);
  118.  *        }
  119.  *    }
  120.  * }
  121.  *
  122.  * </pre>
  123.  *
  124.  * @version     1.6, 10/08/95
  125.  * @author     Jim Graham
  126.  */
  127. public class MediaTracker {
  128.     Component target;
  129.     MediaEntry head;
  130.  
  131.     /**
  132.      * Create a Media tracker to track images for a given Component.
  133.      * @param comp the component on which the images will eventually be drawn
  134.      */
  135.     public MediaTracker(Component comp) {
  136.     target = comp;
  137.     }
  138.  
  139.     /**
  140.      * Add an image to the list of images being tracked.  The image
  141.      * will eventually be rendered at its default (unscaled) size.
  142.      * @param image the image to be tracked
  143.      * @param id the identifier used to later track this image
  144.      */
  145.     public void addImage(Image image, int id) {
  146.     addImage(image, id, -1, -1);
  147.     }
  148.  
  149.     /**
  150.      * Add a scaled image to the list of images being tracked.  The
  151.      * image will eventually be rendered at the indicated size.
  152.      * @param image the image to be tracked
  153.      * @param id the identifier used to later track this image
  154.      * @param w the width that the image will be rendered at
  155.      * @param h the height that the image will be rendered at
  156.      */
  157.     public synchronized void addImage(Image image, int id, int w, int h) {
  158.     head = MediaEntry.insert(head,
  159.                  new ImageMediaEntry(this, image, id, w, h));
  160.     }
  161.  
  162.     /**
  163.      * Check to see if all images have finished loading, but do not start
  164.      * loading the images if they are not already loading.
  165.      * If there is an error while loading or scaling an image then that
  166.      * image is considered "complete".
  167.      * Use isErrorAny or isErrorID to check for errors.
  168.      * @return true if all images have finished loading or have an error
  169.      * @see #checkAll(boolean)
  170.      * @see #checkID
  171.      * @see #isErrorAny
  172.      * @see #isErrorID
  173.      */
  174.     public boolean checkAll() {
  175.     return checkAll(false);
  176.     }
  177.  
  178.     /**
  179.      * Check to see if all images have finished loading and start loading
  180.      * any images that are not yet being loaded if load is true.
  181.      * If there is an error while loading or scaling an image then that
  182.      * image is considered "complete".
  183.      * Use isErrorAny or isErrorID to check for errors.
  184.      * @param load start loading the images if this parameter is true
  185.      * @return true if all images have finished loading or have an error
  186.      * @see #isErrorAny
  187.      * @see #isErrorID
  188.      * @see #checkID(int, boolean)
  189.      * @see #checkAll()
  190.      */
  191.     public synchronized boolean checkAll(boolean load) {
  192.     MediaEntry cur = head;
  193.     boolean done = true;
  194.     while (cur != null) {
  195.         if (!cur.isDone()) {
  196.         done = false;
  197.         if (load) {
  198.             cur.startLoad();
  199.         }
  200.         }
  201.         cur = cur.next;
  202.     }
  203.     return done;
  204.     }
  205.  
  206.     /**
  207.      * Check the error status of all of the images.
  208.      * @return true if any of the images had an error during loading
  209.      * @see #isErrorID
  210.      */
  211.     public synchronized boolean isErrorAny() {
  212.     MediaEntry cur = head;
  213.     while (cur != null) {
  214.         if (cur.isErrored()) {
  215.         return true;
  216.         }
  217.         cur = cur.next;
  218.     }
  219.     return false;
  220.     }
  221.  
  222.     /**
  223.      * Start loading all images and wait until they have finished loading
  224.      * or receive an error.
  225.      * If there is an error while loading or scaling an image then that
  226.      * image is considered "complete".
  227.      * Use isErrorAny or isErrorID to check for errors.
  228.      * @see #waitForID
  229.      * @see #isErrorAny
  230.      * @see #isErrorID
  231.      */
  232.     public synchronized void waitForAll() throws InterruptedException {
  233.     while (true) {
  234.         if (checkAll(true)) {
  235.         return;
  236.         }
  237.         wait();
  238.     }
  239.     }
  240.  
  241.     /**
  242.      * Check to see if all images tagged with the indicated ID have
  243.      * finished loading, but do not start loading the images if they
  244.      * are not already loading.
  245.      * If there is an error while loading or scaling an image then that
  246.      * image is considered "complete".
  247.      * Use isErrorAny or isErrorID to check for errors.
  248.      * @param id the identifier used to determine which images to check
  249.      * @return true if all tagged images have finished loading or have an error
  250.      * @see #checkID(int, boolean)
  251.      * @see #checkAll
  252.      * @see #isErrorAny
  253.      * @see #isErrorID
  254.      */
  255.     public boolean checkID(int id) {
  256.     return checkID(id, false);
  257.     }
  258.  
  259.     /**
  260.      * Check to see if all images tagged with the indicated ID have
  261.      * finished loading and start loading any images with that ID that
  262.      * are not yet being loaded if load is true.
  263.      * If there is an error while loading or scaling an image then that
  264.      * image is considered "complete".
  265.      * Use isErrorAny or isErrorID to check for errors.
  266.      * @param id the identifier used to determine which images to check
  267.      * @param load start loading the images if this parameter is true
  268.      * @return true if all tagged images have finished loading or have an error
  269.      * @see #checkID(int)
  270.      * @see #checkAll
  271.      * @see #isErrorAny
  272.      * @see #isErrorID
  273.      */
  274.     public synchronized boolean checkID(int id, boolean load) {
  275.     MediaEntry cur = head;
  276.     boolean done = true;
  277.     while (cur != null) {
  278.         if (cur.getID() == id && !cur.isDone()) {
  279.         done = false;
  280.         if (load) {
  281.             cur.startLoad();
  282.         }
  283.         }
  284.         cur = cur.next;
  285.     }
  286.     return done;
  287.     }
  288.  
  289.     /**
  290.      * Check the error status of all of the images with the specified ID.
  291.      * @param id the identifier used to determine which images to check
  292.      * @return true if any of the tagged images had an error during loading
  293.      * @see #isErrorAny
  294.      */
  295.     public synchronized boolean isErrorID(int id) {
  296.     MediaEntry cur = head;
  297.     while (cur != null) {
  298.         if (cur.getID() == id && cur.isErrored()) {
  299.         return true;
  300.         }
  301.         cur = cur.next;
  302.     }
  303.     return false;
  304.     }
  305.  
  306.     /**
  307.      * Start loading all images with the specified ID and wait until they
  308.      * have finished loading or receive an error.
  309.      * If there is an error while loading or scaling an image then that
  310.      * image is considered "complete".
  311.      * Use isErrorAny or isErrorID to check for errors.
  312.      * @see #waitForAll
  313.      * @see #isErrorAny
  314.      * @see #isErrorID
  315.      */
  316.     public synchronized void waitForID(int id)
  317.     throws InterruptedException
  318.     {
  319.     while (true) {
  320.         if (checkID(id, true)) {
  321.         return;
  322.         }
  323.         wait();
  324.     }
  325.     }
  326.  
  327.     synchronized void setDone() {
  328.     notifyAll();
  329.     }
  330. }
  331.  
  332. abstract class MediaEntry {
  333.     MediaTracker tracker;
  334.     int ID;
  335.     MediaEntry next;
  336.  
  337.     boolean loaded;
  338.     boolean errored;
  339.  
  340.     MediaEntry(MediaTracker mt, int id) {
  341.     tracker = mt;
  342.     ID = id;
  343.     }
  344.  
  345.     static MediaEntry insert(MediaEntry head, MediaEntry me) {
  346.     MediaEntry cur = head;
  347.     MediaEntry prev = null;
  348.     while (cur != null) {
  349.         if (cur.ID > me.ID) {
  350.         break;
  351.         }
  352.         prev = cur;
  353.         cur = cur.next;
  354.     }
  355.     me.next = cur;
  356.     if (prev == null) {
  357.         head = me;
  358.     } else {
  359.         prev.next = me;
  360.     }
  361.     return head;
  362.     }
  363.  
  364.     int getID() {
  365.     return ID;
  366.     }
  367.  
  368.     abstract void startLoad();
  369.  
  370.     synchronized boolean isDone() {
  371.     return loaded || errored;
  372.     }
  373.  
  374.     synchronized boolean isLoaded() {
  375.     return loaded;
  376.     }
  377.  
  378.     synchronized boolean isErrored() {
  379.     return errored;
  380.     }
  381.  
  382.     void setLoaded() {
  383.     synchronized (this) {
  384.         loaded = true;
  385.     }
  386.     tracker.setDone();
  387.     }
  388.  
  389.     void setError() {
  390.     synchronized (this) {
  391.         errored = true;
  392.     }
  393.     tracker.setDone();
  394.     }
  395. }
  396.  
  397. class ImageMediaEntry extends MediaEntry implements ImageObserver {
  398.     Image image;
  399.     int width;
  400.     int height;
  401.  
  402.     ImageMediaEntry(MediaTracker mt, Image img, int c, int w, int h) {
  403.     super(mt, c);
  404.     image = img;
  405.     width = w;
  406.     height = h;
  407.     }
  408.  
  409.     void startLoad() {
  410.     if (tracker.target.prepareImage(image, width, height, this)) {
  411.         setLoaded();
  412.     }
  413.     }
  414.  
  415.     public boolean imageUpdate(Image img, int infoflags,
  416.                    int x, int y, int w, int h) {
  417.     if ((infoflags & ERROR) != 0) {
  418.         setError();
  419.         return false;
  420.     }
  421.     if ((infoflags & (ALLBITS | FRAMEBITS)) != 0) {
  422.         setLoaded();
  423.         return false;
  424.     }
  425.     return true;
  426.     }
  427. }
  428.