001: /**
002: * Copyright (c) 2003-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.interactive.form;
031:
032: import org.pdfbox.cos.COSArray;
033: import org.pdfbox.cos.COSDictionary;
034: import org.pdfbox.cos.COSName;
035: import org.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget;
036:
037: import java.io.IOException;
038:
039: import java.util.List;
040:
041: /**
042: * This is the Factory for creating and returning the correct
043: * field elements.
044: *
045: * @author sug
046: * @version $Revision: 1.8 $
047: */
048: public class PDFieldFactory {
049: private static final int RADIO_BITMASK = 32768;
050: private static final int PUSHBUTTON_BITMASK = 65536;
051: private static final int RADIOS_IN_UNISON_BITMASK = 33554432;
052:
053: private static final String FIELD_TYPE_BTN = "Btn";
054: private static final String FIELD_TYPE_TX = "Tx";
055: private static final String FIELD_TYPE_CH = "Ch";
056: private static final String FIELD_TYPE_SIG = "Sig";
057:
058: /**
059: * Utility class so no constructor.
060: */
061: private PDFieldFactory() {
062: //do nothing.
063: }
064:
065: /**
066: * This method creates a COSField subclass from the given field.
067: * The field is a PDF Dictionary object that must represent a
068: * field element. - othewise null is returned
069: *
070: * @param acroForm The form that the field will be part of.
071: * @param field The dictionary representing a field element
072: *
073: * @return a subclass to COSField according to the kind of field passed to createField
074: * @throws IOException If there is an error determining the field type.
075: */
076: public static PDField createField(PDAcroForm acroForm,
077: COSDictionary field) throws IOException {
078: PDField pdField = new PDUnknownField(acroForm, field);
079: if (isButton(pdField)) {
080: int flags = pdField.getFieldFlags();
081: //BJL, I have found that the radio flag bit is not always set
082: //and that sometimes there is just a kids dictionary.
083: //so, if there is a kids dictionary then it must be a radio button
084: //group.
085: COSArray kids = (COSArray) field
086: .getDictionaryObject(COSName.getPDFName("Kids"));
087: if (kids != null || isRadio(flags)) {
088: pdField = new PDRadioCollection(acroForm, field);
089: } else if (isPushButton(flags)) {
090: pdField = new PDPushButton(acroForm, field);
091: } else {
092: pdField = new PDCheckbox(acroForm, field);
093: }
094:
095: } else if (isChoiceField(pdField)) {
096: pdField = new PDChoiceField(acroForm, field);
097: } else if (isTextbox(pdField)) {
098: pdField = new PDTextbox(acroForm, field);
099: } else if (isSignature(pdField)) {
100: pdField = new PDSignature(acroForm, field);
101: } else {
102: //do nothing and return an unknown field type.
103: }
104: return pdField;
105: }
106:
107: /**
108: * This method determines if the given
109: * field is a radiobutton collection.
110: *
111: * @param flags The field flags.
112: *
113: * @return the result of the determination
114: */
115: private static boolean isRadio(int flags) {
116: return (flags & RADIO_BITMASK) > 0;
117: }
118:
119: /**
120: * This method determines if the given
121: * field is a pushbutton.
122: *
123: * @param flags The field flags.
124: *
125: * @return the result of the determination
126: */
127: private static boolean isPushButton(int flags) {
128: return (flags & PUSHBUTTON_BITMASK) > 0;
129: }
130:
131: /**
132: * This method determines if the given field is a choicefield
133: * Choicefields are either listboxes or comboboxes.
134: *
135: * @param field the field to determine
136: * @return the result of the determination
137: */
138: private static boolean isChoiceField(PDField field)
139: throws IOException {
140: return FIELD_TYPE_CH.equals(field.findFieldType());
141: }
142:
143: /**
144: * This method determines if the given field is a button.
145: *
146: * @param field the field to determine
147: * @return the result of the determination
148: *
149: * @throws IOException If there is an error determining the field type.
150: */
151: private static boolean isButton(PDField field) throws IOException {
152: String ft = field.findFieldType();
153: boolean retval = FIELD_TYPE_BTN.equals(ft);
154: List kids = field.getKids();
155: if (ft == null && kids != null && kids.size() > 0) {
156: //sometimes if it is a button the type is only defined by one
157: //of the kids entries
158: Object obj = kids.get(0);
159: COSDictionary kidDict = null;
160: if (obj instanceof PDField) {
161: kidDict = ((PDField) obj).getDictionary();
162: } else if (obj instanceof PDAnnotationWidget) {
163: kidDict = ((PDAnnotationWidget) obj).getDictionary();
164: } else {
165: throw new IOException(
166: "Error:Unexpected type of kids field:" + obj);
167: }
168: retval = isButton(new PDUnknownField(field.getAcroForm(),
169: kidDict));
170: }
171: return retval;
172: }
173:
174: /**
175: * This method determines if the given field is a signature.
176: *
177: * @param field the field to determine
178: * @return the result of the determination
179: */
180: private static boolean isSignature(PDField field)
181: throws IOException {
182: return FIELD_TYPE_SIG.equals(field.findFieldType());
183: }
184:
185: /**
186: * This method determines if the given field is a Textbox.
187: *
188: * @param field the field to determine
189: * @return the result of the determination
190: */
191: private static boolean isTextbox(PDField field) throws IOException {
192: return FIELD_TYPE_TX.equals(field.findFieldType());
193: }
194: }
|