001: /**
002: * Copyright (c) 2004, www.pdfbox.org
003: * All rights reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions are met:
007: *
008: * 1. Redistributions of source code must retain the above copyright notice,
009: * this list of conditions and the following disclaimer.
010: * 2. 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: * 3. Neither the name of pdfbox; nor the names of its
014: * contributors may be used to endorse or promote products derived from this
015: * software without specific prior written permission.
016: *
017: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
018: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
019: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
020: * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
021: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
022: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
023: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
024: * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
026: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027: *
028: * http://www.pdfbox.org
029: *
030: */package org.pdfbox.pdmodel.fdf;
031:
032: import java.io.IOException;
033: import java.io.Writer;
034:
035: import java.util.ArrayList;
036: import java.util.List;
037:
038: import org.pdfbox.cos.COSArray;
039: import org.pdfbox.cos.COSBase;
040: import org.pdfbox.cos.COSDictionary;
041: import org.pdfbox.cos.COSInteger;
042: import org.pdfbox.cos.COSName;
043: import org.pdfbox.cos.COSNumber;
044: import org.pdfbox.cos.COSStream;
045: import org.pdfbox.cos.COSString;
046:
047: import org.pdfbox.pdmodel.common.COSObjectable;
048: import org.pdfbox.pdmodel.common.COSArrayList;
049: import org.pdfbox.pdmodel.common.PDTextStream;
050:
051: import org.pdfbox.pdmodel.interactive.action.PDActionFactory;
052: import org.pdfbox.pdmodel.interactive.action.PDAdditionalActions;
053: import org.pdfbox.pdmodel.interactive.action.type.PDAction;
054:
055: import org.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary;
056:
057: import org.pdfbox.util.XMLUtil;
058:
059: import org.w3c.dom.Element;
060: import org.w3c.dom.Node;
061: import org.w3c.dom.NodeList;
062:
063: /**
064: * This represents an FDF field that is part of the FDF document.
065: *
066: * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
067: * @version $Revision: 1.5 $
068: */
069: public class FDFField implements COSObjectable {
070: private COSDictionary field;
071:
072: /**
073: * Default constructor.
074: */
075: public FDFField() {
076: field = new COSDictionary();
077: }
078:
079: /**
080: * Constructor.
081: *
082: * @param f The FDF field.
083: */
084: public FDFField(COSDictionary f) {
085: field = f;
086: }
087:
088: /**
089: * This will create an FDF field from an XFDF XML document.
090: *
091: * @param fieldXML The XML document that contains the XFDF data.
092: * @throws IOException If there is an error reading from the dom.
093: */
094: public FDFField(Element fieldXML) throws IOException {
095: this ();
096: this .setPartialFieldName(fieldXML.getAttribute("name"));
097: NodeList nodeList = fieldXML.getChildNodes();
098: List kids = new ArrayList();
099: for (int i = 0; i < nodeList.getLength(); i++) {
100: Node node = nodeList.item(i);
101: if (node instanceof Element) {
102: Element child = (Element) node;
103: if (child.getTagName().equals("value")) {
104: setValue(XMLUtil.getNodeValue(child));
105: } else if (child.getTagName().equals("value-richtext")) {
106: setRichText(new PDTextStream(XMLUtil
107: .getNodeValue(child)));
108: } else if (child.getTagName().equals("field")) {
109: kids.add(new FDFField(child));
110: }
111: }
112: }
113: if (kids.size() > 0) {
114: setKids(kids);
115: }
116:
117: }
118:
119: /**
120: * This will write this element as an XML document.
121: *
122: * @param output The stream to write the xml to.
123: *
124: * @throws IOException If there is an error writing the XML.
125: */
126: public void writeXML(Writer output) throws IOException {
127: output
128: .write("<field name=\"" + getPartialFieldName()
129: + "\">\n");
130: Object value = getValue();
131: if (value != null) {
132: output.write("<value>" + value + "</value>\n");
133: }
134: PDTextStream rt = getRichText();
135: if (rt != null) {
136: output.write("<value-richtext>" + rt.getAsString()
137: + "</value-richtext>\n");
138: }
139: List kids = getKids();
140: if (kids != null) {
141: for (int i = 0; i < kids.size(); i++) {
142: ((FDFField) kids.get(i)).writeXML(output);
143: }
144: }
145: output.write("</field>\n");
146: }
147:
148: /**
149: * Convert this standard java object to a COS object.
150: *
151: * @return The cos object that matches this Java object.
152: */
153: public COSBase getCOSObject() {
154: return field;
155: }
156:
157: /**
158: * Convert this standard java object to a COS object.
159: *
160: * @return The cos object that matches this Java object.
161: */
162: public COSDictionary getCOSDictionary() {
163: return field;
164: }
165:
166: /**
167: * This will get the list of kids. This will return a list of FDFField objects.
168: * This will return null if the underlying list is null.
169: *
170: * @return The list of kids.
171: */
172: public List getKids() {
173: COSArray kids = (COSArray) field.getDictionaryObject("Kids");
174: List retval = null;
175: if (kids != null) {
176: List actuals = new ArrayList();
177: for (int i = 0; i < kids.size(); i++) {
178: actuals.add(new FDFField((COSDictionary) kids
179: .getObject(i)));
180: }
181: retval = new COSArrayList(actuals, kids);
182: }
183: return retval;
184: }
185:
186: /**
187: * This will set the list of kids.
188: *
189: * @param kids A list of FDFField objects.
190: */
191: public void setKids(List kids) {
192: field.setItem("Kids", COSArrayList.converterToCOSArray(kids));
193: }
194:
195: /**
196: * This will get the "T" entry in the field dictionary. A partial field
197: * name. Where the fully qualified field name is a concatenation of
198: * the parent's fully qualified field name and "." as a separator. For example<br/>
199: * Address.State<br />
200: * Address.City<br />
201: *
202: * @return The partial field name.
203: */
204: public String getPartialFieldName() {
205: return field.getString("T");
206: }
207:
208: /**
209: * This will set the partial field name.
210: *
211: * @param partial The partial field name.
212: */
213: public void setPartialFieldName(String partial) {
214: field.setString("T", partial);
215: }
216:
217: /**
218: * This will set the value for the field. This will return type will either be <br />
219: * String : Checkboxes, Radio Button <br />
220: * java.util.List of strings: Choice Field
221: * PDTextStream: Textfields
222: *
223: * @return The value of the field.
224: *
225: * @throws IOException If there is an error getting the value.
226: */
227: public Object getValue() throws IOException {
228: Object retval = null;
229: COSBase value = field.getDictionaryObject("V");
230: if (value instanceof COSName) {
231: retval = ((COSName) value).getName();
232: } else if (value instanceof COSArray) {
233: retval = COSArrayList
234: .convertCOSStringCOSArrayToList((COSArray) value);
235: } else if (value instanceof COSString
236: || value instanceof COSStream) {
237: retval = PDTextStream.createTextStream(value);
238: } else if (value == null) {
239: //Ok, value is null so do nothing
240: } else {
241: throw new IOException("Error:Unknown type for field import"
242: + value);
243: }
244: return retval;
245: }
246:
247: /**
248: * You should pass in a string, or a java.util.List of strings to set the
249: * value.
250: *
251: * @param value The value that should populate when imported.
252: *
253: * @throws IOException If there is an error setting the value.
254: */
255: public void setValue(Object value) throws IOException {
256: COSBase cos = null;
257: if (value instanceof List) {
258: cos = COSArrayList
259: .convertStringListToCOSStringCOSArray((List) value);
260: } else if (value instanceof String) {
261: cos = COSName.getPDFName((String) value);
262: } else if (value instanceof COSObjectable) {
263: cos = ((COSObjectable) value).getCOSObject();
264: } else if (value == null) {
265: //do nothing and let cos remain null as well.
266: } else {
267: throw new IOException("Error:Unknown type for field import"
268: + value);
269: }
270: field.setItem("V", cos);
271: }
272:
273: /**
274: * This will get the Ff entry of the cos dictionary. If it it not present then
275: * this method will return null.
276: *
277: * @return The field flags.
278: */
279: public Integer getFieldFlags() {
280: Integer retval = null;
281: COSNumber ff = (COSNumber) field.getDictionaryObject("Ff");
282: if (ff != null) {
283: retval = new Integer(ff.intValue());
284: }
285: return retval;
286: }
287:
288: /**
289: * This will get the field flags that are associated with this field. The Ff entry
290: * in the FDF field dictionary.
291: *
292: * @param ff The new value for the field flags.
293: */
294: public void setFieldFlags(Integer ff) {
295: COSInteger value = null;
296: if (ff != null) {
297: value = new COSInteger(ff.intValue());
298: }
299: field.setItem("Ff", value);
300: }
301:
302: /**
303: * This will get the field flags that are associated with this field. The Ff entry
304: * in the FDF field dictionary.
305: *
306: * @param ff The new value for the field flags.
307: */
308: public void setFieldFlags(int ff) {
309: field.setItem("Ff", new COSInteger(ff));
310: }
311:
312: /**
313: * This will get the SetFf entry of the cos dictionary. If it it not present then
314: * this method will return null.
315: *
316: * @return The field flags.
317: */
318: public Integer getSetFieldFlags() {
319: Integer retval = null;
320: COSNumber ff = (COSNumber) field.getDictionaryObject("SetFf");
321: if (ff != null) {
322: retval = new Integer(ff.intValue());
323: }
324: return retval;
325: }
326:
327: /**
328: * This will get the field flags that are associated with this field. The SetFf entry
329: * in the FDF field dictionary.
330: *
331: * @param ff The new value for the "set field flags".
332: */
333: public void setSetFieldFlags(Integer ff) {
334: COSInteger value = null;
335: if (ff != null) {
336: value = new COSInteger(ff.intValue());
337: }
338: field.setItem("SetFf", value);
339: }
340:
341: /**
342: * This will get the field flags that are associated with this field. The SetFf entry
343: * in the FDF field dictionary.
344: *
345: * @param ff The new value for the "set field flags".
346: */
347: public void setSetFieldFlags(int ff) {
348: field.setItem("SetFf", new COSInteger(ff));
349: }
350:
351: /**
352: * This will get the ClrFf entry of the cos dictionary. If it it not present then
353: * this method will return null.
354: *
355: * @return The field flags.
356: */
357: public Integer getClearFieldFlags() {
358: Integer retval = null;
359: COSNumber ff = (COSNumber) field.getDictionaryObject("ClrFf");
360: if (ff != null) {
361: retval = new Integer(ff.intValue());
362: }
363: return retval;
364: }
365:
366: /**
367: * This will get the field flags that are associated with this field. The ClrFf entry
368: * in the FDF field dictionary.
369: *
370: * @param ff The new value for the "clear field flags".
371: */
372: public void setClearFieldFlags(Integer ff) {
373: COSInteger value = null;
374: if (ff != null) {
375: value = new COSInteger(ff.intValue());
376: }
377: field.setItem("ClrFf", value);
378: }
379:
380: /**
381: * This will get the field flags that are associated with this field. The ClrFf entry
382: * in the FDF field dictionary.
383: *
384: * @param ff The new value for the "clear field flags".
385: */
386: public void setClearFieldFlags(int ff) {
387: field.setItem("ClrFf", new COSInteger(ff));
388: }
389:
390: /**
391: * This will get the F entry of the cos dictionary. If it it not present then
392: * this method will return null.
393: *
394: * @return The widget field flags.
395: */
396: public Integer getWidgetFieldFlags() {
397: Integer retval = null;
398: COSNumber f = (COSNumber) field.getDictionaryObject("F");
399: if (f != null) {
400: retval = new Integer(f.intValue());
401: }
402: return retval;
403: }
404:
405: /**
406: * This will get the widget field flags that are associated with this field. The F entry
407: * in the FDF field dictionary.
408: *
409: * @param f The new value for the field flags.
410: */
411: public void setWidgetFieldFlags(Integer f) {
412: COSInteger value = null;
413: if (f != null) {
414: value = new COSInteger(f.intValue());
415: }
416: field.setItem("F", value);
417: }
418:
419: /**
420: * This will get the field flags that are associated with this field. The F entry
421: * in the FDF field dictionary.
422: *
423: * @param f The new value for the field flags.
424: */
425: public void setWidgetFieldFlags(int f) {
426: field.setItem("F", new COSInteger(f));
427: }
428:
429: /**
430: * This will get the SetF entry of the cos dictionary. If it it not present then
431: * this method will return null.
432: *
433: * @return The field flags.
434: */
435: public Integer getSetWidgetFieldFlags() {
436: Integer retval = null;
437: COSNumber ff = (COSNumber) field.getDictionaryObject("SetF");
438: if (ff != null) {
439: retval = new Integer(ff.intValue());
440: }
441: return retval;
442: }
443:
444: /**
445: * This will get the widget field flags that are associated with this field. The SetF entry
446: * in the FDF field dictionary.
447: *
448: * @param ff The new value for the "set widget field flags".
449: */
450: public void setSetWidgetFieldFlags(Integer ff) {
451: COSInteger value = null;
452: if (ff != null) {
453: value = new COSInteger(ff.intValue());
454: }
455: field.setItem("SetF", value);
456: }
457:
458: /**
459: * This will get the widget field flags that are associated with this field. The SetF entry
460: * in the FDF field dictionary.
461: *
462: * @param ff The new value for the "set widget field flags".
463: */
464: public void setSetWidgetFieldFlags(int ff) {
465: field.setItem("SetF", new COSInteger(ff));
466: }
467:
468: /**
469: * This will get the ClrF entry of the cos dictionary. If it it not present then
470: * this method will return null.
471: *
472: * @return The widget field flags.
473: */
474: public Integer getClearWidgetFieldFlags() {
475: Integer retval = null;
476: COSNumber ff = (COSNumber) field.getDictionaryObject("ClrF");
477: if (ff != null) {
478: retval = new Integer(ff.intValue());
479: }
480: return retval;
481: }
482:
483: /**
484: * This will get the field flags that are associated with this field. The ClrF entry
485: * in the FDF field dictionary.
486: *
487: * @param ff The new value for the "clear widget field flags".
488: */
489: public void setClearWidgetFieldFlags(Integer ff) {
490: COSInteger value = null;
491: if (ff != null) {
492: value = new COSInteger(ff.intValue());
493: }
494: field.setItem("ClrF", value);
495: }
496:
497: /**
498: * This will get the field flags that are associated with this field. The ClrF entry
499: * in the FDF field dictionary.
500: *
501: * @param ff The new value for the "clear field flags".
502: */
503: public void setClearWidgetFieldFlags(int ff) {
504: field.setItem("ClrF", new COSInteger(ff));
505: }
506:
507: /**
508: * This will get the appearance dictionary that specifies the appearance of
509: * a pushbutton field.
510: *
511: * @return The AP entry of this dictionary.
512: */
513: public PDAppearanceDictionary getAppearanceDictionary() {
514: PDAppearanceDictionary retval = null;
515: COSDictionary dict = (COSDictionary) field
516: .getDictionaryObject("AP");
517: if (dict != null) {
518: retval = new PDAppearanceDictionary(dict);
519: }
520: return retval;
521: }
522:
523: /**
524: * This will set the appearance dictionary.
525: *
526: * @param ap The apperance dictionary.
527: */
528: public void setAppearanceDictionary(PDAppearanceDictionary ap) {
529: field.setItem("AP", ap);
530: }
531:
532: /**
533: * This will get named page references..
534: *
535: * @return The named page references.
536: */
537: public FDFNamedPageReference getAppearanceStreamReference() {
538: FDFNamedPageReference retval = null;
539: COSDictionary ref = (COSDictionary) field
540: .getDictionaryObject("APRef");
541: if (ref != null) {
542: retval = new FDFNamedPageReference(ref);
543: }
544: return retval;
545: }
546:
547: /**
548: * This will set the named page references.
549: *
550: * @param ref The named page references.
551: */
552: public void setAppearanceStreamReference(FDFNamedPageReference ref) {
553: field.setItem("APRef", ref);
554: }
555:
556: /**
557: * This will get the icon fit that is associated with this field.
558: *
559: * @return The IF entry.
560: */
561: public FDFIconFit getIconFit() {
562: FDFIconFit retval = null;
563: COSDictionary dic = (COSDictionary) field
564: .getDictionaryObject("IF");
565: if (dic != null) {
566: retval = new FDFIconFit(dic);
567: }
568: return retval;
569: }
570:
571: /**
572: * This will set the icon fit entry.
573: *
574: * @param fit The icon fit object.
575: */
576: public void setIconFit(FDFIconFit fit) {
577: field.setItem("IF", fit);
578: }
579:
580: /**
581: * This will return a list of options for a choice field. The value in the
582: * list will be 1 of 2 types. java.lang.String or FDFOptionElement.
583: *
584: * @return A list of all options.
585: */
586: public List getOptions() {
587: List retval = null;
588: COSArray array = (COSArray) field.getDictionaryObject("Opt");
589: if (array != null) {
590: List objects = new ArrayList();
591: for (int i = 0; i < array.size(); i++) {
592: COSBase next = array.getObject(i);
593: if (next instanceof COSString) {
594: objects.add(((COSString) next).getString());
595: } else {
596: COSArray value = (COSArray) next;
597: objects.add(new FDFOptionElement(value));
598: }
599: }
600: retval = new COSArrayList(objects, array);
601: }
602: return retval;
603: }
604:
605: /**
606: * This will set the options for the choice field. The objects in the list
607: * should either be java.lang.String or FDFOptionElement.
608: *
609: * @param options The options to set.
610: */
611: public void setOptions(List options) {
612: COSArray value = COSArrayList.converterToCOSArray(options);
613: field.setItem("Opt", value);
614: }
615:
616: /**
617: * This will get the action that is associated with this field.
618: *
619: * @return The A entry in the field dictionary.
620: */
621: public PDAction getAction() {
622: return PDActionFactory.createAction((COSDictionary) field
623: .getDictionaryObject("A"));
624: }
625:
626: /**
627: * This will set the action that is associated with this field.
628: *
629: * @param a The new action.
630: */
631: public void setAction(PDAction a) {
632: field.setItem("A", a);
633: }
634:
635: /**
636: * This will get a list of additional actions that will get executed based
637: * on events.
638: *
639: * @return The AA entry in this field dictionary.
640: */
641: public PDAdditionalActions getAdditionalActions() {
642: PDAdditionalActions retval = null;
643: COSDictionary dict = (COSDictionary) field
644: .getDictionaryObject("AA");
645: if (dict != null) {
646: retval = new PDAdditionalActions(dict);
647: }
648:
649: return retval;
650: }
651:
652: /**
653: * This will set the additional actions that are associated with this field.
654: *
655: * @param aa The additional actions.
656: */
657: public void setAdditionalActions(PDAdditionalActions aa) {
658: field.setItem("AA", aa);
659: }
660:
661: /**
662: * This will set the rich text that is associated with this field.
663: *
664: * @return The rich text XHTML stream.
665: */
666: public PDTextStream getRichText() {
667: COSBase rv = field.getDictionaryObject("RV");
668: return PDTextStream.createTextStream(rv);
669: }
670:
671: /**
672: * This will set the rich text value.
673: *
674: * @param rv The rich text value for the stream.
675: */
676: public void setRichText(PDTextStream rv) {
677: field.setItem("RV", rv);
678: }
679: }
|