diff options
-rw-r--r-- | libjava/ChangeLog | 47 | ||||
-rw-r--r-- | libjava/java/awt/MediaTracker.java | 520 |
2 files changed, 439 insertions, 128 deletions
diff --git a/libjava/ChangeLog b/libjava/ChangeLog index 378723b9e29..6360762deb3 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,50 @@ +2005-04-19 Roman Kennke <roman@kennke.org> + + * java/awt/MediaTracker.java: + Reindented tabs to spaces. + +2005-04-19 Roman Kennke <roman@kennke.org> + + * java/awt/MediaTracker.java + (MediaEntry.imageUpdate): Removed check for SOMEBITS, this + confused the media tracker and lead to lockups. The LOADING + bit is handled on other places. + (addImage): Removed the 'start image tracking' stuff. This + is not necessary and could confuse the media tracker. + (checkAll): Improved the check for image status so that + images that already complete images are detected. Also now + are really all images checked and if necessary loaded. Before + the method bailed out after the first incomplete image. + (statusAll): Detect images that are complete after the + call to Component.prepareImage(..). + (checkID): The same as in checkAll. + (statusID): The same as in statusAll. + +2005-04-19 Roman Kennke <roman@kennke.org> + + * java/awt/MediaTracker.java + (addImage): Synchronized list access. + (waitForAll): Fixed comparison of time (changed < to >). + (waitForID): Fixed comparison of time (changed < to >). + (removeImage): Synchronized list access. + +2005-04-19 Roman Kennke <roman@kennke.org> + + * java/awt/MediaTracker.java + Added API documentation. + +2005-04-19 Roman Kennke <roman@kennke.org> + + * java/awt/MediaTracker.java + (MediaEntry.imageUpdate): Fixed flags. The different flags + must not be ORed together. + (checkAll): Modified to handle different meaning of the flags. + (waitForAll): Fixed so that it waits maximum the + specified amount of milliseconds. + (statusAll): Modified to handle different meaning of the flags. + (waitForID): Fixed so that it waits maximum the + specified amount of milliseconds. + 2005-04-19 vid Gilbert <david.gilbert@object-refinery.com> * java/awt/Font.java (decode): Handle null argument and allow diff --git a/libjava/java/awt/MediaTracker.java b/libjava/java/awt/MediaTracker.java index e69832d11a0..2c51fbd19a1 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; + } } } } |