001    /* ========================================================================
002     * JCommon : a free general purpose class library for the Java(tm) platform
003     * ========================================================================
004     *
005     * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
006     * 
007     * Project Info:  http://www.jfree.org/jcommon/index.html
008     *
009     * This library is free software; you can redistribute it and/or modify it 
010     * under the terms of the GNU Lesser General Public License as published by 
011     * the Free Software Foundation; either version 2.1 of the License, or 
012     * (at your option) any later version.
013     *
014     * This library is distributed in the hope that it will be useful, but 
015     * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
016     * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
017     * License for more details.
018     *
019     * You should have received a copy of the GNU Lesser General Public
020     * License along with this library; if not, write to the Free Software
021     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
022     * USA.  
023     *
024     * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
025     * in the United States and other countries.]
026     * 
027     * -------------------------
028     * WaitingImageObserver.java
029     * -------------------------
030     * (C)opyright 2000-2004, by Thomas Morgner and Contributors.
031     *
032     * Original Author:  Thomas Morgner
033     * Contributor(s):   Stefan Prange;
034     *
035     * $Id: WaitingImageObserver.java,v 1.3 2005/10/18 13:24:19 mungady Exp $
036     *
037     * Changes (from 8-Feb-2002)
038     * -------------------------
039     * 15-Apr-2002 : first version used by ImageElement.
040     * 16-May-2002 : Line delimiters adjusted
041     * 04-Jun-2002 : Documentation and added a NullPointerCheck for the constructor.
042     * 14-Jul-2002 : BugFixed: WaitingImageObserver dead-locked (bugfix by Stefan 
043     *               Prange)
044     * 18-Mar-2003 : Updated header and made minor Javadoc changes (DG);
045     * 21-Sep-2003 : Moved from JFreeReport.
046     */
047    
048    package org.jfree.util;
049    
050    import java.awt.Graphics;
051    import java.awt.Image;
052    import java.awt.image.BufferedImage;
053    import java.awt.image.ImageObserver;
054    import java.io.Serializable;
055    
056    /**
057     * This image observer blocks until the image is completely loaded. AWT
058     * defers the loading of images until they are painted on a graphic.
059     *
060     * While printing reports it is not very nice, not to know whether a image
061     * was completely loaded, so this observer forces the loading of the image
062     * until a final state (either ALLBITS, ABORT or ERROR) is reached.
063     *
064     * @author Thomas Morgner
065     */
066    public class WaitingImageObserver implements ImageObserver, Serializable, 
067                                                 Cloneable
068    {
069      /** For serialization. */
070      static final long serialVersionUID = -807204410581383550L;
071        
072      /** The lock. */
073      private boolean lock;
074    
075      /** The image. */
076      private Image image;
077    
078      /** A flag that signals an error. */
079      private boolean error;
080    
081      /**
082       * Creates a new <code>ImageObserver<code> for the given <code>Image<code>. 
083       * The observer has to be started by an external thread.
084       *
085       * @param image  the image to observe (<code>null</code> not permitted).
086       */
087      public WaitingImageObserver(final Image image) {
088        if (image == null) {
089          throw new NullPointerException();
090        }
091        this.image = image;
092        this.lock = true;
093      }
094    
095      /**
096       * Callback function used by AWT to inform that more data is available. The 
097       * observer waits until either all data is loaded or AWT signals that the 
098       * image cannot be loaded.
099       *
100       * @param     img   the image being observed.
101       * @param     infoflags   the bitwise inclusive OR of the following
102       *               flags:  <code>WIDTH</code>, <code>HEIGHT</code>,
103       *               <code>PROPERTIES</code>, <code>SOMEBITS</code>,
104       *               <code>FRAMEBITS</code>, <code>ALLBITS</code>,
105       *               <code>ERROR</code>, <code>ABORT</code>.
106       * @param     x   the <i>x</i> coordinate.
107       * @param     y   the <i>y</i> coordinate.
108       * @param     width    the width.
109       * @param     height   the height.
110       *
111       * @return    <code>false</code> if the infoflags indicate that the
112       *            image is completely loaded; <code>true</code> otherwise.
113       */
114      public boolean imageUpdate(
115          final Image img,
116          final int infoflags,
117          final int x,
118          final int y,
119          final int width,
120          final int height) {
121        if ((infoflags & ImageObserver.ALLBITS) == ImageObserver.ALLBITS) {
122            this.lock = false;
123            this.error = false;
124        }
125        else if ((infoflags & ImageObserver.ABORT) == ImageObserver.ABORT
126            || (infoflags & ImageObserver.ERROR) == ImageObserver.ERROR) {
127            this.lock = false;
128            this.error = true;
129        }
130        return true;
131      }
132    
133      /**
134       * The workerthread. Simply draws the image to a BufferedImage's 
135       * Graphics-Object and waits for the AWT to load the image.
136       */
137      public void waitImageLoaded() {
138        final BufferedImage img = new BufferedImage(
139            1, 1, BufferedImage.TYPE_INT_RGB
140        );
141        final Graphics g = img.getGraphics();
142    
143        while (this.lock) {
144          if (g.drawImage(this.image, 0, 0, img.getWidth(this), 
145                img.getHeight(this), this)) {
146            return;
147          }
148          try {
149            Thread.sleep(200);
150          }
151          catch (InterruptedException e) {
152            Log.info(
153              "WaitingImageObserver.waitImageLoaded(): InterruptedException thrown", 
154              e
155            );
156          }
157        }
158      }
159    
160      /**
161       * Clones this WaitingImageObserver.
162       *
163       * @return a clone.
164       *
165       * @throws CloneNotSupportedException this should never happen.
166       */
167      public Object clone() throws CloneNotSupportedException {
168        final WaitingImageObserver obs = (WaitingImageObserver) super.clone();
169        return obs;
170      }
171    
172      /**
173       * Returns true if there is an error condition, and false otherwise.
174       *
175       * @return A boolean.
176       */
177      public boolean isError() {
178        return this.error;
179      }
180    }