diff options
Diffstat (limited to 'libjava/java/awt')
-rw-r--r-- | libjava/java/awt/MediaTracker.java | 520 |
1 files changed, 392 insertions, 128 deletions
diff --git a/libjava/java/awt/MediaTracker.java b/libjava/java/awt/MediaTracker.java index e69832d..2c51fbd 100644 --- a/libjava/java/awt/MediaTracker.java +++ b/libjava/java/awt/MediaTracker.java @@ -45,95 +45,191 @@ import java.util.ArrayList; * This class is used for keeping track of the status of various media * objects. * + * Media objects are tracked by assigning them an ID. It is possible + * to assign the same ID to mutliple objects, effectivly grouping them + * together. In this case the status flags ({@link #statusID}) and error flag + * (@link #isErrorID} and {@link #getErrorId}) are ORed together. This + * means that you cannot say exactly which media object has which status, + * at most you can say that there <em>are</em> certain media objects with + * some certain status. + * + * At the moment only images are supported by this class. + * * @author Aaron M. Renn (arenn@urbanophile.com) * @author Bryce McKinlay */ public class MediaTracker implements java.io.Serializable { + /** Indicates that the media is still loading. */ public static final int LOADING = 1 << 0; + + /** Indicates that the loading operation has been aborted. */ public static final int ABORTED = 1 << 1; + + /** Indicates that an error has occured during loading of the media. */ public static final int ERRORED = 1 << 2; + + /** Indicates that the media has been successfully and completely loaded. */ public static final int COMPLETE = 1 << 3; - + + /** The component on which the media is eventually been drawn. */ Component target; + + /** The head of the linked list of tracked media objects. */ MediaEntry head; + /** Our serialVersionUID for serialization. */ static final long serialVersionUID = -483174189758638095L; + /** + * This represents a media object that is tracked by a MediaTracker. + * It also implements a simple linked list. + */ // FIXME: The serialized form documentation says MediaEntry is a // serializable field, but the serialized form of MediaEntry itself // doesn't appear to be documented. class MediaEntry implements ImageObserver { + /** The ID of the media object. */ int id; + + /** The media object. (only images are supported ATM). */ Image image; + + /** The link to the next entry in the list. */ MediaEntry next; + + /** The tracking status. */ int status; + + /** The width of the image. */ int width; + + /** The height of the image. */ int height; + /** + * Receives notification from an {@link java.awt.image.ImageProducer} + * that more data of the image is available. + * + * @param img the image that is updated + * @param flags flags from the ImageProducer that indicate the status + * of the loading process + * @param x the X coordinate of the upper left corner of the image + * @param y the Y coordinate of the upper left corner of the image + * @param width the width of the image + * @param height the height of the image + * + * @return <code>true</code> if more data is needed, <code>false</code> + * otherwise + * + * @see {@link java.awt.image.ImageObserver} + */ public boolean imageUpdate(Image img, int flags, int x, int y, - int width, int height) + int width, int height) { if ((flags & ABORT) != 0) - status = ABORTED | COMPLETE; + status = ABORTED; else if ((flags & ERROR) != 0) - status = ERRORED | COMPLETE; + status = ERRORED; else if ((flags & ALLBITS) != 0) status = COMPLETE; - else if ((flags & SOMEBITS) != 0) - status = LOADING; else status = 0; - if ((status & COMPLETE) == COMPLETE) - { - synchronized (MediaTracker.this) + synchronized (MediaTracker.this) { MediaTracker.this.notifyAll(); } - } + // If status is not COMPLETE then we need more updates. - return (status & COMPLETE) == 0; + return ((status & (COMPLETE | ERRORED | ABORTED)) == 0); } } + /** + * Constructs a new MediaTracker for the component <code>c</code>. The + * component should be the component that uses the media (i.e. draws it). + * + * @param c the Component that wants to use the media + */ public MediaTracker(Component c) { target = c; } + /** + * Adds an image to the tracker with the specified <code>ID</code>. + * + * @param image the image to be added + * @param id the ID of the tracker list to which the image is added + */ public void addImage(Image image, int id) { MediaEntry e = new MediaEntry(); e.id = id; e.image = image; - e.next = head; - head = e; - // Start tracking image status. - int flags = target.checkImage(image, e); - e.imageUpdate(image, flags, -1, -1, -1, -1); + synchronized(this) + { + e.next = head; + head = e; + } } + /** + * Adds an image to the tracker with the specified <code>ID</code>. + * The image is expected to be rendered with the specified width and + * height. + * + * @param image the image to be added + * @param id the ID of the tracker list to which the image is added + * @param width the width of the image + * @param height the height of the image + */ public void addImage(Image image, int id, int width, int height) { MediaEntry e = new MediaEntry(); e.id = id; e.image = image; - e.next = head; e.width = width; e.height = height; - head = e; - // Start tracking image status. - int flags = target.checkImage(image, width, height, e); - e.imageUpdate(image, flags, -1, -1, width, height); + synchronized(this) + { + e.next = head; + head = e; + } } + /** + * Checks if all media objects have finished loading, i.e. are + * {@link #COMPLETE}, {@link #ABORTED} or {@link #ERRORED}. + * + * If the media objects are not already loading, a call to this + * method does <em>not</em> start loading. This is equivalent to + * a call to <code>checkAll(false)</code>. + * + * @return if all media objects have finished loading either by beeing + * complete, have been aborted or errored. + */ public boolean checkAll() { return checkAll(false); } + /** + * Checks if all media objects have finished loading, i.e. are + * {@link #COMPLETE}, {@link #ABORTED} or {@link #ERRORED}. + * + * If the media objects are not already loading, and <code>load</code> + * is <code>true</code> then a call to this + * method starts loading the media objects. + * + * @param load if <code>true</code> this method starts loading objects + * that are not already loading + * + * @return if all media objects have finished loading either by beeing + * complete, have been aborted or errored. + */ public boolean checkAll(boolean load) { MediaEntry e = head; @@ -141,37 +237,53 @@ public class MediaTracker implements java.io.Serializable while (e != null) { - if ((e.status & COMPLETE) == 0) - { - if (load) - { - result = false; - if (e.status == 0) - { - target.prepareImage(e.image, e); - e.status = LOADING; - } - } - else - return false; - } - e = e.next; + if ((e.status & (COMPLETE | ERRORED | ABORTED)) == 0) + { + if (load && ((e.status & LOADING) == 0)) + { + e.status = LOADING; + result = false; + boolean complete = target.prepareImage(e.image, e); + if (complete) + { + e.status = COMPLETE; + result = true; + } + } + else + result = false; + } + e = e.next; } return result; } + /** + * Checks if any of the registered media objects has encountered an error + * during loading. + * + * @return <code>true</code> if at least one media object has encountered + * an error during loading, <code>false</code> otherwise + * + */ public boolean isErrorAny() { MediaEntry e = head; while (e != null) { if ((e.status & ERRORED) != 0) - return true; + return true; e = e.next; } return false; } + /** + * Returns all media objects that have encountered errors during loading. + * + * @return an array of all media objects that have encountered errors + * or <code>null</code> if there were no errors at all + */ public Object[] getErrorsAny() { MediaEntry e = head; @@ -179,11 +291,11 @@ public class MediaTracker implements java.io.Serializable while (e != null) { if ((e.status & ERRORED) != 0) - { - if (result == null) - result = new ArrayList(); - result.add(e.image); - } + { + if (result == null) + result = new ArrayList(); + result.add(e.image); + } e = e.next; } if (result == null) @@ -192,6 +304,13 @@ public class MediaTracker implements java.io.Serializable return result.toArray(); } + /** + * Waits for all media objects to finish loading, either by completing + * successfully or by aborting or encountering an error. + * + * @throws InterruptedException if another thread interrupted the + * current thread while waiting + */ public void waitForAll() throws InterruptedException { synchronized (this) @@ -201,20 +320,51 @@ public class MediaTracker implements java.io.Serializable } } + /** + * Waits for all media objects to finish loading, either by completing + * successfully or by aborting or encountering an error. + * + * This method waits at most <code>ms</code> milliseconds. If the + * media objects have not completed loading within this timeframe, this + * method returns <code>false</code>, otherwise <code>true</code>. + * + * @param ms timeframe in milliseconds to wait for the media objects to + * finish + * + * @return <code>true</code> if all media objects have successfully loaded + * within the timeframe, <code>false</code> otherwise + * + * @throws InterruptedException if another thread interrupted the + * current thread while waiting + */ public boolean waitForAll(long ms) throws InterruptedException { long start = System.currentTimeMillis(); + boolean result = checkAll(true); synchronized (this) { - while (!checkAll(true)) - wait(ms); + while (result == false) + { + wait(ms); + result = checkAll(true); + if ((System.currentTimeMillis() - start) > ms) + break; + } } - if ((System.currentTimeMillis() - start) < ms) - return true; - else - return false; + + return result; } + /** + * Returns the status flags of all registered media objects ORed together. + * If <code>load</code> is <code>true</code> then media objects that + * are not already loading will be started to load. + * + * @param load if set to <code>true</code> then media objects that are + * not already loading are started + * + * @return the status flags of all tracked media objects ORed together + */ public int statusAll(boolean load) { int result = 0; @@ -222,21 +372,44 @@ public class MediaTracker implements java.io.Serializable while (e != null) { if (load && e.status == 0) - { - target.prepareImage(e.image, e); - e.status = LOADING; - } + { + boolean complete = target.prepareImage(e.image, e); + if (complete) + e.status = COMPLETE; + else + e.status = LOADING; + } result |= e.status; - e = e.next; + e = e.next; } return result; } + /** + * Checks if the media objects with <code>ID</code> have completed loading. + * + * @param id the ID of the media objects to check + * + * @return <code>true</code> if all media objects with <code>ID</code> + * have successfully finished + */ public boolean checkID(int id) { return checkID(id, false); } + /** + * Checks if the media objects with <code>ID</code> have completed loading. + * If <code>load</code> is <code>true</code> then media objects that + * are not already loading will be started to load. + * + * @param id the ID of the media objects to check + * @param load if set to <code>true</code> then media objects that are + * not already loading are started + * + * @return <code>true</code> if all media objects with <code>ID</code> + * have successfully finished + */ public boolean checkID(int id, boolean load) { MediaEntry e = head; @@ -244,37 +417,57 @@ public class MediaTracker implements java.io.Serializable while (e != null) { - if (e.id == id && ((e.status & COMPLETE) == 0)) - { - if (load) - { - result = false; - if (e.status == 0) - { - target.prepareImage(e.image, e); - e.status = LOADING; - } - } - else - return false; - } - e = e.next; + if (e.id == id && ((e.status & (COMPLETE | ABORTED | ERRORED)) == 0)) + { + if (load && ((e.status & LOADING) == 0)) + { + e.status = LOADING; + result = false; + boolean complete = target.prepareImage(e.image, e); + if (complete) + { + e.status = COMPLETE; + result = true; + } + } + else + result = false; + } + e = e.next; } return result; } + /** + * Returns <code>true</code> if any of the media objects with <code>ID</code> + * have encountered errors during loading, false otherwise. + * + * @param id the ID of the media objects to check + * + * @return <code>true</code> if any of the media objects with <code>ID</code> + * have encountered errors during loading, false otherwise + */ public boolean isErrorID(int id) { MediaEntry e = head; while (e != null) { if (e.id == id && ((e.status & ERRORED) != 0)) - return true; + return true; e = e.next; } return false; } + /** + * Returns all media objects with the specified ID that have encountered + * an error. + * + * @param id the ID of the media objects to check + * + * @return an array of all media objects with the specified ID that + * have encountered an error + */ public Object[] getErrorsID(int id) { MediaEntry e = head; @@ -282,11 +475,11 @@ public class MediaTracker implements java.io.Serializable while (e != null) { if (e.id == id && ((e.status & ERRORED) != 0)) - { - if (result == null) - result = new ArrayList(); - result.add(e.image); - } + { + if (result == null) + result = new ArrayList(); + result.add(e.image); + } e = e.next; } if (result == null) @@ -295,6 +488,15 @@ public class MediaTracker implements java.io.Serializable return result.toArray(); } + /** + * Waits for all media objects with the specified ID to finish loading, + * either by completing successfully or by aborting or encountering an error. + * + * @param id the ID of the media objects to wait for + * + * @throws InterruptedException if another thread interrupted the + * current thread while waiting + */ public void waitForID(int id) throws InterruptedException { MediaEntry e = head; @@ -305,21 +507,56 @@ public class MediaTracker implements java.io.Serializable } } + /** + * Waits for all media objects with the specified ID to finish loading, + * either by completing successfully or by aborting or encountering an error. + * + * This method waits at most <code>ms</code> milliseconds. If the + * media objects have not completed loading within this timeframe, this + * method returns <code>false</code>, otherwise <code>true</code>. + * + * @param id the ID of the media objects to wait for + * @param ms timeframe in milliseconds to wait for the media objects to + * finish + * + * @return <code>true</code> if all media objects have successfully loaded + * within the timeframe, <code>false</code> otherwise + * + * @throws InterruptedException if another thread interrupted the + * current thread while waiting + */ public boolean waitForID(int id, long ms) throws InterruptedException { MediaEntry e = head; long start = System.currentTimeMillis(); + boolean result = checkID(id, true); + synchronized (this) { - while (checkID (id, true) == false) - wait(ms); - } - if ((System.currentTimeMillis() - start) < ms) - return true; - else - return false; + while (result == false) + { + wait(ms); + result = checkID(id, true); + if ((System.currentTimeMillis() - start) > ms) + break; + } + } + + return result; } + /** + * Returns the status flags of the media objects with the specified ID + * ORed together. + * + * If <code>load</code> is <code>true</code> then media objects that + * are not already loading will be started to load. + * + * @param load if set to <code>true</code> then media objects that are + * not already loading are started + * + * @return the status flags of all tracked media objects ORed together + */ public int statusID(int id, boolean load) { int result = 0; @@ -327,73 +564,100 @@ public class MediaTracker implements java.io.Serializable while (e != null) { if (e.id == id) - { + { if (load && e.status == 0) - { - target.prepareImage(e.image, e); - e.status = LOADING; - } + { + boolean complete = target.prepareImage(e.image, e); + if (complete) + e.status = COMPLETE; + else + e.status = LOADING; + } result |= e.status; - } - e = e.next; + } + e = e.next; } return result; } + /** + * Removes an image from this MediaTracker. + * + * @param image the image to be removed + */ public void removeImage(Image image) { - MediaEntry e = head; - MediaEntry prev = null; - while (e != null) + synchronized (this) { - if (e.image == image) - { - if (prev == null) - head = e.next; - else - prev.next = e.next; - } - prev = e; - e = e.next; + MediaEntry e = head; + MediaEntry prev = null; + while (e != null) + { + if (e.image == image) + { + if (prev == null) + head = e.next; + else + prev.next = e.next; + } + prev = e; + e = e.next; + } } } + /** + * Removes an image with the specified ID from this MediaTracker. + * + * @param image the image to be removed + */ public void removeImage(Image image, int id) { - MediaEntry e = head; - MediaEntry prev = null; - while (e != null) + synchronized (this) { - if (e.id == id && e.image == image) - { - if (prev == null) - head = e.next; - else - prev.next = e.next; - } - else - prev = e; - e = e.next; - } + MediaEntry e = head; + MediaEntry prev = null; + while (e != null) + { + if (e.id == id && e.image == image) + { + if (prev == null) + head = e.next; + else + prev.next = e.next; + } + else + prev = e; + e = e.next; + } + } } + /** + * Removes an image with the specified ID and scale from this MediaTracker. + * + * @param image the image to be removed + */ public void removeImage(Image image, int id, int width, int height) { - MediaEntry e = head; - MediaEntry prev = null; - while (e != null) + synchronized (this) { - if (e.id == id && e.image == image - && e.width == width && e.height == height) - { - if (prev == null) - head = e.next; - else - prev.next = e.next; - } - else - prev = e; - e = e.next; + MediaEntry e = head; + MediaEntry prev = null; + while (e != null) + { + if (e.id == id && e.image == image + && e.width == width && e.height == height) + { + if (prev == null) + head = e.next; + else + prev.next = e.next; + } + else + prev = e; + e = e.next; + } } } } |