1 /* MediaTracker.java -- Class used for keeping track of images
2 Copyright (C) 1999, 2002, 2004, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
41 import java.awt.image.ImageObserver;
42 import java.util.ArrayList;
45 * This class is used for keeping track of the status of various media
48 * Media objects are tracked by assigning them an ID. It is possible
49 * to assign the same ID to mutliple objects, effectivly grouping them
50 * together. In this case the status flags ({@link #statusID}) and error flag
51 * (@link #isErrorID} and {@link #getErrorsID}) are ORed together. This
52 * means that you cannot say exactly which media object has which status,
53 * at most you can say that there <em>are</em> certain media objects with
54 * some certain status.
56 * At the moment only images are supported by this class.
58 * @author Aaron M. Renn (arenn@urbanophile.com)
59 * @author Bryce McKinlay
61 public class MediaTracker implements java.io.Serializable
63 /** Indicates that the media is still loading. */
64 public static final int LOADING = 1 << 0;
66 /** Indicates that the loading operation has been aborted. */
67 public static final int ABORTED = 1 << 1;
69 /** Indicates that an error has occured during loading of the media. */
70 public static final int ERRORED = 1 << 2;
72 /** Indicates that the media has been successfully and completely loaded. */
73 public static final int COMPLETE = 1 << 3;
75 /** The component on which the media is eventually been drawn. */
78 /** The head of the linked list of tracked media objects. */
81 /** Our serialVersionUID for serialization. */
82 static final long serialVersionUID = -483174189758638095L;
85 * This represents a media object that is tracked by a MediaTracker.
86 * It also implements a simple linked list.
88 // FIXME: The serialized form documentation says MediaEntry is a
89 // serializable field, but the serialized form of MediaEntry itself
90 // doesn't appear to be documented.
91 class MediaEntry implements ImageObserver
93 /** The ID of the media object. */
96 /** The media object. (only images are supported ATM). */
99 /** The link to the next entry in the list. */
102 /** The tracking status. */
105 /** The width of the image. */
108 /** The height of the image. */
112 * Receives notification from an {@link java.awt.image.ImageProducer}
113 * that more data of the image is available.
115 * @param img the image that is updated
116 * @param flags flags from the ImageProducer that indicate the status
117 * of the loading process
118 * @param x the X coordinate of the upper left corner of the image
119 * @param y the Y coordinate of the upper left corner of the image
120 * @param width the width of the image
121 * @param height the height of the image
123 * @return <code>true</code> if more data is needed, <code>false</code>
126 * @see java.awt.image.ImageObserver
128 public boolean imageUpdate(Image img, int flags, int x, int y,
129 int width, int height)
131 if ((flags & ABORT) != 0)
133 else if ((flags & ERROR) != 0)
135 else if ((flags & ALLBITS) != 0)
140 synchronized (MediaTracker.this)
142 MediaTracker.this.notifyAll();
145 // If status is not COMPLETE then we need more updates.
146 return ((status & (COMPLETE | ERRORED | ABORTED)) == 0);
151 * Constructs a new MediaTracker for the component <code>c</code>. The
152 * component should be the component that uses the media (i.e. draws it).
154 * @param c the Component that wants to use the media
156 public MediaTracker(Component c)
162 * Adds an image to the tracker with the specified <code>ID</code>.
164 * @param image the image to be added
165 * @param id the ID of the tracker list to which the image is added
167 public void addImage(Image image, int id)
169 MediaEntry e = new MediaEntry();
180 * Adds an image to the tracker with the specified <code>ID</code>.
181 * The image is expected to be rendered with the specified width and
184 * @param image the image to be added
185 * @param id the ID of the tracker list to which the image is added
186 * @param width the width of the image
187 * @param height the height of the image
189 public void addImage(Image image, int id, int width, int height)
191 MediaEntry e = new MediaEntry();
204 * Checks if all media objects have finished loading, i.e. are
205 * {@link #COMPLETE}, {@link #ABORTED} or {@link #ERRORED}.
207 * If the media objects are not already loading, a call to this
208 * method does <em>not</em> start loading. This is equivalent to
209 * a call to <code>checkAll(false)</code>.
211 * @return if all media objects have finished loading either by beeing
212 * complete, have been aborted or errored.
214 public boolean checkAll()
216 return checkAll(false);
220 * Checks if all media objects have finished loading, i.e. are
221 * {@link #COMPLETE}, {@link #ABORTED} or {@link #ERRORED}.
223 * If the media objects are not already loading, and <code>load</code>
224 * is <code>true</code> then a call to this
225 * method starts loading the media objects.
227 * @param load if <code>true</code> this method starts loading objects
228 * that are not already loading
230 * @return if all media objects have finished loading either by beeing
231 * complete, have been aborted or errored.
233 public boolean checkAll(boolean load)
236 boolean result = true;
240 if ((e.status & (COMPLETE | ERRORED | ABORTED)) == 0)
242 if (load && ((e.status & LOADING) == 0))
244 if (target.prepareImage(e.image, e))
249 int flags = target.checkImage(e.image, e);
250 if ((flags & ImageObserver.ABORT) != 0)
252 else if ((flags & ImageObserver.ERROR) != 0)
254 else if ((flags & ImageObserver.ALLBITS) != 0)
257 boolean complete = (e.status
258 & (COMPLETE | ABORTED | ERRORED)) != 0;
271 * Checks if any of the registered media objects has encountered an error
274 * @return <code>true</code> if at least one media object has encountered
275 * an error during loading, <code>false</code> otherwise
278 public boolean isErrorAny()
283 if ((e.status & ERRORED) != 0)
291 * Returns all media objects that have encountered errors during loading.
293 * @return an array of all media objects that have encountered errors
294 * or <code>null</code> if there were no errors at all
296 public Object[] getErrorsAny()
299 ArrayList result = null;
302 if ((e.status & ERRORED) != 0)
305 result = new ArrayList();
313 return result.toArray();
317 * Waits for all media objects to finish loading, either by completing
318 * successfully or by aborting or encountering an error.
320 * @throws InterruptedException if another thread interrupted the
321 * current thread while waiting
323 public void waitForAll() throws InterruptedException
327 while (checkAll(true) == false)
333 * Waits for all media objects to finish loading, either by completing
334 * successfully or by aborting or encountering an error.
336 * This method waits at most <code>ms</code> milliseconds. If the
337 * media objects have not completed loading within this timeframe, this
338 * method returns <code>false</code>, otherwise <code>true</code>.
340 * @param ms timeframe in milliseconds to wait for the media objects to
343 * @return <code>true</code> if all media objects have successfully loaded
344 * within the timeframe, <code>false</code> otherwise
346 * @throws InterruptedException if another thread interrupted the
347 * current thread while waiting
349 public boolean waitForAll(long ms) throws InterruptedException
351 long start = System.currentTimeMillis();
352 boolean result = checkAll(true);
355 while (result == false)
358 result = checkAll(true);
359 if ((System.currentTimeMillis() - start) > ms)
368 * Returns the status flags of all registered media objects ORed together.
369 * If <code>load</code> is <code>true</code> then media objects that
370 * are not already loading will be started to load.
372 * @param load if set to <code>true</code> then media objects that are
373 * not already loading are started
375 * @return the status flags of all tracked media objects ORed together
377 public int statusAll(boolean load)
383 if (load && e.status == 0)
385 if (target.prepareImage(e.image, e))
390 int flags = target.checkImage(e.image, e);
391 if ((flags & ImageObserver.ABORT) != 0)
393 else if ((flags & ImageObserver.ERROR) != 0)
395 else if ((flags & ImageObserver.ALLBITS) != 0)
406 * Checks if the media objects with <code>ID</code> have completed loading.
408 * @param id the ID of the media objects to check
410 * @return <code>true</code> if all media objects with <code>ID</code>
411 * have successfully finished
413 public boolean checkID(int id)
415 return checkID(id, false);
419 * Checks if the media objects with <code>ID</code> have completed loading.
420 * If <code>load</code> is <code>true</code> then media objects that
421 * are not already loading will be started to load.
423 * @param id the ID of the media objects to check
424 * @param load if set to <code>true</code> then media objects that are
425 * not already loading are started
427 * @return <code>true</code> if all media objects with <code>ID</code>
428 * have successfully finished
430 public boolean checkID(int id, boolean load)
433 boolean result = true;
437 if (e.id == id && ((e.status & (COMPLETE | ABORTED | ERRORED)) == 0))
439 if (load && ((e.status & LOADING) == 0))
442 if (target.prepareImage(e.image, e))
446 int flags = target.checkImage(e.image, e);
447 if ((flags & ImageObserver.ABORT) != 0)
449 else if ((flags & ImageObserver.ERROR) != 0)
451 else if ((flags & ImageObserver.ALLBITS) != 0)
454 boolean complete = (e.status
455 & (COMPLETE | ABORTED | ERRORED)) != 0;
468 * Returns <code>true</code> if any of the media objects with <code>ID</code>
469 * have encountered errors during loading, false otherwise.
471 * @param id the ID of the media objects to check
473 * @return <code>true</code> if any of the media objects with <code>ID</code>
474 * have encountered errors during loading, false otherwise
476 public boolean isErrorID(int id)
481 if (e.id == id && ((e.status & ERRORED) != 0))
489 * Returns all media objects with the specified ID that have encountered
492 * @param id the ID of the media objects to check
494 * @return an array of all media objects with the specified ID that
495 * have encountered an error
497 public Object[] getErrorsID(int id)
500 ArrayList result = null;
503 if (e.id == id && ((e.status & ERRORED) != 0))
506 result = new ArrayList();
514 return result.toArray();
518 * Waits for all media objects with the specified ID to finish loading,
519 * either by completing successfully or by aborting or encountering an error.
521 * @param id the ID of the media objects to wait for
523 * @throws InterruptedException if another thread interrupted the
524 * current thread while waiting
526 public void waitForID(int id) throws InterruptedException
531 while (checkID (id, true) == false)
537 * Waits for all media objects with the specified ID to finish loading,
538 * either by completing successfully or by aborting or encountering an error.
540 * This method waits at most <code>ms</code> milliseconds. If the
541 * media objects have not completed loading within this timeframe, this
542 * method returns <code>false</code>, otherwise <code>true</code>.
544 * @param id the ID of the media objects to wait for
545 * @param ms timeframe in milliseconds to wait for the media objects to
548 * @return <code>true</code> if all media objects have successfully loaded
549 * within the timeframe, <code>false</code> otherwise
551 * @throws InterruptedException if another thread interrupted the
552 * current thread while waiting
554 public boolean waitForID(int id, long ms) throws InterruptedException
557 long start = System.currentTimeMillis();
558 boolean result = checkID(id, true);
562 while (result == false)
565 result = checkID(id, true);
566 if ((System.currentTimeMillis() - start) > ms)
575 * Returns the status flags of the media objects with the specified ID
578 * If <code>load</code> is <code>true</code> then media objects that
579 * are not already loading will be started to load.
581 * @param load if set to <code>true</code> then media objects that are
582 * not already loading are started
584 * @return the status flags of all tracked media objects ORed together
586 public int statusID(int id, boolean load)
594 if (load && e.status == 0)
596 if (target.prepareImage(e.image, e))
601 int flags = target.checkImage(e.image, e);
602 if ((flags & ImageObserver.ABORT) != 0)
604 else if ((flags & ImageObserver.ERROR) != 0)
606 else if ((flags & ImageObserver.ALLBITS) != 0)
618 * Removes an image from this MediaTracker.
620 * @param image the image to be removed
622 public void removeImage(Image image)
627 MediaEntry prev = null;
630 if (e.image == image)
644 * Removes an image with the specified ID from this MediaTracker.
646 * @param image the image to be removed
648 public void removeImage(Image image, int id)
653 MediaEntry prev = null;
656 if (e.id == id && e.image == image)
671 * Removes an image with the specified ID and scale from this MediaTracker.
673 * @param image the image to be removed
675 public void removeImage(Image image, int id, int width, int height)
680 MediaEntry prev = null;
683 if (e.id == id && e.image == image
684 && e.width == width && e.height == height)