From 4ba0d291d3385a38c08c02c82f919b3f8f66390c Mon Sep 17 00:00:00 2001 From: Marek Kasik Date: Mon, 15 Jun 2015 11:29:14 +0200 Subject: [PATCH 2/4] Add ability to reset forms Add reset() method to FormField class and its descendants. Use DV field for resetting FormFieldText, FormFieldChoice and FormFieldButton. Add reset() also to Form class. --- poppler/Form.cc | 154 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ poppler/Form.h | 18 +++++++ 2 files changed, 172 insertions(+) diff --git a/poppler/Form.cc b/poppler/Form.cc index 661ed89..48014ea 100644 --- a/poppler/Form.cc +++ b/poppler/Form.cc @@ -788,6 +788,12 @@ void FormField::updateChildrenAppearance() } } +void FormField::reset() +{ + for (int i = 0; i < numChildren; i++) + children[i]->reset (); +} + //------------------------------------------------------------------------ // FormFieldButton //------------------------------------------------------------------------ @@ -800,6 +806,7 @@ FormFieldButton::FormFieldButton(PDFDoc *docA, Object *aobj, const Ref& ref, For siblings = NULL; numSiblings = 0; appearanceState.initNull(); + defaultAppearanceState.initNull(); Object obj1; btype = formButtonCheck; @@ -823,6 +830,7 @@ FormFieldButton::FormFieldButton(PDFDoc *docA, Object *aobj, const Ref& ref, For // Even though V is inheritable we are interested in the value of this // field, if not present it's probably because it's a button in a set. dict->lookup("V", &appearanceState); + dict->lookup("DV", &defaultAppearanceState); } } @@ -968,6 +976,16 @@ FormFieldButton::~FormFieldButton() gfree(siblings); } +void FormFieldButton::reset() +{ + if (getDefaultAppearanceState ()) { + setState (getDefaultAppearanceState ()); + } else { + appearanceState.initNull (); + obj.getDict ()->remove ("V"); + } +} + //------------------------------------------------------------------------ // FormFieldText //------------------------------------------------------------------------ @@ -977,6 +995,7 @@ FormFieldText::FormFieldText(PDFDoc *docA, Object *aobj, const Ref& ref, FormFie Dict* dict = obj.getDict(); Object obj1; content = NULL; + default_content = NULL; multiline = password = fileSelect = doNotSpellCheck = doNotScroll = comb = richText = false; maxLen = 0; @@ -1017,6 +1036,20 @@ FormFieldText::FormFieldText(PDFDoc *docA, Object *aobj, const Ref& ref, FormFie } } obj1.free(); + + if (Form::fieldLookup(dict, "DV", &obj1)->isString()) { + if (obj1.getString()->hasUnicodeMarker()) { + if (obj1.getString()->getLength() > 2) + default_content = obj1.getString()->copy(); + } else if (obj1.getString()->getLength() > 0) { + //non-unicode string -- assume pdfDocEncoding and try to convert to UTF16BE + int tmp_length; + char* tmp_str = pdfDocEncodingToUTF16(obj1.getString(), &tmp_length); + default_content = new GooString(tmp_str, tmp_length); + delete [] tmp_str; + } + } + obj1.free(); } #ifdef DEBUG_FORMS @@ -1058,6 +1091,15 @@ void FormFieldText::setContentCopy (GooString* new_content) FormFieldText::~FormFieldText() { delete content; + delete default_content; +} + +void FormFieldText::reset() +{ + setContentCopy (default_content); + + if (default_content == NULL) + obj.getDict()->remove("V"); } @@ -1069,6 +1111,7 @@ FormFieldChoice::FormFieldChoice(PDFDoc *docA, Object *aobj, const Ref& ref, For { numChoices = 0; choices = NULL; + defaultChoices = NULL; editedChoice = NULL; topIdx = 0; @@ -1202,6 +1245,58 @@ FormFieldChoice::FormFieldChoice(PDFDoc *docA, Object *aobj, const Ref& ref, For } } obj1.free(); + + Form::fieldLookup(dict, "DV", &obj1); + if (obj1.isString() || obj1.isArray()) { + defaultChoices = new GBool[numChoices]; + memset(defaultChoices, 0, sizeof(GBool) * numChoices); + + if (obj1.isString()) { + GBool optionFound = gFalse; + + for (int i = 0; i < numChoices; i++) { + if (choices[i].exportVal) { + if (choices[i].exportVal->cmp(obj1.getString()) == 0) { + optionFound = gTrue; + } + } else if (choices[i].optionName) { + if (choices[i].optionName->cmp(obj1.getString()) == 0) { + optionFound = gTrue; + } + } + + if (optionFound) { + defaultChoices[i] = true; + break; // We've determined that this option is selected. No need to keep on scanning + } + } + } else if (obj1.isArray()) { + for (int i = 0; i < numChoices; i++) { + for (int j = 0; j < obj1.arrayGetLength(); j++) { + Object obj2; + obj1.arrayGet(j, &obj2); + GBool matches = gFalse; + + if (choices[i].exportVal) { + if (choices[i].exportVal->cmp(obj2.getString()) == 0) { + matches = gTrue; + } + } else if (choices[i].optionName) { + if (choices[i].optionName->cmp(obj2.getString()) == 0) { + matches = gTrue; + } + } + + obj2.free(); + + if (matches) { + defaultChoices[i] = true; + break; // We've determined that this option is selected. No need to keep on scanning + } + } + } + } + } } FormFieldChoice::~FormFieldChoice() @@ -1364,6 +1459,21 @@ GooString *FormFieldChoice::getSelectedChoice() { return NULL; } +void FormFieldChoice::reset() +{ + delete editedChoice; + editedChoice = NULL; + + if (defaultChoices) { + for (int i = 0; i < numChoices; i++) + choices[i].selected = defaultChoices[i]; + } else { + unselectAll (); + } + + updateSelection (); +} + //------------------------------------------------------------------------ // FormFieldSignature //------------------------------------------------------------------------ @@ -1377,6 +1487,10 @@ FormFieldSignature::~FormFieldSignature() } +void FormFieldSignature::reset() +{ +} + #ifdef DEBUG_FORMS void FormFieldSignature::print(int indent) { @@ -1564,6 +1678,46 @@ FormWidget* Form::findWidgetByRef (Ref aref) return NULL; } +void Form::reset (GooList *fields, GBool excludeFields) +{ + FormField *field; + GooString *field2; + GBool found; + GBool resetAllFields; + + resetAllFields = fields->getLength () == 0; + for (int i = 0; i < numFields; i++) { + field = rootFields[i]; + + if (!resetAllFields) { + found = gFalse; + for (int j = 0; j < fields->getLength (); j++) { + field2 = (GooString *) fields->get (j); + + if (field2->endsWith (" R")) { + int field2_gen; + int field2_num; + + if (sscanf (field2->getCString (), "%d %d R", &field2_num, &field2_gen) == 2 && + field2_num == field->getRef().num && + field2_gen == field->getRef().gen) + found = gTrue; + } + + if (field->getFullyQualifiedName()->cmp(field2) == 0) { + found = gTrue; + break; + } + } + } + + if (resetAllFields || + (found && !excludeFields) || + (!found && excludeFields)) + field->reset(); + } +} + //------------------------------------------------------------------------ // FormPageWidgets //------------------------------------------------------------------------ diff --git a/poppler/Form.h b/poppler/Form.h index 3778ff6..78d6c82 100644 --- a/poppler/Form.h +++ b/poppler/Form.h @@ -35,6 +35,7 @@ class Annots; class LinkAction; class GfxResources; class PDFDoc; +class GooList; enum FormFieldType { formButton, @@ -293,6 +294,7 @@ public: virtual void print(int indent = 0); #endif + virtual void reset (); protected: void _createWidget (Object *obj, Ref aref); @@ -343,6 +345,7 @@ public: GBool getState(char *state); char *getAppearanceState() { return appearanceState.isName() ? appearanceState.getName() : NULL; } + char *getDefaultAppearanceState() { return defaultAppearanceState.isName() ? defaultAppearanceState.getName() : NULL; } void fillChildrenSiblingsID (); @@ -358,6 +361,9 @@ public: #endif virtual ~FormFieldButton(); + + void reset (); + protected: void updateState(char *state); @@ -370,6 +376,7 @@ protected: int active_child; //only used for combo box bool noAllOff; Object appearanceState; // V + Object defaultAppearanceState; // DV }; //------------------------------------------------------------------------ @@ -398,8 +405,12 @@ public: #ifdef DEBUG_FORMS void print(int indent = 0); #endif + + void reset (); + protected: GooString* content; + GooString* default_content; bool multiline; bool password; bool fileSelect; @@ -457,6 +468,8 @@ public: void print(int indent = 0); #endif + void reset (); + protected: void unselectAll(); void updateSelection(); @@ -475,6 +488,7 @@ protected: int numChoices; ChoiceOpt* choices; + bool* defaultChoices; GooString* editedChoice; int topIdx; // TI }; @@ -492,6 +506,9 @@ public: #ifdef DEBUG_FORMS void print(int indent = 0); #endif + + void reset (); + }; //------------------------------------------------------------------------ @@ -525,6 +542,7 @@ public: FormWidget* findWidgetByRef (Ref aref); void postWidgetsLoad(); + void reset (GooList *fields, GBool exclude_fields); private: FormField** rootFields; int numFields; -- 2.4.3