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.pd;
031:
032: import java.util.ArrayList;
033: import java.util.Iterator;
034: import java.util.List;
035: import de.intarsys.pdf.content.CSContent;
036: import de.intarsys.pdf.cos.COSInteger;
037: import de.intarsys.pdf.cos.COSName;
038: import de.intarsys.pdf.cos.COSObject;
039: import de.intarsys.pdf.cos.COSString;
040: import de.intarsys.pdf.font.PDFont;
041:
042: /**
043: * Abstract superclass to factor out commons between AcroForm and AcroForm
044: * field.
045: *
046: */
047: abstract public class PDAcroFormNode extends PDObject {
048: /**
049: * The meta class implementation
050: */
051: static public class MetaClass extends PDObject.MetaClass {
052: protected MetaClass(Class instanceClass) {
053: super (instanceClass);
054: }
055:
056: public Class getRootClass() {
057: return PDAcroFormNode.class;
058: }
059: }
060:
061: /** The name for the Encoding. */
062: static public final COSName DK_Encoding = COSName
063: .constant("Encoding");
064:
065: /** The name for the default resources. */
066: static public final COSName DK_DR = COSName.constant("DR");
067:
068: /** The name for the fonts. */
069: static public final COSName DK_Font = COSName.constant("Font");
070:
071: /** The name for the DefaultAppereance entry. */
072: static public final COSName DK_DA = COSName.constant("DA");
073:
074: /** The name for the Quadding entry. */
075: static public final COSName DK_Q = COSName.constant("Q");
076:
077: /** The meta class instance */
078: static public final MetaClass META = new MetaClass(MetaClass.class
079: .getDeclaringClass());
080:
081: /**
082: * Create a canonical form of the field name.
083: *
084: * @param name
085: * The field name to be converted.
086: * @return The canonical for of the field name.
087: */
088: static public String canonicalize(String name) {
089: return name.toLowerCase();
090: }
091:
092: private CSContent defaultAppearanceContent;
093:
094: private DefaultAppearance defaultAppearance;
095:
096: protected PDAcroFormNode(COSObject object) {
097: super (object);
098: }
099:
100: /**
101: * Insert a {@link PDAcroFormField} in the receiver node.
102: *
103: * @param field
104: * The field to be inserted.
105: */
106: abstract public void addField(PDAcroFormField field);
107:
108: /**
109: * Remove a {@link PDAcroFormField} from the receiver.
110: *
111: * @param field
112: * The field to remove.
113: * @return <code>true</code> if <code>field</code> was removed.
114: */
115: abstract public boolean removeField(PDAcroFormField field);
116:
117: protected PDAcroFormField basicGetField(String name,
118: boolean canonical) {
119: List children = getGenericChildren();
120: if ((children == null) || (name == null)) {
121: return null;
122: }
123: String childName = null;
124: String childPath = null;
125: int separatorIndex = name.indexOf('.');
126: if (separatorIndex < 0) {
127: childName = name;
128: } else {
129: childName = name.substring(0, separatorIndex);
130: childPath = name.substring(separatorIndex + 1);
131: }
132: for (Iterator i = children.iterator(); i.hasNext();) {
133: PDAcroFormField field = (PDAcroFormField) i.next();
134: String fieldName = field.getLocalName(canonical);
135: if (childName.equals(fieldName)) {
136: if (childPath == null) {
137: return field;
138: } else {
139: return field.basicGetField(childPath, canonical);
140: }
141: } else if (fieldName == null) {
142: // must descend when /T is undefined ?
143: PDAcroFormField child = field.basicGetField(name,
144: canonical);
145: if (child != null) {
146: return child;
147: }
148: }
149: }
150: return null;
151: }
152:
153: protected List collectLeafFields(List result) {
154: for (Iterator i = getGenericChildren().iterator(); i.hasNext();) {
155: PDAcroFormField child = (PDAcroFormField) i.next();
156: child.collectLeafFields(result);
157: }
158: return result;
159: }
160:
161: /**
162: * The {@link PDAcroForm} for this node.
163: *
164: * @return The {@link PDAcroForm} for this node.
165: */
166: abstract public PDAcroForm getAcroForm();
167:
168: /**
169: * Get an annotation from the tree beyond <code>this</code> identified by
170: * <code>index</code>.
171: *
172: * @return An annotation from the tree beyond <code>this</code> identified
173: * by <code>index</code>.
174: */
175: public PDAnnotation getAnnotation(int index) {
176: return (PDAnnotation) getAnnotations().get(index);
177: }
178:
179: /**
180: * A list of all annotations in the tree beyond <code>this</code>.
181: *
182: * @return A list of all annotations in the tree beyond <code>this</code>.
183: */
184: public List getAnnotations() {
185: // todo 2 caching?
186: return getAnnotations(new ArrayList());
187: }
188:
189: /**
190: * Recursively collect all annotations in the tree beyond <code>this</code>.
191: *
192: * @param annotations
193: * The annotations collected so far.
194: *
195: * @return The enhanced list of annotations for this subtree.
196: */
197: protected List getAnnotations(List annotations) {
198: for (Iterator i = getGenericChildren().iterator(); i.hasNext();) {
199: PDAcroFormNode kid = (PDAcroFormNode) i.next();
200: kid.getAnnotations(annotations);
201: }
202: return annotations;
203: }
204:
205: protected DefaultAppearance getDefaultAppearance() {
206: if (defaultAppearance == null) {
207: defaultAppearance = new DefaultAppearance(this );
208: }
209: return defaultAppearance;
210: }
211:
212: /**
213: * The {@link CSContent} fragment defining the default appearance to be used
214: * for variable text fields.
215: *
216: * @return The {@link CSContent} fragment defining the default appearance to
217: * be used for variable text fields.
218: */
219: public CSContent getDefaultAppearanceContent() {
220: if (defaultAppearanceContent == null) {
221: COSString cosObject = cosGetFieldInheritable(DK_DA)
222: .asString();
223: if (cosObject != null) {
224: defaultAppearanceContent = CSContent
225: .createFromBytes(cosObject.byteValue());
226: }
227: }
228: return defaultAppearanceContent;
229: }
230:
231: /**
232: * The font object defined by the default appearance.
233: *
234: * @return The font object defined by the default appearance.
235: */
236: public PDFont getDefaultAppearanceFont() {
237: return getDefaultAppearance().getFont();
238: }
239:
240: /**
241: * The font color defined by the default appearance.
242: *
243: * @return The font color defined by the default appearance.
244: */
245: public float[] getDefaultAppearanceFontColor() {
246: return getDefaultAppearance().getFontColorValues();
247: }
248:
249: /**
250: * The font name used by the default appearance to select a font from the
251: * resources.
252: *
253: * @return The font name used by the default appearance to select a font
254: * from the resources.
255: */
256: public COSName getDefaultAppearanceFontName() {
257: return getDefaultAppearance().getFontName();
258: }
259:
260: /**
261: * The font size defined by the default appearance,
262: *
263: * @return The font size defined by the default appearance,
264: */
265: public float getDefaultAppearanceFontSize() {
266: return getDefaultAppearance().getFontSize();
267: }
268:
269: /**
270: * The sub-node identified by <code>path</code>. The <code>path</code>
271: * may be a navigation path containing multiple segments separated by a ".",
272: * each segment identifying a sub node in the node found so far.
273: * <p>
274: * The navigation starts at this and the first path segment is matched
275: * against the node's children. Example:<br>
276: *
277: * <code>
278: * AcroForm
279: * |
280: * + Field1
281: * |
282: * + Group1
283: * |
284: * + FieldA
285: * |
286: * + FieldB
287: *
288: * When requesting the form itself, Field1 is addressed
289: *
290: * form.getField("Field1");
291: *
292: * FieldA can be looked up
293: *
294: * form.getField("Group1.FieldA");
295: *
296: * or
297: *
298: * group = form.getField("Group1");
299: * group.getField("FieldA");
300: * </code>
301: *
302: * @param path
303: * The navigation path to the field.
304: * @return The sub-node identified by <code>path</code>.
305: */
306: public PDAcroFormField getField(String path) {
307: return getField(path, false);
308: }
309:
310: /**
311: * The sub-node identified by <code>path</code>. The <code>path</code>
312: * may be a navigation path containing multiple segments separated by a ".",
313: * each segment identifying a sub node in the node found so far. If
314: * <code>canonicalName</code> is <code>true</code>, the name will be
315: * transformed to a canonical format before lookup.
316: *
317: * @param name
318: * The navigation path to the field.
319: * @param canonicalName
320: * Flag if lookup uses canonical form.
321: * @return The sub-node identified by <code>path</code>
322: */
323: public PDAcroFormField getField(String name, boolean canonicalName) {
324: String basicname = canonicalName ? canonicalize(name) : name;
325: return basicGetField(basicname, canonicalName);
326: }
327:
328: /**
329: * The list of all final nodes (fields) within this node.
330: *
331: * @return The list of all final nodes (fields) within this node.
332: */
333: public List collectLeafFields() {
334: return collectLeafFields(new ArrayList());
335: }
336:
337: /**
338: * The justification of variable text within the field.
339: * <ul>
340: * <li>0</li>
341: * left (default)
342: * <li>1</li>
343: * centered
344: * <li>2</li>
345: * right
346: * </ul>
347: *
348: * @return An int representing the intended quadding for this field
349: */
350: public int getQuadding() {
351: COSInteger cosObject = cosGetFieldInheritable(DK_Q).asInteger();
352: if (cosObject == null) {
353: return 0;
354: }
355: return cosObject.intValue();
356: }
357:
358: /*
359: * (non-Javadoc)
360: *
361: * @see de.intarsys.pdf.cos.COSBasedObject#invalidateCaches()
362: */
363: public void invalidateCaches() {
364: super .invalidateCaches();
365: defaultAppearanceContent = null;
366: defaultAppearance = null;
367: }
368:
369: protected void setDefaultAppearance(
370: DefaultAppearance defaultAppearanceParser) {
371: this .defaultAppearance = defaultAppearanceParser;
372: }
373:
374: /**
375: * Set the content stream fragment to be used as the default appearance with
376: * variable text fields.
377: *
378: * @param pContent
379: * The new default appearance content.
380: */
381: public void setDefaultAppearanceContent(CSContent pContent) {
382: if (pContent != null) {
383: cosSetField(DK_DA, COSString.create(pContent.toByteArray()));
384: } else {
385: cosRemoveField(DK_DA);
386: }
387: }
388:
389: /**
390: * Set the font to be used as the default font in variable text fields.
391: *
392: * @param font
393: * The font to be used as the default font in variable text
394: * fields.
395: */
396: public void setDefaultAppearanceFont(PDFont font) {
397: getDefaultAppearance().setFont(font);
398: }
399:
400: /**
401: * Set the font color to be used as the default font color in variable text
402: * fields.
403: *
404: * @param color
405: * The font color to be used as the default font color in
406: * variable text fields.
407: */
408: public void setDefaultAppearanceFontColor(float[] color) {
409: getDefaultAppearance().setFontColorValues(color);
410: }
411:
412: /**
413: * Set the font size to be used as the default font size in variable text
414: * fields.
415: *
416: * @param size
417: * The font size to be used as the default font size in variable
418: * text fields.
419: */
420: public void setDefaultAppearanceFontSize(float size) {
421: getDefaultAppearance().setFontSize(size);
422: }
423:
424: /**
425: * Set the justification of variable text within the field.
426: *
427: * @param quadding
428: * THe new quadding value
429: */
430: public void setQuadding(int quadding) {
431: cosSetFieldInheritable(DK_Q, COSInteger.create(quadding));
432: }
433: }
|