package com.tom_roush.pdfbox.pdmodel.interactive.form; import com.tom_roush.pdfbox.cos.COSArray; import com.tom_roush.pdfbox.cos.COSBase; import com.tom_roush.pdfbox.cos.COSDictionary; import com.tom_roush.pdfbox.cos.COSInteger; import com.tom_roush.pdfbox.cos.COSName; import com.tom_roush.pdfbox.pdmodel.common.COSArrayList; import com.tom_roush.pdfbox.pdmodel.common.COSObjectable; import com.tom_roush.pdfbox.pdmodel.fdf.FDFField; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * A non terminal field in an interactive form. * * A non terminal field is a node in the fields tree node whose descendants * are fields. * * The attributes such as FT (field type) or V (field value) do not logically * belong to the non terminal field but are inheritable attributes * for descendant terminal fields. */ public class PDNonTerminalField extends PDField { /** * Constructor. * * @param acroForm The form that this field is part of. */ public PDNonTerminalField(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 to be created */ public PDNonTerminalField(PDAcroForm acroForm, COSDictionary field, PDNonTerminalField parent) { super(acroForm, field, parent); } @Override public int getFieldFlags() { int retval = 0; COSInteger ff = (COSInteger) dictionary.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; } @Override void importFDF(FDFField fdfField) throws IOException { super.importFDF(fdfField); List<FDFField> fdfKids = fdfField.getKids(); List<PDField> children = getChildren(); for (int i = 0; fdfKids != null && i < fdfKids.size(); i++) { for (COSObjectable pdKid : children) { if (pdKid instanceof PDField) { PDField pdChild = (PDField) pdKid; FDFField fdfChild = fdfKids.get(i); String fdfName = fdfChild.getPartialFieldName(); if (fdfName != null && fdfName.equals(pdChild.getPartialName())) { pdChild.importFDF(fdfChild); } } } } } @Override FDFField exportFDF() throws IOException { FDFField fdfField = new FDFField(); fdfField.setPartialFieldName(getPartialName()); fdfField.setValue(getValue()); List<PDField> children = getChildren(); List<FDFField> fdfChildren = new ArrayList<FDFField>(); for (PDField child : children) { fdfChildren.add(child.exportFDF()); } fdfField.setKids(fdfChildren); return fdfField; } /** * Returns this field's children. These may be either terminal or non-terminal fields. * * @return he list of child fields. */ public List<PDField> getChildren() { List<PDField> children = new ArrayList<PDField>(); COSArray kids = (COSArray) dictionary.getDictionaryObject(COSName.KIDS); for (int i = 0; i < kids.size(); i++) { PDField field = PDField .fromDictionary(acroForm, (COSDictionary) kids.getObject(i), this); if (field != null) { children.add(field); } } return children; } /** * Sets the child fields. * * @param children The list of child fields. */ public void setChildren(List<PDField> children) { COSArray kidsArray = COSArrayList.converterToCOSArray(children); dictionary.setItem(COSName.KIDS, kidsArray); } /** * {@inheritDoc} * <p><b>Note:</b> while non-terminal fields <b>do</b> inherit field values, this method returns * the local value, without inheritance. */ @Override public String getFieldType() { return dictionary.getNameAsString(COSName.FT); } /** * {@inheritDoc} * * <p><b>Note:</b> while non-terminal fields <b>do</b> inherit field values, this method returns * the local value, without inheritance. */ public COSBase getValue() { return dictionary.getDictionaryObject(COSName.V); } /** * {@inheritDoc} * * <p><b>Note:</b> while non-terminal fields <b>do</b> inherit field values, this method returns * the local value, without inheritance. */ @Override public String getValueAsString() { COSBase fieldValue = dictionary.getDictionaryObject(COSName.V); return fieldValue != null ? fieldValue.toString() : ""; } /** * Sets the value of this field. This may be of any kind which is valid for this field's * children. * * <p><b>Note:</b> while non-terminal fields <b>do</b> inherit field values, this method returns * the local value, without inheritance. */ public void setValue(COSBase object) throws IOException { dictionary.setItem(COSName.V, object); // todo: propagate change event to children? // todo: construct appearances of children? } /** * Returns the default value of this field. This may be of any kind which is valid for this field's * children. * * <p><b>Note:</b> while non-terminal fields <b>do</b> inherit field values, this method returns * the local value, without inheritance. */ public COSBase getDefaultValue() { return dictionary.getDictionaryObject(COSName.DV); } /** * Sets the default of this field. This may be of any kind which is valid for this field's * children. * * <p><b>Note:</b> while non-terminal fields <b>do</b> inherit field values, this method returns * the local value, without inheritance. */ public void setDefaultValue(COSBase value) { dictionary.setItem(COSName.V, value); } }