0001: /*
0002: * $RCSfile: CollectionOp.java,v $
0003: *
0004: * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * Use is subject to license terms.
0007: *
0008: * $Revision: 1.2 $
0009: * $Date: 2006/06/16 22:52:05 $
0010: * $State: Exp $
0011: */
0012: package javax.media.jai;
0013:
0014: import java.awt.RenderingHints;
0015: import java.awt.image.RenderedImage;
0016: import java.awt.image.renderable.ParameterBlock;
0017: import java.awt.image.renderable.RenderContext;
0018: import java.awt.image.renderable.RenderableImage;
0019: import java.beans.PropertyChangeEvent;
0020: import java.beans.PropertyChangeListener;
0021: import java.util.Collection;
0022: import java.util.Collections;
0023: import java.util.Comparator;
0024: import java.util.HashSet;
0025: import java.util.Iterator;
0026: import java.util.Locale;
0027: import java.util.Set;
0028: import java.util.SortedSet;
0029: import java.util.TreeSet;
0030: import java.util.Vector;
0031: import javax.media.jai.registry.CIFRegistry;
0032: import javax.media.jai.registry.RCIFRegistry;
0033: import javax.media.jai.registry.CollectionRegistryMode;
0034: import javax.media.jai.registry.RenderableCollectionRegistryMode;
0035: import com.sun.media.jai.util.ImageUtil;
0036: import com.sun.media.jai.util.PropertyUtil;
0037:
0038: /**
0039: * A node in a <code>CollectionImage</code> chain. A <code>CollectionOp</code>
0040: * stores an operation name, a <code>ParameterBlock</code> containing sources
0041: * and parameters, and a <code>RenderingHints</code> containing hints which
0042: * may be used in rendering the node. A set of nodes may be joined together
0043: * via the source <code>Vector</code>s within their respective
0044: * <code>ParameterBlock</code>s to form a <u>d</u>irected <u>a</u>cyclic
0045: * <u>g</u>raph (DAG). The topology, i.e., connectivity, of the graph may be
0046: * altered by changing the node's sources. The operation name, parameters,
0047: * and rendering hints may also be changed. A <code>CollectionOp</code> may
0048: * be used in either the rendered or the renderable mode for
0049: * <code>Collection</code>s, i.e., "collection" or "renderableCollection"
0050: * mode, respectively.
0051: *
0052: * <p> A <code>CollectionOp</code> may be constructed directly as, for example,
0053: * <pre>
0054: * <code>
0055: * Collection srcCol;
0056: * double[] constants;
0057: * ParameterBlock pb =
0058: * (new ParameterBlock()).addSource(srcCol).add(constants);
0059: * CollectionOp node =
0060: * new CollectionOp("addConstToCollection", pb, null);
0061: * </code>
0062: * </pre>
0063: * or by the <code>createCollection</code> or <code>createCollectionNS()</code>
0064: * "collection" mode methods or the <code>createRenderableCollection()</code>
0065: * or <code>createRenderableCollectionNS()</code> "renderableCollection" mode
0066: * methods defined in the <code>JAI</code> class. The difference between
0067: * direct construction of a node and creation via a convenience method is that
0068: * in the latter case:
0069: *
0070: * <ol>
0071: * <li> It is verified that the operation supports the appropriate mode,
0072: * i.e., "collection" or "renderableCollection".</li>
0073: * <li> It is verified that the operation generates a
0074: * <code>CollectionImage</code>, a <code>RenderedImage</code>
0075: * ("collection" mode only), or a <code>RenderableImage</code>
0076: * ("renderableCollection" mode only).</li>
0077: * <li> Global <code>RenderingHints</code> maintained by the <code>JAI</code>
0078: * instance are merged with the local <code>RenderingHints</code> with the
0079: * local hints taking precedence.</li>
0080: * <li> Using the <code>validateArguments()</code> method of the associated
0081: * <code>OperationDescriptor</code>, the arguments (sources and parameters)
0082: * are validated as being compatible with the specified operation in
0083: * the appropriate mode.</li>
0084: * <li> If the arguments are valid, then the <code>CollectionOp</code> is
0085: * created; otherwise any source <code>Collection</code>s are
0086: * "unwrapped" until a valid argument list is obtained or it is
0087: * determined that such is impossible.
0088: * <li> If the operation is in the rendered mode and is defined to be
0089: * "immediate" (the <code>isImmediate()</code> method of the corresponding
0090: * <code>OperationDescriptor</code> returns <code>true</code>)
0091: * then the node is rendered.</li>
0092: * </ol>
0093: *
0094: * <p> When a chain of nodes is rendered by any means a "parallel" chain of
0095: * <code>CollectionImage</code>s is created. Each node in the chain of
0096: * <code>CollectionOp</code>s corresponds to a node in the chain of
0097: * <code>CollectionImage</code>s. <code>Collection</code> methods invoked
0098: * on the <code>CollectionOp</code> are in general forwarded to the associated
0099: * <code>CollectionImage</code> which is referred to as the <i>rendering</i>
0100: * of the node. The rendering of the node may be a rendered or renderable
0101: * <code>CollectionImage</code>, i.e., eventually contain
0102: * <code>RenderedImage</code>s or <code>RenderableImage</code>s, respectively,
0103: * depending on the mode in which the node is used.
0104: *
0105: * <p> The translation between <code>CollectionOp</code> chains and
0106: * <code>CollectionImage</code> chains makes use of two levels of
0107: * indirection provided by the <code>OperationRegistry</code> and either the
0108: * <code>CollectionImageFactory</code> (CIF) or the
0109: * <code>RenderableCollectionImageFactory</code> (RCIF) facilities.
0110: * First, the local <code>OperationRegistry</code> is used to map the
0111: * operation name into a CIF or RCIF. This factory then constructs
0112: * a <code>CollectionImage</code>. The local
0113: * <code>OperationRegistry</code> is used in order to take advantage
0114: * of the best possible implementation of the operation.
0115: *
0116: * <p> A node may be rendered explicitly by invoking the method
0117: * <code>getCollection()</code> which also returns the rendering of the
0118: * node. A node may be rendered implicitly by invoking any method
0119: * defined in the <code>Collection</code> interface. A rendering of a
0120: * node may also be obtained by means of the <code>createInstance()</code>
0121: * method. This method returns a <code>Collection</code> rendering without
0122: * marking the node as having been rendered. If the node is not
0123: * marked as rendered then it will not fire
0124: * <code>CollectionChangeEvent</code>s as described below.
0125: *
0126: * <p> <code>CollectionOp</code> nodes may participate in Java Bean-style
0127: * events. The <code>PropertyChangeEmitter</code> methods may be used
0128: * to register and unregister <code>PropertyChangeListener</code>s.
0129: * <code>CollectionOp</code>s are also <code>PropertyChangeListener</code>s
0130: * so that they may be registered as listeners of other
0131: * <code>PropertyChangeEmitter</code>s or the equivalent. Each
0132: * <code>CollectionOp</code> also automatically receives any
0133: * <code>CollectionChangeEvent</code>s emitted by any of its sources which
0134: * are also <code>CollectionOp</code>s and <code>RenderingChangeEvent</code>s
0135: * from any <code>RenderedOp</code> sources.
0136: *
0137: * <p> Certain <code>PropertyChangeEvent</code>s may be emitted by the
0138: * <code>CollectionOp</code>. These include the
0139: * <code>PropertyChangeEventJAI</code>s and
0140: * <code>PropertySourceChangeEvent</code>s required by virtue of implementing
0141: * the <code>OperationNode</code> interface. Additionally a
0142: * <code>CollectionChangeEvent</code> may be emitted if the node is
0143: * operating in the "collection" mode, has already been rendered, and one of
0144: * the following conditions is satisfied:
0145: * <ul>
0146: * <li>any of the critical attributes is changed (edited), i.e., the
0147: * operation name, operation registry, node sources, parameters, or rendering
0148: * hints; or</li>
0149: * <li>the node receives a <code>CollectionChangeEvent</code> from one of
0150: * its <code>CollectionOp</code> sources or a <code>RenderingChangeEvent</code>
0151: * from one if its <code>RenderedOp</code>.</li>
0152: * </ul>
0153: * In either case the following sequence of actions should occur:
0154: * <ol>
0155: * <li> A. If the operation name or the registry has changed, a new
0156: * <code>CollectionImage</code> will be generated by the
0157: * <code>OperationRegistry</code> for the new operation.
0158: * <br> B. If the operation name has not changed, an attempt will be made to
0159: * re-use some elements of the previously generated
0160: * <code>CollectionImage</code> by invoking <code>update()</code> on the
0161: * <code>CollectionImageFactory</code> which generated it. If this attempt
0162: * fails, a new <code>CollectionImage</code> for this operation will be
0163: * requested from the <code>OperationRegistry</code>.</li>
0164: * <li> A <code>CollectionChangeEvent</code> will be fired to all registered
0165: * listeners of the "Collection" <code>PropertyChangeEvent</code> and to all
0166: * sinks which are <code>PropertyChangeListener</code>s. The new and old
0167: * values set on the event object correspond to the previous and current
0168: * <code>CollectionImage</code>s, respectively, associated with this node.</li>
0169: * </ol>
0170: *
0171: * <p> <code>CollectionOp</code> nodes are <code>WritablePropertySource</code>s
0172: * and so manage a name-value database of image meta-data also known as image
0173: * properties. Properties may be set on and requested from a node. The
0174: * value of a property not explicitly set on the node (via
0175: * <code>setProperty()</code>) is obtained from the property environment of
0176: * the node. When a property is derived from the property environment it is
0177: * cached locally to ensure synchronization, i.e., that properties do not
0178: * change spontaneously if for example the same property is modified upstream.
0179: *
0180: * <p> The property environment of a <code>CollectionOp</code> is initially
0181: * derived from that of the corresponding <code>OperationDescriptor</code>
0182: * as maintained by the <code>OperationRegistry</code>. It may be modified
0183: * locally by adding <code>PropertyGenerator</code>s, directives to copy
0184: * certain properties from specific sources, or requests to suppress certain
0185: * properties. These modifications per se cannot be undone directly but
0186: * may be eliminated as a side effect of other changes to the node as
0187: * described below.
0188: *
0189: * <p> When a property value is requested an attempt will be made to derive
0190: * it from the several entities in the following order of precedence:
0191: * <ol>
0192: * <li> local properties; </li>
0193: * <li> the rendering of the node if it is a <code>PropertySource</code>;</li>
0194: * <li> any registered <code>PropertyGenerator</code>s, or
0195: * <br> a source specified via a copy-from-source directive;</li>
0196: * <li> the first source which defines the property. </li>
0197: * </ol>
0198: * Local properties are those which have been cached locally either by virtue
0199: * of direct invocation of <code>setProperty()</code> or due to caching of a
0200: * property derived from the property environment.
0201: *
0202: * <p> All dynamically computed properties of a <code>CollectionOp</code> which
0203: * have been cached locally, i.e., those cached properties which were not set
0204: * by an explicit call to <code>setProperty()</code>, will be cleared when any
0205: * of the critical attributes of the node is edited. By implication these
0206: * properties will also be cleared when a <code>CollectionChangeEvent</code>
0207: * is received from any node source. The property environment or the cached
0208: * properties may also be cleared by invoking <code>resetProperties()</code>.
0209: *
0210: * @see CollectionImage
0211: * @see OperationRegistry
0212: * @see RenderableOp
0213: * @see RenderedOp
0214: *
0215: */
0216: public class CollectionOp extends CollectionImage implements
0217: OperationNode, PropertyChangeListener {
0218:
0219: /**
0220: * An object to assist in implementing <code>OperationNode</code>.
0221: *
0222: * @since JAI 1.1
0223: */
0224: protected OperationNodeSupport nodeSupport;
0225:
0226: /**
0227: * The <code>PropertySource</code> containing the combined properties
0228: * of all of the node's sources.
0229: *
0230: * @since JAI 1.1
0231: */
0232: protected PropertySource thePropertySource;
0233:
0234: /**
0235: * Flag indicating whether the operation is being instantiated in
0236: * renderable mode.
0237: *
0238: * @since JAI 1.1
0239: */
0240: protected boolean isRenderable = false;
0241:
0242: /**
0243: * The RenderingHints when the node was last rendered, i.e., when
0244: * "theImage" was set to its current value.
0245: */
0246: private transient RenderingHints oldHints;
0247:
0248: /** Node event names. */
0249: private static Set nodeEventNames = null;
0250:
0251: static {
0252: nodeEventNames = new HashSet();
0253: nodeEventNames.add("operationname");
0254: nodeEventNames.add("operationregistry");
0255: nodeEventNames.add("parameterblock");
0256: nodeEventNames.add("sources");
0257: nodeEventNames.add("parameters");
0258: nodeEventNames.add("renderinghints");
0259: }
0260:
0261: /**
0262: * Constructs a <code>CollectionOp</code> that will be used to
0263: * instantiate a particular <code>Collection</code> operation from a given
0264: * operation registry, an operation name, a <code>ParameterBlock</code>,
0265: * and a set of rendering hints.
0266: *
0267: * <p> This method does not validate the contents of the supplied
0268: * <code>ParameterBlock</code>. The caller should ensure that
0269: * the sources and parameters in the <code>ParameterBlock</code>
0270: * are suitable for the operation this node represents; otherwise
0271: * some form of error or exception may occur at the time of rendering.
0272: *
0273: * <p> The <code>ParameterBlock</code> may include
0274: * <code>DeferredData</code> parameters. These will not be evaluated
0275: * until their values are actually required, i.e., when a collection
0276: * rendering is requested.
0277: *
0278: * <p> The node is added automatically as a sink of any
0279: * <code>PlanarImage</code> or <code>CollectionImage</code> sources.
0280: *
0281: * @param registry The <code>OperationRegistry</code> to be used for
0282: * instantiation. if <code>null</code>, the default registry
0283: * is used. Saved by reference.
0284: * @param opName The operation name. Saved by reference.
0285: * @param pb The sources and other parameters. If <code>null</code>,
0286: * it is assumed that this node has no sources and parameters.
0287: * This parameter is cloned.
0288: * @param hints The rendering hints. If <code>null</code>, it is assumed
0289: * that no hints are associated with the rendering.
0290: * This parameter is cloned.
0291: * @param isRenderable Whether the operation is being executed in
0292: * renderable mode.
0293: *
0294: * @throws <code>IllegalArgumentException</code> if <code>opName</code>
0295: * is <code>null</code>.
0296: *
0297: * @since JAI 1.1
0298: */
0299: public CollectionOp(OperationRegistry registry, String opName,
0300: ParameterBlock pb, RenderingHints hints,
0301: boolean isRenderable) {
0302:
0303: if (opName == null) {
0304: throw new IllegalArgumentException(JaiI18N
0305: .getString("Generic0"));
0306: }
0307:
0308: if (pb == null) {
0309: // Ensure that the PB is non-null.
0310: pb = new ParameterBlock();
0311: } else {
0312: // Clone the PB per the doc.
0313: pb = (ParameterBlock) pb.clone();
0314: }
0315:
0316: if (hints != null) {
0317: // Clone the hints per the doc.
0318: hints = (RenderingHints) hints.clone();
0319: }
0320:
0321: // Initialize the various helper objects.
0322: eventManager = new PropertyChangeSupportJAI(this );
0323:
0324: properties = new WritablePropertySourceImpl(null, null,
0325: eventManager);
0326:
0327: nodeSupport = new OperationNodeSupport(getRegistryModeName(),
0328: opName, registry, pb, hints, eventManager);
0329:
0330: this .isRenderable = isRenderable;
0331:
0332: // Add the node as a PropertyChangeListener of itself for
0333: // the critical attributes of the node. Case is ignored
0334: // in the property names but infix caps are used here anyway.
0335: addPropertyChangeListener("OperationName", this );
0336: addPropertyChangeListener("OperationRegistry", this );
0337: addPropertyChangeListener("ParameterBlock", this );
0338: addPropertyChangeListener("Sources", this );
0339: addPropertyChangeListener("Parameters", this );
0340: addPropertyChangeListener("RenderingHints", this );
0341:
0342: // Add self as a sink of any CollectionImage or PlanarImage sources.
0343: Vector nodeSources = pb.getSources();
0344: if (nodeSources != null) {
0345: Iterator it = nodeSources.iterator();
0346: while (it.hasNext()) {
0347: Object src = it.next();
0348: if (src instanceof CollectionImage) {
0349: ((CollectionImage) src).addSink(this );
0350: } else if (src instanceof PlanarImage) {
0351: ((PlanarImage) src).addSink(this );
0352: }
0353: }
0354: }
0355: }
0356:
0357: /**
0358: * Constructs a <code>CollectionOp</code> that will be used to
0359: * instantiate a particular <code>Collection</code> operation from a given
0360: * operation registry, an operation name, a <code>ParameterBlock</code>,
0361: * and a set of rendering hints. The operation will use the rendered mode.
0362: *
0363: * <p> This method does not validate the contents of the supplied
0364: * <code>ParameterBlock</code>. The caller should ensure that
0365: * the sources and parameters in the <code>ParameterBlock</code>
0366: * are suitable for the operation this node represents; otherwise
0367: * some form of error or exception may occur at the time of rendering.
0368: *
0369: * <p> The <code>ParameterBlock</code> may include
0370: * <code>DeferredData</code> parameters. These will not be evaluated
0371: * until their values are actually required, i.e., when a collection
0372: * rendering is requested.
0373: *
0374: * @param registry The <code>OperationRegistry</code> to be used for
0375: * instantiation. if <code>null</code>, the default registry
0376: * is used. Saved by reference.
0377: * @param opName The operation name. Saved by reference.
0378: * @param pb The sources and other parameters. If <code>null</code>,
0379: * it is assumed that this node has no sources and parameters.
0380: * This parameter is cloned.
0381: * @param hints The rendering hints. If <code>null</code>, it is assumed
0382: * that no hints are associated with the rendering.
0383: * This parameter is cloned.
0384: *
0385: * @throws IllegalArgumentException if <code>opName</code> is
0386: * <code>null</code>.
0387: */
0388: public CollectionOp(OperationRegistry registry, String opName,
0389: ParameterBlock pb, RenderingHints hints) {
0390: this (registry, opName, pb, hints, false);
0391: }
0392:
0393: /**
0394: * Constructs a <code>CollectionOp</code> that will be used to
0395: * instantiate a particular <code>Collection</code> operation from a given
0396: * operation name, a <code>ParameterBlock</code>, and a set of
0397: * rendering hints. The default operation registry is used.
0398: *
0399: * <p> This method does not validate the contents of the supplied
0400: * <code>ParameterBlock</code>. The caller should ensure that
0401: * the sources and parameters in the <code>ParameterBlock</code>
0402: * are suitable for the operation this node represents; otherwise
0403: * some form of error or exception may occur at the time of rendering.
0404: *
0405: * <p> The <code>ParameterBlock</code> may include
0406: * <code>DeferredData</code> parameters. These will not be evaluated
0407: * until their values are actually required, i.e., when a collection
0408: * rendering is requested.
0409: *
0410: * @param opName The operation name. Saved by reference.
0411: * @param pb The sources and other parameters. If <code>null</code>,
0412: * it is assumed that this node has no sources and parameters.
0413: * This parameter is cloned.
0414: * @param hints The rendering hints. If <code>null</code>, it is assumed
0415: * that no hints are associated with the rendering.
0416: * This parameter is cloned.
0417: *
0418: * @throws <code>IllegalArgumentException</code> if <code>opName</code> is
0419: * <code>null</code>.
0420: */
0421: public CollectionOp(String opName, ParameterBlock pb,
0422: RenderingHints hints) {
0423: this (null, opName, pb, hints);
0424: }
0425:
0426: /**
0427: * Constructs a <code>CollectionOp</code> that will be used to
0428: * instantiate a particular <code>Collection</code> operation from a given
0429: * operation registry, an operation name, and a
0430: * <code>ParameterBlock</code> There are no rendering hints
0431: * associated with this operation.
0432: * The operation will use the rendered mode.
0433: *
0434: * <p> This method does not validate the contents of the supplied
0435: * <code>ParameterBlock</code>. The caller should ensure that
0436: * the sources and parameters in the <code>ParameterBlock</code>
0437: * are suitable for the operation this node represents; otherwise
0438: * some form of error or exception may occur at the time of rendering.
0439: *
0440: * <p> The <code>ParameterBlock</code> may include
0441: * <code>DeferredData</code> parameters. These will not be evaluated
0442: * until their values are actually required, i.e., when a collection
0443: * rendering is requested.
0444: *
0445: * @param registry The <code>OperationRegistry</code> to be used for
0446: * instantiation. if <code>null</code>, the default registry
0447: * is used. Saved by reference.
0448: * @param opName The operation name. Saved by reference.
0449: * @param pb The sources and other parameters. If <code>null</code>,
0450: * it is assumed that this node has no sources and parameters.
0451: * This parameter is cloned.
0452: *
0453: * @throws <code>IllegalArgumentException</code> if <code>opName</code> is
0454: * <code>null</code>.
0455: *
0456: * @deprecated as of JAI 1.1.
0457: * @see #CollectionOp(OperationRegistry,String,ParameterBlock,RenderingHints)
0458: */
0459: public CollectionOp(OperationRegistry registry, String opName,
0460: ParameterBlock pb) {
0461: this (registry, opName, pb, null);
0462: }
0463:
0464: /**
0465: * Returns whether the operation is being instantiated in renderable mode.
0466: *
0467: * @since JAI 1.1
0468: */
0469: public boolean isRenderable() {
0470: return isRenderable;
0471: }
0472:
0473: /**
0474: * Returns the name of the <code>RegistryMode</code> corresponding to
0475: * this <code>CollectionOp</code>.
0476: *
0477: * @since JAI 1.1
0478: */
0479: public String getRegistryModeName() {
0480: return isRenderable ? RenderableCollectionRegistryMode.MODE_NAME
0481: : CollectionRegistryMode.MODE_NAME;
0482: }
0483:
0484: /* ----- Critical attribute accessors and mutators. ----- */
0485:
0486: /**
0487: * Returns the <code>OperationRegistry</code> that is used
0488: * by this node. If the registry had not been set, the default
0489: * registry is returned.
0490: */
0491: public synchronized OperationRegistry getRegistry() {
0492: return nodeSupport.getRegistry();
0493: }
0494:
0495: /**
0496: * Sets the <code>OperationRegistry</code> that is used by
0497: * this node. If the specified registry is <code>null</code>, the
0498: * default registry is used. The parameter is saved by reference.
0499: *
0500: * <p> If the supplied registry does not equal the current registry, a
0501: * <code>PropertyChangeEventJAI</code> named "OperationRegistry"
0502: * will be fired and a <code>CollectionChangeEvent</code> may be
0503: * fired if the node has already been rendered.
0504: *
0505: * @param registry The new <code>OperationRegistry</code> to be set;
0506: * it may be <code>null</code>.
0507: */
0508: public synchronized void setRegistry(OperationRegistry registry) {
0509: nodeSupport.setRegistry(registry);
0510: }
0511:
0512: /**
0513: * Returns the name of the operation this node represents as
0514: * a <code>String</code>.
0515: */
0516: public String getOperationName() {
0517: return nodeSupport.getOperationName();
0518: }
0519:
0520: /**
0521: * Sets the name of the operation this node represents.
0522: * The parameter is saved by reference.
0523: *
0524: * <p> If the supplied name does not equal the current operation name, a
0525: * <code>PropertyChangeEventJAI</code> named "OperationName"
0526: * will be fired and a <code>CollectionChangeEvent</code> may be
0527: * fired if the node has already been rendered.
0528: *
0529: * @param opName The new operation name to be set.
0530: *
0531: * @throws <code>IllegalArgumentException</code> if <code>opName</code> is
0532: * <code>null</code>.
0533: */
0534: public synchronized void setOperationName(String opName) {
0535: nodeSupport.setOperationName(opName);
0536: }
0537:
0538: /** Returns a clone of the <code>ParameterBlock</code> of this node. */
0539: public ParameterBlock getParameterBlock() {
0540: return (ParameterBlock) nodeSupport.getParameterBlock().clone();
0541: }
0542:
0543: /**
0544: * Sets the <code>ParameterBlock</code> of this node.
0545: * If the specified new <code>ParameterBlock</code> is <code>null</code>,
0546: * it is assumed that this node has no input sources and parameters.
0547: * The supplied parameter is cloned.
0548: *
0549: * <p> This method does not validate the contents of the supplied
0550: * <code>ParameterBlock</code>. The caller should ensure that
0551: * the sources and parameters in the <code>ParameterBlock</code>
0552: * are suitable for the operation this node represents; otherwise
0553: * some form of error or exception may occur at the time of rendering.
0554: *
0555: * <p> If the supplied <code>ParameterBlock</code> does not equal the
0556: * current <code>ParameterBlock</code>, a
0557: * <code>PropertyChangeEventJAI</code> named "ParameterBlock", "Sources",
0558: * or "Parameters" will be fired. A <code>CollectionChangeEvent</code>
0559: * may also be fired if the node has already been rendered.
0560: *
0561: * <p> The <code>ParameterBlock</code> may include
0562: * <code>DeferredData</code> parameters. These will not be evaluated
0563: * until their values are actually required, i.e., when a collection
0564: * rendering is requested.
0565: *
0566: * <p> The node is registered as a sink of any <code>PlanarImage</code>
0567: * or <code>CollectionImage</code> sources contained in the supplied
0568: * <code>ParameterBlock</code>. The node is also removed as a sink of
0569: * any previous <code>PlanarImage</code> or <code>CollectionImage</code>
0570: * sources if these are not in the new <code>ParameterBlock</code>.
0571: *
0572: * @param pb The new <code>ParameterBlock</code> to be set;
0573: * it may be <code>null</code>.
0574: */
0575: public synchronized void setParameterBlock(ParameterBlock pb) {
0576: Vector nodeSources = nodeSupport.getParameterBlock()
0577: .getSources();
0578: if (nodeSources != null && nodeSources.size() > 0) {
0579: Iterator it = nodeSources.iterator();
0580: while (it.hasNext()) {
0581: Object src = it.next();
0582: if (src instanceof PlanarImage) {
0583: ((PlanarImage) src).removeSink(this );
0584: } else if (src instanceof CollectionImage) {
0585: ((CollectionImage) src).removeSink(this );
0586: }
0587: }
0588: }
0589:
0590: if (pb != null) {
0591: Vector newSources = pb.getSources();
0592: ;
0593: if (newSources != null && newSources.size() > 0) {
0594: Iterator it = newSources.iterator();
0595: while (it.hasNext()) {
0596: Object src = it.next();
0597: if (src instanceof PlanarImage) {
0598: ((PlanarImage) src).addSink(this );
0599: } else if (src instanceof CollectionImage) {
0600: ((CollectionImage) src).addSink(this );
0601: }
0602: }
0603: }
0604: }
0605:
0606: nodeSupport.setParameterBlock(pb == null ? new ParameterBlock()
0607: : (ParameterBlock) pb.clone());
0608: }
0609:
0610: /**
0611: * Returns a clone of the <code>RenderingHints</code> of this node or
0612: * <code>null</code>.
0613: */
0614: public RenderingHints getRenderingHints() {
0615: RenderingHints hints = nodeSupport.getRenderingHints();
0616: return hints == null ? null : (RenderingHints) hints.clone();
0617: }
0618:
0619: /**
0620: * Sets the <code>RenderingHints</code> of this node.
0621: * The supplied parameter is cloned if non-<code>null</code>.
0622: *
0623: * <p> If the supplied <code>RenderingHints</code> does not equal the
0624: * current <code>RenderingHints</code>, a
0625: * <code>PropertyChangeEventJAI</code> named "RenderingHints"
0626: * will be fired and a <code>CollectionChangeEvent</code> may be
0627: * fired if the node has already been rendered.
0628: *
0629: * @param hints The new <code>RenderingHints</code> to be set;
0630: * it may be <code>null</code>.
0631: */
0632: public synchronized void setRenderingHints(RenderingHints hints) {
0633: if (hints != null) {
0634: hints = (RenderingHints) hints.clone();
0635: }
0636: nodeSupport.setRenderingHints(hints);
0637: }
0638:
0639: /* ----- Collection generation methods. ----- */
0640:
0641: /**
0642: * Returns the <code>Collection</code> rendering associated with
0643: * this operation.
0644: *
0645: * <p> This method does not validate the sources and parameters
0646: * stored in the <code>ParameterBlock</code> against the specification
0647: * of the operation this node represents. It is the responsibility
0648: * of the caller to ensure that the data in the
0649: * <code>ParameterBlock</code> are suitable for this operation.
0650: * Otherwise, some kind of exception or error will occur. Invoking
0651: * this method will cause any <code>DeferredData</code> parameters
0652: * in the <code>ParameterBlock</code> to be evaluated.
0653: *
0654: * <p> Invoking this method will cause any source <code>RenderedOp</code>
0655: * nodes to be rendered using <code>getRendering()</code> and any
0656: * source <code>CollectionOp</code> nodes to be rendered using
0657: * <code>getCollection()</code>. Any <code>DeferredData</code> parameters
0658: * in the <code>ParameterBlock</code> will also be evaluated.
0659: *
0660: * @throws RuntimeException if the image factory charged with rendering
0661: * the node is unable to create a rendering.
0662: */
0663: public Collection getCollection() {
0664: createCollection();
0665: return imageCollection;
0666: }
0667:
0668: /** Creates a <code>Collection</code> rendering if none exists. */
0669: private synchronized void createCollection() {
0670: if (imageCollection == null) {
0671: imageCollection = createInstance(true);
0672: }
0673: }
0674:
0675: /**
0676: * Instantiates a <code>Collection</code> operator that computes
0677: * the result of this <code>CollectionOp</code>.
0678: *
0679: * <p> This method does not validate the sources and parameters
0680: * stored in the <code>ParameterBlock</code> against the specification
0681: * of the operation this node represents. It is the responsibility
0682: * of the caller to ensure that the data in the
0683: * <code>ParameterBlock</code> are suitable for this operation.
0684: * Otherwise, some kind of exception or error will occur.
0685: *
0686: * <p> Invoking this method will cause any source <code>RenderedOp</code>
0687: * or <code>CollectionOp</code> nodes to be rendered using their
0688: * respective <code>createInstance()</code> methods. Any
0689: * <code>DeferredData</code> parameters in the <code>ParameterBlock</code>
0690: * will also be evaluated.
0691: *
0692: * @throws RuntimeException if the image factory charged with rendering
0693: * the node is unable to create a rendering.
0694: */
0695: public synchronized Collection createInstance() {
0696: return createInstance(false);
0697: }
0698:
0699: /**
0700: * This method performs the actions described by the documentation of
0701: * <code>createInstance()</code>. The parameter value selects the method
0702: * used to render the source(s).
0703: *
0704: * @throws RuntimeException if the image factory charged with rendering
0705: * the node is unable to create a rendering.
0706: */
0707: private synchronized Collection createInstance(boolean isChainFrozen) {
0708: // Get the PB evaluating any DeferredData objects in the process.
0709: ParameterBlock args = ImageUtil.evaluateParameters(nodeSupport
0710: .getParameterBlock());
0711:
0712: ParameterBlock pb = new ParameterBlock();
0713: pb.setParameters(args.getParameters());
0714:
0715: int numSources = args.getNumSources();
0716: for (int i = 0; i < numSources; i++) {
0717: Object source = args.getSource(i);
0718: Object src = null;
0719:
0720: if (source instanceof RenderedOp) {
0721: src = isChainFrozen ? ((RenderedOp) source)
0722: .getRendering() : ((RenderedOp) source)
0723: .createInstance();
0724: } else if (source instanceof CollectionOp) {
0725: CollectionOp co = (CollectionOp) source;
0726: src = isChainFrozen ? co.getCollection() : co
0727: .createInstance();
0728: } else if (source instanceof RenderedImage
0729: || source instanceof RenderableImage
0730: || source instanceof Collection) {
0731: src = source;
0732: } else {
0733: // Source is some other type. Pass on (for now).
0734: src = source;
0735: }
0736: pb.addSource(src);
0737: }
0738:
0739: Collection instance = null;
0740: if (isRenderable) {
0741: instance = RCIFRegistry.create(nodeSupport.getRegistry(),
0742: nodeSupport.getOperationName(), pb);
0743: } else {
0744: CollectionImageFactory cif = CIFRegistry.get(nodeSupport
0745: .getRegistry(), nodeSupport.getOperationName());
0746: instance = cif.create(pb, nodeSupport.getRenderingHints());
0747:
0748: // Set the CollectionImageFactory on the result.
0749: if (instance != null) {
0750: ((CollectionImage) instance).setImageFactory(cif);
0751: }
0752: }
0753:
0754: // Throw an error if the rendering is null.
0755: if (instance == null) {
0756: throw new RuntimeException(JaiI18N
0757: .getString("CollectionOp0"));
0758: }
0759:
0760: // Save the RenderingHints.
0761: oldHints = nodeSupport.getRenderingHints() == null ? null
0762: : (RenderingHints) nodeSupport.getRenderingHints()
0763: .clone();
0764:
0765: return instance;
0766: }
0767:
0768: /**
0769: * Returns the <code>Collection</code> rendering associated with this
0770: * operation with any contained <code>RenderableImage</code>s rendered
0771: * using the supplied <code>RenderContext</code> parameter. If the
0772: * operation is being executed in rendered mode
0773: * (<code>isRenderable()</code> returns <code>false</code>), invoking
0774: * this method is equivalent to invoking <code>getCollection()</code>,
0775: * i.e., the parameter is ignored. If the operation is being
0776: * executed in renderable mode, the <code>Collection</code> will differ
0777: * from that returned by <code>getCollection()</code> due to any contained
0778: * <code>RenderableImage</code>s having been rendered. If the
0779: * <code>Collection</code> contains any nested <code>Collection</code>s,
0780: * these will be unwrapped recursively such that a rendering is created
0781: * for all <code>RenderableImage</code>s encountered. Any
0782: * <code>RenderingHints</code> in the <code>RenderContext</code> are
0783: * merged with those set on the node with the argument hints taking
0784: * precedence.
0785: *
0786: * @since JAI 1.1
0787: */
0788: public Collection createRendering(RenderContext renderContext) {
0789: if (!isRenderable) {
0790: return this ;
0791: }
0792:
0793: // Merge argument hints with node hints.
0794: RenderingHints mergedHints = JAI.mergeRenderingHints(
0795: nodeSupport.getRenderingHints(), renderContext
0796: .getRenderingHints());
0797: if (mergedHints != renderContext.getRenderingHints()) {
0798: renderContext = (RenderContext) renderContext.clone();
0799: renderContext.setRenderingHints(mergedHints);
0800: }
0801:
0802: return renderCollection(imageCollection, renderContext);
0803: }
0804:
0805: /**
0806: * Returns a new <code>Collection</code> with any
0807: * <code>RenderableImage</code>s rendered using the supplied
0808: * <code>RenderContext</code>. This method is re-entrant and
0809: * invokes itself if there is a nested <code>Collection</code>.
0810: */
0811: private Collection renderCollection(Collection cIn, RenderContext rc) {
0812: if (cIn == null || rc == null) {
0813: throw new IllegalArgumentException(); // no message.
0814: }
0815:
0816: Collection cOut;
0817: if (cIn instanceof Set) {
0818: cOut = Collections.synchronizedSet(new HashSet(cIn.size()));
0819: } else if (cIn instanceof SortedSet) {
0820: Comparator comparator = ((SortedSet) cIn).comparator();
0821: cOut = Collections.synchronizedSortedSet(new TreeSet(
0822: comparator));
0823: } else {
0824: cOut = new Vector(cIn.size());
0825: }
0826:
0827: Iterator it = cIn.iterator();
0828: while (it.hasNext()) {
0829: Object element = it.next();
0830: if (element instanceof RenderableImage) {
0831: cOut.add(((RenderableImage) cIn).createRendering(rc));
0832: } else if (element instanceof Collection) {
0833: cOut.add(renderCollection((Collection) element, rc));
0834: } else {
0835: cOut.add(element);
0836: }
0837: }
0838:
0839: return cOut;
0840: }
0841:
0842: /* ----- PropertyChangeListener method. ----- */
0843:
0844: /**
0845: * Implementation of <code>PropertyChangeListener</code>.
0846: *
0847: * <p> When invoked with an event which is an instance of either
0848: * <code>CollectionChangeEvent</code> or
0849: * <code>RenderingChangeEvent</code> emitted by a
0850: * <code>CollectionOp</code> or <code>RenderedOp</code> source,
0851: * respectively, the node will respond by
0852: * re-rendering itself while retaining any data possible.
0853: *
0854: * @since JAI 1.1
0855: */
0856: public synchronized void propertyChange(PropertyChangeEvent evt) {
0857: // If this is a renderable node just return as CollectionChangeEvents
0858: // should not be emitted for "renderablecollection" mode.
0859: if (isRenderable())
0860: return;
0861:
0862: //
0863: // React if and only if the node has been rendered and
0864: // A: a non-PropertySourceChangeEvent PropertyChangeEventJAI
0865: // was received from this node, or
0866: // B: a CollectionChangeEvent was received from a source node, or
0867: // C: a RenderingChangeEvent was received from a source node.
0868: //
0869:
0870: // Cache event and node sources.
0871: Object evtSrc = evt.getSource();
0872: Vector nodeSources = nodeSupport.getParameterBlock()
0873: .getSources();
0874:
0875: // Get the name of the bean property and convert it to lower
0876: // case now for efficiency later.
0877: String propName = evt.getPropertyName().toLowerCase(
0878: Locale.ENGLISH);
0879:
0880: if (imageCollection != null
0881: && ((evt instanceof PropertyChangeEventJAI
0882: && evtSrc == this
0883: && !(evt instanceof PropertySourceChangeEvent) && nodeEventNames
0884: .contains(propName)) || ((evt instanceof CollectionChangeEvent || evt instanceof RenderingChangeEvent) && nodeSources
0885: .contains(evtSrc)))) {
0886:
0887: // Save the previous rendering.
0888: Collection theOldCollection = imageCollection;
0889:
0890: // Initialize the event flag.
0891: boolean fireEvent = false;
0892:
0893: if (!(imageCollection instanceof CollectionImage)) {
0894:
0895: // Collection is not a CollectionImage so no update possible;
0896: // invalidate the entire rendering.
0897: fireEvent = true;
0898: imageCollection = null;
0899:
0900: } else if (evtSrc == this
0901: && (propName.equals("operationname") || propName
0902: .equals("operationregistry"))) {
0903:
0904: // Operation name or OperationRegistry changed:
0905: // invalidate the entire rendering.
0906: fireEvent = true;
0907: imageCollection = null;
0908:
0909: } else if (evt instanceof CollectionChangeEvent) {
0910:
0911: // Set the event flag.
0912: fireEvent = true;
0913:
0914: // Save the previous image factory. We know that the old
0915: // Collection is a CollectionImage or the first branch of
0916: // the if-block would have been entered above.
0917: CollectionImageFactory oldCIF = ((CollectionImage) theOldCollection)
0918: .getImageFactory();
0919:
0920: if (oldCIF == null) {
0921:
0922: // The factory is null: no update possible.
0923: imageCollection = null;
0924:
0925: } else {
0926:
0927: // CollectionChangeEvent from a source CollectionOp.
0928: CollectionChangeEvent ccEvent = (CollectionChangeEvent) evt;
0929:
0930: // Construct old and new ParameterBlocks.
0931: Vector parameters = nodeSupport.getParameterBlock()
0932: .getParameters();
0933: parameters = ImageUtil
0934: .evaluateParameters(parameters);
0935: ParameterBlock oldPB = new ParameterBlock(
0936: (Vector) nodeSources.clone(), parameters);
0937: ParameterBlock newPB = new ParameterBlock(
0938: (Vector) nodeSources.clone(), parameters);
0939: int sourceIndex = nodeSources.indexOf(ccEvent
0940: .getSource());
0941: oldPB.setSource(ccEvent.getOldValue(), sourceIndex);
0942: newPB.setSource(ccEvent.getNewValue(), sourceIndex);
0943:
0944: // Update the collection.
0945: imageCollection = oldCIF.update(oldPB, oldHints,
0946: newPB, oldHints,
0947: (CollectionImage) theOldCollection, this );
0948: }
0949:
0950: } else {
0951: // not op name, registry change, nor CollectionChangeEvent
0952:
0953: // Save the previous image factory.
0954: CollectionImageFactory oldCIF = ((CollectionImage) theOldCollection)
0955: .getImageFactory();
0956:
0957: if (oldCIF == null
0958: || oldCIF != CIFRegistry.get(nodeSupport
0959: .getRegistry(), nodeSupport
0960: .getOperationName())) {
0961:
0962: // Impossible to update unless the old and new CIFs
0963: // are equal and non-null.
0964: imageCollection = null;
0965:
0966: // Set event flag.
0967: fireEvent = true;
0968:
0969: } else {
0970:
0971: // Attempt to update the Collection rendering.
0972:
0973: ParameterBlock oldPB = null;
0974: ParameterBlock newPB = null;
0975:
0976: boolean updateCollection = false;
0977:
0978: if (propName.equals("parameterblock")) {
0979: oldPB = (ParameterBlock) evt.getOldValue();
0980: newPB = (ParameterBlock) evt.getNewValue();
0981: updateCollection = true;
0982: } else if (propName.equals("sources")) {
0983: // Replace source(s)
0984: Vector params = nodeSupport.getParameterBlock()
0985: .getParameters();
0986: oldPB = new ParameterBlock((Vector) evt
0987: .getOldValue(), params);
0988: newPB = new ParameterBlock((Vector) evt
0989: .getNewValue(), params);
0990: updateCollection = true;
0991: } else if (propName.equals("parameters")) {
0992: // Replace parameter(s)
0993: oldPB = new ParameterBlock(nodeSources,
0994: (Vector) evt.getOldValue());
0995: newPB = new ParameterBlock(nodeSources,
0996: (Vector) evt.getNewValue());
0997: updateCollection = true;
0998: } else if (propName.equals("renderinghints")) {
0999: oldPB = newPB = nodeSupport.getParameterBlock();
1000: updateCollection = true;
1001: } else if (evt instanceof RenderingChangeEvent) {
1002: // Event from a RenderedOp source.
1003:
1004: // Replace appropriate source.
1005: int renderingIndex = nodeSources.indexOf(evt
1006: .getSource());
1007: Vector oldSources = (Vector) nodeSources
1008: .clone();
1009: Vector newSources = (Vector) nodeSources
1010: .clone();
1011: oldSources.set(renderingIndex, evt
1012: .getOldValue());
1013: newSources.set(renderingIndex, evt
1014: .getNewValue());
1015:
1016: Vector params = nodeSupport.getParameterBlock()
1017: .getParameters();
1018:
1019: oldPB = new ParameterBlock(oldSources, params);
1020: newPB = new ParameterBlock(newSources, params);
1021:
1022: updateCollection = true;
1023: }
1024:
1025: if (updateCollection) {
1026: // Set event flag.
1027: fireEvent = true;
1028:
1029: // Evaluate any DeferredData parameters.
1030: oldPB = ImageUtil.evaluateParameters(oldPB);
1031: newPB = ImageUtil.evaluateParameters(newPB);
1032:
1033: // Update the collection.
1034: RenderingHints newHints = nodeSupport
1035: .getRenderingHints();
1036: if ((imageCollection = oldCIF.update(oldPB,
1037: oldHints, newPB, newHints,
1038: (CollectionImage) theOldCollection,
1039: this )) != null) {
1040: oldHints = newHints;
1041: }
1042: }
1043: }
1044: }
1045:
1046: // Re-render the node. This will only occur if imageCollection
1047: // has been set to null above.
1048: getCollection();
1049:
1050: // Fire an event if the flag was set.
1051: if (fireEvent) {
1052: // Clear the synthetic and cached properties and reset the
1053: // property source.
1054: resetProperties(true);
1055:
1056: // Create the event object.
1057: CollectionChangeEvent ccEvent = new CollectionChangeEvent(
1058: this , theOldCollection, imageCollection);
1059:
1060: // Fire to all registered listeners.
1061: eventManager.firePropertyChange(ccEvent);
1062:
1063: // Fire to all PropertyChangeListener sinks.
1064: Set sinks = getSinks();
1065: if (sinks != null) {
1066: Iterator it = sinks.iterator();
1067: while (it.hasNext()) {
1068: Object sink = it.next();
1069: if (sink instanceof PropertyChangeListener) {
1070: ((PropertyChangeListener) sink)
1071: .propertyChange(ccEvent);
1072: }
1073: }
1074: }
1075: }
1076: }
1077: }
1078:
1079: /* ----- Property-related methods. ----- */
1080:
1081: /** Creates a <code>PropertySource</code> if none exists. */
1082: private synchronized void createPropertySource() {
1083: if (thePropertySource == null) {
1084: getCollection();
1085:
1086: PropertySource defaultPS = null;
1087: if (imageCollection instanceof PropertySource) {
1088: // Create a <code>PropertySource</code> wrapper of the rendering.
1089: defaultPS = new PropertySource() {
1090: /**
1091: * Retrieve the names from an instance of the node.
1092: */
1093: public String[] getPropertyNames() {
1094: return ((PropertySource) imageCollection)
1095: .getPropertyNames();
1096: }
1097:
1098: public String[] getPropertyNames(String prefix) {
1099: return PropertyUtil.getPropertyNames(
1100: getPropertyNames(), prefix);
1101: }
1102:
1103: public Class getPropertyClass(String name) {
1104: return null;
1105: }
1106:
1107: /**
1108: * Retrieve the actual property values from a
1109: * rendering of the node.
1110: */
1111: public Object getProperty(String name) {
1112: return ((PropertySource) imageCollection)
1113: .getProperty(name);
1114: }
1115: };
1116: }
1117:
1118: // Create a <code>PropertySource</code> encapsulating the
1119: // property environment of the node.
1120: thePropertySource = nodeSupport.getPropertySource(this ,
1121: defaultPS);
1122:
1123: // Add the <code>PropertySource</code> to the helper object.
1124: properties.addProperties(thePropertySource);
1125: }
1126: }
1127:
1128: /**
1129: * Resets the <code>PropertySource</code>. If the parameter is
1130: * <code>true</code> then the property environment is completely
1131: * reset; if <code>false</code> then only cached properties are
1132: * cleared, i.e., those which were derived from the property
1133: * environment and are now stored in the local cache.
1134: *
1135: * @since JAI 1.1
1136: */
1137: protected synchronized void resetProperties(
1138: boolean resetPropertySource) {
1139: properties.clearCachedProperties();
1140: if (resetPropertySource && thePropertySource != null) {
1141: properties.removePropertySource(thePropertySource);
1142: thePropertySource = null;
1143: }
1144: }
1145:
1146: /**
1147: * Returns the names of properties available from this node.
1148: * These properties are a combination of those derived
1149: * from prior nodes in the operation chain and those set locally.
1150: *
1151: * @return An array of <code>String</code>s containing valid
1152: * property names or <code>null</code> if there are none.
1153: *
1154: * @since JAI 1.1
1155: */
1156: public synchronized String[] getPropertyNames() {
1157: createPropertySource();
1158: return properties.getPropertyNames();
1159: }
1160:
1161: /**
1162: * Returns the class expected to be returned by a request for
1163: * the property with the specified name. If this information
1164: * is unavailable, <code>null</code> will be returned.
1165: *
1166: * @return The <code>Class</code> expected to be return by a
1167: * request for the value of this property or <code>null</code>.
1168: * @exception IllegalArgumentException if <code>name</code>
1169: * is <code>null</code>.
1170: *
1171: * @since JAI 1.1
1172: */
1173: public Class getPropertyClass(String name) {
1174: createPropertySource();
1175: return properties.getPropertyClass(name);
1176: }
1177:
1178: /**
1179: * Gets a property from the property set of this <code>Collection</code>.
1180: * If the property name is not recognized,
1181: * <code>java.awt.Image.UndefinedProperty</code> will be returned.
1182: *
1183: * @param name the name of the property to get, as a String.
1184: * @return a reference to the property Object, or the value
1185: * java.awt.Image.UndefinedProperty.
1186: * @exception IllegalArgumentException if <code>name</code>
1187: * is <code>null</code>.
1188: *
1189: * @since JAI 1.1
1190: */
1191: public Object getProperty(String name) {
1192: createPropertySource();
1193: return properties.getProperty(name);
1194: }
1195:
1196: /**
1197: * Sets a local property on a node. Local property settings override
1198: * properties derived from prior nodes in the operation chain.
1199: *
1200: * @param name a String representing the property name.
1201: * @param value the property's value, as an Object.
1202: * @exception IllegalArgumentException if <code>name</code>
1203: * or <code>value</code>
1204: * is <code>null</code>.
1205: *
1206: * @since JAI 1.1
1207: */
1208: public void setProperty(String name, Object value) {
1209: createPropertySource();
1210: properties.setProperty(name, value);
1211: }
1212:
1213: /**
1214: * Removes the named property from the local property
1215: * set of the <code>CollectionOp</code> as well as from its property
1216: * environment.
1217: *
1218: * @exception IllegalArgumentException if <code>name</code>
1219: * is <code>null</code>.
1220: *
1221: * @since JAI 1.1
1222: */
1223: public void removeProperty(String name) {
1224: createPropertySource();
1225: properties.removeProperty(name);
1226: }
1227:
1228: /**
1229: * Returns the property associated with the specified property name,
1230: * or <code>java.awt.Image.UndefinedProperty</code> if the specified
1231: * property is not set on the image. This method is dynamic in the
1232: * sense that subsequent invocations of this method on the same object
1233: * may return different values as a function of changes in the property
1234: * environment of the node, e.g., a change in which
1235: * <code>PropertyGenerator</code>s are registered or in the values
1236: * associated with properties of node sources. The case of the property
1237: * name passed to this method is ignored.
1238: *
1239: * @param name A <code>String</code> naming the property.
1240: *
1241: * @throws IllegalArgumentException if
1242: * <code>name</code> is <code>null</code>.
1243: *
1244: * @since JAI 1.1
1245: */
1246: public synchronized Object getDynamicProperty(String name) {
1247: createPropertySource();
1248: return thePropertySource.getProperty(name);
1249: }
1250:
1251: /**
1252: * Adds a PropertyGenerator to the node. The property values
1253: * emitted by this property generator override any previous
1254: * definitions.
1255: *
1256: * @param pg a PropertyGenerator to be added to this node's
1257: * property environment.
1258: *
1259: * @since JAI 1.1
1260: */
1261: public void addPropertyGenerator(PropertyGenerator pg) {
1262: nodeSupport.addPropertyGenerator(pg);
1263: }
1264:
1265: /**
1266: * Forces a property to be copied from the specified source node.
1267: * By default, a property is copied from the first source node
1268: * that emits it. The result of specifying an invalid source is
1269: * undefined.
1270: *
1271: * @param propertyName the name of the property to be copied.
1272: * @param sourceIndex the index of the from which to copy the property.
1273: * @throws IllegalArgumentException if <code>propertyName</code> is
1274: * <code>null</code>.
1275: *
1276: * @since JAI 1.1
1277: */
1278: public synchronized void copyPropertyFromSource(
1279: String propertyName, int sourceIndex) {
1280: nodeSupport.copyPropertyFromSource(propertyName, sourceIndex);
1281: }
1282:
1283: /**
1284: * Removes a named property from the property environment of this
1285: * node. Unless the property is stored locally either due
1286: * to having been set explicitly via <code>setProperty()</code>
1287: * or to having been cached for property
1288: * synchronization purposes, subsequent calls to
1289: * <code>getProperty(name)</code> will return
1290: * <code>java.awt.Image.UndefinedProperty</code>, and <code>name</code>
1291: * will not appear on the list of properties emitted by
1292: * <code>getPropertyNames()</code>. To delete the property from the
1293: * local property set of the node, <code>removeProperty()</code> should
1294: * be used.
1295: *
1296: * @param name a String naming the property to be suppressed.
1297: * @throws <code>IllegalArgumentException</code> if
1298: * <code>name</code> is <code>null</code>.
1299: *
1300: * @since JAI 1.1
1301: */
1302: public void suppressProperty(String name) {
1303: nodeSupport.suppressProperty(name);
1304: }
1305:
1306: /*****************************************************************
1307: * The following methods override public or protected methods in *
1308: * CollectionImage thus causing the Collection to be created. *
1309: *****************************************************************/
1310:
1311: /**
1312: * Creates the <code>Collection</code> rendering if none yet exists, and
1313: * returns the number of elements in this <code>Collection</code>.
1314: */
1315: public int size() {
1316: createCollection();
1317: return imageCollection.size();
1318: }
1319:
1320: /**
1321: * Creates the <code>Collection</code> rendering if none yet exists, and
1322: * returns <code>true</code> if this <code>Collection</code> contains
1323: * no element.
1324: */
1325: public boolean isEmpty() {
1326: createCollection();
1327: return imageCollection.isEmpty();
1328: }
1329:
1330: /**
1331: * Creates the <code>Collection</code> rendering if none yet exists, and
1332: * returns <code>true</code> if this <code>Collection</code> contains
1333: * the specified object.
1334: */
1335: public boolean contains(Object o) {
1336: createCollection();
1337: return imageCollection.contains(o);
1338: }
1339:
1340: /**
1341: * Creates the <code>Collection</code> rendering if none yet exists, and
1342: * returns an <code>Iterator</code> over the elements in this
1343: * <code>Collection</code>.
1344: */
1345: public Iterator iterator() {
1346: createCollection();
1347: return imageCollection.iterator();
1348: }
1349:
1350: /**
1351: * Creates the <code>Collection</code> rendering if none yet exists, and
1352: * returns an array containing all of the elements in this
1353: * <code>Collection</code>.
1354: */
1355: public Object[] toArray() {
1356: createCollection();
1357: return imageCollection.toArray();
1358: }
1359:
1360: /**
1361: * Creates the <code>Collection</code> rendering if none yet exists, and
1362: * returns an array containing all of the elements in this
1363: * <code>Collection</code> whose runtime type is that of the specified
1364: * array.
1365: *
1366: * @throws <code>ArrayStoreException</code> if the runtime type of the
1367: * specified array is not a supertype of the runtime type of
1368: * every element in this <code>Collection</code>.
1369: */
1370: public Object[] toArray(Object[] a) {
1371: createCollection();
1372: return imageCollection.toArray(a);
1373: }
1374:
1375: /**
1376: * Creates the <code>Collection</code> rendering if none yet exists, and
1377: * adds the specified object to this <code>Collection</code>.
1378: */
1379: public boolean add(Object o) {
1380: createCollection();
1381: return imageCollection.add(o);
1382: }
1383:
1384: /**
1385: * Creates the <code>Collection</code> rendering if none yet exists, and
1386: * removes the specified object from this <code>Collection</code>.
1387: */
1388: public boolean remove(Object o) {
1389: createCollection();
1390: return imageCollection.remove(o);
1391: }
1392:
1393: /**
1394: * Creates the <code>Collection</code> rendering if none yet exists, and
1395: * returns <code>true</code> if this <code>Collection</code> contains
1396: * all of the elements in the specified <code>Collection</code>.
1397: */
1398: public boolean containsAll(Collection c) {
1399: createCollection();
1400: return imageCollection.containsAll(c);
1401: }
1402:
1403: /**
1404: * Creates the <code>Collection</code> rendering if none yet exists, and
1405: * adds all of the elements in the specified <code>Collection</code>
1406: * to this <code>Collection</code>.
1407: */
1408: public boolean addAll(Collection c) {
1409: createCollection();
1410: return imageCollection.addAll(c);
1411: }
1412:
1413: /**
1414: * Creates the <code>Collection</code> rendering if none yet exists, and
1415: * removes all this <code>Collection</code>'s elements that are also
1416: * contained in the specified <code>Collection</code>.
1417: */
1418: public boolean removeAll(Collection c) {
1419: createCollection();
1420: return imageCollection.removeAll(c);
1421: }
1422:
1423: /**
1424: * Creates the <code>Collection</code> rendering if none yet exists, and
1425: * retains only the elements in this <code>Collection</code> that are
1426: * contained in the specified <code>Collection</code>.
1427: */
1428: public boolean retainAll(Collection c) {
1429: createCollection();
1430: return imageCollection.retainAll(c);
1431: }
1432:
1433: /**
1434: * Creates the <code>Collection</code> rendering if none yet exists, and
1435: * removes all of the elements from this <code>Collection</code>.
1436: */
1437: public void clear() {
1438: createCollection();
1439: imageCollection.clear();
1440: }
1441: }
|