001: /*
002: * $RCSfile: CollectionImage.java,v $
003: *
004: * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Use is subject to license terms.
007: *
008: * $Revision: 1.1 $
009: * $Date: 2005/02/11 04:57:05 $
010: * $State: Exp $
011: */
012: package javax.media.jai;
013:
014: import java.awt.Image;
015: import java.beans.PropertyChangeListener;
016: import java.lang.ref.WeakReference;
017: import java.util.Collection;
018: import java.util.HashSet;
019: import java.util.Iterator;
020: import java.util.List;
021: import java.util.Set;
022: import java.util.Vector;
023: import com.sun.media.jai.util.PropertyUtil;
024:
025: /**
026: * An abstract superclass for classes representing a <code>Collection</code>
027: * of images. It may be a <code>Collection</code> of
028: * <code>RenderedImage</code>s or <code>RenderableImage</code>s, a
029: * <code>Collection</code> of <code>Collection</code>s that include images.
030: * In other words, this class supports nested <code>Collection</code>s, but
031: * at the very bottom, there must be images associated with the
032: * <code>Collection</code> objects.
033: *
034: *
035: */
036: public abstract class CollectionImage implements ImageJAI, Collection {
037:
038: /**
039: * A <code>Collection</code> of objects. It may be a
040: * <code>Collection</code> of images of the same type, a
041: * <code>Collection</code> of objects of the same type, each
042: * containing an image, or a <code>Collection</code> of
043: * <code>Collection</code>s whose leaf objects are images
044: * or objects that contain images.
045: */
046: protected Collection imageCollection;
047:
048: /**
049: * The <code>CollectionImageFactory</code> which created this
050: * <code>CollectionImage</code>; may be <code>null</code> which
051: * implies that the <code>CollectionImage</code> was not created
052: * by a <code>CollectionImageFactory</code>.
053: *
054: * @since JAI 1.1
055: */
056: protected CollectionImageFactory imageFactory;
057: private Boolean isFactorySet = Boolean.FALSE;
058:
059: /**
060: * A helper object to manage firing events.
061: *
062: * @since JAI 1.1
063: */
064: protected PropertyChangeSupportJAI eventManager = null;
065:
066: /**
067: * A helper object to manage the image properties.
068: *
069: * @since JAI 1.1
070: */
071: protected WritablePropertySourceImpl properties = null;
072:
073: /**
074: * A <code>Set</code> of <code>WeakReference</code>s to the
075: * sinks of this <code>CollectionImage</code>.
076: *
077: * @since JAI 1.1
078: */
079: protected Set sinks;
080:
081: /**
082: * Default constructor. The <code>imageCollection</code> parameter is
083: * <code>null</code>. Subclasses that use this constructor must either
084: * set the <code>imageCollection</code> parameter themselves, or override
085: * the methods defined in the <code>Collection</code> interface.
086: * Otherwise, a <code>NullPointerException</code> may be thrown at a later
087: * time when methods which use to the <code>imageCollection</code>
088: * instance variable are invoked.
089: */
090: protected CollectionImage() {
091: eventManager = new PropertyChangeSupportJAI(this );
092: properties = new WritablePropertySourceImpl(null, null,
093: eventManager);
094: }
095:
096: /**
097: * Constructs a class that contains an image <code>Collection</code>.
098: *
099: * @param collection A <code>Collection</code> of objects that
100: * include images.
101: *
102: * @throws IllegalArgumentException if <code>collection</code> is
103: * <code>null</code>.
104: */
105: public CollectionImage(Collection collection) {
106: this ();
107:
108: if (collection == null) {
109: throw new IllegalArgumentException(JaiI18N
110: .getString("Generic0"));
111: }
112:
113: imageCollection = collection;
114: }
115:
116: /* ----- Element retrieval method. ----- */
117:
118: /**
119: * Returns the element at the given index in <code>imageCollection</code>.
120: * If <code>imageCollection</code> is a <code>List</code> then the call is
121: * forwarded to <code>imageCollection</code>; otherwise an array is created
122: * by applying <code>toArray()</code> to <code>imageCollection</code> and
123: * the indicated element of that array is returned. Note that in the
124: * latter case no guarantee as to element ordering beyond that stated in
125: * the specification of <code>Collection.toArray()</code>.
126: *
127: * @param index The index of the desired element.
128: * @throws IndexOutOfBoundsException if the index is out of range
129: * (<code>index</code> < 0 || <code>index</code> ≥
130: * <code>imageCollection.size()</code>).
131: *
132: * @since JAI 1.1
133: */
134: public Object get(int index) {
135: if (index < 0 || index >= imageCollection.size()) {
136: throw new IndexOutOfBoundsException(); // No message needed.
137: }
138:
139: if (imageCollection instanceof List) {
140: return ((List) imageCollection).get(index);
141: } else {
142: return imageCollection.toArray((Object[]) null)[index];
143: }
144: }
145:
146: /* ----- Image factory methods. ----- */
147:
148: /**
149: * Sets the <code>imageFactory</code> instance variable to the supplied
150: * value. The parameter may be <code>null</code>. It is recommended
151: * that this method be invoked as soon as the <code>CollectionImage</code>
152: * is constructed.
153: *
154: * @param imageFactory The creating <code>CollectionImageFactory</code> or
155: * <code>null</code>
156: * @throws IllegalStateException if the corresponding instance variable
157: * was already set.
158: *
159: * @since JAI 1.1
160: */
161: public void setImageFactory(CollectionImageFactory imageFactory) {
162: synchronized (isFactorySet) {
163: if (isFactorySet.booleanValue()) {
164: throw new IllegalStateException();
165: }
166: this .imageFactory = imageFactory;
167: isFactorySet = Boolean.TRUE;
168: }
169: }
170:
171: /**
172: * If this <code>CollectionImage</code> was created by a
173: * <code>CollectionImageFactory</code> then return a reference to
174: * that factory; otherwise return <code>null</code>.
175: *
176: * @since JAI 1.1
177: */
178: public CollectionImageFactory getImageFactory() {
179: synchronized (isFactorySet) {
180: return imageFactory;
181: }
182: }
183:
184: /* ----- Sink methods. ----- */
185:
186: /**
187: * Adds a sink to the set of sinks.
188: *
189: * @since JAI 1.1
190: */
191: public synchronized boolean addSink(Object sink) {
192: if (sink == null) {
193: throw new IllegalArgumentException(JaiI18N
194: .getString("Generic0"));
195: }
196:
197: if (sinks == null) {
198: sinks = new HashSet();
199: }
200:
201: return sinks.add(new WeakReference(sink));
202: }
203:
204: /**
205: * Removes a sink from the set of sinks.
206: *
207: * @return <code>true</code> if and only if the set of sinks
208: * changed as a result of the call.
209: *
210: * @since JAI 1.1
211: */
212: public synchronized boolean removeSink(Object sink) {
213: if (sink == null) {
214: throw new IllegalArgumentException(JaiI18N
215: .getString("Generic0"));
216: }
217:
218: if (sinks == null) {
219: return false;
220: }
221:
222: boolean result = false;
223: Iterator it = sinks.iterator();
224: while (it.hasNext()) {
225: Object referent = ((WeakReference) it.next()).get();
226: if (referent == sink) {
227: // Remove the sink.
228: it.remove();
229: result = true;
230: // Do not break: could be more than one.
231: } else if (referent == null) {
232: // A cleared reference: might as well remove it.
233: it.remove(); // ignore return value here.
234: }
235: }
236:
237: return result;
238:
239: }
240:
241: /**
242: * Retrieves the set of sinks or <code>null</code> if
243: * there are none.
244: *
245: * @since JAI 1.1
246: */
247: public synchronized Set getSinks() {
248: Set v = null;
249:
250: if (sinks != null && sinks.size() > 0) {
251: v = new HashSet(sinks.size());
252:
253: Iterator it = sinks.iterator();
254: while (it.hasNext()) {
255: Object o = ((WeakReference) it.next()).get();
256:
257: if (o != null) {
258: v.add(o);
259: }
260: }
261:
262: if (v.size() == 0) {
263: v = null;
264: }
265: }
266:
267: return v;
268: }
269:
270: /**
271: * Removes all sinks from the set of sinks.
272: *
273: * @since JAI 1.1
274: */
275: public synchronized void removeSinks() {
276: sinks = null;
277: }
278:
279: /* ----- WritablePropertySource methods. ----- */
280:
281: /**
282: * Returns an array of <code>String</code>s recognized as names by this
283: * property source. If no property names match, <code>null</code>
284: * will be returned.
285: *
286: * @return An array of <code>String</code>s which are the valid
287: * property names or <code>null</code> if there are none.
288: */
289: public String[] getPropertyNames() {
290: return properties.getPropertyNames();
291: }
292:
293: /**
294: * Returns an array of <code>String</code>s recognized as names by
295: * this property source that begin with the supplied prefix. If
296: * no property names are recognized, or no property names match,
297: * <code>null</code> will be returned.
298: * The comparison is done in a case-independent manner.
299: *
300: * <p> The default implementation calls
301: * <code>getPropertyNames()</code> and searches the list of names
302: * for matches.
303: *
304: * @return An array of <code>String</code>s giving the valid
305: * property names or <code>null</code> if there are none.
306: *
307: * @throws <code>IllegalArgumentException</code> if <code>prefix</code>
308: * is <code>null</code>.
309: */
310: public String[] getPropertyNames(String prefix) {
311: return PropertyUtil
312: .getPropertyNames(getPropertyNames(), prefix);
313: }
314:
315: /**
316: * Returns the class expected to be returned by a request for
317: * the property with the specified name. If this information
318: * is unavailable, <code>null</code> will be returned.
319: *
320: * @return The <code>Class</code> expected to be return by a
321: * request for the value of this property or <code>null</code>.
322: *
323: * @exception IllegalArgumentException if <code>name</code>
324: * is <code>null</code>.
325: *
326: * @since JAI 1.1
327: */
328: public Class getPropertyClass(String name) {
329: return properties.getPropertyClass(name);
330: }
331:
332: /**
333: * Returns the specified property. The default implementation
334: * returns <code>java.awt.Image.UndefinedProperty</code>.
335: *
336: * @exception IllegalArgumentException if <code>name</code>
337: * is <code>null</code>.
338: */
339: public Object getProperty(String name) {
340: return properties.getProperty(name);
341: }
342:
343: /**
344: * Returns the specified property. The default implementation
345: * returns <code>java.awt.Image.UndefinedProperty</code>.
346: *
347: * @exception IllegalArgumentException if <code>name</code>
348: * is <code>null</code>.
349: * @deprecated as of JAI 1.1.
350: */
351: public Object getProperty(String name, Collection collection) {
352: return Image.UndefinedProperty;
353: }
354:
355: /**
356: * Sets a property on a <code>CollectionImage</code>. Some
357: * <code>CollectionImage</code> subclasses may ignore attempts to set
358: * properties.
359: *
360: * @param name a <code>String</code> containing the property's name.
361: * @param value the property, as a general <code>Object</code>.
362: *
363: * @throws IllegalArgumentException If <code>name</code> or
364: * <code>value</code> is <code>null</code>.
365: *
366: * @since JAI 1.1
367: */
368: public void setProperty(String name, Object value) {
369: properties.setProperty(name, value);
370: }
371:
372: /**
373: * Removes the named property from the <code>CollectionImage</code>.
374: * Some <code>CollectionImage</code> subclasses may ignore attempts to
375: * remove properties.
376: *
377: * @since JAI 1.1
378: */
379: public void removeProperty(String name) {
380: properties.removeProperty(name);
381: }
382:
383: /* ----- PropertyChangeEmitter methods. ----- */
384:
385: /**
386: * Add a PropertyChangeListener to the listener list. The
387: * listener is registered for all properties.
388: *
389: * @since JAI 1.1
390: */
391: public void addPropertyChangeListener(
392: PropertyChangeListener listener) {
393: eventManager.addPropertyChangeListener(listener);
394: }
395:
396: /**
397: * Add a PropertyChangeListener for a specific property. The
398: * listener will be invoked only when a call on
399: * firePropertyChange names that specific property. The case of
400: * the name is ignored.
401: *
402: * @since JAI 1.1
403: */
404: public void addPropertyChangeListener(String propertyName,
405: PropertyChangeListener listener) {
406: eventManager.addPropertyChangeListener(propertyName, listener);
407: }
408:
409: /**
410: * Remove a PropertyChangeListener from the listener list. This
411: * removes a PropertyChangeListener that was registered for all
412: * properties.
413: *
414: * @since JAI 1.1
415: */
416: public void removePropertyChangeListener(
417: PropertyChangeListener listener) {
418: eventManager.removePropertyChangeListener(listener);
419: }
420:
421: /**
422: * Remove a PropertyChangeListener for a specific property. The case
423: * of the name is ignored.
424: *
425: * @since JAI 1.1
426: */
427: public void removePropertyChangeListener(String propertyName,
428: PropertyChangeListener listener) {
429: eventManager.removePropertyChangeListener(propertyName,
430: listener);
431: }
432:
433: /* ----- Collection methods. ----- */
434:
435: /** Returns the number of elements in this <code>Collection</code>. */
436: public int size() {
437: return imageCollection.size();
438: }
439:
440: /**
441: * Returns <code>true</code> if this <code>Collection</code>
442: * contains no elements.
443: */
444: public boolean isEmpty() {
445: return imageCollection.isEmpty();
446: }
447:
448: /**
449: * Returns <code>true</code> if this <code>Collection</code>
450: * contains the specified object.
451: */
452: public boolean contains(Object o) {
453: return imageCollection.contains(o);
454: }
455:
456: /**
457: * Returns an <code>Iterator</code> over the elements in this
458: * <code>Collection</code>.
459: */
460: public Iterator iterator() {
461: return imageCollection.iterator();
462: }
463:
464: /**
465: * Returns an array containing all of the elements in this
466: * <code>Collection</code>.
467: */
468: public Object[] toArray() {
469: return imageCollection.toArray();
470: }
471:
472: /**
473: * Returns an array containing all of the elements in this collection
474: * whose runtime type is that of the specified array.
475: *
476: * @throws ArrayStoreException if the runtime type of the specified array
477: * is not a supertype of the runtime type of every element in this
478: * <code>Collection</code>.
479: */
480: public Object[] toArray(Object[] a) {
481: return imageCollection.toArray(a);
482: }
483:
484: /**
485: * Adds the specified object to this <code>Collection</code>.
486: *
487: * @return <code>true</code> if and only if the parameter is added to the
488: * <code>Collection</code>.
489: */
490: public boolean add(Object o) {
491: return imageCollection.add(o);
492: }
493:
494: /**
495: * Removes the specified object from this <code>Collection</code>.
496: *
497: * @return <code>true</code> if and only if the parameter is removed
498: * from the <code>Collection</code>.
499: */
500: public boolean remove(Object o) {
501: return imageCollection.remove(o);
502: }
503:
504: /**
505: * Returns <code>true</code> if this <code>Collection</code> contains
506: * all of the elements in the specified <code>Collection</code>.
507: */
508: public boolean containsAll(Collection c) {
509: return imageCollection.containsAll(c);
510: }
511:
512: /**
513: * Adds all of the elements in the specified <code>Collection</code>
514: * to this <code>Collection</code>.
515: *
516: * @return <code>true</code> if this <code>Collection</code> changed
517: * as a result of the call.
518: */
519: public boolean addAll(Collection c) {
520: return imageCollection.addAll(c);
521: }
522:
523: /**
524: * Removes all this collection's elements that are also contained in the
525: * specified <code>Collection</code>.
526: *
527: * @return <code>true</code> if this <code>Collection</code> changed
528: * as a result of the call.
529: */
530: public boolean removeAll(Collection c) {
531: return imageCollection.removeAll(c);
532: }
533:
534: /**
535: * Retains only the elements in this <code>Collection</code> that are
536: * contained in the specified <code>Collection</code>.
537: *
538: * @return <code>true</code> if this <code>Collection</code> changed
539: * as a result of the call.
540: */
541: public boolean retainAll(Collection c) {
542: return imageCollection.retainAll(c);
543: }
544:
545: /** Removes all of the elements from this <code>Collection</code>. */
546: public void clear() {
547: imageCollection.clear();
548: }
549: }
|