poppler/Form.cc | 227 +++++++++++++++++++++----------------------------------- poppler/Form.h | 21 +---- 2 files changed, 91 insertions(+), 157 deletions(-)
New commits: commit 14d145371e86ccb92f09b1ca750ced52171b2885 Author: Carlos Garcia Campos <[email protected]> Date: Tue Mar 8 20:14:57 2011 +0100 forms: Remove loadDefaults method Moving the code to initialize form field stuff to form field constructors and widget stuff to form widget constructors. Clean up an simplify the code. diff --git a/poppler/Form.cc b/poppler/Form.cc index 908b6fa..4698124 100644 --- a/poppler/Form.cc +++ b/poppler/Form.cc @@ -67,7 +67,6 @@ FormWidget::FormWidget(XRef *xrefA, Object *aobj, unsigned num, Ref aref, FormFi ref = aref; double t; ID = 0; - defaultsLoaded = gFalse; fontSize = 0.0; modified = gFalse; childNum = num; @@ -256,9 +255,36 @@ FormWidgetButton::FormWidgetButton (XRef *xrefA, Object *aobj, unsigned num, Ref type = formButton; parent = static_cast<FormFieldButton*>(field); onStr = NULL; - state = gFalse; siblingsID = NULL; numSiblingsID = 0; + + Object obj1, obj2; + + // Find the name of the ON state in the AP dictionnary + // The reference say the Off state, if it existe, _must_ be stored in the AP dict under the name /Off + // The "on" state may be stored under any other name + if (obj.dictLookup("AP", &obj1)->isDict()) { + if (obj1.dictLookup("N", &obj2)->isDict()) { + for (int i = 0; i < obj2.dictGetLength(); i++) { + char *key = obj2.dictGetKey(i); + if (strcmp (key, "Off") != 0) { + onStr = new GooString (key); + break; + } + } + } + obj2.free(); + } + obj1.free(); +} + +char *FormWidgetButton::getOnStr() { + if (onStr) + return onStr->getCString(); + + // 12.7.4.2.3 Check Boxes + // Yes should be used as the name for the on state + return parent->getButtonType() == formButtonCheck ? (char *)"Yes" : NULL; } FormWidgetButton::~FormWidgetButton () @@ -273,108 +299,32 @@ FormButtonType FormWidgetButton::getButtonType () const return parent->getButtonType (); } -void FormWidgetButton::setState (GBool astate, GBool calledByParent) -{ - //pushButtons don't have state - if (parent->getButtonType() == formButtonPush) - return; - //the state modification may be denied by the parent. e.g we don't want to let the user put all combo boxes to false - if (!calledByParent) { //avoid infinite recursion - modified = gTrue; - if (!parent->setState(childNum, astate)) { - return; - } - } - state = astate; - - //update appearance - char *offStr = "Off"; - Object obj1; - obj1.initName(state ? onStr->getCString() : offStr); - updateField ("V", &obj1); +void FormWidgetButton::setAppearanceState(char *state) { + modified = gTrue; - obj1.initName(state ? onStr->getCString() : offStr); - //modify the Appearance State entry as well + Object obj1; + obj1.initName(state); obj.getDict()->set("AS", &obj1); - //notify the xref about the update xref->setModifiedObject(&obj, ref); } -void FormWidgetButton::loadDefaults () +void FormWidgetButton::setState (GBool astate, GBool calledByParent) { - if (defaultsLoaded) - return; - - defaultsLoaded = gTrue; - - Dict *dict = obj.getDict(); - Object obj1; - //pushButtons don't have state - if (parent->getButtonType() != formButtonPush ){ - //find the name of the state in the AP dictionnary (/Yes, /Off) - //The reference say the Off state, if it existe, _must_ be stored in the AP dict under the name /Off - //The "on" state may be stored under any other name - if (dict->lookup("AP", &obj1)->isDict()) { - Dict *tmpDict = obj1.getDict(); - int length = tmpDict->getLength(); - for(int i=0; i<length; i++) { - Object obj2; - tmpDict->getVal(i, &obj2); - if (obj2.isDict()) { - Dict *tmpDict2 = obj2.getDict(); - int length2 = tmpDict2->getLength(); - for(int j=0; j<length2; j++) { - Object obj3; - tmpDict2->getVal(j, &obj3); - char *key = tmpDict2->getKey(j); - if(strcmp(key, "Off")) { //if we don't have Off, we have the name of the "on" state - onStr = new GooString (key); - } - obj3.free(); - if (onStr) - break; - } - } else if (obj2.isStream()) { - // TODO do something with str and obj3 - Stream *str = obj2.getStream(); - Dict *tmpDict2 = str->getDict(); - Object obj3; - tmpDict2->lookup("Length", &obj3); - onStr = new GooString ("D"); - obj3.free(); - } - obj2.free(); - if (onStr) - break; - } - } - obj1.free(); + if (parent->getButtonType() == formButtonPush) + return; - //We didn't found the "on" state for the button - if (!onStr) { - error(-1, "FormWidgetButton:: unable to find the on state for the button\n"); - onStr = new GooString(""); // TODO is this the best solution? - } - } + // Silently return if can't set ON state + if (astate && !onStr) + return; - if (Form::fieldLookup(dict, "V", &obj1)->isName()) { - Object obj2; - if (dict->lookup("AS", &obj2)->isName(obj1.getName())) { - if (strcmp (obj1.getName(), "Off") != 0) { - setState(gTrue); - } - } - obj2.free(); - } else if (obj1.isArray()) { //handle the case where we have multiple choices - error(-1, "FormWidgetButton:: multiple choice isn't supported yet\n"); - } - obj1.free(); + parent->setState(astate ? onStr->getCString() : (char *)"Off"); + // Parent will call setAppearanceState() } GBool FormWidgetButton::getState () { - return state; + return (onStr && parent->getAppearanceState() && strcmp(parent->getAppearanceState(), onStr->getCString()) == 0); } void FormWidgetButton::setNumSiblingsID (int i) @@ -391,14 +341,6 @@ FormWidgetText::FormWidgetText (XRef *xrefA, Object *aobj, unsigned num, Ref ref parent = static_cast<FormFieldText*>(field); } -void FormWidgetText::loadDefaults () -{ - if (defaultsLoaded) - return; - - defaultsLoaded = gTrue; -} - GooString* FormWidgetText::getContent () { return parent->getContent(); @@ -467,14 +409,6 @@ FormWidgetChoice::FormWidgetChoice(XRef *xrefA, Object *aobj, unsigned num, Ref parent = static_cast<FormFieldChoice*>(field); } -void FormWidgetChoice::loadDefaults () -{ - if (defaultsLoaded) - return; - - defaultsLoaded = gTrue; -} - FormWidgetChoice::~FormWidgetChoice() { } @@ -658,7 +592,7 @@ FormField::FormField(XRef* xrefA, Object *aobj, const Ref& aref, std::set<int> * children = (FormField**)greallocn(children, numChildren, sizeof(FormField*)); obj3.free(); - children[numChildren-1] = Form::createFieldFromDict (&obj2, xrefA, childRef.getRef(), &usedParentsAux); + children[numChildren-1] = Form::createFieldFromDict (&obj2, xref, childRef.getRef(), &usedParentsAux); } // 1 - we will handle 'collapsed' fields (field + annot in the same dict) // as if the annot was in the Kids array of the field @@ -679,10 +613,10 @@ FormField::FormField(XRef* xrefA, Object *aobj, const Ref& aref, std::set<int> * // As said in 1, if this is a 'collapsed' field, behave like if we had a // child annot if (dict->lookup("Subtype", &obj1)->isName()) { - _createWidget(aobj, ref); + _createWidget(&obj, ref); } obj1.free(); - + //flags if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) { int flags = obj1.getInt(); @@ -728,19 +662,6 @@ FormField::~FormField() delete defaultAppearance; } -void FormField::loadChildrenDefaults () -{ - if(!terminal) { - for(int i=0; i<numChildren; i++) { - children[i]->loadChildrenDefaults(); - } - } else { - for (int i=0; i<numChildren; i++) { - widgets[i]->loadDefaults(); - } - } -} - void FormField::fillChildrenSiblingsID() { if(terminal) return; @@ -845,7 +766,7 @@ void FormFieldButton::fillChildrenSiblingsID() } } -GBool FormFieldButton::setState (int num, GBool s) +GBool FormFieldButton::setState(char *state) { if (readOnly) { error(-1, "FormFieldButton::setState called on a readOnly field\n"); @@ -855,28 +776,54 @@ GBool FormFieldButton::setState (int num, GBool s) // A check button could behave as a radio button // when it's in a set of more than 1 buttons if (btype == formButtonRadio || btype == formButtonCheck) { - if (!s && noAllOff) + GBool isOn = strcmp(state, "Off") != 0; + + if (!isOn && noAllOff) return gFalse; //don't allow to set all radio to off - if (s == gTrue) { - active_child = num; - for(int i=0; i<numChildren; i++) { - if (i==active_child) continue; - static_cast<FormWidgetButton*>(widgets[i])->setState(gFalse, gTrue); - } + char *current = getAppearanceState(); + + if (isOn) { + char *current = getAppearanceState(); + GBool currentFound = gFalse, newFound = gFalse; + + for (int i = 0; i < numChildren; i++) { + FormWidgetButton *widget = static_cast<FormWidgetButton*>(widgets[i]); + + if (!widget->getOnStr()) + continue; + + char *onStr = widget->getOnStr(); + if (current && strcmp(current, onStr) == 0) { + widget->setAppearanceState("Off"); + currentFound = gTrue; + } - //The parent field's V entry holds a name object corresponding to the ap- - //pearance state of whichever child field is currently in the on state - if (active_child >= 0) { - FormWidgetButton* actChild = static_cast<FormWidgetButton*>(widgets[active_child]); - if (actChild->getOnStr()) - updateState(actChild->getOnStr()->getCString()); + if (strcmp(state, onStr) == 0) { + widget->setAppearanceState(state); + newFound = gTrue; + } + + if (currentFound && newFound) + break; } } else { - active_child = -1; - updateState("Off"); + for (int i = 0; i < numChildren; i++) { + FormWidgetButton *widget = static_cast<FormWidgetButton*>(widgets[i]); + + if (!widget->getOnStr()) + continue; + + char *onStr = widget->getOnStr(); + if (current && strcmp(current, onStr) == 0) { + widget->setAppearanceState("Off"); + break; + } + } } + updateState(state); } + return gTrue; } @@ -1370,8 +1317,6 @@ FormField *Form::createFieldFromDict (Object* obj, XRef *xrefA, const Ref& pref, field = new FormField(xrefA, obj, pref, usedParents); } obj2.free(); - - field->loadChildrenDefaults(); return field; } diff --git a/poppler/Form.h b/poppler/Form.h index 8d25e2c..74539ca 100644 --- a/poppler/Form.h +++ b/poppler/Form.h @@ -69,9 +69,6 @@ class FormWidget { public: virtual ~FormWidget(); - // see the description of FormField::LoadChildrenDefaults - virtual void loadDefaults () {} - // Check if point is inside the field bounding rect GBool inRect(double x, double y) { return x1 <= x && x <= x2 && y1 <= y && y <= y2; } @@ -121,7 +118,6 @@ protected: Object obj; Ref ref; XRef *xref; - GBool defaultsLoaded; GBool modified; GooString *partialName; // T field GooString *alternateUiName; // TU field @@ -161,9 +157,8 @@ public: void setState (GBool state, GBool calledByParent=gFalse); GBool getState (); - GooString* getOnStr() { return onStr; } - - void loadDefaults(); + char* getOnStr(); + void setAppearanceState(char *state); void setNumSiblingsID (int i); void setSiblingsID (int i, unsigned id) { siblingsID[i] = id; } @@ -178,7 +173,6 @@ protected: int numSiblingsID; GooString *onStr; FormFieldButton *parent; - GBool state; }; //------------------------------------------------------------------------ @@ -196,8 +190,6 @@ public: //except a UTF16BE string void setContent(GooString* new_content); - void loadDefaults (); - bool isMultiline () const; bool isPassword () const; bool isFileSelect () const; @@ -219,7 +211,6 @@ public: FormWidgetChoice(XRef *xrefA, Object *dict, unsigned num, Ref ref, FormField *p); ~FormWidgetChoice(); - void loadDefaults (); int getNumChoices(); //return the display name of the i-th choice (UTF16BE) GooString* getChoice(int i); @@ -288,9 +279,6 @@ public: VariableTextQuadding getTextQuadding() const { return quadding; } FormWidget* findWidgetByRef (Ref aref); - // Since while loading their defaults, children may call parents methods, it's better - // to do that when parents are completly constructed - void loadChildrenDefaults(); // only implemented in FormFieldButton virtual void fillChildrenSiblingsID (); @@ -298,6 +286,7 @@ public: protected: void _createWidget (Object *obj, Ref aref); + void createChildren(std::set<int> *usedParents); FormFieldType type; // field type Ref ref; @@ -332,10 +321,10 @@ public: bool noToggleToOff () const { return noAllOff; } // returns gTrue if the state modification is accepted - GBool setState (int num, GBool s); + GBool setState (char *state); char *getAppearanceState() { return appearanceState.isName() ? appearanceState.getName() : NULL; } - + void fillChildrenSiblingsID (); virtual ~FormFieldButton(); _______________________________________________ poppler mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/poppler
