Home » pdfbox-1.1.0-src » org.apache.pdfbox.pdmodel.interactive.form » [javadoc | source]

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    */
   17   package org.apache.pdfbox.pdmodel.interactive.form;
   18   
   19   import org.apache.pdfbox.pdmodel.interactive.action.PDFormFieldAdditionalActions;
   20   import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget;
   21   
   22   import org.apache.pdfbox.pdmodel.common.COSArrayList;
   23   import org.apache.pdfbox.pdmodel.common.COSObjectable;
   24   
   25   import org.apache.pdfbox.cos.COSArray;
   26   import org.apache.pdfbox.cos.COSBase;
   27   import org.apache.pdfbox.cos.COSDictionary;
   28   import org.apache.pdfbox.cos.COSInteger;
   29   import org.apache.pdfbox.cos.COSName;
   30   
   31   import org.apache.pdfbox.pdmodel.common.PDTextStream;
   32   
   33   import org.apache.pdfbox.pdmodel.fdf.FDFField;
   34   import org.apache.pdfbox.util.BitFlagHelper;
   35   
   36   import java.io.IOException;
   37   
   38   import java.util.ArrayList;
   39   import java.util.List;
   40   
   41   /**
   42    * This is the superclass for a Field element in a PDF.
   43    * Based on the COS object model from PDFBox.
   44    *
   45    * @author sug
   46    * @version $Revision: 1.23 $
   47    */
   48   public abstract class PDField implements COSObjectable
   49   {
   50       /**
   51        * A Ff flag.
   52        */
   53       public static final int FLAG_READ_ONLY = 1;
   54       /**
   55        * A Ff flag.
   56        */
   57       public static final int FLAG_REQUIRED = 1 << 1;
   58       /**
   59        * A Ff flag.
   60        */
   61       public static final int FLAG_NO_EXPORT = 1 << 2;
   62   
   63   
   64       private PDAcroForm acroForm;
   65   
   66       private COSDictionary dictionary;
   67   
   68       /**
   69        * Constructor.
   70        *
   71        * @param theAcroForm The form that this field is part of.
   72        */
   73       public PDField( PDAcroForm theAcroForm )
   74       {
   75           acroForm = theAcroForm;
   76           dictionary = new COSDictionary();
   77           //no required fields in base field class
   78       }
   79   
   80   
   81       /**
   82        * Creates a COSField from a COSDictionary, expected to be
   83        * a correct object definition for a field in PDF.
   84        *
   85        * @param theAcroForm The form that this field is part of.
   86        * @param field the PDF objet to represent as a field.
   87        */
   88       public PDField(PDAcroForm theAcroForm, COSDictionary field)
   89       {
   90           acroForm = theAcroForm;
   91           dictionary = field;
   92       }
   93   
   94       /**
   95        * Returns the partial name of the field.
   96        *
   97        * @return the name of the field
   98        */
   99       public String getPartialName()
  100       {
  101           return getDictionary().getString( "T" );
  102       }
  103   
  104       /**
  105        * This will set the partial name of the field.
  106        *
  107        * @param name The new name for the field.
  108        */
  109       public void setPartialName( String name )
  110       {
  111           getDictionary().setString( "T", name );
  112       }
  113   
  114       /**
  115        * Returns the fully qualified name of the field, which is a concatenation of
  116        * the names of all the parents fields.
  117        *
  118        * @return the name of the field
  119        *
  120        * @throws IOException If there is an error generating the fully qualified name.
  121        */
  122       public String getFullyQualifiedName() throws IOException
  123       {
  124           PDField parent = getParent();
  125           String parentName = null;
  126           if( parent != null )
  127           {
  128               parentName = parent.getFullyQualifiedName();
  129           }
  130           String finalName = getPartialName();
  131           if( parentName != null )
  132           {
  133               finalName = parentName + "." + finalName;
  134           }
  135           return finalName;
  136       }
  137   
  138       /**
  139        * Gets the alternate name of the field.
  140        * 
  141        * @return the alternate name of the field
  142        */
  143       public String getAlternateFieldName()
  144       {
  145           return this.getDictionary().getString("TU");
  146       }
  147   
  148       /**
  149        * This will set the alternate name of the field.
  150        * 
  151        * @param alternateFieldName the alternate name of the field
  152        */
  153       public void setAlternateFieldName(String alternateFieldName)
  154       {
  155           this.getDictionary().setString("TU", alternateFieldName);
  156       }
  157   
  158       /**
  159        * Get the FT entry of the field.  This is a read only field and is set depending
  160        * on the actual type.  The field type is an inheritable attribute.  This method will
  161        * return only the direct value on this object.  Use the findFieldType for an upward
  162        * recursive search.
  163        *
  164        * @return The Field type.
  165        *
  166        * @see PDField#findFieldType()
  167        */
  168       public String getFieldType()
  169       {
  170           return getDictionary().getNameAsString( "FT" );
  171       }
  172   
  173       /**
  174        * Find the field type and optionally do a recursive upward search.  Sometimes the fieldtype
  175        * will be specified on the parent instead of the direct object.  This will look at this
  176        * object for the field type, if none is specified then it will look to the parent if there
  177        * is a parent.  If there is no parent and no field type has been found then this
  178        * will return null.
  179        *
  180        * @return The field type or null if none was found.
  181        */
  182       public String findFieldType()
  183       {
  184           return findFieldType( getDictionary() );
  185       }
  186   
  187       private String findFieldType( COSDictionary dic )
  188       {
  189           String retval = dic.getNameAsString( "FT" );
  190           if( retval == null )
  191           {
  192               COSDictionary parent = (COSDictionary)dic.getDictionaryObject( "Parent", "P" );
  193               if( parent != null )
  194               {
  195                   retval = findFieldType( parent );
  196               }
  197           }
  198           return retval;
  199   
  200       }
  201   
  202   
  203       /**
  204        * setValue sets the fields value to a given string.
  205        *
  206        * @param value the string value
  207        *
  208        * @throws IOException If there is an error creating the appearance stream.
  209        */
  210       public abstract void setValue(String value) throws IOException;
  211   
  212       /**
  213        * getValue gets the fields value to as a string.
  214        *
  215        * @return The string value of this field.
  216        *
  217        * @throws IOException If there is an error getting the value.
  218        */
  219       public abstract String getValue() throws IOException;
  220   
  221       /**
  222        * sets the field to be read-only.
  223        *
  224        * @param readonly The new flag for readonly.
  225        */
  226       public void setReadonly(boolean readonly)
  227       {
  228           BitFlagHelper.setFlag( getDictionary(), "Ff", FLAG_READ_ONLY, readonly );
  229       }
  230   
  231       /**
  232        *
  233        * @return true if the field is readonly
  234        */
  235       public boolean isReadonly()
  236       {
  237           return BitFlagHelper.getFlag( getDictionary(), "Ff", FLAG_READ_ONLY );
  238       }
  239   
  240       /**
  241        * sets the field to be required.
  242        *
  243        * @param required The new flag for required.
  244        */
  245       public void setRequired(boolean required)
  246       {
  247           BitFlagHelper.setFlag( getDictionary(), "Ff", FLAG_REQUIRED, required );
  248       }
  249   
  250       /**
  251        *
  252        * @return true if the field is required
  253        */
  254       public boolean isRequired()
  255       {
  256           return BitFlagHelper.getFlag( getDictionary(), "Ff", FLAG_REQUIRED );
  257       }
  258   
  259       /**
  260        * sets the field to be not exported..
  261        *
  262        * @param noExport The new flag for noExport.
  263        */
  264       public void setNoExport(boolean noExport)
  265       {
  266           BitFlagHelper.setFlag( getDictionary(), "Ff", FLAG_NO_EXPORT, noExport );
  267       }
  268   
  269       /**
  270        *
  271        * @return true if the field is not to be exported.
  272        */
  273       public boolean isNoExport()
  274       {
  275           return BitFlagHelper.getFlag( getDictionary(), "Ff", FLAG_NO_EXPORT );
  276       }
  277   
  278       /**
  279        * This will get the flags for this field.
  280        *
  281        * @return flags The set of flags.
  282        */
  283       public int getFieldFlags()
  284       {
  285           int retval = 0;
  286           COSInteger ff = (COSInteger)getDictionary().getDictionaryObject( COSName.getPDFName( "Ff" ) );
  287           if( ff != null )
  288           {
  289               retval = ff.intValue();
  290           }
  291           return retval;
  292       }
  293   
  294       /**
  295        * This will set the flags for this field.
  296        *
  297        * @param flags The new flags.
  298        */
  299       public void setFieldFlags( int flags )
  300       {
  301           getDictionary().setInt( COSName.getPDFName( "Ff" ), flags );
  302       }
  303   
  304       /**
  305        * This will import a fdf field from a fdf document.
  306        *
  307        * @param fdfField The fdf field to import.
  308        *
  309        * @throws IOException If there is an error importing the data for this field.
  310        */
  311       public void importFDF( FDFField fdfField ) throws IOException
  312       {
  313           Object fieldValue = fdfField.getValue();
  314           int fieldFlags = getFieldFlags();
  315   
  316           if( fieldValue != null )
  317           {
  318               if( fieldValue instanceof String )
  319               {
  320                   setValue( (String)fieldValue );
  321               }
  322               else if( fieldValue instanceof PDTextStream )
  323               {
  324                   setValue( ((PDTextStream)fieldValue).getAsString() );
  325               }
  326               else
  327               {
  328                   throw new IOException( "Unknown field type:" + fieldValue.getClass().getName() );
  329               }
  330           }
  331           Integer ff = fdfField.getFieldFlags();
  332           if( ff != null )
  333           {
  334               setFieldFlags( ff.intValue() );
  335           }
  336           else
  337           {
  338               //these are suppose to be ignored if the Ff is set.
  339               Integer setFf = fdfField.getSetFieldFlags();
  340   
  341               if( setFf != null )
  342               {
  343                   int setFfInt = setFf.intValue();
  344                   fieldFlags = fieldFlags | setFfInt;
  345                   setFieldFlags( fieldFlags );
  346               }
  347   
  348               Integer clrFf = fdfField.getClearFieldFlags();
  349               if( clrFf != null )
  350               {
  351                   //we have to clear the bits of the document fields for every bit that is
  352                   //set in this field.
  353                   //
  354                   //Example:
  355                   //docFf = 1011
  356                   //clrFf = 1101
  357                   //clrFfValue = 0010;
  358                   //newValue = 1011 & 0010 which is 0010
  359                   int clrFfValue = clrFf.intValue();
  360                   clrFfValue ^= 0xFFFFFFFF;
  361                   fieldFlags = fieldFlags & clrFfValue;
  362                   setFieldFlags( fieldFlags );
  363               }
  364           }
  365   
  366           PDAnnotationWidget widget = getWidget();
  367           if( widget != null )
  368           {
  369               int annotFlags = widget.getAnnotationFlags();
  370               Integer f = fdfField.getWidgetFieldFlags();
  371               if( f != null && widget != null )
  372               {
  373                   widget.setAnnotationFlags( f.intValue() );
  374               }
  375               else
  376               {
  377                   //these are suppose to be ignored if the F is set.
  378                   Integer setF = fdfField.getSetWidgetFieldFlags();
  379                   if( setF != null )
  380                   {
  381                       annotFlags = annotFlags | setF.intValue();
  382                       widget.setAnnotationFlags( annotFlags );
  383                   }
  384   
  385                   Integer clrF = fdfField.getClearWidgetFieldFlags();
  386                   if( clrF != null )
  387                   {
  388                       //we have to clear the bits of the document fields for every bit that is
  389                       //set in this field.
  390                       //
  391                       //Example:
  392                       //docF = 1011
  393                       //clrF = 1101
  394                       //clrFValue = 0010;
  395                       //newValue = 1011 & 0010 which is 0010
  396                       int clrFValue = clrF.intValue();
  397                       clrFValue ^= 0xFFFFFFFFL;
  398                       annotFlags = annotFlags & clrFValue;
  399                       widget.setAnnotationFlags( annotFlags );
  400                   }
  401               }
  402           }
  403           List fdfKids = fdfField.getKids();
  404           List pdKids = getKids();
  405           for( int i=0; fdfKids != null && i<fdfKids.size(); i++ )
  406           {
  407               FDFField fdfChild = (FDFField)fdfKids.get( i );
  408               String fdfName = fdfChild.getPartialFieldName();
  409               for( int j=0; j<pdKids.size(); j++ )
  410               {
  411                   Object pdChildObj = pdKids.get( j );
  412                   if( pdChildObj instanceof PDField )
  413                   {
  414                       PDField pdChild = (PDField)pdChildObj;
  415                       if( fdfName != null && fdfName.equals( pdChild.getPartialName() ) )
  416                       {
  417                           pdChild.importFDF( fdfChild );
  418                       }
  419                   }
  420               }
  421           }
  422       }
  423   
  424       /**
  425        * This will get the single associated widget that is part of this field.  This
  426        * occurs when the Widget is embedded in the fields dictionary.  Sometimes there
  427        * are multiple sub widgets associated with this field, in which case you want to
  428        * use getKids().  If the kids entry is specified, then the first entry in that
  429        * list will be returned.
  430        *
  431        * @return The widget that is associated with this field.
  432        * @throws IOException If there is an error getting the widget object.
  433        */
  434       public PDAnnotationWidget getWidget() throws IOException
  435       {
  436           PDAnnotationWidget retval = null;
  437           List kids = getKids();
  438           if( kids == null )
  439           {
  440               retval = new PDAnnotationWidget( getDictionary() );
  441           }
  442           else if( kids.size() > 0 )
  443           {
  444               Object firstKid = kids.get( 0 );
  445               if( firstKid instanceof PDAnnotationWidget )
  446               {
  447                   retval = (PDAnnotationWidget)firstKid;
  448               }
  449               else
  450               {
  451                   retval = ((PDField)firstKid).getWidget();
  452               }
  453           }
  454           else
  455           {
  456               retval = null;
  457           }
  458           return retval;
  459       }
  460   
  461       /**
  462        * Get the parent field to this field, or null if none exists.
  463        *
  464        * @return The parent field.
  465        *
  466        * @throws IOException If there is an error creating the parent field.
  467        */
  468       public PDField getParent() throws IOException
  469       {
  470           PDField parent = null;
  471           COSDictionary parentDic = (COSDictionary)getDictionary().getDictionaryObject( "Parent" );
  472           if( parentDic != null )
  473           {
  474               parent = PDFieldFactory.createField( getAcroForm(), parentDic );
  475           }
  476           return parent;
  477       }
  478   
  479       /**
  480        * Set the parent of this field.
  481        *
  482        * @param parent The parent to this field.
  483        */
  484       public void setParent( PDField parent )
  485       {
  486           getDictionary().setItem( "Parent", parent );
  487       }
  488   
  489       /**
  490        * This will find one of the child elements.  The name array are the components
  491        * of the name to search down the tree of names.  The nameIndex is where to
  492        * start in that array.  This method is called recursively until it finds
  493        * the end point based on the name array.
  494        *
  495        * @param name An array that picks the path to the field.
  496        * @param nameIndex The index into the array.
  497        * @return The field at the endpoint or null if none is found.
  498        * @throws IOException If there is an error creating the field.
  499        */
  500       public PDField findKid( String[] name, int nameIndex ) throws IOException
  501       {
  502           PDField retval = null;
  503           COSArray kids = (COSArray)getDictionary().getDictionaryObject( COSName.KIDS );
  504           if( kids != null )
  505           {
  506               for (int i = 0; retval == null && i < kids.size(); i++)
  507               {
  508                   COSDictionary kidDictionary = (COSDictionary)kids.getObject(i);
  509                   if( name[nameIndex].equals( kidDictionary.getString( "T" ) ) )
  510                   {
  511                       retval = PDFieldFactory.createField( acroForm, kidDictionary );
  512                       if( name.length > nameIndex+1 )
  513                       {
  514                           retval = retval.findKid( name, nameIndex+1 );
  515                       }
  516                   }
  517               }
  518           }
  519           return retval;
  520       }
  521   
  522       /**
  523        * This will get all the kids of this field.  The values in the list
  524        * will either be PDWidget or PDField.  Normally they will be PDWidget objects
  525        * unless this is a non-terminal field and they will be child PDField objects.
  526        *
  527        * @return A list of either PDWidget or PDField objects.
  528        * @throws IOException If there is an error retrieving the kids.
  529        */
  530       public List getKids() throws IOException
  531       {
  532           List retval = null;
  533           COSArray kids = (COSArray)getDictionary().getDictionaryObject(COSName.KIDS);
  534           if( kids != null )
  535           {
  536               List kidsList = new ArrayList();
  537               for (int i = 0; i < kids.size(); i++)
  538               {
  539                   COSDictionary kidDictionary = (COSDictionary)kids.getObject(i);
  540                   COSDictionary parent = (COSDictionary)kidDictionary.getDictionaryObject( "Parent" );
  541                   if( kidDictionary.getDictionaryObject( "FT" ) != null ||
  542                       (parent != null && parent.getDictionaryObject( "FT" ) != null ) )
  543                   {
  544                       kidsList.add( PDFieldFactory.createField( acroForm, kidDictionary ));
  545                   }
  546                   else if( "Widget".equals( kidDictionary.getNameAsString( "Subtype" ) ) )
  547                   {
  548                       kidsList.add( new PDAnnotationWidget( kidDictionary ) );
  549                   }
  550                   else
  551                   {
  552                       //
  553                       kidsList.add( PDFieldFactory.createField( acroForm, kidDictionary ));
  554                   }
  555               }
  556               retval = new COSArrayList( kidsList, kids );
  557           }
  558           return retval;
  559       }
  560   
  561       /**
  562        * This will set the list of kids.
  563        *
  564        * @param kids The list of child widgets.
  565        */
  566       public void setKids( List kids )
  567       {
  568           COSArray kidsArray = COSArrayList.converterToCOSArray( kids );
  569           getDictionary().setItem( COSName.KIDS, kidsArray );
  570       }
  571   
  572       /**
  573        * This will return a string representation of this field.
  574        *
  575        * @return A string representation of this field.
  576        */
  577       public String toString()
  578       {
  579           return "" + getDictionary().getDictionaryObject( COSName.getPDFName( "V" ) );
  580       }
  581   
  582       /**
  583        * This will get the acroform that this field is part of.
  584        *
  585        * @return The form this field is on.
  586        */
  587       public PDAcroForm getAcroForm()
  588       {
  589           return acroForm;
  590       }
  591   
  592       /**
  593        * This will set the form this field is on.
  594        *
  595        * @param value The new form to use.
  596        */
  597       public void setAcroForm(PDAcroForm value)
  598       {
  599           acroForm = value;
  600       }
  601   
  602       /**
  603        * This will get the dictionary associated with this field.
  604        *
  605        * @return The dictionary that this class wraps.
  606        */
  607       public COSDictionary getDictionary()
  608       {
  609           return dictionary;
  610       }
  611   
  612       /**
  613        * Convert this standard java object to a COS object.
  614        *
  615        * @return The cos object that matches this Java object.
  616        */
  617       public COSBase getCOSObject()
  618       {
  619           return dictionary;
  620       }
  621   
  622       /**
  623        * Get the additional actions for this field.  This will return null
  624        * if there are no additional actions for this field.
  625        *
  626        * @return The actions of the field.
  627        */
  628       public PDFormFieldAdditionalActions getActions()
  629       {
  630           COSDictionary aa = (COSDictionary)dictionary.getDictionaryObject( "AA" );
  631           PDFormFieldAdditionalActions retval = null;
  632           if( aa != null )
  633           {
  634               retval = new PDFormFieldAdditionalActions( aa );
  635           }
  636           return retval;
  637       }
  638   
  639       /**
  640        * Set the actions of the field.
  641        *
  642        * @param actions The field actions.
  643        */
  644       public void setActions( PDFormFieldAdditionalActions actions )
  645       {
  646           dictionary.setItem( "AA", actions );
  647       }
  648   }

Home » pdfbox-1.1.0-src » org.apache.pdfbox.pdmodel.interactive.form » [javadoc | source]