Commit 770e2818 authored by Tobias Koenig's avatar Tobias Koenig
Browse files

Evaluate additional actions of screen and widget annotations

This fixes the auto-start feature of PDFs generated with the LaTeX movie
package, which uses the additional action of a widget annotation to start
the movie when entering the page.

BUG: 300051
REVIEW: 106430
FIXED-IN: 4.10
parent b78f6c7f
......@@ -99,11 +99,15 @@ int main()
check_cxx_source_compiles("
#include <poppler-qt4.h>
#include <poppler-annotation.h>
int main()
{
Poppler::MovieObject *movie = 0;
movie->showPosterImage();
const Poppler::Annotation::AdditionalActionType type = Poppler::Annotation::PageOpeningAction;
return 0;
}
" HAVE_POPPLER_0_22)
......
......@@ -15,6 +15,7 @@
#include <QtGui/QColor>
// local includes
#include "action.h"
#include "document.h"
#include "document_p.h"
#include "movie.h"
......@@ -2411,3 +2412,149 @@ void MovieAnnotation::setMovie( Movie *movie )
Q_D( MovieAnnotation );
d->movie = movie;
}
/** ScreenAnnotation [Annotation] */
class Okular::ScreenAnnotationPrivate : public Okular::AnnotationPrivate
{
public:
~ScreenAnnotationPrivate();
QMap< Okular::Annotation::AdditionalActionType, Okular::Action* > m_additionalActions;
};
ScreenAnnotationPrivate::~ScreenAnnotationPrivate()
{
qDeleteAll( m_additionalActions );
}
ScreenAnnotation::ScreenAnnotation()
: Annotation( *new ScreenAnnotationPrivate() )
{
}
ScreenAnnotation::ScreenAnnotation( const QDomNode & node )
: Annotation( *new ScreenAnnotationPrivate(), node )
{
// loop through the whole children looking for a 'screen' element
QDomNode subNode = node.firstChild();
while( subNode.isElement() )
{
QDomElement e = subNode.toElement();
subNode = subNode.nextSibling();
if ( e.tagName() != "screen" )
continue;
// loading complete
break;
}
}
ScreenAnnotation::~ScreenAnnotation()
{
}
void ScreenAnnotation::store( QDomNode & node, QDomDocument & document ) const
{
// recurse to parent objects storing properties
Annotation::store( node, document );
// create [screen] element
QDomElement movieElement = document.createElement( "screen" );
node.appendChild( movieElement );
}
Annotation::SubType ScreenAnnotation::subType() const
{
return AScreen;
}
void ScreenAnnotation::setAdditionalAction( AdditionalActionType type, Action *action )
{
Q_D( ScreenAnnotation );
if ( d->m_additionalActions.contains( type ) )
delete d->m_additionalActions.value( type );
d->m_additionalActions.insert( type, action );
}
Action* ScreenAnnotation::additionalAction( AdditionalActionType type ) const
{
Q_D( const ScreenAnnotation );
if ( !d->m_additionalActions.contains( type ) )
return 0;
else
return d->m_additionalActions.value( type );
}
/** WidgetAnnotation [Annotation] */
class Okular::WidgetAnnotationPrivate : public Okular::AnnotationPrivate
{
public:
~WidgetAnnotationPrivate();
QMap< Okular::Annotation::AdditionalActionType, Okular::Action* > m_additionalActions;
};
WidgetAnnotationPrivate::~WidgetAnnotationPrivate()
{
qDeleteAll( m_additionalActions );
}
WidgetAnnotation::WidgetAnnotation()
: Annotation( *new WidgetAnnotationPrivate() )
{
}
WidgetAnnotation::WidgetAnnotation( const QDomNode & node )
: Annotation( *new WidgetAnnotationPrivate(), node )
{
// loop through the whole children looking for a 'widget' element
QDomNode subNode = node.firstChild();
while( subNode.isElement() )
{
QDomElement e = subNode.toElement();
subNode = subNode.nextSibling();
if ( e.tagName() != "widget" )
continue;
// loading complete
break;
}
}
WidgetAnnotation::~WidgetAnnotation()
{
}
void WidgetAnnotation::store( QDomNode & node, QDomDocument & document ) const
{
// recurse to parent objects storing properties
Annotation::store( node, document );
// create [widget] element
QDomElement movieElement = document.createElement( "widget" );
node.appendChild( movieElement );
}
Annotation::SubType WidgetAnnotation::subType() const
{
return AWidget;
}
void WidgetAnnotation::setAdditionalAction( AdditionalActionType type, Action *action )
{
Q_D( WidgetAnnotation );
if ( d->m_additionalActions.contains( type ) )
delete d->m_additionalActions.value( type );
d->m_additionalActions.insert( type, action );
}
Action* WidgetAnnotation::additionalAction( AdditionalActionType type ) const
{
Q_D( const WidgetAnnotation );
if ( !d->m_additionalActions.contains( type ) )
return 0;
else
return d->m_additionalActions.value( type );
}
......@@ -23,6 +23,7 @@
namespace Okular {
class Action;
class Annotation;
class AnnotationObjectRect;
class AnnotationPrivate;
......@@ -42,6 +43,8 @@ class CaretAnnotationPrivate;
class FileAttachmentAnnotationPrivate;
class SoundAnnotationPrivate;
class MovieAnnotationPrivate;
class ScreenAnnotationPrivate;
class WidgetAnnotationPrivate;
/**
* @short Helper class for (recursive) annotation retrieval/storage.
......@@ -109,6 +112,8 @@ class OKULAR_EXPORT Annotation
AFileAttachment = 9, ///< A file attachment annotation
ASound = 10, ///< A sound annotation
AMovie = 11, ///< A movie annotation
AScreen = 12, ///< A screen annotation
AWidget = 13, ///< A widget annotation
A_BASE = 0 ///< The annotation base class
};
......@@ -174,6 +179,17 @@ class OKULAR_EXPORT Annotation
Completed = 64 ///< Has been completed
};
/**
* Describes the type of additional actions.
*
* @since 0.16 (KDE 4.10)
*/
enum AdditionalActionType
{
PageOpening, ///< Performed when the page containing the annotation is opened.
PageClosing ///< Performed when the page containing the annotation is closed.
};
/**
* A function to be called when the annotation is destroyed.
*
......@@ -1511,6 +1527,117 @@ class OKULAR_EXPORT MovieAnnotation : public Annotation
Q_DISABLE_COPY( MovieAnnotation )
};
/**
* \short Screen annotation.
*
* The screen annotation specifies a region of a page upon which media clips
* may be played. It also serves as an object from which actions can be triggered.
*
* @since 0.16 (KDE 4.10)
*/
class OKULAR_EXPORT ScreenAnnotation : public Annotation
{
public:
/**
* Creates a new screen annotation.
*/
ScreenAnnotation();
/**
* Creates a new screen annotation from the xml @p description
*/
ScreenAnnotation( const QDomNode &description );
/**
* Destroys the screen annotation.
*/
virtual ~ScreenAnnotation();
/**
* Returns the sub type of the screen annotation.
*/
SubType subType() const;
/**
* Stores the screen annotation as xml in @p document
* under the given @p parentNode.
*/
void store( QDomNode &parentNode, QDomDocument &document ) const;
/**
* Sets the additional @p action of the given @p type.
*
* @since 0.16 (KDE 4.10)
*/
void setAdditionalAction( AdditionalActionType type, Action *action );
/**
* Returns the additional action of the given @p type or @c 0 if no action has been defined.
*
* @since 0.16 (KDE 4.10)
*/
Action* additionalAction( AdditionalActionType type ) const;
private:
Q_DECLARE_PRIVATE( ScreenAnnotation )
Q_DISABLE_COPY( ScreenAnnotation )
};
/**
* \short Widget annotation.
*
* The widget annotation represents a widget on a page.
*
* @since 0.16 (KDE 4.10)
*/
class OKULAR_EXPORT WidgetAnnotation : public Annotation
{
public:
/**
* Creates a new widget annotation.
*/
WidgetAnnotation();
/**
* Creates a new widget annotation from the xml @p description
*/
WidgetAnnotation( const QDomNode &description );
/**
* Destroys the widget annotation.
*/
virtual ~WidgetAnnotation();
/**
* Returns the sub type of the widget annotation.
*/
SubType subType() const;
/**
* Stores the widget annotation as xml in @p document
* under the given @p parentNode.
*/
void store( QDomNode &parentNode, QDomDocument &document ) const;
/**
* Sets the additional @p action of the given @p type.
*
* @since 0.16 (KDE 4.10)
*/
void setAdditionalAction( AdditionalActionType type, Action *action );
/**
* Returns the additional action of the given @p type or @c 0 if no action has been defined.
*
* @since 0.16 (KDE 4.10)
*/
Action* additionalAction( AdditionalActionType type ) const;
private:
Q_DECLARE_PRIVATE( WidgetAnnotation )
Q_DISABLE_COPY( WidgetAnnotation )
};
}
#endif
......@@ -310,6 +310,13 @@ Okular::Annotation* createAnnotationFromPopplerAnnotation( Poppler::Annotation *
break;
}
#ifdef HAVE_POPPLER_0_22
case Poppler::Annotation::AWidget:
{
annotation = new Okular::WidgetAnnotation();
break;
}
#endif
#ifdef HAVE_POPPLER_0_20
case Poppler::Annotation::AScreen:
{
......
......@@ -945,6 +945,23 @@ void PDFGenerator::resolveMovieLinkReferences( Okular::Page *page )
resolveMovieLinkReference( const_cast<Okular::Action*>( page->pageAction( Okular::Page::Opening ) ), page );
resolveMovieLinkReference( const_cast<Okular::Action*>( page->pageAction( Okular::Page::Closing ) ), page );
foreach ( Okular::Annotation *annotation, page->annotations() )
{
if ( annotation->subType() == Okular::Annotation::AScreen )
{
Okular::ScreenAnnotation *screenAnnotation = static_cast<Okular::ScreenAnnotation*>( annotation );
resolveMovieLinkReference( screenAnnotation->additionalAction( Okular::Annotation::PageOpening ), page );
resolveMovieLinkReference( screenAnnotation->additionalAction( Okular::Annotation::PageClosing ), page );
}
if ( annotation->subType() == Okular::Annotation::AWidget )
{
Okular::WidgetAnnotation *widgetAnnotation = static_cast<Okular::WidgetAnnotation*>( annotation );
resolveMovieLinkReference( widgetAnnotation->additionalAction( Okular::Annotation::PageOpening ), page );
resolveMovieLinkReference( widgetAnnotation->additionalAction( Okular::Annotation::PageClosing ), page );
}
}
foreach ( Okular::FormField *field, page->formFields() )
resolveMovieLinkReference( field->activationAction(), page );
}
......@@ -1376,6 +1393,36 @@ void PDFGenerator::addAnnotations( Poppler::Page * popplerPage, Okular::Page * p
{
page->addAnnotation(newann);
#ifdef HAVE_POPPLER_0_22
if ( a->subType() == Poppler::Annotation::AScreen )
{
Poppler::ScreenAnnotation *annotScreen = static_cast<Poppler::ScreenAnnotation*>( a );
Okular::ScreenAnnotation *screenAnnotation = static_cast<Okular::ScreenAnnotation*>( newann );
const Poppler::Link *pageOpeningLink = annotScreen->additionalAction( Poppler::Annotation::PageOpeningAction );
if ( pageOpeningLink )
screenAnnotation->setAdditionalAction( Okular::Annotation::PageOpening, createLinkFromPopplerLink( pageOpeningLink ) );
const Poppler::Link *pageClosingLink = annotScreen->additionalAction( Poppler::Annotation::PageClosingAction );
if ( pageClosingLink )
screenAnnotation->setAdditionalAction( Okular::Annotation::PageClosing, createLinkFromPopplerLink( pageClosingLink ) );
}
if ( a->subType() == Poppler::Annotation::AWidget )
{
Poppler::WidgetAnnotation *annotWidget = static_cast<Poppler::WidgetAnnotation*>( a );
Okular::WidgetAnnotation *widgetAnnotation = static_cast<Okular::WidgetAnnotation*>( newann );
const Poppler::Link *pageOpeningLink = annotWidget->additionalAction( Poppler::Annotation::PageOpeningAction );
if ( pageOpeningLink )
widgetAnnotation->setAdditionalAction( Okular::Annotation::PageOpening, createLinkFromPopplerLink( pageOpeningLink ) );
const Poppler::Link *pageClosingLink = annotWidget->additionalAction( Poppler::Annotation::PageClosingAction );
if ( pageClosingLink )
widgetAnnotation->setAdditionalAction( Okular::Annotation::PageClosing, createLinkFromPopplerLink( pageClosingLink ) );
}
#endif
if ( !doDelete )
annotationsHash.insert( newann, a );
}
......
......@@ -99,6 +99,12 @@ QString captionForAnnotation( const Okular::Annotation * ann )
case Okular::Annotation::AMovie:
ret = i18n( "Movie" );
break;
case Okular::Annotation::AScreen:
ret = i18nc( "Caption for a screen annotation", "Screen" );
break;
case Okular::Annotation::AWidget:
ret = i18nc( "Caption for a widget annotation", "Widget" );
break;
case Okular::Annotation::A_BASE:
break;
}
......
......@@ -379,6 +379,20 @@ void PresentationWidget::notifyCurrentPageChanged( int previousPage, int current
// perform the page closing action, if any
if ( m_document->page( previousPage )->pageAction( Okular::Page::Closing ) )
m_document->processAction( m_document->page( previousPage )->pageAction( Okular::Page::Closing ) );
// perform the additional actions of the page's annotations, if any
Q_FOREACH ( const Okular::Annotation *annotation, m_document->page( m_frameIndex )->annotations() )
{
Okular::Action *action = 0;
if ( annotation->subType() == Okular::Annotation::AScreen )
action = static_cast<const Okular::ScreenAnnotation*>( annotation )->additionalAction( Okular::Annotation::PageClosing );
else if ( annotation->subType() == Okular::Annotation::AWidget )
action = static_cast<const Okular::WidgetAnnotation*>( annotation )->additionalAction( Okular::Annotation::PageClosing );
if ( action )
m_document->processAction( action );
}
}
if ( currentPage != -1 )
......@@ -411,6 +425,20 @@ void PresentationWidget::notifyCurrentPageChanged( int previousPage, int current
if ( m_document->page( m_frameIndex )->pageAction( Okular::Page::Opening ) )
m_document->processAction( m_document->page( m_frameIndex )->pageAction( Okular::Page::Opening ) );
// perform the additional actions of the page's annotations, if any
Q_FOREACH ( const Okular::Annotation *annotation, m_document->page( m_frameIndex )->annotations() )
{
Okular::Action *action = 0;
if ( annotation->subType() == Okular::Annotation::AScreen )
action = static_cast<const Okular::ScreenAnnotation*>( annotation )->additionalAction( Okular::Annotation::PageOpening );
else if ( annotation->subType() == Okular::Annotation::AWidget )
action = static_cast<const Okular::WidgetAnnotation*>( annotation )->additionalAction( Okular::Annotation::PageOpening );
if ( action )
m_document->processAction( action );
}
// start autoplay video playback
Q_FOREACH ( VideoWidget *vw, m_frames[ m_frameIndex ]->videoWidgets )
vw->pageEntered();
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment