Choice form field

This commit is contained in:
Jakub Melka 2020-04-19 18:29:33 +02:00
parent 247c2c98f7
commit bf76e3aa22
2 changed files with 65 additions and 1 deletions

View File

@ -36,6 +36,7 @@ PDFForm PDFForm::parse(const PDFObjectStorage* storage, PDFObject object)
form.m_formFields.emplace_back(PDFFormField::parse(storage, fieldRootReference, nullptr));
}
form.m_formType = FormType::AcroForm;
form.m_needAppearances = loader.readBooleanFromDictionary(formDictionary, "NeedAppearances", false);
form.m_signatureFlags = static_cast<SignatureFlags>(loader.readIntegerFromDictionary(formDictionary, "SigFlags", 0));
form.m_calculationOrder = loader.readReferenceArrayFromDictionary(formDictionary, "CO");
@ -43,6 +44,12 @@ PDFForm PDFForm::parse(const PDFObjectStorage* storage, PDFObject object)
form.m_defaultAppearance = loader.readOptionalStringFromDictionary(formDictionary, "DA");
form.m_quadding = loader.readOptionalIntegerFromDictionary(formDictionary, "Q");
form.m_xfa = formDictionary->get("XFA");
if (!form.m_xfa.isNull())
{
// Jakub Melka: handle XFA form
form.m_formType = FormType::XFAForm;
}
}
return form;
@ -69,7 +76,7 @@ PDFFormFieldPointer PDFFormField::parse(const PDFObjectStorage* storage, PDFObje
PDFDocumentDataLoaderDecorator loader(storage);
FieldType formFieldType = parentField ? parentField->getFieldType() : FieldType::Invalid;
if (fieldDictionary->hasKey(FT))
if (fieldDictionary->hasKey("FT"))
{
formFieldType = loader.readEnumByName(fieldDictionary->get("FT"), fieldTypes.begin(), fieldTypes.end(), FieldType::Invalid);
}
@ -178,6 +185,42 @@ PDFFormFieldPointer PDFFormField::parse(const PDFObjectStorage* storage, PDFObje
formFieldText->m_maxLength = loader.readIntegerFromDictionary(fieldDictionary, "MaxLen", maxLengthDefault);
}
if (formFieldChoice)
{
// Parse options - it is array of options values. Option value can be either a single text
// string, or array of two values - export value and text to be displayed.
PDFObject options = storage->getObject(fieldDictionary->get("Opt"));
if (options.isArray())
{
const PDFArray* optionsArray = options.getArray();
formFieldChoice->m_options.reserve(optionsArray->getCount());
for (size_t i = 0; i < optionsArray->getCount(); ++i)
{
PDFFormFieldChoice::Option option;
PDFObject optionItemObject = storage->getObject(optionsArray->getItem(i));
if (optionItemObject.isArray())
{
QStringList stringList = loader.readTextStringList(optionItemObject);
if (stringList.size() == 2)
{
option.exportString = stringList[0];
option.userString = stringList[1];
}
}
else
{
option.userString = loader.readTextString(optionItemObject, QString());
option.exportString = option.userString;
}
formFieldChoice->m_options.emplace_back(qMove(option));
}
}
formFieldChoice->m_topIndex = loader.readIntegerFromDictionary(fieldDictionary, "TI", 0);
}
}
return result;

View File

@ -64,6 +64,7 @@ class PDFFormField
{
public:
explicit inline PDFFormField() = default;
virtual ~PDFFormField() = default;
enum class FieldType
{
@ -230,6 +231,7 @@ private:
QStringList m_options;
};
/// Represents single line, or multiline text field
class PDFFormFieldText : public PDFFormField
{
public:
@ -250,9 +252,28 @@ class PDFFormFieldChoice : public PDFFormField
public:
explicit inline PDFFormFieldChoice() = default;
bool isComboBox() const { return m_fieldFlags.testFlag(Combo); }
bool isEditableComboBox() const { return m_fieldFlags.testFlag(Edit); }
bool isListBox() const { return !isComboBox(); }
struct Option
{
QString exportString;
QString userString;
};
using Options = std::vector<Option>;
const Options& getOptions() const { return m_options; }
PDFInteger getTopIndex() const { return m_topIndex; }
const PDFObject& getSelection() const { return m_selection; }
private:
friend static PDFFormFieldPointer PDFFormField::parse(const PDFObjectStorage* storage, PDFObjectReference reference, PDFFormField* parentField);
Options m_options;
PDFInteger m_topIndex;
PDFObject m_selection;
};
class PDFFormFieldSignature : public PDFFormField