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

Reply via email to