Source for gnu.java.awt.peer.gtk.AsyncImage

   1: /* AsyncImage.java -- Loads images asynchronously
   2:    Copyright (C) 2006 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   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)
   9: any later version.
  10: 
  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.
  15: 
  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
  19: 02110-1301 USA.
  20: 
  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
  24: combination.
  25: 
  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. */
  37: 
  38: 
  39: package gnu.java.awt.peer.gtk;
  40: 
  41: import java.awt.Graphics;
  42: import java.awt.Image;
  43: import java.awt.image.ImageConsumer;
  44: import java.awt.image.ImageObserver;
  45: import java.awt.image.ImageProducer;
  46: import java.net.URL;
  47: import java.util.ArrayList;
  48: import java.util.HashSet;
  49: import java.util.Iterator;
  50: 
  51: /**
  52:  * Supports asynchronous loading of images.
  53:  */
  54: public class AsyncImage
  55:   extends Image
  56: {
  57: 
  58:   /**
  59:    * Returned as source as long as the image is not complete.
  60:    */
  61:   private class NullImageSource
  62:     implements ImageProducer
  63:   {
  64:     private ArrayList<ImageConsumer> consumers;
  65: 
  66:     NullImageSource()
  67:     {
  68:       consumers = new ArrayList<ImageConsumer>();
  69:     }
  70: 
  71:     public void addConsumer(ImageConsumer ic)
  72:     {
  73:       consumers.add(ic);
  74:     }
  75: 
  76:     public boolean isConsumer(ImageConsumer ic)
  77:     {
  78:       return consumers.contains(ic);
  79:     }
  80: 
  81:     public void removeConsumer(ImageConsumer ic)
  82:     {
  83:       consumers.remove(ic);
  84:     }
  85: 
  86:     public void requestTopDownLeftRightResend(ImageConsumer ic)
  87:     {
  88:       startProduction(ic);
  89:     }
  90: 
  91:     public void startProduction(ImageConsumer ic)
  92:     {
  93:       consumers.add(ic);
  94:       for (int i = consumers.size() - 1; i >= 0; i--)
  95:         {
  96:           ImageConsumer c = (ImageConsumer) consumers.get(i);
  97:           c.setDimensions(1, 1);
  98:           ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE);
  99:         }
 100:     }
 101: 
 102:   }
 103: 
 104:   /**
 105:    * Loads the image asynchronously.
 106:    */
 107:   private class Loader
 108:     implements Runnable
 109:   {
 110:     private URL url;
 111:     Loader(URL u)
 112:     {
 113:       url = u;
 114:     }
 115: 
 116:     public void run()
 117:     {
 118:       Image image;
 119:       try
 120:         {
 121:           GtkImage gtkImage = new GtkImage(url);
 122:           image = CairoSurface.getBufferedImage(gtkImage);
 123:         }
 124:       catch (IllegalArgumentException iae)
 125:         {
 126:           image = null;
 127:         }
 128:       realImage = GtkToolkit.imageOrError(image);
 129:       synchronized (AsyncImage.this)
 130:         {
 131:           notifyObservers(ImageObserver.ALLBITS | ImageObserver.HEIGHT
 132:                           | ImageObserver.WIDTH | ImageObserver.PROPERTIES);
 133:           observers = null; // Not needed anymore.
 134:         }
 135:     }
 136:   }
 137: 
 138:   /**
 139:    * The real image. This is null as long as the image is not complete.
 140:    */
 141:   Image realImage;
 142: 
 143:   /**
 144:    * The image observers.
 145:    *
 146:    * This is package private to avoid accessor methods.
 147:    */
 148:   HashSet<ImageObserver> observers;
 149: 
 150:   /**
 151:    * Creates a new AsyncImage that loads from the specified URL.
 152:    */
 153:   AsyncImage(URL url)
 154:   {
 155:     observers = new HashSet<ImageObserver>();
 156:     Loader l = new Loader(url);
 157:     Thread t = new Thread(l);
 158:     t.start();
 159:   }
 160: 
 161:   public void flush()
 162:   {
 163:     // Nothing to do here.
 164:   }
 165: 
 166:   public Graphics getGraphics()
 167:   {
 168:     Image r = realImage;
 169:     Graphics g = null;
 170:     if (r != null)
 171:       g = r.getGraphics(); // Should we return some dummy graphics instead?
 172:     return g;
 173:   }
 174: 
 175:   public int getHeight(ImageObserver observer)
 176:   {
 177:     addObserver(observer);
 178:     int height = 0;
 179:     Image r = realImage;
 180:     if (r != null)
 181:       height = r.getHeight(observer);
 182:     return height;
 183:   }
 184: 
 185:   public Object getProperty(String name, ImageObserver observer)
 186:   {
 187:     addObserver(observer);
 188:     Image r = realImage;
 189:     Object prop = null;
 190:     if (r != null)
 191:       prop = r.getProperty(name, observer);
 192:     return prop;
 193:   }
 194: 
 195:   public ImageProducer getSource()
 196:   {
 197:     Image r = realImage;
 198:     ImageProducer source;
 199:     if (r == null)
 200:       source = new NullImageSource();
 201:     else
 202:       source = r.getSource();
 203:     return source;
 204:   }
 205: 
 206:   public int getWidth(ImageObserver observer)
 207:   {
 208:     addObserver(observer);
 209:     int width = 0;
 210:     Image r = realImage;
 211:     if (r != null)
 212:       width = r.getWidth(observer);
 213:     return width;
 214:   }
 215: 
 216:   void addObserver(ImageObserver obs)
 217:   {
 218:     if (obs != null)
 219:       {
 220:         synchronized (this)
 221:           {
 222:             // This field gets null when image loading is complete and we don't
 223:             // need to store any more observers.
 224:             HashSet<ImageObserver> observs = observers;
 225:             if (observs != null)
 226:               {
 227:                 observs.add(obs);
 228:               }
 229:             else
 230:               {
 231:                 // When the image is complete, notify the observer. Dunno if
 232:                 // that's really needed, but to be sure.
 233:                 obs.imageUpdate(this, ImageObserver.WIDTH
 234:                                 | ImageObserver.HEIGHT
 235:                                 |ImageObserver.ALLBITS
 236:                                 | ImageObserver.PROPERTIES, 0, 0,
 237:                                 realImage.getWidth(null),
 238:                                 realImage.getHeight(null));
 239:               }
 240:           }
 241:       }
 242:   }
 243: 
 244:   static Image realImage(Image img, ImageObserver obs)
 245:   {
 246:     if (img instanceof AsyncImage)
 247:       {
 248:         ((AsyncImage) img).addObserver(obs);
 249:         Image r = ((AsyncImage) img).realImage;
 250:         if (r != null)
 251:           img = r;
 252:       }
 253:     return img;
 254:   }
 255: 
 256:   void notifyObservers(int status)
 257:   {
 258:     assert Thread.holdsLock(this);
 259:     // This field gets null when image loading is complete.
 260:     HashSet observs = observers;
 261:     if (observs != null)
 262:       {
 263:         Image r = realImage;
 264:         Iterator i = observs.iterator();
 265:         while (i.hasNext())
 266:           {
 267:             ImageObserver obs = (ImageObserver) i.next();
 268:             obs.imageUpdate(this, status, 0, 0, r.getWidth(null),
 269:                             r.getHeight(null));
 270:           }
 271:       }
 272:   }
 273: 
 274:   int checkImage(ImageObserver obs)
 275:   {
 276:     addObserver(obs);
 277:     int flags = 0;
 278:     if (realImage != null)
 279:       flags = ImageObserver.ALLBITS | ImageObserver.WIDTH
 280:               | ImageObserver.HEIGHT | ImageObserver.PROPERTIES;
 281:     return flags;
 282:   }
 283: }