From 797d3507311c8a7f2876121bdc520cd1e90c38e6 Mon Sep 17 00:00:00 2001 From: Andre Heinecke Date: Fri, 23 Mar 2018 13:05:07 +0100 Subject: [PATCH] Add support for Next actions following an action Next actions are action dictionaries or an array of action dictonaries. "Next" is an entry in the general action dictionary. These actions are supposed to be performed after each other. So that a single button press can for example both trigger a Hide action and a JavaScript action. --- poppler/Link.cc | 47 ++++++++++++++++++++++++++++++++++++++++++ poppler/Link.h | 14 +++++++++++-- qt5/src/poppler-link-private.h | 6 ++++++ qt5/src/poppler-link.cc | 10 +++++++++ qt5/src/poppler-link.h | 19 ++++++++++++++++- qt5/src/poppler-page.cc | 14 +++++++++++++ 6 files changed, 107 insertions(+), 3 deletions(-) diff --git a/poppler/Link.cc b/poppler/Link.cc index 326cfb97..d0421199 100644 --- a/poppler/Link.cc +++ b/poppler/Link.cc @@ -50,6 +50,14 @@ //------------------------------------------------------------------------ // LinkAction //------------------------------------------------------------------------ +LinkAction::LinkAction(): nextActionList(nullptr) { +} + +LinkAction::~LinkAction() { + if (nextActionList) { + delete nextActionList; + } +} LinkAction *LinkAction::parseDest(Object *obj) { LinkAction *action; @@ -134,9 +142,48 @@ LinkAction *LinkAction::parseAction(Object *obj, GooString *baseURI) { delete action; return nullptr; } + + if (!action) { + return nullptr; + } + + // parse the next actions + Object nextObj = obj->dictLookup("Next"); + GooList *actionList = nullptr; + if (nextObj.isDict()) { + // Single next action + actionList = new GooList(1); + actionList->append(parseAction(&nextObj)); + } else if (nextObj.isArray()) { + Array *a = nextObj.getArray(); + int n = a->getLength(); + actionList = new GooList(n); + for (int i = 0; i < n; ++i) { + Object obj3 = a->get(i); + if (!obj3.isDict()) { + error(errSyntaxWarning, -1, "parseAction: Next array does not contain only dicts"); + continue; + } + actionList->append(parseAction(&obj3)); + } + } + + action->setNextActions(actionList); + return action; } +GooList *LinkAction::nextActions() const { + return nextActionList; +} + +void LinkAction::setNextActions(GooList *actions) { + if (nextActionList) { + delete nextActionList; + } + nextActionList = actions; +} + //------------------------------------------------------------------------ // LinkDest //------------------------------------------------------------------------ diff --git a/poppler/Link.h b/poppler/Link.h index 05892cff..6ad39d3c 100644 --- a/poppler/Link.h +++ b/poppler/Link.h @@ -63,12 +63,12 @@ enum LinkActionKind { class LinkAction { public: - LinkAction() = default; + LinkAction(); LinkAction(const LinkAction &) = delete; LinkAction& operator=(const LinkAction &other) = delete; // Destructor. - virtual ~LinkAction() {} + virtual ~LinkAction(); // Was the LinkAction created successfully? virtual GBool isOk() = 0; @@ -81,6 +81,16 @@ public: // Parse an action dictionary. static LinkAction *parseAction(Object *obj, GooString *baseURI = NULL); + + // A List of the next actions to execute in order. + // The list contains pointer to LinkAction objects. + GooList *nextActions() const; + // Sets the next action list. Takes ownership of the actions. + void setNextActions(GooList *actions); + +private: + + GooList *nextActionList; }; //------------------------------------------------------------------------ diff --git a/qt5/src/poppler-link-private.h b/qt5/src/poppler-link-private.h index 6bc5cb9f..72b4d11c 100644 --- a/qt5/src/poppler-link-private.h +++ b/qt5/src/poppler-link-private.h @@ -23,6 +23,8 @@ class LinkOCGState; namespace Poppler { +class Link; + class LinkPrivate { public: @@ -33,12 +35,16 @@ public: virtual ~LinkPrivate() { + for (Link *l: nextLinks) { + delete l; + } } LinkPrivate(const LinkPrivate &) = delete; LinkPrivate& operator=(const LinkPrivate &) = delete; QRectF linkArea; + QVector nextLinks; }; diff --git a/qt5/src/poppler-link.cc b/qt5/src/poppler-link.cc index 626040fb..e26c3d1c 100644 --- a/qt5/src/poppler-link.cc +++ b/qt5/src/poppler-link.cc @@ -426,7 +426,17 @@ class LinkMoviePrivate : public LinkPrivate Q_D( const Link ); return d->linkArea; } + + QVector< Link * > Link::nextLinks() const + { + return d_ptr->nextLinks; + } + void Link::setNextLinks( const QVector< Link * > &links ) const + { + d_ptr->nextLinks = links; + } + // LinkGoto LinkGoto::LinkGoto( const QRectF &linkArea, QString extFileName, const LinkDestination & destination ) : Link( *new LinkGotoPrivate( linkArea, destination ) ) diff --git a/qt5/src/poppler-link.h b/qt5/src/poppler-link.h index 0753ce99..0505883e 100644 --- a/qt5/src/poppler-link.h +++ b/qt5/src/poppler-link.h @@ -28,6 +28,7 @@ #include #include #include +#include #include "poppler-export.h" struct Ref; @@ -217,7 +218,23 @@ class POPPLER_QT5_EXPORT Link * a general action. The area is given in 0..1 range */ QRectF linkArea() const; - + + /** + * Get the next links to be activiated / executed after this link. + * + * \since 0.64 + */ + QVector nextLinks() const; + + /** + * Set the next links to be activated / executed after this link. + * + * Takes ownership of the link objects pointed to in the vector. + * + * \since 0.64 + */ + void setNextLinks( const QVector< Link * > &links ) const; + protected: /// \cond PRIVATE Link( LinkPrivate &dd ); diff --git a/qt5/src/poppler-page.cc b/qt5/src/poppler-page.cc index 381a608b..d3394ae6 100644 --- a/qt5/src/poppler-page.cc +++ b/qt5/src/poppler-page.cc @@ -347,6 +347,20 @@ Link* PageData::convertLinkActionToLink(::LinkAction * a, DocumentData *parentDo break; } + if ( popplerLink ) + { + GooList *nextActions = a->nextActions(); + if ( nextActions ) + { + QVector links; + for ( int i = 0, N = nextActions->getLength(); i < N; ++i ) + { + links << convertLinkActionToLink( static_cast< ::LinkAction * >( nextActions->get( i ) ), parentDoc, linkArea ); + } + popplerLink->setNextLinks( links ); + } + } + return popplerLink; } -- 2.11.0