More than a year ago Guillermo Amaral posted some patches for enabling form
reset, i've reworked them to the final requirements Carlos and I gave.
I've integrated them + a Okular patch and it "works for me" but I'd like a
review before commiting to master.
But as the feature freeze triggers in 4 days you have that time to review :D
In the core there is a new LinkResetForm that is LinkAction and has the flags
and the field list
In the qt4 frontend there is the mirror public structure but the field list is
a list of fully qualified names instead of a list of field *
Albert
diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index 1d12aee..0ded778 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -2034,7 +2034,7 @@ void AnnotLink::initialize(XRef *xrefA, Catalog *catalog, Dict *dict) {
} else {
obj1.free();
if (dict->lookup("A", &obj1)->isDict()) {
- action = LinkAction::parseAction(&obj1, catalog->getBaseURI());
+ action = LinkAction::parseAction(&obj1, catalog->getBaseURI(), catalog->getForm());
}
}
obj1.free();
@@ -2750,7 +2750,7 @@ void AnnotWidget::initialize(XRef *xrefA, Catalog *catalog, Dict *dict) {
action = NULL;
if(dict->lookup("A", &obj1)->isDict()) {
- action = LinkAction::parseAction(&obj1, catalog->getBaseURI());
+ action = LinkAction::parseAction(&obj1, catalog->getBaseURI(), catalog->getForm());
}
obj1.free();
@@ -4074,7 +4074,7 @@ void AnnotScreen::initialize(XRef *xrefA, Catalog *catalog, Dict* dict) {
action = NULL;
if (dict->lookup("A", &obj1)->isDict()) {
- action = LinkAction::parseAction(&obj1, catalog->getBaseURI());
+ action = LinkAction::parseAction(&obj1, catalog->getBaseURI(), catalog->getForm());
if (action->getKind() == actionRendition && page == 0) {
error (-1, "Invalid Rendition action: associated screen annotation without P");
delete action;
diff --git a/poppler/Form.cc b/poppler/Form.cc
index 1f8b064..ad59780 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -669,6 +669,36 @@ FormWidget* FormField::findWidgetByRef (Ref aref)
return NULL;
}
+FormField* FormField::findFieldByRef (Ref aref)
+{
+ if (aref.num == ref.num && aref.gen == ref.gen) {
+ return this;
+ } else if (!terminal) {
+ for(int i = 0; i < numChildren; i++) {
+ FormField* result = children[i]->findFieldByRef(aref);
+ if (result) {
+ return result;
+ }
+ }
+ }
+ return NULL;
+}
+
+FormField *FormField::findFieldByFullyQualifiedName(GooString *fullyQualifiedName)
+{
+ if (getFullyQualifiedName()->cmp(fullyQualifiedName) == 0) {
+ return this;
+ } else if (!terminal) {
+ for(int i = 0; i < numChildren; i++) {
+ FormField* result = children[i]->findFieldByFullyQualifiedName(fullyQualifiedName);
+ if (result) {
+ return result;
+ }
+ }
+ }
+ return NULL;
+}
+
GooString* FormField::getFullyQualifiedName() {
Object obj1, obj2;
Object parent;
@@ -1415,6 +1445,24 @@ FormWidget* Form::findWidgetByRef (Ref aref)
return NULL;
}
+FormField *Form::findFieldByRef(Ref aref)
+{
+ for(int i = 0; i < numFields; i++) {
+ FormField *result = rootFields[i]->findFieldByRef(aref);
+ if (result) return result;
+ }
+ return NULL;
+}
+
+FormField *Form::findFieldByFullyQualifiedName(GooString *fullyQualifiedName)
+{
+ for(int i = 0; i < numFields; i++) {
+ FormField *result = rootFields[i]->findFieldByFullyQualifiedName(fullyQualifiedName);
+ if (result) return result;
+ }
+ return NULL;
+}
+
//------------------------------------------------------------------------
// FormPageWidgets
//------------------------------------------------------------------------
diff --git a/poppler/Form.h b/poppler/Form.h
index 0cfc95b..88e91cf 100644
--- a/poppler/Form.h
+++ b/poppler/Form.h
@@ -280,7 +280,11 @@ public:
GooString *getFullyQualifiedName();
FormWidget* findWidgetByRef (Ref aref);
+ FormField *findFieldByRef(Ref aref);
+ FormField *findFieldByFullyQualifiedName(GooString *fullyQualifiedName);
FormWidget *getWidget(int i) { return terminal ? widgets[i] : NULL; }
+ int getNumChildren() { return numChildren; }
+ FormField *getChild(int i) { return terminal ? NULL : children[i]; }
// only implemented in FormFieldButton
virtual void fillChildrenSiblingsID ();
@@ -510,6 +514,8 @@ public:
Object* getDefaultResourcesObj() { return &resDict; }
FormWidget* findWidgetByRef (Ref aref);
+ FormField *findFieldByRef(Ref aref);
+ FormField *findFieldByFullyQualifiedName(GooString *fullyQualifiedName);
void postWidgetsLoad(Catalog *catalog);
private:
diff --git a/poppler/Link.cc b/poppler/Link.cc
index 971accf..d50d015 100644
--- a/poppler/Link.cc
+++ b/poppler/Link.cc
@@ -45,6 +45,7 @@
#include "FileSpec.h"
#include "Rendition.h"
#include "Annot.h"
+#include "Form.h"
//------------------------------------------------------------------------
// LinkAction
@@ -61,7 +62,7 @@ LinkAction *LinkAction::parseDest(Object *obj) {
return action;
}
-LinkAction *LinkAction::parseAction(Object *obj, GooString *baseURI) {
+LinkAction *LinkAction::parseAction(Object *obj, GooString *baseURI, Form *forms) {
LinkAction *action;
Object obj2, obj3, obj4;
@@ -125,6 +126,10 @@ LinkAction *LinkAction::parseAction(Object *obj, GooString *baseURI) {
} else if (obj2.isName("SetOCGState")) {
action = new LinkOCGState(obj);
+ // ResetForm action
+ } else if (obj2.isName("ResetForm")) {
+ action = new LinkResetForm(obj, forms);
+
// unknown action
} else if (obj2.isName()) {
action = new LinkUnknown(obj2.getName());
@@ -849,6 +854,47 @@ LinkOCGState::StateList::~StateList() {
}
//------------------------------------------------------------------------
+// LinkResetForm
+//------------------------------------------------------------------------
+
+LinkResetForm::LinkResetForm(Object *obj, Form *forms) {
+ Object obj1;
+
+ fieldList = NULL;
+ numFields = 0;
+ flags = 0;
+
+ if (obj->dictLookup("Fields", &obj1)->isArray()) {
+ numFields = obj1.arrayGetLength();
+ fieldList = (FormField**)greallocn(fieldList, numFields, sizeof(FormField*));
+ for (int i = 0; i < numFields; ++i) {
+ Object obj2;
+
+ obj1.arrayGetNF(i, &obj2);
+ if (obj2.isString()) {
+ fieldList[i] = forms->findFieldByFullyQualifiedName(obj2.getString());
+ } else if (obj2.isRef()) {
+ fieldList[i] = forms->findFieldByRef(obj2.getRef());
+ } else {
+ error(-1, "Found a ResetForm Fields item that is not a String or a Ref");
+ fieldList[i] = NULL;
+ }
+ obj2.free();
+ }
+ obj1.free();
+
+ if (obj->dictLookup("Flags", &obj1)->isInt()) {
+ flags = obj1.getInt();
+ }
+ }
+ obj1.free();
+}
+
+LinkResetForm::~LinkResetForm() {
+ gfree(fieldList);
+}
+
+//------------------------------------------------------------------------
// LinkUnknown
//------------------------------------------------------------------------
diff --git a/poppler/Link.h b/poppler/Link.h
index 84e5801..cbb8b14 100644
--- a/poppler/Link.h
+++ b/poppler/Link.h
@@ -39,6 +39,8 @@ class Sound;
class MediaRendition;
class AnnotLink;
class Annots;
+class Form;
+class FormField;
//------------------------------------------------------------------------
// LinkAction
@@ -55,6 +57,7 @@ enum LinkActionKind {
actionSound, // sound action
actionJavaScript, // JavaScript action
actionOCGState, // Set-OCG-State action
+ actionResetForm, // Reset form action
actionUnknown // anything else
};
@@ -74,7 +77,7 @@ public:
static LinkAction *parseDest(Object *obj);
// Parse an action dictionary.
- static LinkAction *parseAction(Object *obj, GooString *baseURI = NULL);
+ static LinkAction *parseAction(Object *obj, GooString *baseURI, Form *forms);
};
//------------------------------------------------------------------------
@@ -431,6 +434,36 @@ private:
};
//------------------------------------------------------------------------
+// LinkResetForm
+//------------------------------------------------------------------------
+
+class LinkResetForm: public LinkAction {
+public:
+
+ // Build a LinkResetForm with the specified action type.
+ LinkResetForm(Object *obj, Form *form);
+
+ // Destructor.
+ virtual ~LinkResetForm();
+
+ // Was the LinkResetForm create successfully?
+ virtual GBool isOk() { return true; }
+
+ // Accessors.
+ virtual LinkActionKind getKind() { return actionResetForm; }
+
+ FormField *getField(int i) { return fieldList[i]; }
+ int getNumFields() { return numFields; }
+ int getFlags() { return flags; }
+
+private:
+
+ FormField **fieldList;
+ int numFields;
+ int flags;
+};
+
+//------------------------------------------------------------------------
// LinkUnknown
//------------------------------------------------------------------------
diff --git a/poppler/Outline.cc b/poppler/Outline.cc
index bd4e6d0..086d72f 100644
--- a/poppler/Outline.cc
+++ b/poppler/Outline.cc
@@ -97,7 +97,7 @@ OutlineItem::OutlineItem(Dict *dict, XRef *xrefA) {
} else {
obj1.free();
if (!dict->lookup("A", &obj1)->isNull()) {
- action = LinkAction::parseAction(&obj1);
+ action = LinkAction::parseAction(&obj1, NULL, NULL);
}
}
obj1.free();
diff --git a/qt4/src/poppler-link.cc b/qt4/src/poppler-link.cc
index 68c607a..7da921f 100644
--- a/qt4/src/poppler-link.cc
+++ b/qt4/src/poppler-link.cc
@@ -180,6 +180,23 @@ class LinkMoviePrivate : public LinkPrivate
}
#endif
+class LinkResetFormActionPrivate : public LinkPrivate
+{
+ public:
+ LinkResetFormActionPrivate( const QRectF &area, const QStringList &_fieldList, int _flags );
+
+ const QStringList fieldList;
+ LinkResetFormAction::Behaviour behaviour;
+};
+
+ LinkResetFormActionPrivate::LinkResetFormActionPrivate( const QRectF &area, const QStringList &_fieldList, int _flags )
+ : LinkPrivate( area ), fieldList( _fieldList )
+ {
+ if (fieldList.isEmpty()) behaviour = LinkResetFormAction::ResetAllForms;
+ else if (_flags == 0) behaviour = LinkResetFormAction::ResetFormsInFieldList;
+ else behaviour = LinkResetFormAction::ResetAllFormsExceptFieldList;
+ }
+
static void cvtUserToDev(::Page *page, double xu, double yu, int *xd, int *yd) {
double ctm[6];
@@ -584,4 +601,31 @@ class LinkMoviePrivate : public LinkPrivate
}
#endif
+ // LinkResetFormAction
+ LinkResetFormAction::LinkResetFormAction( const QRectF &linkArea, const QStringList &_fieldList, int _flags )
+ : Link( *new LinkResetFormActionPrivate( linkArea, _fieldList, _flags ) )
+ {
+ }
+
+ LinkResetFormAction::~LinkResetFormAction()
+ {
+ }
+
+ QStringList LinkResetFormAction::fieldList() const
+ {
+ Q_D( const LinkResetFormAction );
+ return d->fieldList;
+ }
+
+ LinkResetFormAction::Behaviour LinkResetFormAction::behaviour() const
+ {
+ Q_D( const LinkResetFormAction );
+ return d->behaviour;
+ }
+
+ Link::LinkType LinkResetFormAction::linkType() const
+ {
+ return ResetFormAction;
+ }
+
}
diff --git a/qt4/src/poppler-link.h b/qt4/src/poppler-link.h
index 1aa6d78..506711b 100644
--- a/qt4/src/poppler-link.h
+++ b/qt4/src/poppler-link.h
@@ -40,6 +40,7 @@ class LinkJavaScriptPrivate;
class LinkMoviePrivate;
class LinkDestinationData;
class LinkDestinationPrivate;
+class LinkResetFormActionPrivate;
class SoundObject;
/**
@@ -183,7 +184,8 @@ class POPPLER_QT4_EXPORT Link
Action, ///< A "standard" action to be executed in the viewer
Sound, ///< A link representing a sound to be played
Movie, ///< An action to be executed on a movie
- JavaScript ///< A JavaScript code to be interpreted \since 0.10
+ JavaScript, ///< A JavaScript code to be interpreted \since 0.10
+ ResetFormAction ///< A reset form action to be executed in the viewer \since 0.18
};
/**
@@ -487,6 +489,59 @@ class POPPLER_QT4_EXPORT LinkMovie : public Link
};
#endif
+/**
+ * \brief ResetForm action
+ *
+ * The LinkResetFormAction class represents a link that request a "ResetForm" action
+ * to be performed by the viewer on the displayed document.
+ *
+ * \since 0.18
+ */
+class POPPLER_QT4_EXPORT LinkResetFormAction : public Link
+{
+ public:
+ /**
+ * Flags specifying how the reset should be performed by the viewer.
+ */
+ enum Behaviour
+ {
+ ResetAllForms, ///< Reset all the forms in the document
+ ResetFormsInFieldList, ///< Reset the forms whose fully qualified name is in the list
+ ResetAllFormsExceptFieldList ///< Reset all the forms in the document exect those whose fully qualified name is in the list
+ };
+
+ /**
+ * Create a new LinkResetFormAction link, that
+ * resets form fields on document.
+ *
+ * \param linkArea the active area of the link
+ * \param fieldList list of field names
+ * \param flags action flags
+ */
+ LinkResetFormAction( const QRectF &linkArea, const QStringList &_fieldList, int _flags );
+
+ /**
+ * Destructor.
+ */
+ ~LinkResetFormAction();
+
+ /**
+ * The list of fully qualified names of fields to act on
+ */
+ QStringList fieldList() const;
+
+ /**
+ * Reset behaviour.
+ */
+ Behaviour behaviour() const;
+
+ LinkType linkType() const;
+
+ private:
+ Q_DECLARE_PRIVATE( LinkResetFormAction )
+ Q_DISABLE_COPY( LinkResetFormAction )
+};
+
}
#endif
diff --git a/qt4/src/poppler-page.cc b/qt4/src/poppler-page.cc
index f76700a..819f4ee 100644
--- a/qt4/src/poppler-page.cc
+++ b/qt4/src/poppler-page.cc
@@ -70,6 +70,18 @@ class DummyAnnotation : public Annotation
virtual SubType subType() const { return A_BASE; }
};
+void addFullyQualifiedNameAndChildrenToList(::FormField *field, QStringList *fieldList)
+{
+ if (field)
+ {
+ fieldList->append( QString::fromLatin1(field->getFullyQualifiedName()->getCString()) );
+ for (int i = 0; i < field->getNumChildren(); ++i)
+ {
+ addFullyQualifiedNameAndChildrenToList(field->getChild(i), fieldList);
+ }
+ }
+}
+
Link* PageData::convertLinkActionToLink(::LinkAction * a, const QRectF &linkArea)
{
return convertLinkActionToLink(a, parentDoc, linkArea);
@@ -181,6 +193,20 @@ Link* PageData::convertLinkActionToLink(::LinkAction * a, DocumentData *parentDo
copyString( m_uri, m->getTitle()->getCString() );
*/ break;
+ case actionResetForm:
+ {
+ ::LinkResetForm *lrs = (::LinkResetForm *) a;
+
+ QStringList fieldList;
+ for ( int i = 0; i < lrs->getNumFields(); ++i ) {
+ ::FormField *field = lrs->getField(i);
+ addFullyQualifiedNameAndChildrenToList(field, &fieldList);
+ }
+
+ popplerLink = new LinkResetFormAction( linkArea, fieldList, lrs->getFlags() );
+ }
+ break;
+
case actionUnknown:
break;
}
@@ -491,7 +517,7 @@ Link *Page::action( PageAction act ) const
Object o2;
const char *key = act == Page::Opening ? "O" : "C";
dict->lookup((char*)key, &o2);
- ::LinkAction *lact = ::LinkAction::parseAction(&o2, m_page->parentDoc->doc->getCatalog()->getBaseURI() );
+ ::LinkAction *lact = ::LinkAction::parseAction(&o2, m_page->parentDoc->doc->getCatalog()->getBaseURI(), m_page->parentDoc->doc->getCatalog()->getForm() );
o2.free();
o.free();
Link *popplerLink = NULL;
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler