001: /*
002: * Copyright (c) 2007, intarsys consulting GmbH
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * - Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * - Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * - Neither the name of intarsys nor the names of its contributors may be used
015: * to endorse or promote products derived from this software without specific
016: * prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
022: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
028: * POSSIBILITY OF SUCH DAMAGE.
029: */
030: package de.intarsys.pdf.cos;
031:
032: import java.util.ArrayList;
033: import java.util.HashMap;
034: import java.util.Iterator;
035: import java.util.List;
036: import java.util.Map;
037: import de.intarsys.tools.attribute.IAttributeSupport;
038:
039: /**
040: * A superclass implementation for all containers of other {@link COSObject}
041: * instances.
042: *
043: */
044: abstract public class COSCompositeObject extends COSObject implements
045: ICOSContainer, IAttributeSupport {
046: /**
047: * Generic attribute support
048: */
049: private Map attributes;
050:
051: /**
052: * Collection of listeners to object changes
053: */
054: protected List objectListeners;
055:
056: protected COSCompositeObject() {
057: super ();
058: }
059:
060: /**
061: * Copy constructor for creating save state.
062: *
063: * @param object
064: * The original object.
065: */
066: protected COSCompositeObject(COSObject object) {
067: super (object);
068: }
069:
070: /*
071: * (non-Javadoc)
072: *
073: * @see de.intarsys.tools.attribute.IAttributeSupport#setAttribute(java.lang.Object,
074: * java.lang.Object)
075: */
076: synchronized public Object setAttribute(Object key, Object value) {
077: if (attributes == null) {
078: attributes = new HashMap();
079: }
080: return attributes.put(key, value);
081: }
082:
083: /**
084: * Change the reference to the object contained in this to an indirect one
085: * via reference.
086: *
087: * <p>
088: * This method must be redefined by all containers to reflect the new
089: * reference type in their child references.
090: * </p>
091: *
092: * <p>
093: * This event is delegated to the document to create the correct state for a
094: * new indirect object. If a document is not yet present, the state is
095: * changed when the COSObject (s) are added to the document finally. This
096: * can happen when constructing a COSObject graph "offline" and later add it
097: * to the document.
098: * </p>
099: *
100: * <p>
101: * From the COS invariants you can be sure that the object referenced by ref
102: * is contained in this at most once
103: * </p>
104: *
105: * @param object
106: */
107: public COSIndirectObject referenceIndirect(COSObject object) {
108: return COSIndirectObject.create(object);
109: }
110:
111: /*
112: * (non-Javadoc)
113: *
114: * @see de.intarsys.pdf.cos.ICOSContainer#willChange(de.intarsys.pdf.cos.COSObject)
115: */
116: public void willChange(COSObject change) {
117: container.willChange(change);
118: }
119:
120: /*
121: * (non-Javadoc)
122: *
123: * @see de.intarsys.pdf.cos.COSObject#isPrimitive()
124: */
125: public boolean isPrimitive() {
126: return false;
127: }
128:
129: /*
130: * (non-Javadoc)
131: *
132: * @see de.intarsys.tools.component.IAttributeSupport#getAttribute(java.lang.Object)
133: */
134: synchronized public Object getAttribute(Object key) {
135: if (attributes == null) {
136: return null;
137: }
138: return attributes.get(key);
139: }
140:
141: /*
142: * (non-Javadoc)
143: *
144: * @see de.intarsys.tools.component.IAttributeSupport#removeAttribute(java.lang.Object)
145: */
146: synchronized public Object removeAttribute(Object key) {
147: if (attributes != null) {
148: attributes.remove(key);
149: }
150: return null;
151: }
152:
153: /*
154: * (non-Javadoc)
155: *
156: * @see de.intarsys.pdf.cos.COSObject#addObjectListener(de.intarsys.pdf.cos.ICOSObjectListener)
157: */
158: public void addObjectListener(ICOSObjectListener listener) {
159: List newListeners;
160: if (objectListeners == null) {
161: newListeners = new ArrayList();
162: } else {
163: newListeners = new ArrayList(objectListeners);
164: }
165: newListeners.add(listener);
166: objectListeners = newListeners;
167: }
168:
169: /* (non-Javadoc)
170: * @see de.intarsys.pdf.cos.COSObject#isObjectListenerAvailable()
171: */
172: public boolean isObjectListenerAvailable() {
173: if (objectListeners == null) {
174: return false;
175: } else {
176: return !objectListeners.isEmpty();
177: }
178: }
179:
180: /*
181: * (non-Javadoc)
182: *
183: * @see de.intarsys.pdf.cos.COSObject#removeObjectListener(de.intarsys.pdf.cos.ICOSObjectListener)
184: */
185: public void removeObjectListener(ICOSObjectListener listener) {
186: if (objectListeners == null) {
187: return;
188: }
189: List newListeners;
190: newListeners = new ArrayList(objectListeners);
191: newListeners.remove(listener);
192: objectListeners = newListeners;
193: }
194:
195: /*
196: * (non-Javadoc)
197: *
198: * @see de.intarsys.pdf.cos.ICOSContainer#associate(de.intarsys.pdf.cos.ICOSContainer,
199: * de.intarsys.pdf.cos.COSObject)
200: */
201: public ICOSContainer associate(ICOSContainer newContainer,
202: COSObject object) {
203: if (newContainer == this ) {
204: // error ?
205: return this ;
206: }
207:
208: // sorry, this is an error
209: throw new IllegalStateException(
210: "object may only be contained once (use indirect object)"); //$NON-NLS-1$
211: }
212:
213: /*
214: * (non-Javadoc)
215: *
216: * @see de.intarsys.pdf.cos.ICOSContainer#disassociate(de.intarsys.pdf.cos.ICOSContainer,
217: * de.intarsys.pdf.cos.COSObject)
218: */
219: public ICOSContainer disassociate(ICOSContainer oldContainer,
220: COSObject object) {
221: if (oldContainer == this ) {
222: // object removed from container
223: object.basicSetContainer(COSObject.NULL_CONTAINER);
224: return COSObject.NULL_CONTAINER;
225: }
226:
227: // sorry, this is an error
228: throw new IllegalStateException("association inconsistent"); //$NON-NLS-1$
229: }
230:
231: /*
232: * (non-Javadoc)
233: *
234: * @see de.intarsys.pdf.cos.ICOSContainer#containable(de.intarsys.pdf.cos.COSObject)
235: */
236: public COSDocumentElement containable(COSObject object) {
237: return object;
238: }
239:
240: /*
241: * (non-Javadoc)
242: *
243: * @see de.intarsys.pdf.cos.COSObject#copyDeep()
244: */
245: public final COSObject copyDeep() {
246: return copyDeep(new HashMap());
247: }
248:
249: /*
250: * (non-Javadoc)
251: *
252: * @see de.intarsys.pdf.cos.COSDocumentElement#copyDeep(java.util.Map)
253: */
254: public COSObject copyDeep(Map copied) {
255: COSObject result = copyBasic();
256: if (isIndirect()) {
257: result.beIndirect();
258: copied.put(getIndirectObject(), result);
259: }
260: return result;
261: }
262:
263: /*
264: * (non-Javadoc)
265: *
266: * @see de.intarsys.pdf.cos.ICOSContainer#register(de.intarsys.pdf.cos.COSObject)
267: */
268: public void register(COSDocumentElement object) {
269: COSDocument doc = getDoc();
270: if (doc != null) {
271: object.registerWith(doc);
272: }
273: }
274:
275: /*
276: * (non-Javadoc)
277: *
278: * @see de.intarsys.pdf.cos.COSObject#registerWith(de.intarsys.pdf.cos.COSDocument)
279: */
280: protected void registerWith(COSDocument doc) {
281: // register descendents
282: for (Iterator i = basicIterator(); i.hasNext();) {
283: COSDocumentElement element = (COSDocumentElement) i.next();
284: element.registerWith(doc);
285: }
286: }
287:
288: /*
289: * reference count from non indirect references is always 1
290: *
291: * @see de.intarsys.pdf.cos.ICOSContainer#referenceCount()
292: */
293: public int referenceCount() {
294: return 1;
295: }
296:
297: /*
298: * (non-Javadoc)
299: *
300: * @see de.intarsys.pdf.cos.ICOSContainer#saveStateContainer()
301: */
302: public ICOSContainer saveStateContainer() {
303: return this ;
304: }
305:
306: /*
307: * (non-Javadoc)
308: *
309: * @see de.intarsys.pdf.cos.ICOSContainer#restoreStateContainer(de.intarsys.pdf.cos.ICOSContainer)
310: */
311: public ICOSContainer restoreStateContainer(ICOSContainer pContainer) {
312: return pContainer;
313: }
314:
315: protected void triggerChanged(Object slot, Object oldValue,
316: Object newValue) {
317: if (objectListeners == null) {
318: return;
319: }
320: for (Iterator it = objectListeners.iterator(); it.hasNext();) {
321: ICOSObjectListener listener = (ICOSObjectListener) it
322: .next();
323: listener.changed(this, slot, oldValue, newValue);
324: }
325: }
326: }
|