1 /* 2 * $RCSfile: CollectionImage.java,v $ 3 * 4 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. 5 * 6 * Use is subject to license terms. 7 * 8 * $Revision: 1.1 $ 9 * $Date: 2005/02/11 04:57:05 $ 10 * $State: Exp $ 11 */ 12 package com.lightcrafts.mediax.jai; 13 import java.awt.Image; 14 import java.beans.PropertyChangeListener; 15 import java.lang.ref.WeakReference; 16 import java.util.Collection; 17 import java.util.HashSet; 18 import java.util.Iterator; 19 import java.util.List; 20 import java.util.Set; 21 22 import com.lightcrafts.media.jai.util.PropertyUtil; 23 24 /** 25 * An abstract superclass for classes representing a <code>Collection</code> 26 * of images. It may be a <code>Collection</code> of 27 * <code>RenderedImage</code>s or <code>RenderableImage</code>s, a 28 * <code>Collection</code> of <code>Collection</code>s that include images. 29 * In other words, this class supports nested <code>Collection</code>s, but 30 * at the very bottom, there must be images associated with the 31 * <code>Collection</code> objects. 32 * 33 * 34 */ 35 public abstract class CollectionImage implements ImageJAI, Collection { 36 37 /** 38 * A <code>Collection</code> of objects. It may be a 39 * <code>Collection</code> of images of the same type, a 40 * <code>Collection</code> of objects of the same type, each 41 * containing an image, or a <code>Collection</code> of 42 * <code>Collection</code>s whose leaf objects are images 43 * or objects that contain images. 44 */ 45 protected Collection imageCollection; 46 47 /** 48 * The <code>CollectionImageFactory</code> which created this 49 * <code>CollectionImage</code>; may be <code>null</code> which 50 * implies that the <code>CollectionImage</code> was not created 51 * by a <code>CollectionImageFactory</code>. 52 * 53 * @since JAI 1.1 54 */ 55 protected CollectionImageFactory imageFactory; 56 private Boolean isFactorySet = Boolean.FALSE; 57 58 /** 59 * A helper object to manage firing events. 60 * 61 * @since JAI 1.1 62 */ 63 protected PropertyChangeSupportJAI eventManager = null; 64 65 /** 66 * A helper object to manage the image properties. 67 * 68 * @since JAI 1.1 69 */ 70 protected WritablePropertySourceImpl properties = null; 71 72 /** 73 * A <code>Set</code> of <code>WeakReference</code>s to the 74 * sinks of this <code>CollectionImage</code>. 75 * 76 * @since JAI 1.1 77 */ 78 protected Set sinks; 79 80 /** 81 * Default constructor. The <code>imageCollection</code> parameter is 82 * <code>null</code>. Subclasses that use this constructor must either 83 * set the <code>imageCollection</code> parameter themselves, or override 84 * the methods defined in the <code>Collection</code> interface. 85 * Otherwise, a <code>NullPointerException</code> may be thrown at a later 86 * time when methods which use to the <code>imageCollection</code> 87 * instance variable are invoked. 88 */ CollectionImage()89 protected CollectionImage() { 90 eventManager = new PropertyChangeSupportJAI(this); 91 properties = new WritablePropertySourceImpl(null, null, eventManager); 92 } 93 94 /** 95 * Constructs a class that contains an image <code>Collection</code>. 96 * 97 * @param collection A <code>Collection</code> of objects that 98 * include images. 99 * 100 * @throws IllegalArgumentException if <code>collection</code> is 101 * <code>null</code>. 102 */ CollectionImage(Collection collection)103 public CollectionImage(Collection collection) { 104 this(); 105 106 107 if ( collection == null ) { 108 throw new IllegalArgumentException(JaiI18N.getString("Generic0")); 109 } 110 111 imageCollection = collection; 112 } 113 114 /* ----- Element retrieval method. ----- */ 115 116 /** 117 * Returns the element at the given index in <code>imageCollection</code>. 118 * If <code>imageCollection</code> is a <code>List</code> then the call is 119 * forwarded to <code>imageCollection</code>; otherwise an array is created 120 * by applying <code>toArray()</code> to <code>imageCollection</code> and 121 * the indicated element of that array is returned. Note that in the 122 * latter case no guarantee as to element ordering beyond that stated in 123 * the specification of <code>Collection.toArray()</code>. 124 * 125 * @param index The index of the desired element. 126 * @throws IndexOutOfBoundsException if the index is out of range 127 * (<code>index</code> < 0 || <code>index</code> ≥ 128 * <code>imageCollection.size()</code>). 129 * 130 * @since JAI 1.1 131 */ get(int index)132 public Object get(int index) { 133 if(index < 0 || index >= imageCollection.size()) { 134 throw new IndexOutOfBoundsException(); // No message needed. 135 } 136 137 if(imageCollection instanceof List) { 138 return ((List)imageCollection).get(index); 139 } else { 140 return imageCollection.toArray((Object[])null)[index]; 141 } 142 } 143 144 /* ----- Image factory methods. ----- */ 145 146 /** 147 * Sets the <code>imageFactory</code> instance variable to the supplied 148 * value. The parameter may be <code>null</code>. It is recommended 149 * that this method be invoked as soon as the <code>CollectionImage</code> 150 * is constructed. 151 * 152 * @param imageFactory The creating <code>CollectionImageFactory</code> or 153 * <code>null</code> 154 * @throws IllegalStateException if the corresponding instance variable 155 * was already set. 156 * 157 * @since JAI 1.1 158 */ setImageFactory(CollectionImageFactory imageFactory)159 public void setImageFactory(CollectionImageFactory imageFactory) { 160 synchronized(isFactorySet) { 161 if(isFactorySet.booleanValue()) { 162 throw new IllegalStateException(); 163 } 164 this.imageFactory = imageFactory; 165 isFactorySet = Boolean.TRUE; 166 } 167 } 168 169 /** 170 * If this <code>CollectionImage</code> was created by a 171 * <code>CollectionImageFactory</code> then return a reference to 172 * that factory; otherwise return <code>null</code>. 173 * 174 * @since JAI 1.1 175 */ getImageFactory()176 public CollectionImageFactory getImageFactory() { 177 synchronized(isFactorySet) { 178 return imageFactory; 179 } 180 } 181 182 /* ----- Sink methods. ----- */ 183 184 /** 185 * Adds a sink to the set of sinks. 186 * 187 * @since JAI 1.1 188 */ addSink(Object sink)189 public synchronized boolean addSink(Object sink) { 190 if(sink == null) { 191 throw new IllegalArgumentException(JaiI18N.getString("Generic0")); 192 } 193 194 if(sinks == null) { 195 sinks = new HashSet(); 196 } 197 198 return sinks.add(new WeakReference(sink)); 199 } 200 201 /** 202 * Removes a sink from the set of sinks. 203 * 204 * @return <code>true</code> if and only if the set of sinks 205 * changed as a result of the call. 206 * 207 * @since JAI 1.1 208 */ removeSink(Object sink)209 public synchronized boolean removeSink(Object sink) { 210 if (sink == null) { 211 throw new IllegalArgumentException(JaiI18N.getString("Generic0")); 212 } 213 214 if (sinks == null) { 215 return false; 216 } 217 218 boolean result = false; 219 Iterator it = sinks.iterator(); 220 while(it.hasNext()) { 221 Object referent = ((WeakReference)it.next()).get(); 222 if(referent == sink) { 223 // Remove the sink. 224 it.remove(); 225 result = true; 226 // Do not break: could be more than one. 227 } else if(referent == null) { 228 // A cleared reference: might as well remove it. 229 it.remove(); // ignore return value here. 230 } 231 } 232 233 return result; 234 235 } 236 237 /** 238 * Retrieves the set of sinks or <code>null</code> if 239 * there are none. 240 * 241 * @since JAI 1.1 242 */ getSinks()243 public synchronized Set getSinks() { 244 Set v = null; 245 246 if (sinks != null && sinks.size() > 0) { 247 v = new HashSet(sinks.size()); 248 249 Iterator it = sinks.iterator(); 250 while(it.hasNext()) { 251 Object o = ((WeakReference)it.next()).get(); 252 253 if (o != null) { 254 v.add(o); 255 } 256 } 257 258 if (v.size() == 0) { 259 v = null; 260 } 261 } 262 263 return v; 264 } 265 266 /** 267 * Removes all sinks from the set of sinks. 268 * 269 * @since JAI 1.1 270 */ removeSinks()271 public synchronized void removeSinks() { 272 sinks = null; 273 } 274 275 /* ----- WritablePropertySource methods. ----- */ 276 277 /** 278 * Returns an array of <code>String</code>s recognized as names by this 279 * property source. If no property names match, <code>null</code> 280 * will be returned. 281 * 282 * @return An array of <code>String</code>s which are the valid 283 * property names or <code>null</code> if there are none. 284 */ getPropertyNames()285 public String[] getPropertyNames() { 286 return properties.getPropertyNames(); 287 } 288 289 /** 290 * Returns an array of <code>String</code>s recognized as names by 291 * this property source that begin with the supplied prefix. If 292 * no property names are recognized, or no property names match, 293 * <code>null</code> will be returned. 294 * The comparison is done in a case-independent manner. 295 * 296 * <p> The default implementation calls 297 * <code>getPropertyNames()</code> and searches the list of names 298 * for matches. 299 * 300 * @return An array of <code>String</code>s giving the valid 301 * property names or <code>null</code> if there are none. 302 * 303 * @throws <code>IllegalArgumentException</code> if <code>prefix</code> 304 * is <code>null</code>. 305 */ getPropertyNames(String prefix)306 public String[] getPropertyNames(String prefix) { 307 return PropertyUtil.getPropertyNames(getPropertyNames(), prefix); 308 } 309 310 /** 311 * Returns the class expected to be returned by a request for 312 * the property with the specified name. If this information 313 * is unavailable, <code>null</code> will be returned. 314 * 315 * @return The <code>Class</code> expected to be return by a 316 * request for the value of this property or <code>null</code>. 317 * 318 * @exception IllegalArgumentException if <code>name</code> 319 * is <code>null</code>. 320 * 321 * @since JAI 1.1 322 */ getPropertyClass(String name)323 public Class getPropertyClass(String name) { 324 return properties.getPropertyClass(name); 325 } 326 327 /** 328 * Returns the specified property. The default implementation 329 * returns <code>java.awt.Image.UndefinedProperty</code>. 330 * 331 * @exception IllegalArgumentException if <code>name</code> 332 * is <code>null</code>. 333 */ getProperty(String name)334 public Object getProperty(String name) { 335 return properties.getProperty(name); 336 } 337 338 /** 339 * Returns the specified property. The default implementation 340 * returns <code>java.awt.Image.UndefinedProperty</code>. 341 * 342 * @exception IllegalArgumentException if <code>name</code> 343 * is <code>null</code>. 344 * @deprecated as of JAI 1.1. 345 */ getProperty(String name, Collection collection)346 public Object getProperty(String name, Collection collection) { 347 return Image.UndefinedProperty; 348 } 349 350 /** 351 * Sets a property on a <code>CollectionImage</code>. Some 352 * <code>CollectionImage</code> subclasses may ignore attempts to set 353 * properties. 354 * 355 * @param name a <code>String</code> containing the property's name. 356 * @param value the property, as a general <code>Object</code>. 357 * 358 * @throws IllegalArgumentException If <code>name</code> or 359 * <code>value</code> is <code>null</code>. 360 * 361 * @since JAI 1.1 362 */ setProperty(String name, Object value)363 public void setProperty(String name, Object value) { 364 properties.setProperty(name, value); 365 } 366 367 /** 368 * Removes the named property from the <code>CollectionImage</code>. 369 * Some <code>CollectionImage</code> subclasses may ignore attempts to 370 * remove properties. 371 * 372 * @since JAI 1.1 373 */ removeProperty(String name)374 public void removeProperty(String name) { 375 properties.removeProperty(name); 376 } 377 378 /* ----- PropertyChangeEmitter methods. ----- */ 379 380 /** 381 * Add a PropertyChangeListener to the listener list. The 382 * listener is registered for all properties. 383 * 384 * @since JAI 1.1 385 */ addPropertyChangeListener(PropertyChangeListener listener)386 public void addPropertyChangeListener(PropertyChangeListener listener) { 387 eventManager.addPropertyChangeListener(listener); 388 } 389 390 /** 391 * Add a PropertyChangeListener for a specific property. The 392 * listener will be invoked only when a call on 393 * firePropertyChange names that specific property. The case of 394 * the name is ignored. 395 * 396 * @since JAI 1.1 397 */ addPropertyChangeListener(String propertyName, PropertyChangeListener listener)398 public void addPropertyChangeListener(String propertyName, 399 PropertyChangeListener listener) { 400 eventManager.addPropertyChangeListener(propertyName, listener); 401 } 402 403 /** 404 * Remove a PropertyChangeListener from the listener list. This 405 * removes a PropertyChangeListener that was registered for all 406 * properties. 407 * 408 * @since JAI 1.1 409 */ removePropertyChangeListener(PropertyChangeListener listener)410 public void removePropertyChangeListener(PropertyChangeListener listener) { 411 eventManager.removePropertyChangeListener(listener); 412 } 413 414 /** 415 * Remove a PropertyChangeListener for a specific property. The case 416 * of the name is ignored. 417 * 418 * @since JAI 1.1 419 */ removePropertyChangeListener(String propertyName, PropertyChangeListener listener)420 public void removePropertyChangeListener(String propertyName, 421 PropertyChangeListener listener) { 422 eventManager.removePropertyChangeListener(propertyName, listener); 423 } 424 425 /* ----- Collection methods. ----- */ 426 427 /** Returns the number of elements in this <code>Collection</code>. */ size()428 public int size() { 429 return imageCollection.size(); 430 } 431 432 /** 433 * Returns <code>true</code> if this <code>Collection</code> 434 * contains no elements. 435 */ isEmpty()436 public boolean isEmpty() { 437 return imageCollection.isEmpty(); 438 } 439 440 /** 441 * Returns <code>true</code> if this <code>Collection</code> 442 * contains the specified object. 443 */ contains(Object o)444 public boolean contains(Object o) { 445 return imageCollection.contains(o); 446 } 447 448 /** 449 * Returns an <code>Iterator</code> over the elements in this 450 * <code>Collection</code>. 451 */ iterator()452 public Iterator iterator() { 453 return imageCollection.iterator(); 454 } 455 456 /** 457 * Returns an array containing all of the elements in this 458 * <code>Collection</code>. 459 */ toArray()460 public Object[] toArray() { 461 return imageCollection.toArray(); 462 } 463 464 /** 465 * Returns an array containing all of the elements in this collection 466 * whose runtime type is that of the specified array. 467 * 468 * @throws ArrayStoreException if the runtime type of the specified array 469 * is not a supertype of the runtime type of every element in this 470 * <code>Collection</code>. 471 */ toArray(Object[] a)472 public Object[] toArray(Object[] a) { 473 return imageCollection.toArray(a); 474 } 475 476 /** 477 * Adds the specified object to this <code>Collection</code>. 478 * 479 * @return <code>true</code> if and only if the parameter is added to the 480 * <code>Collection</code>. 481 */ add(Object o)482 public boolean add(Object o) { 483 return imageCollection.add(o); 484 } 485 486 /** 487 * Removes the specified object from this <code>Collection</code>. 488 * 489 * @return <code>true</code> if and only if the parameter is removed 490 * from the <code>Collection</code>. 491 */ remove(Object o)492 public boolean remove(Object o) { 493 return imageCollection.remove(o); 494 } 495 496 /** 497 * Returns <code>true</code> if this <code>Collection</code> contains 498 * all of the elements in the specified <code>Collection</code>. 499 */ containsAll(Collection c)500 public boolean containsAll(Collection c) { 501 return imageCollection.containsAll(c); 502 } 503 504 /** 505 * Adds all of the elements in the specified <code>Collection</code> 506 * to this <code>Collection</code>. 507 * 508 * @return <code>true</code> if this <code>Collection</code> changed 509 * as a result of the call. 510 */ addAll(Collection c)511 public boolean addAll(Collection c) { 512 return imageCollection.addAll(c); 513 } 514 515 /** 516 * Removes all this collection's elements that are also contained in the 517 * specified <code>Collection</code>. 518 * 519 * @return <code>true</code> if this <code>Collection</code> changed 520 * as a result of the call. 521 */ removeAll(Collection c)522 public boolean removeAll(Collection c) { 523 return imageCollection.removeAll(c); 524 } 525 526 /** 527 * Retains only the elements in this <code>Collection</code> that are 528 * contained in the specified <code>Collection</code>. 529 * 530 * @return <code>true</code> if this <code>Collection</code> changed 531 * as a result of the call. 532 */ retainAll(Collection c)533 public boolean retainAll(Collection c) { 534 return imageCollection.retainAll(c); 535 } 536 537 /** Removes all of the elements from this <code>Collection</code>. */ clear()538 public void clear() { 539 imageCollection.clear(); 540 } 541 } 542