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.4 2005/12/18 23:30:36 taqua 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 synchronized 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        notifyAll();
131        return true;
132      }
133    
134      /**
135       * The workerthread. Simply draws the image to a BufferedImage's 
136       * Graphics-Object and waits for the AWT to load the image.
137       */
138      public synchronized void waitImageLoaded() {
139    
140        if (this.lock == false)
141        {
142          return;
143        }
144    
145        final BufferedImage img = new BufferedImage(
146            1, 1, BufferedImage.TYPE_INT_RGB
147        );
148        final Graphics g = img.getGraphics();
149    
150        while (this.lock) {
151          if (g.drawImage(this.image, 0, 0, img.getWidth(this), 
152                img.getHeight(this), this)) {
153            return;
154          }
155          try {
156            wait();
157          }
158          catch (InterruptedException e) {
159            Log.info(
160              "WaitingImageObserver.waitImageLoaded(): InterruptedException thrown", 
161              e
162            );
163          }
164        }
165      }
166    
167      /**
168       * Clones this WaitingImageObserver.
169       *
170       * @return a clone.
171       *
172       * @throws CloneNotSupportedException this should never happen.
173       * @deprecated cloning may lock down the observer
174       */
175      public Object clone() throws CloneNotSupportedException {
176        return (WaitingImageObserver) super.clone();
177      }
178    
179      public boolean isLoadingComplete() {
180        return this.lock == false;
181      }
182    
183      /**
184       * Returns true if there is an error condition, and false otherwise.
185       *
186       * @return A boolean.
187       */
188      public boolean isError() {
189        return this.error;
190      }
191    }