diff --git a/autotests/visibilitytest.cpp b/autotests/visibilitytest.cpp --- a/autotests/visibilitytest.cpp +++ b/autotests/visibilitytest.cpp @@ -166,15 +166,7 @@ m_document->processAction( hideBtn->activationAction() ); - // XXX For now poppler only provides the first action - // in a chain. So only the first hide action is executed. - // The first hide action targets the Button. So for now - // only check this. - // - // This should work in principle: - // verifyTargetStates( false ); - - QCOMPARE( m_fields[QStringLiteral( "TargetButton" )]->isVisible(), false ); + verifyTargetStates( false ); m_document->processAction( showBtn->activationAction() ); diff --git a/core/action.h b/core/action.h --- a/core/action.h +++ b/core/action.h @@ -97,6 +97,21 @@ */ QVariant nativeId() const; + /** + * Returns the next actions to be executed after. + * + * @since 1.5 + */ + QVector< Action * > nextActions() const; + + /** + * Sets the next actions. + * + * Takes ownership of the objects in the actions vector. + * @since 1.5 + */ + void setNextActions( const QVector< Action * > &actions ); + protected: /// @cond PRIVATE Action( ActionPrivate &dd ); diff --git a/core/action.cpp b/core/action.cpp --- a/core/action.cpp +++ b/core/action.cpp @@ -29,9 +29,11 @@ virtual ~ActionPrivate() { + qDeleteAll( m_nextActions ); } QVariant m_nativeId; + QVector< Action * > m_nextActions; }; Action::Action( ActionPrivate &dd ) @@ -61,6 +63,18 @@ return d->m_nativeId; } +QVector< Action * > Action::nextActions() const +{ + Q_D( const Action ); + return d->m_nextActions; +} + +void Action::setNextActions( const QVector< Action * > &actions ) +{ + Q_D( Action ); + d->m_nextActions = actions; +} + // GotoAction class Okular::GotoActionPrivate : public Okular::ActionPrivate diff --git a/core/document.cpp b/core/document.cpp --- a/core/document.cpp +++ b/core/document.cpp @@ -4074,14 +4074,14 @@ if ( go->isExternal() && !d->openRelativeFile( go->fileName() ) ) { qCWarning(OkularCoreDebug).nospace() << "Action: Error opening '" << go->fileName() << "'."; - return; + break; } else { const DocumentViewport nextViewport = d->nextDocumentViewport(); // skip local links that point to nowhere (broken ones) if ( !nextViewport.isValid() ) - return; + break; setViewport( nextViewport, nullptr, true ); d->m_nextDocumentViewport = DocumentViewport(); @@ -4096,7 +4096,7 @@ if ( fileName.endsWith( QLatin1String(".pdf"), Qt::CaseInsensitive ) ) { d->openRelativeFile( fileName ); - return; + break; } // Albert: the only pdf i have that has that kind of link don't define @@ -4118,15 +4118,15 @@ // this case is a link pointing to an executable with a parameter // that also is an executable, possibly a hand-crafted pdf KMessageBox::information( d->m_widget, i18n("The document is trying to execute an external application and, for your safety, Okular does not allow that.") ); - return; + break; } } else { // this case is a link pointing to an executable with no parameters // core developers find unacceptable executing it even after asking the user KMessageBox::information( d->m_widget, i18n("The document is trying to execute an external application and, for your safety, Okular does not allow that.") ); - return; + break; } } @@ -4208,7 +4208,7 @@ if ((url.scheme() == "http") && url.host().isEmpty() && url.fileName().endsWith("pdf")) { d->openRelativeFile(url.fileName()); - return; + break; } // handle documents with relative path @@ -4252,6 +4252,11 @@ } break; } + + for ( const Action *a : action->nextActions() ) + { + processAction( a ); + } } void Document::processSourceReference( const SourceReference * ref ) diff --git a/generators/poppler/CMakeLists.txt b/generators/poppler/CMakeLists.txt --- a/generators/poppler/CMakeLists.txt +++ b/generators/poppler/CMakeLists.txt @@ -75,11 +75,14 @@ check_cxx_source_compiles(" #include #include +#include int main() { Poppler::FormField *f; f->setReadOnly(true); f->setVisible(true); + Poppler::Link *l; + l->nextLinks(); } " HAVE_POPPLER_0_64) diff --git a/generators/poppler/formfields.cpp b/generators/poppler/formfields.cpp --- a/generators/poppler/formfields.cpp +++ b/generators/poppler/formfields.cpp @@ -15,7 +15,7 @@ #include -extern Okular::Action* createLinkFromPopplerLink(const Poppler::Link *popplerLink); +extern Okular::Action* createLinkFromPopplerLink(const Poppler::Link *popplerLink, bool deletePopplerLink = true); #ifdef HAVE_POPPLER_0_53 #define SET_ACTIONS \ diff --git a/generators/poppler/generator_pdf.cpp b/generators/poppler/generator_pdf.cpp --- a/generators/poppler/generator_pdf.cpp +++ b/generators/poppler/generator_pdf.cpp @@ -311,7 +311,7 @@ /** * Note: the function will take ownership of the popplerLink object. */ -Okular::Action* createLinkFromPopplerLink(const Poppler::Link *popplerLink) +Okular::Action* createLinkFromPopplerLink(const Poppler::Link *popplerLink, bool deletePopplerLink = true) { if (!popplerLink) return nullptr; @@ -327,8 +327,6 @@ const Poppler::LinkRendition *popplerLinkRendition; Okular::DocumentViewport viewport; - bool deletePopplerLink = true; - switch(popplerLink->linkType()) { case Poppler::Link::None: @@ -384,6 +382,17 @@ case Poppler::Link::Rendition: { + if (!deletePopplerLink) + { + // If links should not be deleted it probably means that they + // are part of a nextActions chain. There is no support + // to resolveMediaLinkReferences on nextActions. It would also + // be neccessary to ensure that resolveMediaLinkReferences does + // not delete the Links which are part of a nextActions list + // to avoid a double deletion. + qCDebug(OkularPdfDebug) << "parsing rendition link without deletion is not supported. Action chain might be broken."; + break; + } deletePopplerLink = false; // we'll delete it inside resolveMediaLinkReferences() after we have resolved all references popplerLinkRendition = static_cast( popplerLink ); @@ -420,6 +429,12 @@ case Poppler::Link::Movie: { + if (!deletePopplerLink) + { + // See comment above in Link::Rendition + qCDebug(OkularPdfDebug) << "parsing movie link without deletion is not supported. Action chain might be broken."; + break; + } deletePopplerLink = false; // we'll delete it inside resolveMediaLinkReferences() after we have resolved all references popplerLinkMovie = static_cast( popplerLink ); @@ -462,6 +477,18 @@ #endif } +#ifdef HAVE_POPPLER_0_64 + if (link) + { + QVector< Okular::Action * > nextActions; + for ( const Poppler::Link *nl : popplerLink->nextLinks() ) + { + nextActions << createLinkFromPopplerLink( nl, false ); + } + link->setNextActions( nextActions ); + } +#endif + if ( deletePopplerLink ) delete popplerLink;