001: /*
002: * $RCSfile: PropertyEnvironment.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:16 $
010: * $State: Exp $
011: */
012: package javax.media.jai;
013:
014: import com.sun.media.jai.util.CaselessStringKeyHashtable;
015: import com.sun.media.jai.util.PropertyUtil;
016: import java.awt.Rectangle;
017: import java.util.Enumeration;
018: import java.util.Hashtable;
019: import java.util.Iterator;
020: import java.util.Vector;
021: import javax.media.jai.util.CaselessStringKey;
022:
023: /**
024: * A class that implements the <code>PropertySource</code> interface.
025: * Property names are treated in a case-insensitive manner.
026: *
027: *
028: * @since JAI 1.1
029: */
030: // In JAI 1.0.2 this class was namex javax.media.jai.PropertySourceImpl
031: // and was package scope (as it is now).
032: class PropertyEnvironment implements PropertySource {
033:
034: /** The local PropertyGenerators of this PropertyEnvironment. */
035: Vector pg;
036:
037: /**
038: * The sources of the associated node. The elements should
039: * be PropertySources.
040: */
041: Vector sources;
042:
043: // Dummy value to associate with a key in "suppressed"
044: private static final Object PRESENT = new Object();
045:
046: /** The names of suppressed properties. */
047: CaselessStringKeyHashtable suppressed;
048:
049: /**
050: * Sources of properties of this node. The keys are property names
051: * and the values are Integers which should be indexes into the Vector
052: * of sources.
053: */
054: CaselessStringKeyHashtable sourceForProp;
055:
056: /**
057: * The associated node, which is either a RenderedOp or a RenderableOp.
058: */
059: private Object op;
060:
061: /**
062: * Hash of property names. Values are either PropertyGenerators,
063: * PropertySources, or Integers.
064: */
065: private CaselessStringKeyHashtable propNames;
066:
067: /**
068: * Locally added default PropertySource which will override the default
069: * property inheritance mechanism, viz., inheritance from the lowest
070: * indexed source if no other means was specified.
071: */
072: private PropertySource defaultPropertySource = null;
073:
074: /**
075: * Flag which is set to indicate that the default PropertySource
076: * has not yet been mapped into the property name table. Initially
077: * true as there is nothing to map.
078: */
079: private boolean areDefaultsMapped = true;
080:
081: /**
082: * Constructs a <code>PropertyEnvironment</code>
083: *
084: * @param sources <code>PropertySource</code>s in operation source order.
085: * @param generators <code>PropertyGenerator</code>s.
086: * @param suppressed Names of suppressed properties.
087: * @param sourceForProp Hash by property name of indexes of
088: * <code>PropertySource</code>s in <code>sources</code> from
089: * which to derive properties.
090: * @param op The operation node.
091: */
092: public PropertyEnvironment(Vector sources, Vector generators,
093: Vector suppressed, Hashtable sourceForProp, Object op) {
094: this .sources = sources;
095: this .pg = generators == null ? null : (Vector) generators
096: .clone();
097:
098: // "suppressed" should never be null
099: this .suppressed = new CaselessStringKeyHashtable();
100:
101: if (suppressed != null) {
102: Enumeration e = suppressed.elements();
103:
104: while (e.hasMoreElements()) {
105: this .suppressed.put(e.nextElement(), PRESENT);
106: }
107: }
108:
109: this .sourceForProp = (sourceForProp == null) ? null
110: : new CaselessStringKeyHashtable(sourceForProp);
111:
112: this .op = op;
113:
114: hashNames();
115: }
116:
117: /**
118: * Returns an array of Strings recognized as names by this
119: * property source.
120: *
121: * @return an array of Strings giving the valid property names.
122: */
123: public String[] getPropertyNames() {
124: mapDefaults();
125:
126: int count = 0;
127: String names[] = new String[propNames.size()];
128: for (Enumeration e = propNames.keys(); e.hasMoreElements();) {
129: names[count++] = ((CaselessStringKey) e.nextElement())
130: .getName();
131: }
132:
133: return names;
134: }
135:
136: /**
137: * Returns an array of <code>String</code>s recognized as names by
138: * this property source that begin with the supplied prefix. If
139: * no property names match, <code>null</code> will be returned.
140: * The comparison is done in a case-independent manner.
141: *
142: * <p> The default implementation calls <code>getPropertyNames()</code>
143: * and searches the list of names for matches.
144: *
145: * @return an array of <code>String</code>s giving the valid
146: * property names.
147: */
148: public String[] getPropertyNames(String prefix) {
149: // This gives us a list of all non-suppressed properties
150: String[] propertyNames = getPropertyNames();
151: return PropertyUtil.getPropertyNames(propertyNames, prefix);
152: }
153:
154: /**
155: * Returns the class expected to be returned by a request for
156: * the property with the specified name. If this information
157: * is unavailable, <code>null</code> will be returned.
158: *
159: * <p> This implemention returns <code>null</code> to avoid
160: * provoking deferred calculations.
161: *
162: * @return The <code>Class</code> expected to be return by a
163: * request for the value of this property or <code>null</code>.
164: */
165: public Class getPropertyClass(String propertyName) {
166: if (propertyName == null) {
167: throw new IllegalArgumentException(JaiI18N
168: .getString("Generic0"));
169: }
170: return null;
171: }
172:
173: /**
174: * Returns the value of a property.
175: *
176: * @param name the name of the property, as a String.
177: * @return the value of the property, as an Object.
178: */
179: public Object getProperty(String name) {
180: if (name == null) {
181: throw new IllegalArgumentException(JaiI18N
182: .getString("Generic0"));
183: }
184:
185: mapDefaults();
186:
187: Object o = propNames.get(name);
188:
189: Object property = null;
190: if (o == null) {
191: return java.awt.Image.UndefinedProperty;
192: } else if (o instanceof PropertyGenerator) {
193: property = ((PropertyGenerator) o).getProperty(name, op);
194: } else if (o instanceof Integer) { // copy from source
195: int srcIndex = ((Integer) o).intValue();
196: PropertySource src = (PropertySource) sources
197: .elementAt(srcIndex);
198: property = src.getProperty(name);
199: } else if (o instanceof PropertySource) {
200: property = ((PropertySource) o).getProperty(name);
201: }
202:
203: return property;
204: }
205:
206: /** ---- Methods to modify the local property environment. ---- */
207:
208: public void copyPropertyFromSource(String propertyName,
209: int sourceIndex) {
210: PropertySource propertySource = (PropertySource) sources
211: .elementAt(sourceIndex);
212: propNames.put(propertyName, propertySource);
213: suppressed.remove(propertyName);
214: }
215:
216: public void suppressProperty(String propertyName) {
217: suppressed.put(propertyName, PRESENT);
218: hashNames();
219: }
220:
221: public void addPropertyGenerator(PropertyGenerator generator) {
222: if (pg == null) {
223: pg = new Vector();
224: }
225: pg.addElement(generator);
226:
227: // Remove suppressed status of any property being generated by
228: // this PropertyGenerator
229: removeSuppressedProps(generator);
230: hashNames();
231: }
232:
233: /**
234: * Sets a PropertySource from which to derive all non-suppressed
235: * properties emitted by the PropertySource if and only if neither
236: * a PropertyGenerator nor a copy-from-source directive exists
237: * for the requested property. This PropertySource will supersede
238: * automatic inheritance from any (operation) sources. It should
239: * be used, for example, when a rendered node wishes to derive
240: * property values from its rendering without overriding any user
241: * configuration settings in the property environment of the node.
242: */
243: public void setDefaultPropertySource(PropertySource ps) {
244: // If no change just return.
245: if (ps == defaultPropertySource) {
246: return;
247: }
248:
249: if (defaultPropertySource != null) {
250: // Return the table to zero state if defaults existed before.
251: hashNames();
252: }
253:
254: // Unset the flag.
255: areDefaultsMapped = false;
256:
257: // Cache the parameter.
258: defaultPropertySource = ps;
259: }
260:
261: /**
262: * Updates "propNames" hash with the default PropertySource. This
263: * method allows deferred access to the default PropertySource so
264: * as to postpone calculations which access thereto might incur.
265: * Does nothing unless the default PropertySource has changed.
266: */
267: private void mapDefaults() {
268: if (!areDefaultsMapped) {
269: // Set the flag.
270: areDefaultsMapped = true;
271:
272: // Update with default PropertySource only if non-null.
273: if (defaultPropertySource != null) {
274: String[] names = defaultPropertySource
275: .getPropertyNames();
276: if (names != null) {
277: int length = names.length;
278: for (int i = 0; i < length; i++) {
279: if (!suppressed.containsKey(names[i])) {
280: Object o = propNames.get(names[i]);
281: if (o == null || // undefined property
282: o instanceof Integer) { // default inheritance
283: // Add "defaultPropertySource" or
284: // replace default inheritance.
285: propNames.put(names[i],
286: defaultPropertySource);
287: }
288: }
289: }
290: }
291: }
292: }
293: }
294:
295: private void removeSuppressedProps(PropertyGenerator generator) {
296: String names[] = generator.getPropertyNames();
297: for (int i = 0; i < names.length; i++) {
298: suppressed.remove(names[i]);
299: }
300: }
301:
302: private void hashNames() {
303: propNames = new CaselessStringKeyHashtable();
304:
305: // Copy properties from sources. This is the default behavior if no
306: // other property source is specified. The sources are represented
307: // via Integer values in propNames.
308: if (sources != null) {
309: // Then get property names from each source
310: for (int i = sources.size() - 1; i >= 0; i--) {
311: Object o = sources.elementAt(i);
312:
313: if (o instanceof PropertySource) {
314: PropertySource source = (PropertySource) o;
315: String[] propertyNames = source.getPropertyNames();
316:
317: if (propertyNames != null) {
318: for (int j = 0; j < propertyNames.length; j++) {
319: String name = propertyNames[j];
320: if (!suppressed.containsKey(name)) {
321: propNames.put(name, new Integer(i));
322: }
323: }
324: }
325: }
326: }
327: }
328:
329: // Get non-suppressed properties from PropertyGenerators.
330: // The propNames values are PropertyGenerator instances.
331: if (pg != null) {
332: PropertyGenerator generator;
333:
334: for (Iterator it = pg.iterator(); it.hasNext();) {
335: generator = (PropertyGenerator) it.next();
336: if (generator.canGenerateProperties(op)) {
337: String[] propertyNames = generator
338: .getPropertyNames();
339: if (propertyNames != null) {
340: for (int i = 0; i < propertyNames.length; i++) {
341: String name = propertyNames[i];
342: if (!suppressed.containsKey(name)) {
343: propNames.put(name, generator);
344: }
345: }
346: }
347: }
348: }
349: }
350:
351: // Lastly, honor all the copyPropertyFromSource directives
352: // The propNames values are PropertySource instances.
353: if (sourceForProp != null) {
354: for (Enumeration e = sourceForProp.keys(); e
355: .hasMoreElements();) {
356: CaselessStringKey name = (CaselessStringKey) e
357: .nextElement();
358:
359: if (!suppressed.containsKey(name)) {
360: Integer i = (Integer) sourceForProp.get(name);
361: PropertySource propertySource = (PropertySource) sources
362: .elementAt(i.intValue());
363: propNames.put(name, propertySource);
364: }
365: }
366: }
367:
368: // Unset the default mapping flag.
369: areDefaultsMapped = false;
370: }
371: }
|