You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by le...@apache.org on 2014/08/16 17:21:10 UTC

svn commit: r1618374 [1/2] - in /pdfbox/trunk: examples/src/main/java/org/apache/pdfbox/examples/fdf/ pdfbox/src/main/java/org/apache/pdfbox/pdmodel/ pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/ pdfbox/src/main/j...

Author: lehmi
Date: Sat Aug 16 15:21:09 2014
New Revision: 1618374

URL: http://svn.apache.org/r1618374
Log:
PDFBOX-2261: reorganized the creation/handling of acroform elements

Added:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDFieldTreeNode.java   (with props)
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDNonTerminalField.java   (with props)
Modified:
    pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/fdf/PrintFields.java
    pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/fdf/SetField.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateStructure.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigBuilder.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroForm.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDButton.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDCheckbox.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDChoice.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDComboBox.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDField.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDFieldFactory.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDListBox.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDPushButton.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDRadioButton.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDSignatureField.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDTextField.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDVariableText.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/PDFMergerUtility.java
    pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/TestFDF.java

Modified: pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/fdf/PrintFields.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/fdf/PrintFields.java?rev=1618374&r1=1618373&r2=1618374&view=diff
==============================================================================
--- pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/fdf/PrintFields.java (original)
+++ pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/fdf/PrintFields.java Sat Aug 16 15:21:09 2014
@@ -26,13 +26,14 @@ import org.apache.pdfbox.pdmodel.common.
 import org.apache.pdfbox.pdmodel.encryption.InvalidPasswordException;
 import org.apache.pdfbox.pdmodel.encryption.StandardDecryptionMaterial;
 import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
-import org.apache.pdfbox.pdmodel.interactive.form.PDField;
+import org.apache.pdfbox.pdmodel.interactive.form.PDFieldTreeNode;
+import org.apache.pdfbox.pdmodel.interactive.form.PDNonTerminalField;
 import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;
 
 /**
  * This example will take a PDF document and print all the fields from the file.
  * 
- * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
+ * @author Ben Litchfield
  * 
  */
 public class PrintFields
@@ -49,36 +50,36 @@ public class PrintFields
     {
         PDDocumentCatalog docCatalog = pdfDocument.getDocumentCatalog();
         PDAcroForm acroForm = docCatalog.getAcroForm();
-        List fields = acroForm.getFields();
-        Iterator fieldsIter = fields.iterator();
+        List<PDFieldTreeNode> fields = acroForm.getFields();
+        Iterator<PDFieldTreeNode> fieldsIter = fields.iterator();
 
         System.out.println(new Integer(fields.size()).toString() + " top-level fields were found on the form");
 
         while (fieldsIter.hasNext())
         {
-            PDField field = (PDField) fieldsIter.next();
+            PDFieldTreeNode field = fieldsIter.next();
             processField(field, "|--", field.getPartialName());
         }
     }
 
-    private void processField(PDField field, String sLevel, String sParent) throws IOException
+    private void processField(PDFieldTreeNode field, String sLevel, String sParent) throws IOException
     {
+        String partialName = field != null ? field.getPartialName() : "";
         List<COSObjectable> kids = field.getKids();
         if (kids != null)
         {
             Iterator<COSObjectable> kidsIter = kids.iterator();
-            if (!sParent.equals(field.getPartialName()))
+            if (field != null && !sParent.equals(field.getPartialName()))
             {
-                sParent = sParent + "." + field.getPartialName();
+                sParent = sParent + "." + partialName;
             }
             System.out.println(sLevel + sParent);
-            // System.out.println(sParent + " is of type " + field.getClass().getName());
             while (kidsIter.hasNext())
             {
                 Object pdfObj = kidsIter.next();
-                if (pdfObj instanceof PDField)
+                if (pdfObj instanceof PDFieldTreeNode)
                 {
-                    PDField kid = (PDField) pdfObj;
+                    PDFieldTreeNode kid = (PDFieldTreeNode) pdfObj;
                     processField(kid, "|  " + sLevel, sParent);
                 }
             }
@@ -91,11 +92,16 @@ public class PrintFields
                 // PDSignatureField doesn't have a value
                 fieldValue = "PDSignatureField";
             }
+            else if(field instanceof PDNonTerminalField)
+            {
+                // Non terminal fields don't have a value
+                fieldValue = "node";
+            }
             else
             {
                 fieldValue = field.getValue();
             }
-            String outputString = sLevel + sParent + "." + field.getPartialName() + " = " + fieldValue + ",  type="
+            String outputString = sLevel + sParent + "." + partialName + " = " + fieldValue + ",  type="
                     + field.getClass().getName();
             System.out.println(outputString);
         }

Modified: pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/fdf/SetField.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/fdf/SetField.java?rev=1618374&r1=1618373&r2=1618374&view=diff
==============================================================================
--- pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/fdf/SetField.java (original)
+++ pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/fdf/SetField.java Sat Aug 16 15:21:09 2014
@@ -23,7 +23,7 @@ import org.apache.pdfbox.pdmodel.PDDocum
 import org.apache.pdfbox.pdmodel.encryption.InvalidPasswordException;
 import org.apache.pdfbox.pdmodel.encryption.StandardDecryptionMaterial;
 import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
-import org.apache.pdfbox.pdmodel.interactive.form.PDField;
+import org.apache.pdfbox.pdmodel.interactive.form.PDFieldTreeNode;
 
 /**
  * This example will take a PDF document and set a FDF field in it.
@@ -46,7 +46,7 @@ public class SetField
     {
         PDDocumentCatalog docCatalog = pdfDocument.getDocumentCatalog();
         PDAcroForm acroForm = docCatalog.getAcroForm();
-        PDField field = acroForm.getField(name);
+        PDFieldTreeNode field = acroForm.getField(name);
         if (field != null)
         {
             field.setValue(value);

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java?rev=1618374&r1=1618373&r2=1618374&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java Sat Aug 16 15:21:09 2014
@@ -62,7 +62,7 @@ import org.apache.pdfbox.pdmodel.interac
 import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface;
 import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureOptions;
 import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
-import org.apache.pdfbox.pdmodel.interactive.form.PDField;
+import org.apache.pdfbox.pdmodel.interactive.form.PDFieldTreeNode;
 import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;
 
 /**
@@ -328,14 +328,14 @@ public class PDDocument implements Close
         // Create Annotation / Field for signature
         List<PDAnnotation> annotations = page.getAnnotations();
 
-        List<PDField> fields = acroForm.getFields();
+        List<PDFieldTreeNode> fields = acroForm.getFields();
         PDSignatureField signatureField = null;
         if(fields == null) 
         {
-            fields = new ArrayList();
+            fields = new ArrayList<PDFieldTreeNode>();
             acroForm.setFields(fields);
         }
-        for (PDField pdField : fields)
+        for (PDFieldTreeNode pdField : fields)
         {
             if (pdField instanceof PDSignatureField)
             {
@@ -354,13 +354,13 @@ public class PDDocument implements Close
         }
 
         // Set the AcroForm Fields
-        List<PDField> acroFormFields = acroForm.getFields();
+        List<PDFieldTreeNode> acroFormFields = acroForm.getFields();
         COSDictionary acroFormDict = acroForm.getDictionary();
         acroFormDict.setDirect(true);
         acroFormDict.setInt(COSName.SIG_FLAGS, 3);
 
         boolean checkFields = false;
-        for (PDField field : acroFormFields)
+        for (PDFieldTreeNode field : acroFormFields)
         {
             if (field instanceof PDSignatureField)
             {
@@ -513,7 +513,7 @@ public class PDDocument implements Close
             acroFormDict.setInt(COSName.SIG_FLAGS, 1); // 1 if at least one signature field is available
         }
 
-        List<PDField> field = acroForm.getFields();
+        List<PDFieldTreeNode> field = acroForm.getFields();
 
         for (PDSignatureField sigField : sigFields)
         {
@@ -522,11 +522,11 @@ public class PDDocument implements Close
 
             // Check if the field already exist
             boolean checkFields = false;
-            for (Object obj : field)
+            for (PDFieldTreeNode fieldNode : field)
             {
-                if (obj instanceof PDSignatureField)
+                if (fieldNode instanceof PDSignatureField)
                 {
-                    if (((PDSignatureField) obj).getCOSObject().equals(sigField.getCOSObject()))
+                    if (fieldNode.getCOSObject().equals(sigField.getCOSObject()))
                     {
                         checkFields = true;
                         sigField.getCOSObject().setNeedToBeUpdate(true);
@@ -812,7 +812,7 @@ public class PDDocument implements Close
             List<COSDictionary> signatureDictionary = document.getSignatureFields(false);
             for (COSDictionary dict : signatureDictionary)
             {
-                fields.add(new PDSignatureField(acroForm, dict));
+                fields.add(new PDSignatureField(acroForm, dict, null));
             }
         }
         return fields;

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateStructure.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateStructure.java?rev=1618374&r1=1618373&r2=1618374&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateStructure.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateStructure.java Sat Aug 16 15:21:09 2014
@@ -36,7 +36,7 @@ import org.apache.pdfbox.pdmodel.graphic
 import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary;
 import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
 import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
-import org.apache.pdfbox.pdmodel.interactive.form.PDField;
+import org.apache.pdfbox.pdmodel.interactive.form.PDFieldTreeNode;
 import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;
 
 /**
@@ -66,7 +66,7 @@ public class PDFTemplateStructure
     private PDFormXObject innerForm;
     private PDStream imageFormStream;
     private PDResources imageFormResources;
-    private List<PDField> acroFormFields;
+    private List<PDFieldTreeNode> acroFormFields;
     private String innerFormName;
     private String imageFormName;
     private String imageName;
@@ -554,7 +554,7 @@ public class PDFTemplateStructure
      * Gets acroFormFields
      * @return the AcroForm fields
      */
