org.apache.pdfbox.pdmodel.interactive.form.PDTerminalField Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pdfbox Show documentation
Show all versions of pdfbox Show documentation
The Apache PDFBox library is an open source Java tool for working with PDF documents.
/*
* 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.COSInteger;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.common.COSArrayList;
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.
* Fields may be one of four types: button, text, choice, or signature.
*
* @author sug
*/
public abstract class PDTerminalField extends PDField
{
/**
* Constructor.
*
* @param acroForm The form that this field is part of.
*/
protected PDTerminalField(PDAcroForm acroForm)
{
super(acroForm);
}
/**
* Constructor.
*
* @param acroForm The form that this field is part of.
* @param field the PDF object to represent as a field.
* @param parent the parent node of the node
*/
PDTerminalField(PDAcroForm acroForm, COSDictionary field, PDNonTerminalField parent)
{
super(acroForm, field, parent);
}
/**
* Set the actions of the field.
*
* @param actions The field actions.
*/
public void setActions(PDFormFieldAdditionalActions actions)
{
getCOSObject().setItem(COSName.AA, actions);
}
@Override
public int getFieldFlags()
{
int retval = 0;
COSInteger ff = (COSInteger) getCOSObject().getDictionaryObject(COSName.FF);
if (ff != null)
{
retval = ff.intValue();
}
else if (getParent() != null)
{
retval = getParent().getFieldFlags();
}
return retval;
}
@Override
public String getFieldType()
{
String fieldType = getCOSObject().getNameAsString(COSName.FT);
if (fieldType == null && getParent() != null)
{
fieldType = getParent().getFieldType();
}
return fieldType;
}
@Override
public void importFDF(FDFField fdfField) throws IOException
{
super.importFDF(fdfField);
PDAnnotationWidget widget = getWidgets().get(0); // fixme: ignores multiple widgets
if (widget != null)
{
int annotFlags = widget.getAnnotationFlags();
Integer f = fdfField.getWidgetFieldFlags();
if (f != 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);
}
}
}
}
@Override
FDFField exportFDF() throws IOException
{
FDFField fdfField = new FDFField();
fdfField.setPartialFieldName(getPartialName());
fdfField.setValue(getCOSObject().getDictionaryObject(COSName.V));
// fixme: the old code which was here assumed that Kids were PDField instances,
// which is never true. They're annotation widgets.
return fdfField;
}
/**
* Returns the widget annotations associated with this field.
*
* @return The list of widget annotations.
*/
@Override
public List getWidgets()
{
List widgets = new ArrayList();
COSArray kids = (COSArray)getCOSObject().getDictionaryObject(COSName.KIDS);
if (kids == null)
{
// the field itself is a widget
widgets.add(new PDAnnotationWidget(getCOSObject()));
}
else if (kids.size() > 0)
{
// there are multiple widgets
for (int i = 0; i < kids.size(); i++)
{
COSBase kid = kids.getObject(i);
if (kid instanceof COSDictionary)
{
widgets.add(new PDAnnotationWidget((COSDictionary)kid));
}
}
}
return widgets;
}
/**
* Sets the field's widget annotations.
*
* @param children The list of widget annotations.
*/
public void setWidgets(List children)
{
COSArray kidsArray = COSArrayList.converterToCOSArray(children);
getCOSObject().setItem(COSName.KIDS, kidsArray);
for (PDAnnotationWidget widget : children)
{
widget.getCOSObject().setItem(COSName.PARENT, this);
}
}
/**
* 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 getWidgets(). 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.
* @deprecated Fields may have more than one widget, call {@link #getWidgets()} instead.
*/
@Deprecated
public PDAnnotationWidget getWidget()
{
return getWidgets().get(0);
}
/**
* Applies a value change to the field. Generates appearances if required and raises events.
*
* @throws IOException if the appearance couldn't be generated
*/
protected final void applyChange() throws IOException
{
if (!getAcroForm().getNeedAppearances())
{
constructAppearances();
}
// if we supported JavaScript we would raise a field changed event here
}
/**
* Constructs appearance streams and appearance dictionaries for all widget annotations.
* Subclasses should not call this method directly but via {@link #applyChange()}.
*
* @throws IOException if the appearance couldn't be generated
*/
abstract void constructAppearances() throws IOException;
}