-    public List<PDField> getAcroFormFields()
+    public List<PDFieldTreeNode> getAcroFormFields()
     {
         return acroFormFields;
     }
@@ -563,7 +563,7 @@ public class PDFTemplateStructure
      * Sets acroFormFields
      * @param acroFormFields
      */
-    public void setAcroFormFields(List<PDField> acroFormFields)
+    public void setAcroFormFields(List<PDFieldTreeNode> acroFormFields)
     {
         this.acroFormFields = acroFormFields;
     }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigBuilder.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigBuilder.java?rev=1618374&r1=1618373&r2=1618374&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigBuilder.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigBuilder.java Sat Aug 16 15:21:09 2014
@@ -39,7 +39,7 @@ import org.apache.pdfbox.pdmodel.interac
 import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream;
 import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
 import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
-import org.apache.pdfbox.pdmodel.interactive.form.PDField;
+import org.apache.pdfbox.pdmodel.interactive.form.PDFieldTreeNode;
 import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;
 
 /**
@@ -118,7 +118,7 @@ public class PDVisibleSigBuilder impleme
             throws IOException
     {
         @SuppressWarnings("unchecked")
-        List<PDField> acroFormFields = acroForm.getFields();
+        List<PDFieldTreeNode> acroFormFields = acroForm.getFields();
         COSDictionary acroFormDict = acroForm.getDictionary();
         acroFormDict.setDirect(true);
         acroFormDict.setInt(COSName.SIG_FLAGS, 3);

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroForm.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroForm.java?rev=1618374&r1=1618373&r2=1618374&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroForm.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroForm.java Sat Aug 16 15:21:09 2014
@@ -50,7 +50,7 @@ public final class PDAcroForm implements
     private COSDictionary acroForm;
     private PDDocument document;
 
-    private Map fieldCache;
+    private Map<String,PDFieldTreeNode> fieldCache;
 
     /**
      * Constructor.
@@ -62,7 +62,7 @@ public final class PDAcroForm implements
         document = doc;
         acroForm = new COSDictionary();
         COSArray fields = new COSArray();
-        acroForm.setItem( COSName.getPDFName( "Fields" ), fields );
+        acroForm.setItem( COSName.FIELDS, fields );
     }
 
     /**
@@ -107,13 +107,13 @@ public final class PDAcroForm implements
      */
     public void importFDF( FDFDocument fdf ) throws IOException
     {
-        List fields = fdf.getCatalog().getFDF().getFields();
+        List<?> fields = fdf.getCatalog().getFDF().getFields();
         if( fields != null )
         {
             for (Object field : fields)
             {
                 FDFField fdfField = (FDFField) field;
-                PDField docField = getField( fdfField.getPartialFieldName() );
+                PDFieldTreeNode docField = getField( fdfField.getPartialFieldName() );
                 if( docField != null )
                 {
                     docField.importFDF( fdfField );
@@ -135,12 +135,12 @@ public final class PDAcroForm implements
         FDFDictionary fdfDict = new FDFDictionary();
         catalog.setFDF( fdfDict );
 
-        List fdfFields = new ArrayList();
-        List fields = getFields();
-        Iterator fieldIter = fields.iterator();
+        List<FDFField> fdfFields = new ArrayList<FDFField>();
+        List<PDFieldTreeNode> fields = getFields();
+        Iterator<PDFieldTreeNode> fieldIter = fields.iterator();
         while( fieldIter.hasNext() )
         {
-            PDField docField = (PDField)fieldIter.next();
+            PDFieldTreeNode docField = fieldIter.next();
             addFieldAndChildren( docField, fdfFields );
         }
         fdfDict.setID( document.getDocument().getDocumentID() );
@@ -151,20 +151,19 @@ public final class PDAcroForm implements
         return fdf;
     }
 
-    private void addFieldAndChildren( PDField docField, List fdfFields ) throws IOException
+    private void addFieldAndChildren( PDFieldTreeNode docField, List<FDFField> fdfFields ) throws IOException
     {
         Object fieldValue = docField.getValue();
         FDFField fdfField = new FDFField();
         fdfField.setPartialFieldName( docField.getPartialName() );
         fdfField.setValue( fieldValue );
-        List kids = docField.getKids();
-        List childFDFFields = new ArrayList();
+        List<COSObjectable> kids = docField.getKids();
+        List<FDFField> childFDFFields = new ArrayList<FDFField>();
         if( kids != null )
         {
-
-            for (Object kid : kids)
+            for (COSObjectable kid : kids)
             {
-                addFieldAndChildren((PDField) kid, childFDFFields);
+                addFieldAndChildren((PDFieldTreeNode) kid, childFDFFields);
             }
             if( childFDFFields.size() > 0 )
             {
@@ -182,31 +181,29 @@ public final class PDAcroForm implements
      * will be a org.apache.pdfbox.pdmodel.field.PDField.
      *
      * @return A list of all the fields.
-     * @throws IOException If there is an error while getting the list of fields.
+     * 
      */
-    public List<PDField> getFields() throws IOException
+    public List<PDFieldTreeNode> getFields()
     {
-        COSArray cosFields = (COSArray) acroForm.getDictionaryObject(COSName.getPDFName("Fields"));
-
+        COSArray cosFields = (COSArray) acroForm.getDictionaryObject(COSName.FIELDS);
         if( cosFields == null )
         {
             return null;
         }
-
-        List<PDField> pdFields = new ArrayList<PDField>();
+        List<PDFieldTreeNode> pdFields = new ArrayList<PDFieldTreeNode>();
         for (int i = 0; i < cosFields.size(); i++)
         {
             COSDictionary element = (COSDictionary) cosFields.getObject(i);
             if (element != null)
             {
-                PDField field = PDFieldFactory.createField( this, element );
+                PDFieldTreeNode field = PDFieldFactory.createField( this, element, null );
                 if( field != null )
                 {
                     pdFields.add(field);
                 }
             }
         }
-        return new COSArrayList<PDField>( pdFields, cosFields );
+        return new COSArrayList<PDFieldTreeNode>( pdFields, cosFields );
     }
 
     /**
@@ -214,9 +211,9 @@ public final class PDAcroForm implements
      *
      * @param fields The fields that are part of this form.
      */
-    public void setFields( List fields )
+    public void setFields( List<PDFieldTreeNode> fields )
     {
-        acroForm.setItem( "Fields", COSArrayList.converterToCOSArray( fields ));
+        acroForm.setItem( COSName.FIELDS, COSArrayList.converterToCOSArray( fields ));
     }
 
     /**
@@ -232,12 +229,12 @@ public final class PDAcroForm implements
     {
         if( cache )
         {
-            fieldCache = new HashMap();
-            List fields = getFields();
-            Iterator fieldIter = fields.iterator();
+            fieldCache = new HashMap<String,PDFieldTreeNode>();
+            List<PDFieldTreeNode> fields = getFields();
+            Iterator<PDFieldTreeNode> fieldIter = fields.iterator();
             while( fieldIter.hasNext() )
             {
-                PDField next = (PDField)fieldIter.next();
+                PDFieldTreeNode next = fieldIter.next();
                 fieldCache.put( next.getFullyQualifiedName(), next );
             }
         }
@@ -266,19 +263,17 @@ public final class PDAcroForm implements
      *
      * @throws IOException If there is an error getting the field type.
      */
-    public PDField getField( String name ) throws IOException
+    public PDFieldTreeNode getField( String name ) throws IOException
     {
-        PDField retval = null;
+        PDFieldTreeNode retval = null;
         if( fieldCache != null )
         {
-            retval = (PDField)fieldCache.get( name );
+            retval = fieldCache.get( name );
         }
         else
         {
             String[] nameSubSection = name.split( "\\." );
-            COSArray fields =
-                (COSArray) acroForm.getDictionaryObject(
-                    COSName.getPDFName("Fields"));
+            COSArray fields = (COSArray) acroForm.getDictionaryObject(COSName.FIELDS);
 
             for (int i = 0; i < fields.size() && retval == null; i++)
             {
@@ -286,15 +281,15 @@ public final class PDAcroForm implements
                 if( element != null )
                 {
                     COSString fieldName =
-                        (COSString)element.getDictionaryObject( COSName.getPDFName( "T" ) );
+                        (COSString)element.getDictionaryObject( COSName.T );
                     if( fieldName.getString().equals( name ) ||
                         fieldName.getString().equals( nameSubSection[0] ) )
                     {
-                        PDField root = PDFieldFactory.createField( this, element );
+                        PDFieldTreeNode root = PDFieldFactory.createField( this, element, null );
 
                         if( nameSubSection.length > 1 )
                         {
-                            PDField kid = root.findKid( nameSubSection, 1 );
+                            PDFieldTreeNode kid = root.findKid( nameSubSection, 1 );
                             if( kid != null )
                             {
                                 retval = kid;
@@ -323,7 +318,7 @@ public final class PDAcroForm implements
     public PDResources getDefaultResources()
     {
         PDResources retval = null;
-        COSDictionary dr = (COSDictionary)acroForm.getDictionaryObject( COSName.getPDFName( "DR" ) );
+        COSDictionary dr = (COSDictionary)acroForm.getDictionaryObject( COSName.DR );
         if( dr != null )
         {
             retval = new PDResources( dr );
@@ -343,7 +338,7 @@ public final class PDAcroForm implements
         {
             drDict = dr.getCOSDictionary();
         }
-        acroForm.setItem( COSName.getPDFName( "DR" ), drDict );
+        acroForm.setItem( COSName.DR, drDict );
     }
 
     @Override

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDButton.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDButton.java?rev=1618374&r1=1618373&r2=1618374&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDButton.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDButton.java Sat Aug 16 15:21:09 2014
@@ -34,9 +34,33 @@ import java.util.List;
  */
 public abstract class PDButton extends PDField
 {
-    PDButton(PDAcroForm acroForm, COSDictionary field)
+    /**
+     * A Ff flag.
+     */
+    public static final int FLAG_NO_TOGGLE_TO_OFF = 1 << 14;
+    /**
+     * A Ff flag.
+     */
+    public static final int FLAG_RADIO = 1 << 15;
+    /**
+     * A Ff flag.
+     */
+    public static final int FLAG_PUSHBUTTON = 1 << 16;
+    /**
+     * A Ff flag.
+     */
+    public static final int FLAG_RADIOS_IN_UNISON = 1 << 25;
+
+    /**
+     * Constructor.
+     * 
+     * @param theAcroForm The form that this field is part of.
+     * @param field the PDF object to represent as a field.
+     * @param parentNode the parent node of the node to be created
+     */
+    protected PDButton(PDAcroForm acroForm, COSDictionary field, PDFieldTreeNode parentNode)
     {
-        super(acroForm, field);
+        super(acroForm, field, parentNode);
     }
 
     /**
@@ -44,18 +68,18 @@ public abstract class PDButton extends P
      *
      * @return A list of java.lang.String values.
      */
-    public List getOptions()
+    public List<String> getOptions()
     {
-        List retval = null;
-        COSArray array = (COSArray)getDictionary().getDictionaryObject( COSName.getPDFName( "Opt" ) );
+        List<String> retval = null;
+        COSArray array = (COSArray)getDictionary().getDictionaryObject( COSName.OPT );
         if( array != null )
         {
-            List strings = new ArrayList();
+            List<String> strings = new ArrayList<String>();
             for( int i=0; i<array.size(); i++ )
             {
                 strings.add( ((COSString)array.getObject( i )).getString() );
             }
-            retval = new COSArrayList( strings, array );
+            retval = new COSArrayList<String>( strings, array );
         }
         return retval;
     }
@@ -65,10 +89,8 @@ public abstract class PDButton extends P
      *
      * @param options The list of options for the button.
      */
-    public void setOptions( List options )
+    public void setOptions( List<String> options )
     {
-        getDictionary().setItem(
-            COSName.getPDFName( "Opt" ),
-            COSArrayList.converterToCOSArray( options ) );
+        getDictionary().setItem(COSName.OPT, COSArrayList.converterToCOSArray( options ) );
     }
 }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDCheckbox.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDCheckbox.java?rev=1618374&r1=1618373&r2=1618374&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDCheckbox.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDCheckbox.java Sat Aug 16 15:21:09 2014
@@ -30,30 +30,29 @@ import java.io.IOException;
  */
 public final class PDCheckbox extends PDButton
 {
-    private static final COSName KEY = COSName.getPDFName("AS");
-    private static final COSName OFF_VALUE = COSName.getPDFName("Off");
 
     private COSName value;
 
     /**
-     * @see PDField#PDField(PDAcroForm,COSDictionary)
-     *
-     * @param theAcroForm The acroForm for this field.
-     * @param field The checkbox field dictionary
+     * Constructor.
+     * 
+     * @param theAcroForm The form that this field is part of.
+     * @param field the PDF object to represent as a field.
+     * @param parentNode the parent node of the node to be created
      */
-    public PDCheckbox( PDAcroForm theAcroForm, COSDictionary field)
+    public PDCheckbox( PDAcroForm theAcroForm, COSDictionary field, PDFieldTreeNode parentNode)
     {
-        super( theAcroForm, field);
-        COSDictionary ap = (COSDictionary) field.getDictionaryObject(COSName.getPDFName("AP"));
+        super( theAcroForm, field, parentNode);
+        COSDictionary ap = (COSDictionary) field.getDictionaryObject(COSName.AP);
         if( ap != null )
         {
-            COSBase n = ap.getDictionaryObject(COSName.getPDFName("N"));
+            COSBase n = ap.getDictionaryObject(COSName.N);
 
             if( n instanceof COSDictionary )
             {
                 for( COSName name : ((COSDictionary)n).keySet() )
                 {
-                    if( !name.equals( OFF_VALUE ))
+                    if( !name.equals( COSName.OFF ))
                     {
                         value = name;
                     }
@@ -63,7 +62,7 @@ public final class PDCheckbox extends PD
         }
         else
         {
-            value = (COSName)getDictionary().getDictionaryObject( "V" );
+            value = (COSName)getDictionary().getDictionaryObject( COSName.V);
         }
     }
 
@@ -76,7 +75,7 @@ public final class PDCheckbox extends PD
     {
         boolean retval = false;
         String onValue = getOnValue();
-        COSName radioValue = (COSName)getDictionary().getDictionaryObject( KEY );
+        COSName radioValue = (COSName)getDictionary().getDictionaryObject( COSName.AS );
         if( radioValue != null && value != null && radioValue.getName().equals( onValue ) )
         {
             retval = true;
@@ -90,7 +89,7 @@ public final class PDCheckbox extends PD
      */
     public void check()
     {
-        getDictionary().setItem(KEY, value);
+        getDictionary().setItem(COSName.AS, value);
     }
 
     /**
@@ -98,7 +97,7 @@ public final class PDCheckbox extends PD
      */
     public void unCheck()
     {
-        getDictionary().setItem(KEY, OFF_VALUE);
+        getDictionary().setItem(COSName.AS, COSName.OFF);
     }
 
     /**
@@ -106,14 +105,14 @@ public final class PDCheckbox extends PD
      */
     public void setValue(String newValue)
     {
-        getDictionary().setName( "V", newValue );
+        getDictionary().setName( COSName.V, newValue );
         if( newValue == null )
         {
-            getDictionary().setItem( KEY, OFF_VALUE );
+            getDictionary().setItem( COSName.AS, COSName.OFF );
         }
         else
         {
-            getDictionary().setName( KEY, newValue );
+            getDictionary().setName( COSName.AS, newValue );
         }
     }
 
@@ -124,7 +123,7 @@ public final class PDCheckbox extends PD
      */
     public String getOffValue()
     {
-        return OFF_VALUE.getName();
+        return COSName.OFF.getName();
     }
 
     /**
@@ -135,15 +134,15 @@ public final class PDCheckbox extends PD
     public String getOnValue()
     {
         String retval = null;
-        COSDictionary ap = (COSDictionary) getDictionary().getDictionaryObject(COSName.getPDFName("AP"));
-        COSBase n = ap.getDictionaryObject(COSName.getPDFName("N"));
+        COSDictionary ap = (COSDictionary) getDictionary().getDictionaryObject(COSName.AP);
+        COSBase n = ap.getDictionaryObject(COSName.N);
 
         //N can be a COSDictionary or a COSStream
         if( n instanceof COSDictionary )
         {
             for( COSName key :((COSDictionary)n).keySet() )
             {
-                if( !key.equals( OFF_VALUE) )
+                if( !key.equals( COSName.OFF) )
                 {
                     retval = key.getName();
                 }
@@ -161,7 +160,7 @@ public final class PDCheckbox extends PD
      */
     public String getValue() throws IOException
     {
-        return getDictionary().getNameAsString( "V" );
+        return getDictionary().getNameAsString( COSName.V );
     }
 
 }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDChoice.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDChoice.java?rev=1618374&r1=1618373&r2=1618374&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDChoice.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDChoice.java Sat Aug 16 15:21:09 2014
@@ -31,9 +31,16 @@ import org.apache.pdfbox.cos.COSString;
  */
 public abstract class PDChoice extends PDVariableText
 {
-    PDChoice(PDAcroForm acroForm, COSDictionary field)
+    /**
+     * Constructor.
+     * 
+     * @param theAcroForm The form that this field is part of.
+     * @param field the PDF object to represent as a field.
+     * @param parentNode the parent node of the node to be created
+     */
+    protected PDChoice(PDAcroForm acroForm, COSDictionary field, PDFieldTreeNode parentNode)
     {
-        super(acroForm, field);
+        super(acroForm, field, parentNode);
     }
 
     // returns the "Opt" index for the given string

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDComboBox.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDComboBox.java?rev=1618374&r1=1618373&r2=1618374&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDComboBox.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDComboBox.java Sat Aug 16 15:21:09 2014
@@ -30,13 +30,15 @@ public final class PDComboBox extends PD
     private static final int FLAG_EDIT = 0x40000;
 
     /**
-     * Creates a new combo box field
-     * @param acroForm the parent form
-     * @param field the COS field
+     * Constructor.
+     * 
+     * @param theAcroForm The form that this field is part of.
+     * @param field the PDF object to represent as a field.
+     * @param parentNode the parent node of the node to be created
      */
-    public PDComboBox(PDAcroForm acroForm, COSDictionary field)
+    public PDComboBox(PDAcroForm acroForm, COSDictionary field, PDFieldTreeNode parentNode)
     {
-        super(acroForm, field);
+        super(acroForm, field, parentNode);
     }
 
     @Override

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDField.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDField.java?rev=1618374&r1=1618373&r2=1618374&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDField.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDField.java Sat Aug 16 15:21:09 2014
@@ -16,21 +16,10 @@
  */
 package org.apache.pdfbox.pdmodel.interactive.form;
 
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.pdfbox.cos.COSArray;
-import org.apache.pdfbox.cos.COSBase;
 import org.apache.pdfbox.cos.COSDictionary;
 import org.apache.pdfbox.cos.COSInteger;
 import org.apache.pdfbox.cos.COSName;
-import org.apache.pdfbox.pdmodel.common.COSArrayList;
-import org.apache.pdfbox.pdmodel.common.COSObjectable;
-import org.apache.pdfbox.pdmodel.common.PDTextStream;
-import org.apache.pdfbox.pdmodel.fdf.FDFField;
 import org.apache.pdfbox.pdmodel.interactive.action.PDFormFieldAdditionalActions;
-import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget;
 
 /**
  * A field in an interactive form.
@@ -38,251 +27,72 @@ import org.apache.pdfbox.pdmodel.interac
  *
  * @author sug
  */
-public abstract class PDField implements COSObjectable
+public abstract class PDField extends PDFieldTreeNode
 {
     /**
-     * A Ff flag.
-     */
-    public static final int FLAG_READ_ONLY = 1;
-    /**
-     * A Ff flag.
-     */
-    public static final int FLAG_REQUIRED = 1 << 1;
-    /**
-     * A Ff flag.
-     */
-    public static final int FLAG_NO_EXPORT = 1 << 2;
-
-    /**
-     * Field type Text.
-     */
-    public static final String FIELD_TYPE_TEXT = "Tx";
-    /**
-     * Field type Button.
-     */
-    public static final String FIELD_TYPE_BUTTON = "Btn";
-    /**
-     * Field type Button.
-     */
-    public static final String FIELD_TYPE_CHOICE = "Ch";
-    /**
-     * Field type Button.
-     */
-    public static final String FIELD_TYPE_SIGNATURE = "Sig";
-
-    private PDAcroForm acroForm;
-
-    private COSDictionary dictionary;
-
-    /**
      * Constructor.
      * 
      * @param theAcroForm The form that this field is part of.
      */
-    PDField(PDAcroForm theAcroForm)
+    protected PDField(PDAcroForm theAcroForm)
     {
-        acroForm = theAcroForm;
-        dictionary = new COSDictionary();
-        // no required fields in base field class
+        super(theAcroForm);
     }
 
     /**
-     * Creates a COSField from a COSDictionary, expected to be a correct object definition for a field in PDF.
+     * Constructor.
      * 
      * @param theAcroForm The form that this field is part of.
-     * @param field the PDF objet to represent as a field.
-     */
-    protected PDField(PDAcroForm theAcroForm, COSDictionary field)
-    {
-        acroForm = theAcroForm;
-        dictionary = field;
-    }
-
-    /**
-     * Returns the partial name of the field.
-     * 
-     * @return the name of the field
-     */
-    public String getPartialName()
-    {
-        return getDictionary().getString(COSName.T);
-    }
-
-    /**
-     * This will set the partial name of the field.
-     * 
-     * @param name The new name for the field.
+     * @param field the PDF object to represent as a field.
+     * @param parentNode the parent node of the node to be created
      */
-    public void setPartialName(String name)
+    protected PDField(PDAcroForm theAcroForm, COSDictionary field, PDFieldTreeNode parentNode)
     {
-        getDictionary().setString(COSName.T, name);
+        super(theAcroForm, field, parentNode);
     }
 
     /**
-     * Returns the fully qualified name of the field, which is a concatenation of the names of all the parents fields.
-     * 
-     * @return the name of the field
-     * 
-     * @throws IOException If there is an error generating the fully qualified name.
-     */
-    public String getFullyQualifiedName() throws IOException
-    {
-        PDField parent = getParent();
-        String parentName = null;
-        if (parent != null)
-        {
-            parentName = parent.getFullyQualifiedName();
-        }
-        String finalName = getPartialName();
-        if (parentName != null)
-        {
-            finalName = parentName + "." + finalName;
-        }
-        return finalName;
-    }
-
-    /**
-     * Gets the alternate name of the field.
-     * 
-     * @return the alternate name of the field
-     */
-    public String getAlternateFieldName()
-    {
-        return this.getDictionary().getString(COSName.TU);
-    }
-
-    /**
-     * This will set the alternate name of the field.
-     * 
-     * @param alternateFieldName the alternate name of the field
-     */
-    public void setAlternateFieldName(String alternateFieldName)
-    {
-        this.getDictionary().setString(COSName.TU, alternateFieldName);
-    }
-
-    /**
-     * Get the FT entry of the field. This is a read only field and is set depending on the actual type. The field type
-     * is an inheritable attribute. This method will return only the direct value on this object. Use the findFieldType
-     * for an upward recursive search.
-     * 
-     * @return The Field type.
+     * This will return a string representation of this field.
      * 
-     * @see PDField#findFieldType()
+     * @return A string representation of this field.
      */
-    public String getFieldType()
+    @Override
+    public String toString()
     {
-        return getDictionary().getNameAsString(COSName.FT);
+        return "" + getDictionary().getDictionaryObject(COSName.V);
     }
 
     /**
-     * Find the field type and optionally do a recursive upward search. Sometimes the fieldtype will be specified on the
-     * parent instead of the direct object. This will look at this object for the field type, if none is specified then
-     * it will look to the parent if there is a parent. If there is no parent and no field type has been found then this
-     * will return null.
+     * Get the additional actions for this field. This will return null if there are no additional actions for this
+     * field.
      * 
-     * @return The field type or null if none was found.
+     * @return The actions of the field.
      */
-    public String findFieldType()
-    {
-        return findFieldType(getDictionary());
-    }
-
-    // used by factory class
-    static String findFieldType(COSDictionary dic)
+    public PDFormFieldAdditionalActions getActions()
     {
-        String retval = dic.getNameAsString(COSName.FT);
-        if (retval == null)
+        COSDictionary aa = (COSDictionary) getDictionary().getDictionaryObject(COSName.AA);
+        PDFormFieldAdditionalActions retval = null;
+        if (aa != null)
         {
-            COSDictionary parent = (COSDictionary) dic.getDictionaryObject(COSName.PARENT, COSName.P);
-            if (parent != null)
-            {
-                retval = findFieldType(parent);
-            }
+            retval = new PDFormFieldAdditionalActions(aa);
         }
         return retval;
     }
 
     /**
-     * setValue sets the fields value to a given string.
-     * 
-     * @param value the string value
-     * 
-     * @throws IOException If there is an error creating the appearance stream.
-     */
-    public abstract void setValue(String value) throws IOException;
-
-    /**
-     * getValue gets the fields value to as a string.
-     * 
-     * @return The string value of this field.
-     * 
-     * @throws IOException If there is an error getting the value.
-     */
-    public abstract String getValue() throws IOException;
-
-    /**
-     * sets the field to be read-only.
-     * 
-     * @param readonly The new flag for readonly.
-     */
-    public void setReadonly(boolean readonly)
-    {
-        getDictionary().setFlag( COSName.FF, FLAG_READ_ONLY, readonly);
-    }
-
-    /**
-     * 
-     * @return true if the field is readonly
-     */
-    public boolean isReadonly()
-    {
-        return getDictionary().getFlag( COSName.FF, FLAG_READ_ONLY);
-    }
-
-    /**
-     * sets the field to be required.
-     * 
-     * @param required The new flag for required.
-     */
-    public void setRequired(boolean required)
-    {
-        getDictionary().setFlag( COSName.FF, FLAG_REQUIRED, required);
-    }
-
-    /**
-     * 
-     * @return true if the field is required
-     */
-    public boolean isRequired()
-    {
-        return getDictionary().getFlag( COSName.FF, FLAG_REQUIRED);
-    }
-
-    /**
-     * sets the field to be not exported..
-     * 
-     * @param noExport The new flag for noExport.
-     */
-    public void setNoExport(boolean noExport)
-    {
-        getDictionary().setFlag( COSName.FF, FLAG_NO_EXPORT, noExport);
-    }
-
-    /**
+     * Set the actions of the field.
      * 
-     * @return true if the field is not to be exported.
+     * @param actions The field actions.
      */
-    public boolean isNoExport()
+    public void setActions(PDFormFieldAdditionalActions actions)
     {
-        return getDictionary().getFlag( COSName.FF, FLAG_NO_EXPORT);
+        getDictionary().setItem(COSName.AA, actions);
     }
-
+    
     /**
-     * This will get the flags for this field.
-     * 
-     * @return flags The set of flags.
+     * {@inheritDoc}
      */
+    @Override
     public int getFieldFlags()
     {
         int retval = 0;
@@ -291,376 +101,26 @@ public abstract class PDField implements
         {
             retval = ff.intValue();
         }
-        return retval;
-    }
-
-    /**
-     * This will set the flags for this field.
-     * 
-     * @param flags The new flags.
-     */
-    public void setFieldFlags(int flags)
-    {
-        getDictionary().setInt(COSName.FF, flags);
-    }
-
-    /**
-     * This will import a fdf field from a fdf document.
-     * 
-     * @param fdfField The fdf field to import.
-     * 
-     * @throws IOException If there is an error importing the data for this field.
-     */
-    public void importFDF(FDFField fdfField) throws IOException
-    {
-        Object fieldValue = fdfField.getValue();
-        int fieldFlags = getFieldFlags();
-
-        if (fieldValue != null)
-        {
-            if (fieldValue instanceof String)
-            {
-                setValue((String) fieldValue);
-            }
-            else if (fieldValue instanceof PDTextStream)
-            {
-                setValue(((PDTextStream) fieldValue).getAsString());
-            }
-            else
-            {
-                throw new IOException("Unknown field type:" + fieldValue.getClass().getName());
-            }
-        }
-        Integer ff = fdfField.getFieldFlags();
-        if (ff != null)
-        {
-            setFieldFlags(ff);
-        }
-        else
-        {
-            // these are suppose to be ignored if the Ff is set.
-            Integer setFf = fdfField.getSetFieldFlags();
-
-            if (setFf != null)
-            {
-                int setFfInt = setFf;
-                fieldFlags = fieldFlags | setFfInt;
-                setFieldFlags(fieldFlags);
-            }
-
-            Integer clrFf = fdfField.getClearFieldFlags();
-            if (clrFf != null)
-            {
-                // we have to clear the bits of the document fields for every bit that is
-                // set in this field.
-                //
-                // Example:
-                // docFf = 1011
-                // clrFf = 1101
-                // clrFfValue = 0010;
-                // newValue = 1011 & 0010 which is 0010
-                int clrFfValue = clrFf;
-                clrFfValue ^= 0xFFFFFFFF;
-                fieldFlags = fieldFlags & clrFfValue;
-                setFieldFlags(fieldFlags);
-            }
-        }
-
-        PDAnnotationWidget widget = getWidget();
-        if (widget != null)
-        {
-            int annotFlags = widget.getAnnotationFlags();
-            Integer f = fdfField.getWidgetFieldFlags();
-            if (f != null && widget != null)
-            {
-                widget.setAnnotationFlags(f);
-            }
-            else
-            {
-                // these are suppose to be ignored if the F is set.
-                Integer setF = fdfField.getSetWidgetFieldFlags();
-                if (setF != null)
-                {
-                    annotFlags = annotFlags | setF;
-                    widget.setAnnotationFlags(annotFlags);
-                }
-
-                Integer clrF = fdfField.getClearWidgetFieldFlags();
-                if (clrF != null)
-                {
-                    // we have to clear the bits of the document fields for every bit that is
-                    // set in this field.
-                    //
-                    // Example:
-                    // docF = 1011
-                    // clrF = 1101
-                    // clrFValue = 0010;
-                    // newValue = 1011 & 0010 which is 0010
-                    int clrFValue = clrF;
-                    clrFValue ^= 0xFFFFFFFFL;
-                    annotFlags = annotFlags & clrFValue;
-                    widget.setAnnotationFlags(annotFlags);
-                }
-            }
-        }
-        List<FDFField> fdfKids = fdfField.getKids();
-        List<COSObjectable> pdKids = getKids();
-        for (int i = 0; fdfKids != null && i < fdfKids.size(); i++)
-        {
-            FDFField fdfChild = fdfKids.get(i);
-            String fdfName = fdfChild.getPartialFieldName();
-            for (COSObjectable pdKid : pdKids)
-            {
-                Object pdChildObj = pdKid;
-                if (pdChildObj instanceof PDField)
-                {
-                    PDField pdChild = (PDField) pdChildObj;
-                    if (fdfName != null && fdfName.equals(pdChild.getPartialName()))
-                    {
-                        pdChild.importFDF(fdfChild);
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * This will get the single associated widget that is part of this field. This occurs when the Widget is embedded in
-     * the fields dictionary. Sometimes there are multiple sub widgets associated with this field, in which case you
-     * want to use getKids(). If the kids entry is specified, then the first entry in that list will be returned.
-     * 
-     * @return The widget that is associated with this field.
-     * @throws IOException If there is an error getting the widget object.
-     */
-    public PDAnnotationWidget getWidget() throws IOException
-    {
-        PDAnnotationWidget retval = null;
-        List<COSObjectable> kids = getKids();
-        if (kids == null)
-        {
-            retval = new PDAnnotationWidget(getDictionary());
-        }
-        else if (kids.size() > 0)
-        {
-            Object firstKid = kids.get(0);
-            if (firstKid instanceof PDAnnotationWidget)
-            {
-                retval = (PDAnnotationWidget) firstKid;
-            }
-            else
-            {
-                retval = ((PDField) firstKid).getWidget();
-            }
-        }
-        else
-        {
-            retval = null;
-        }
-        return retval;
-    }
-
-    /**
-     * Get the parent field to this field, or null if none exists.
-     * 
-     * @return The parent field.
-     * 
-     * @throws IOException If there is an error creating the parent field.
-     */
-    public PDField getParent() throws IOException
-    {
-        PDField parent = null;
-        COSDictionary parentDic = (COSDictionary) getDictionary().getDictionaryObject(COSName.PARENT, COSName.P);
-        if (parentDic != null)
-        {
-            parent = PDFieldFactory.createField(getAcroForm(), parentDic);
-        }
-        return parent;
-    }
-
-    /**
-     * Set the parent of this field.
-     * 
-     * @param parent The parent to this field.
-     */
-    public void setParent(PDField parent)
-    {
-        getDictionary().setItem(COSName.PARENT, parent);
-    }
-
-    /**
-     * This will find one of the child elements. The name array are the components of the name to search down the tree
-     * of names. The nameIndex is where to start in that array. This method is called recursively until it finds the end
-     * point based on the name array.
-     * 
-     * @param name An array that picks the path to the field.
-     * @param nameIndex The index into the array.
-     * @return The field at the endpoint or null if none is found.
-     * @throws IOException If there is an error creating the field.
-     */
-    public PDField findKid(String[] name, int nameIndex) throws IOException
-    {
-        PDField retval = null;
-        COSArray kids = (COSArray) getDictionary().getDictionaryObject(COSName.KIDS);
-        if (kids != null)
-        {
-            for (int i = 0; retval == null && i < kids.size(); i++)
-            {
-                COSDictionary kidDictionary = (COSDictionary) kids.getObject(i);
-                if (name[nameIndex].equals(kidDictionary.getString(COSName.T)))
-                {
-                    retval = PDFieldFactory.createField(acroForm, kidDictionary);
-                    if (name.length > nameIndex + 1)
-                    {
-                        retval = retval.findKid(name, nameIndex + 1);
-                    }
-                }
-            }
-        }
-        return retval;
-    }
-
-    /**
-     * This will get all the kids of this field. The values in the list will either be PDWidget or PDField. Normally
-     * they will be PDWidget objects unless this is a non-terminal field and they will be child PDField objects.
-     *
-     * @return A list of either PDWidget or PDField objects.
-     * @throws IOException If there is an error retrieving the kids.
-     */
-    public List<COSObjectable> getKids() throws IOException
-    {
-        return getKids(acroForm, getDictionary());
-    }
-
-    // used by factory class
-    static List<COSObjectable> getKids(PDAcroForm form, COSDictionary dictionary)
-            throws IOException
-    {
-        List<COSObjectable> retval = null;
-        COSArray kids = (COSArray) dictionary.getDictionaryObject(COSName.KIDS);
-        if (kids != null)
+        else if (getParent() != null)
         {
-            List<COSObjectable> kidsList = new ArrayList<COSObjectable>();
-            for (int i = 0; i < kids.size(); i++)
-            {
-                COSDictionary kidDictionary = (COSDictionary) kids.getObject(i);
-                if (kidDictionary == null)
-                {
-                    continue;
-                }
-                COSDictionary parent = (COSDictionary) kidDictionary.getDictionaryObject(COSName.PARENT, COSName.P);
-                if (kidDictionary.getDictionaryObject(COSName.FT) != null
-                        || (parent != null && parent.getDictionaryObject(COSName.FT) != null))
-                {
-                    PDField field = PDFieldFactory.createField(form, kidDictionary);
-                    if (field != null)
-                    {
-                        kidsList.add(field);
-                    }
-                }
-                else if ("Widget".equals(kidDictionary.getNameAsString(COSName.SUBTYPE)))
-                {
-                    kidsList.add(new PDAnnotationWidget(kidDictionary));
-                }
-                else
-                {
-                    PDField field = PDFieldFactory.createField(form, kidDictionary);
-                    if (field != null)
-                    {
-                        kidsList.add(field);
-                    }
-                }
-            }
-            retval = new COSArrayList<COSObjectable>(kidsList, kids);
+            retval = getParent().getFieldFlags();
         }
         return retval;
     }
 
     /**
-     * This will set the list of kids.
-     * 
-     * @param kids The list of child widgets.
-     */
-    public void setKids(List<COSObjectable> kids)
-    {
-        COSArray kidsArray = COSArrayList.converterToCOSArray(kids);
-        getDictionary().setItem(COSName.KIDS, kidsArray);
-    }
-
-    /**
-     * This will return a string representation of this field.
-     * 
-     * @return A string representation of this field.
+     * {@inheritDoc}
      */
     @Override
-    public String toString()
-    {
-        return "" + getDictionary().getDictionaryObject(COSName.V);
-    }
-
-    /**
-     * This will get the acroform that this field is part of.
-     * 
-     * @return The form this field is on.
-     */
-    public PDAcroForm getAcroForm()
-    {
-        return acroForm;
-    }
-
-    /**
-     * This will set the form this field is on.
-     * 
-     * @param value The new form to use.
-     */
-    public void setAcroForm(PDAcroForm value)
-    {
-        acroForm = value;
-    }
-
-    /**
-     * This will get the dictionary associated with this field.
-     * 
-     * @return The dictionary that this class wraps.
-     */
-    public COSDictionary getDictionary()
-    {
-        return dictionary;
-    }
-
-    /**
-     * Convert this standard java object to a COS object.
-     * 
-     * @return The cos object that matches this Java object.
-     */
-    public COSBase getCOSObject()
-    {
-        return dictionary;
-    }
-
-    /**
-     * Get the additional actions for this field. This will return null if there are no additional actions for this
-     * field.
-     * 
-     * @return The actions of the field.
-     */
-    public PDFormFieldAdditionalActions getActions()
+    public String getFieldType()
     {
-        COSDictionary aa = (COSDictionary) dictionary.getDictionaryObject(COSName.AA);
-        PDFormFieldAdditionalActions retval = null;
-        if (aa != null)
+        String fieldType = getDictionary().getNameAsString(COSName.FT);
+        if (fieldType == null && getParent() != null)
         {
-            retval = new PDFormFieldAdditionalActions(aa);
+            fieldType = getParent().getFieldType();
         }
-        return retval;
+        return fieldType;
     }
 
-    /**
-     * Set the actions of the field.
-     * 
-     * @param actions The field actions.
-     */
-    public void setActions(PDFormFieldAdditionalActions actions)
-    {
-        dictionary.setItem(COSName.AA, actions);
-    }
+
 }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDFieldFactory.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDFieldFactory.java?rev=1618374&r1=1618373&r2=1618374&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDFieldFactory.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDFieldFactory.java Sat Aug 16 15:21:09 2014
@@ -18,10 +18,6 @@ package org.apache.pdfbox.pdmodel.intera
 
 import org.apache.pdfbox.cos.COSDictionary;
 import org.apache.pdfbox.cos.COSName;
-import org.apache.pdfbox.pdmodel.common.COSObjectable;
-
-import java.io.IOException;
-import java.util.List;
 
 /**
  * Factory for creating instances of PDField.
@@ -30,14 +26,7 @@ import java.util.List;
  */
 public final class PDFieldFactory
 {
-    // button flags
-    private static final int FLAG_RADIO = 0x8000;
-    private static final int FLAG_PUSHBUTTON = 0x10000;
-    private static final int FLAG_RADIOS_IN_UNISON = 0x2000000;
-
-    // choice flags
-    private static final int FLAG_COMBO = 0x20000;
-
+ 
     private PDFieldFactory()
     {
     }
@@ -47,56 +36,52 @@ public final class PDFieldFactory
      * @param form the form that the field is part of
      * @param field the dictionary representing a field element
      * @return the corresponding PDField instance
-     * @throws IOException if the field cannot be read
      */
-    public static PDField createField(PDAcroForm form, COSDictionary field) throws IOException
+    public static PDFieldTreeNode createField(PDAcroForm form, COSDictionary field, PDFieldTreeNode parentNode)
     {
         String fieldType = PDField.findFieldType(field);
-        if (PDField.FIELD_TYPE_CHOICE.equals(fieldType))
+        if (PDFieldTreeNode.FIELD_TYPE_CHOICE.equals(fieldType))
         {
             int flags = field.getInt(COSName.FF, 0);
-            if ((flags & FLAG_COMBO) != 0)
+            if ((flags & PDVariableText.FLAG_COMB) != 0)
             {
-                return new PDComboBox(form, field);
+                return new PDComboBox(form, field, parentNode);
             }
             else
             {
-                return new PDListBox(form, field);
+                return new PDListBox(form, field, parentNode);
             }
         }
-        else if (PDField.FIELD_TYPE_TEXT.equals(fieldType))
+        else if (PDFieldTreeNode.FIELD_TYPE_TEXT.equals(fieldType))
         {
-            return new PDTextField(form, field);
+            return new PDTextField(form, field, parentNode);
         }
-        else if (PDField.FIELD_TYPE_SIGNATURE.equals(fieldType))
+        else if (PDFieldTreeNode.FIELD_TYPE_SIGNATURE.equals(fieldType))
         {
-            return new PDSignatureField(form, field);
+            return new PDSignatureField(form, field, parentNode);
         }
-        else if (PDField.FIELD_TYPE_BUTTON.equals(fieldType))
+        else if (PDFieldTreeNode.FIELD_TYPE_BUTTON.equals(fieldType))
         {
             int flags = field.getInt(COSName.FF, 0);
             // BJL: I have found that the radio flag bit is not always set
             // and that sometimes there is just a kids dictionary.
             // so, if there is a kids dictionary then it must be a radio button group.
-            // TODO JH: this is due to inheritance, we need proper support for "non-terminal fields"
-
-            if ((flags & FLAG_RADIO) != 0 || field.getDictionaryObject(COSName.KIDS) != null)
+            if ((flags & PDButton.FLAG_RADIO) != 0 || field.getDictionaryObject(COSName.KIDS) != null)
             {
-                return new PDRadioButton(form, field);
+                return new PDRadioButton(form, field, parentNode);
             }
-            else if ((flags & FLAG_PUSHBUTTON) != 0)
+            else if ((flags & PDButton.FLAG_PUSHBUTTON) != 0)
             {
-                return new PDPushButton(form, field);
+                return new PDPushButton(form, field, parentNode);
             }
             else
             {
-                return new PDCheckbox(form, field);
+                return new PDCheckbox(form, field, parentNode);
             }
         }
         else
         {
-            // todo: inheritance and "non-terminal fields" are not supported yet
-            return null;
+            return new PDNonTerminalField(form, field, parentNode); 
         }
     }
 

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDFieldTreeNode.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDFieldTreeNode.java?rev=1618374&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDFieldTreeNode.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDFieldTreeNode.java Sat Aug 16 15:21:09 2014
@@ -0,0 +1,600 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pdfbox.pdmodel.interactive.form;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.pdfbox.cos.COSArray;
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.pdmodel.common.COSArrayList;
+import org.apache.pdfbox.pdmodel.common.COSObjectable;
+import org.apache.pdfbox.pdmodel.common.PDTextStream;
+import org.apache.pdfbox.pdmodel.fdf.FDFField;
+import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget;
+
+/**
+ * A field in an interactive form.
+ *
+ * @author Andreas Lehmkühler
+ * 
+ */
+public abstract class PDFieldTreeNode implements COSObjectable
+{
+    /**
+     * A Ff flag.
+     */
+    public static final int FLAG_READ_ONLY = 1;
+    /**
+     * A Ff flag.
+     */
+    public static final int FLAG_REQUIRED = 1 << 1;
+    /**
+     * A Ff flag.
+     */
+    public static final int FLAG_NO_EXPORT = 1 << 2;
+
+    /**
+     * Field type Text.
+     */
+    public static final String FIELD_TYPE_TEXT = "Tx";
+    /**
+     * Field type Button.
+     */
+    public static final String FIELD_TYPE_BUTTON = "Btn";
+    /**
+     * Field type Button.
+     */
+    public static final String FIELD_TYPE_CHOICE = "Ch";
+    /**
+     * Field type Button.
+     */
+    public static final String FIELD_TYPE_SIGNATURE = "Sig";
+
+    private PDAcroForm acroForm;
+
+    private COSDictionary dictionary;
+
+    private PDFieldTreeNode parent = null;
+
+    /**
+     * Constructor.
+     * 
+     * @param theAcroForm The form that this field is part of.
+     */
+    protected PDFieldTreeNode(PDAcroForm theAcroForm)
+    {
+        this(theAcroForm, new COSDictionary(), null);
+    }
+
+    /**
+     * Constructor.
+     * 
+     * @param theAcroForm The form that this field is part of.
+     * @param field the PDF object to represent as a field.
+     * @param parentNode the parent node of the node to be created
+     */
+    protected PDFieldTreeNode(PDAcroForm theAcroForm, COSDictionary field, PDFieldTreeNode parentNode)
+    {
+        acroForm = theAcroForm;
+        dictionary = field;
+        parent = parentNode;
+    }
+
+    /**
+     * Get the FT entry of the field. This is a read only field and is set depending on the actual type. The field type
+     * is an inheritable attribute.
+     * 
+     * @return The Field type.
+     * 
+     */
+    public abstract String getFieldType();
+
+    // used by factory class
+    static String findFieldType(COSDictionary dic)
+    {
+        String retval = dic.getNameAsString(COSName.FT);
+        if (retval == null)
+        {
+            COSDictionary parent = (COSDictionary) dic.getDictionaryObject(COSName.PARENT,
+                    COSName.P);
+            if (parent != null)
+            {
+                retval = findFieldType(parent);
+            }
+        }
+        return retval;
+    }
+
+    /**
+     * setValue sets the fields value to a given string.
+     * 
+     * @param value the string value
+     * 
+     * @throws IOException If there is an error creating the appearance stream.
+     */
+    public abstract void setValue(String value) throws IOException;
+
+    /**
+     * getValue gets the fields value to as a string.
+     * 
+     * @return The string value of this field.
+     * 
+     * @throws IOException If there is an error getting the value.
+     */
+    public abstract String getValue() throws IOException;
+
+    /**
+     * sets the field to be read-only.
+     * 
+     * @param readonly The new flag for readonly.
+     */
+    public void setReadonly(boolean readonly)
+    {
+        getDictionary().setFlag(COSName.FF, FLAG_READ_ONLY, readonly);
+    }
+
+    /**
+     * 
+     * @return true if the field is readonly
+     */
+    public boolean isReadonly()
+    {
+        return getDictionary().getFlag(COSName.FF, FLAG_READ_ONLY);
+    }
+
+    /**
+     * sets the field to be required.
+     * 
+     * @param required The new flag for required.
+     */
+    public void setRequired(boolean required)
+    {
+        getDictionary().setFlag(COSName.FF, FLAG_REQUIRED, required);
+    }
+
+    /**
+     * 
+     * @return true if the field is required
+     */
+    public boolean isRequired()
+    {
+        return getDictionary().getFlag(COSName.FF, FLAG_REQUIRED);
+    }
+
+    /**
+     * sets the field to be not exported..
+     * 
+     * @param noExport The new flag for noExport.
+     */
+    public void setNoExport(boolean noExport)
+    {
+        getDictionary().setFlag(COSName.FF, FLAG_NO_EXPORT, noExport);
+    }
+
+    /**
+     * 
+     * @return true if the field is not to be exported.
+     */
+    public boolean isNoExport()
+    {
+        return getDictionary().getFlag(COSName.FF, FLAG_NO_EXPORT);
+    }
+
+    /**
+     * This will get the flags for this field.
+     * 
+     * @return flags The set of flags.
+     */
+    public abstract int getFieldFlags();
+
+    /**
+     * This will set the flags for this field.
+     * 
+     * @param flags The new flags.
+     */
+    public void setFieldFlags(int flags)
+    {
+        getDictionary().setInt(COSName.FF, flags);
+    }
+
+    /**
+     * This will import a fdf field from a fdf document.
+     * 
+     * @param fdfField The fdf field to import.
+     * 
+     * @throws IOException If there is an error importing the data for this field.
+     */
+    public void importFDF(FDFField fdfField) throws IOException
+    {
+        Object fieldValue = fdfField.getValue();
+        int fieldFlags = getFieldFlags();
+
+        if (fieldValue != null)
+        {
+            if (fieldValue instanceof String)
+            {
+                setValue((String) fieldValue);
+            }
+            else if (fieldValue instanceof PDTextStream)
+            {
+                setValue(((PDTextStream) fieldValue).getAsString());
+            }
+            else
+            {
+                throw new IOException("Unknown field type:" + fieldValue.getClass().getName());
+            }
+        }
+        Integer ff = fdfField.getFieldFlags();
+        if (ff != null)
+        {
+            setFieldFlags(ff);
+        }
+        else
+        {
+            // these are suppose to be ignored if the Ff is set.
+            Integer setFf = fdfField.getSetFieldFlags();
+
+            if (setFf != null)
+            {
+                int setFfInt = setFf;
+                fieldFlags = fieldFlags | setFfInt;
+                setFieldFlags(fieldFlags);
+            }
+
+            Integer clrFf = fdfField.getClearFieldFlags();
+            if (clrFf != null)
+            {
+                // we have to clear the bits of the document fields for every bit that is
+                // set in this field.
+                //
+                // Example:
+                // docFf = 1011
+                // clrFf = 1101
+                // clrFfValue = 0010;
+                // newValue = 1011 & 0010 which is 0010
+                int clrFfValue = clrFf;
+                clrFfValue ^= 0xFFFFFFFF;
+                fieldFlags = fieldFlags & clrFfValue;
+                setFieldFlags(fieldFlags);
+            }
+        }
+
+        PDAnnotationWidget widget = getWidget();
+        if (widget != null)
+        {
+            int annotFlags = widget.getAnnotationFlags();
+            Integer f = fdfField.getWidgetFieldFlags();
+            if (f != null && widget != null)
+            {
+                widget.setAnnotationFlags(f);
+            }
+            else
+            {
+                // these are suppose to be ignored if the F is set.
+                Integer setF = fdfField.getSetWidgetFieldFlags();
+                if (setF != null)
+                {
+                    annotFlags = annotFlags | setF;
+                    widget.setAnnotationFlags(annotFlags);
+                }
+
+                Integer clrF = fdfField.getClearWidgetFieldFlags();
+                if (clrF != null)
+                {
+                    // we have to clear the bits of the document fields for every bit that is
+                    // set in this field.
+                    //
+                    // Example:
+                    // docF = 1011
+                    // clrF = 1101
+                    // clrFValue = 0010;
+                    // newValue = 1011 & 0010 which is 0010
+                    int clrFValue = clrF;
+                    clrFValue ^= 0xFFFFFFFFL;
+                    annotFlags = annotFlags & clrFValue;
+                    widget.setAnnotationFlags(annotFlags);
+                }
+            }
+        }
+        List<FDFField> fdfKids = fdfField.getKids();
+        List<COSObjectable> pdKids = getKids();
+        for (int i = 0; fdfKids != null && i < fdfKids.size(); i++)
+        {
+            FDFField fdfChild = fdfKids.get(i);
+            String fdfName = fdfChild.getPartialFieldName();
+            for (COSObjectable pdKid : pdKids)
+            {
+                if (pdKid instanceof PDFieldTreeNode)
+                {
+                    PDFieldTreeNode pdChild = (PDFieldTreeNode) pdKid;
+                    if (fdfName != null && fdfName.equals(pdChild.getPartialName()))
+                    {
+                        pdChild.importFDF(fdfChild);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * This will get the single associated widget that is part of this field. This occurs when the Widget is embedded in
+     * the fields dictionary. Sometimes there are multiple sub widgets associated with this field, in which case you
+     * want to use getKids(). If the kids entry is specified, then the first entry in that list will be returned.
+     * 
+     * @return The widget that is associated with this field.
+     */
+    public PDAnnotationWidget getWidget()
+    {
+        PDAnnotationWidget retval = null;
+        List<COSObjectable> kids = getKids();
+        if (kids == null)
+        {
+            retval = new PDAnnotationWidget(getDictionary());
+        }
+        else if (kids.size() > 0)
+        {
+            Object firstKid = kids.get(0);
+            if (firstKid instanceof PDAnnotationWidget)
+            {
+                retval = (PDAnnotationWidget) firstKid;
+            }
+            else
+            {
+                retval = ((PDFieldTreeNode) firstKid).getWidget();
+            }
+        }
+        else
+        {
+            retval = null;
+        }
+        return retval;
+    }
+
+    /**
+     * Get the parent field to this field, or null if none exists.
+     * 
+     * @return The parent field.
+     * 
+     */
+    public PDFieldTreeNode getParent()
+    {
+        return parent;
+    }
+
+    /**
+     * Set the parent of this field.
+     * 
+     * @param parent The parent to this field.
+     */
+    public void setParent(PDFieldTreeNode parentNode)
+    {
+        parent = parentNode;
+        if (parentNode != null)
+        {
+            getDictionary().setItem(COSName.PARENT, parent.getDictionary());
+        }
+        else
+        {
+            getDictionary().removeItem(COSName.PARENT);
+        }
+    }
+
+    /**
+     * This will find one of the child elements. The name array are the components of the name to search down the tree
+     * of names. The nameIndex is where to start in that array. This method is called recursively until it finds the end
+     * point based on the name array.
+     * 
+     * @param name An array that picks the path to the field.
+     * @param nameIndex The index into the array.
+     * @return The field at the endpoint or null if none is found.
+     */
+    public PDFieldTreeNode findKid(String[] name, int nameIndex)
+    {
+        PDFieldTreeNode retval = null;
+        COSArray kids = (COSArray) getDictionary().getDictionaryObject(COSName.KIDS);
+        if (kids != null)
+        {
+            for (int i = 0; retval == null && i < kids.size(); i++)
+            {
+                COSDictionary kidDictionary = (COSDictionary) kids.getObject(i);
+                if (name[nameIndex].equals(kidDictionary.getString(COSName.T)))
+                {
+                    retval = (PDFieldTreeNode) PDFieldFactory.createField(acroForm, kidDictionary, this);
+                    if (name.length > nameIndex + 1)
+                    {
+                        retval = retval.findKid(name, nameIndex + 1);
+                    }
+                }
+            }
+        }
+        return retval;
+    }
+
+    /**
+     * This will get all the kids of this field. The values in the list will either be PDWidget or PDField. Normally
+     * they will be PDWidget objects unless this is a non-terminal field and they will be child PDField objects.
+     *
+     * @return A list of either PDWidget or PDField objects.
+     */
+    public List<COSObjectable> getKids()
+    {
+        List<COSObjectable> retval = null;
+        COSArray kids = (COSArray) dictionary.getDictionaryObject(COSName.KIDS);
+        if (kids != null)
+        {
+            List<COSObjectable> kidsList = new ArrayList<COSObjectable>();
+            for (int i = 0; i < kids.size(); i++)
+            {
+                COSDictionary kidDictionary = (COSDictionary) kids.getObject(i);
+                if (kidDictionary == null)
+                {
+                    continue;
+                }
+                COSDictionary parent = (COSDictionary) kidDictionary.getDictionaryObject(
+                        COSName.PARENT, COSName.P);
+                if (kidDictionary.getDictionaryObject(COSName.FT) != null
+                        || (parent != null && parent.getDictionaryObject(COSName.FT) != null))
+                {
+                    PDFieldTreeNode field = PDFieldFactory.createField(acroForm, kidDictionary, this);
+                    if (field != null)
+                    {
+                        kidsList.add(field);
+                    }
+                }
+                else if ("Widget".equals(kidDictionary.getNameAsString(COSName.SUBTYPE)))
+                {
+                    kidsList.add(new PDAnnotationWidget(kidDictionary));
+                }
+                else
+                {
+                    PDFieldTreeNode field = PDFieldFactory.createField(acroForm, kidDictionary, this);
+                    if (field != null)
+                    {
+                        kidsList.add(field);
+                    }
+                }
+            }
+            retval = new COSArrayList<COSObjectable>(kidsList, kids);
+        }
+        return retval;
+    }
+
+    /**
+     * This will set the list of kids.
+     * 
+     * @param kids The list of child widgets.
+     */
+    public void setKids(List<COSObjectable> kids)
+    {
+        COSArray kidsArray = COSArrayList.converterToCOSArray(kids);
+        getDictionary().setItem(COSName.KIDS, kidsArray);
+    }
+
+    /**
+     * This will return a string representation of this field.
+     * 
+     * @return A string representation of this field.
+     */
+    @Override
+    public String toString()
+    {
+        return "" + getDictionary().getDictionaryObject(COSName.V);
+    }
+
+    /**
+     * This will get the acroform that this field is part of.
+     * 
+     * @return The form this field is on.
+     */
+    public PDAcroForm getAcroForm()
+    {
+        return acroForm;
+    }
+
+    /**
+     * This will set the form this field is on.
+     * 
+     * @param value The new form to use.
+     */
+    public void setAcroForm(PDAcroForm value)
+    {
+        acroForm = value;
+    }
+
+    /**
+     * This will get the dictionary associated with this field.
+     * 
+     * @return The dictionary that this class wraps.
+     */
+    public COSDictionary getDictionary()
+    {
+        return dictionary;
+    }
+
+    /**
+     * Convert this standard java object to a COS object.
+     * 
+     * @return The cos object that matches this Java object.
+     */
+    public COSBase getCOSObject()
+    {
+        return dictionary;
+    }
+
+    /**
+     * Returns the partial name of the field.
+     * 
+     * @return the name of the field
+     */
+    public String getPartialName()
+    {
+        return getDictionary().getString(COSName.T);
+    }
+
+    /**
+     * This will set the partial name of the field.
+     * 
+     * @param name The new name for the field.
+     */
+    public void setPartialName(String name)
+    {
+        getDictionary().setString(COSName.T, name);
+    }
+
+    /**
+     * Returns the fully qualified name of the field, which is a concatenation of the names of all the parents fields.
+     * 
+     * @return the name of the field
+     * 
+     * @throws IOException If there is an error generating the fully qualified name.
+     */
+    public String getFullyQualifiedName() throws IOException
+    {
+        String parentName = parent.getFullyQualifiedName();
+        String finalName = getPartialName();
+        if (parentName != null)
+        {
+            finalName = parentName + "." + finalName;
+        }
+        return finalName;
+    }
+
+    /**
+     * Gets the alternate name of the field.
+     * 
+     * @return the alternate name of the field
+     */
+    public String getAlternateFieldName()
+    {
+        return this.getDictionary().getString(COSName.TU);
+    }
+
+    /**
+     * This will set the alternate name of the field.
+     * 
+     * @param alternateFieldName the alternate name of the field
+     */
+    public void setAlternateFieldName(String alternateFieldName)
+    {
+        this.getDictionary().setString(COSName.TU, alternateFieldName);
+    }
+
+}

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDFieldTreeNode.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDListBox.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDListBox.java?rev=1618374&r1=1618373&r2=1618374&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDListBox.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDListBox.java Sat Aug 16 15:21:09 2014
@@ -30,13 +30,15 @@ import java.io.IOException;
 public final class PDListBox extends PDChoice
 {
     /**
-     * Creates a new list box field
-     * @param acroForm the parent form
-     * @param field the COS field
+     * Constructor.
+     * 
+     * @param theAcroForm The form that this field is part of.
+     * @param field the PDF object to represent as a field.
+     * @param parentNode the parent node of the node to be created
      */
-    public PDListBox(PDAcroForm acroForm, COSDictionary field)
+    public PDListBox(PDAcroForm acroForm, COSDictionary field, PDFieldTreeNode parentNode)
     {
-        super(acroForm, field);
+        super(acroForm, field, parentNode);
     }
 
     @Override

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDNonTerminalField.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDNonTerminalField.java?rev=1618374&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDNonTerminalField.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDNonTerminalField.java Sat Aug 16 15:21:09 2014
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pdfbox.pdmodel.interactive.form;
+
+import java.io.IOException;
+
+import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSInteger;
+import org.apache.pdfbox.cos.COSName;
+
+/**
+ * A non terminal field in an interactive form.
+ *
+ * @author Andreas Lehmkühler
+ */
+public class PDNonTerminalField extends PDFieldTreeNode
+{
+    /**
+     * Constructor.
+     * 
+     * @param theAcroForm The form that this field is part of.
+     */
+    public PDNonTerminalField(PDAcroForm theAcroForm)
+    {
+        super(theAcroForm);
+    }
+
+    /**
+     * Constructor.
+     * 
+     * @param theAcroForm The form that this field is part of.
+     * @param field the PDF object to represent as a field.
+     * @param parentNode the parent node of the node to be created
+     */
+    public PDNonTerminalField(PDAcroForm theAcroForm, COSDictionary field, PDFieldTreeNode parentNode)
+    {
+        super(theAcroForm, field, parentNode);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int getFieldFlags()
+    {
+        int retval = 0;
+        COSInteger ff = (COSInteger) getDictionary().getDictionaryObject(COSName.FF);
+        if (ff != null)
+        {
+            retval = ff.intValue();
+        }
+        // There is no need to look up the parent hierarchy within a non terminal field
+        return retval;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getFieldType()
+    {
+        // There is no need to look up the parent hierarchy within a non terminal field
+        return getDictionary().getNameAsString(COSName.FT);
+    }
+
+    @Override
+    public void setValue(String value) throws IOException
+    {
+        // non terminal fields don't have a value
+    }
+
+    @Override
+    public String getValue() throws IOException
+    {
+        // non terminal fields don't have a value
+        return null;
+    }
+
+}

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDNonTerminalField.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDPushButton.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDPushButton.java?rev=1618374&r1=1618373&r2=1618374&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDPushButton.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDPushButton.java Sat Aug 16 15:21:09 2014
@@ -32,14 +32,15 @@ public class PDPushButton extends PDButt
 {
 
     /**
-     * @see PDField#PDField(PDAcroForm, COSDictionary)
-     *
-     * @param theAcroForm The acroForm for this field.
-     * @param field The field for this push button.
+     * Constructor.
+     * 
+     * @param theAcroForm The form that this field is part of.
+     * @param field the PDF object to represent as a field.
+     * @param parentNode the parent node of the node to be created
      */
-    public PDPushButton( PDAcroForm theAcroForm, COSDictionary field)
+    public PDPushButton( PDAcroForm theAcroForm, COSDictionary field, PDFieldTreeNode parentNode)
     {
-        super(theAcroForm, field);
+        super(theAcroForm, field, parentNode);
     }
 
     /**