Implement autostart support for movie annotations

Evaluate MovieActions to implement autostart behavior for movie annotations.

REVIEW:104271
This commit is contained in:
Tobias Koenig 2012-04-03 14:18:10 +02:00
parent 5f87327c61
commit 4639ded310
13 changed files with 282 additions and 20 deletions

View file

@ -92,6 +92,7 @@ int main()
{
Poppler::ScreenAnnotation *annot = 0;
Poppler::LinkRendition *link = 0;
const Poppler::LinkMovie::Operation operation = Poppler::LinkMovie::Play;
return 0;
}
" HAVE_POPPLER_0_20)

View file

@ -29,6 +29,8 @@ class Okular::ActionPrivate
virtual ~ActionPrivate()
{
}
QVariant m_nativeId;
};
Action::Action( ActionPrivate &dd )
@ -46,6 +48,18 @@ QString Action::actionTip() const
return "";
}
void Action::setNativeId( const QVariant &id )
{
Q_D( Action );
d->m_nativeId = id;
}
QVariant Action::nativeId() const
{
Q_D( const Action );
return d->m_nativeId;
}
// GotoAction
class Okular::GotoActionPrivate : public Okular::ActionPrivate
@ -400,18 +414,20 @@ QString ScriptAction::script() const
// MovieAction
#if 0
class Okular::MovieActionPrivate : public Okular::ActionPrivate
{
public:
MovieActionPrivate()
: ActionPrivate()
MovieActionPrivate( MovieAction::OperationType operation )
: ActionPrivate(), m_operation( operation ), m_annotation( 0 )
{
}
MovieAction::OperationType m_operation;
MovieAnnotation *m_annotation;
};
MovieAction::MovieAction()
: Action( *new MovieActionPrivate() )
MovieAction::MovieAction( OperationType operation )
: Action( *new MovieActionPrivate( operation ) )
{
}
@ -428,4 +444,21 @@ QString MovieAction::actionTip() const
{
return i18n( "Play movie..." );
}
#endif
MovieAction::OperationType MovieAction::operation() const
{
Q_D( const Okular::MovieAction );
return d->m_operation;
}
void MovieAction::setAnnotation( MovieAnnotation *annotation )
{
Q_D( Okular::MovieAction );
d->m_annotation = annotation;
}
MovieAnnotation* MovieAction::annotation() const
{
Q_D( const Okular::MovieAction );
return d->m_annotation;
}

View file

@ -14,6 +14,7 @@
#include "okular_export.h"
#include <QtCore/QString>
#include <QtCore/QVariant>
namespace Okular {
@ -25,6 +26,7 @@ class DocumentActionPrivate;
class SoundActionPrivate;
class ScriptActionPrivate;
class MovieActionPrivate;
class MovieAnnotation;
class Sound;
class DocumentViewport;
@ -70,6 +72,26 @@ class OKULAR_EXPORT Action
*/
virtual QString actionTip() const;
/**
* Sets the "native" @p id of the action.
*
* This is for use of the Generator, that can optionally store an
* handle (a pointer, an identifier, etc) of the "native" action
* object, if any.
*
* @note Okular makes no use of this
*
* @since 0.15 (KDE 4.9)
*/
void setNativeId( const QVariant &id );
/**
* Returns the "native" id of the action.
*
* @since 0.15 (KDE 4.9)
*/
QVariant nativeId() const;
protected:
/// @cond PRIVATE
Action( ActionPrivate &dd );
@ -398,17 +420,28 @@ class OKULAR_EXPORT ScriptAction : public Action
Q_DISABLE_COPY( ScriptAction )
};
#if 0
/**
* The Movie action plays a video on activation.
* The Movie action executes an operation on a video on activation.
*
* @since 0.15 (KDE 4.9)
*/
class MovieAction : public Action
class OKULAR_EXPORT MovieAction : public Action
{
public:
/**
* Describes the possible operation types.
*/
enum OperationType {
Play,
Stop,
Pause,
Resume
};
/**
* Creates a new movie action.
*/
MovieAction();
MovieAction( OperationType operation );
/**
* Destroys the movie action.
@ -425,11 +458,25 @@ class MovieAction : public Action
*/
QString actionTip() const;
/**
* Returns the operation type.
*/
OperationType operation() const;
/**
* Sets the @p annotation that is associated with the movie action.
*/
void setAnnotation( MovieAnnotation *annotation );
/**
* Returns the annotation or @c 0 if no annotation has been set.
*/
MovieAnnotation* annotation() const;
private:
Q_DECLARE_PRIVATE( MovieAction )
Q_DISABLE_COPY( MovieAction )
};
#endif
}

View file

@ -3005,8 +3005,7 @@ void Document::processAction( const Action * action )
} break;
case Action::Movie:
//const MovieAction * movie = static_cast< const MovieAction * >( action );
// TODO this (Movie action)
emit processMovieAction( static_cast< const MovieAction * >( action ) );
break;
}
}

View file

@ -45,6 +45,7 @@ class ExportFormat;
class FontInfo;
class Generator;
class Action;
class MovieAction;
class Page;
class PixmapRequest;
class SourceReference;
@ -735,6 +736,11 @@ class OKULAR_EXPORT Document : public QObject
*/
void sourceReferenceActivated(const QString& absFileName, int line, int col, bool *handled);
/**
* This signal is emitted whenever an movie action is triggered and the UI should process it.
*/
void processMovieAction( const Okular::MovieAction *action );
private:
/// @cond PRIVATE
friend class DocumentPrivate;

View file

@ -68,6 +68,8 @@ Okular::Annotation* createAnnotationFromPopplerAnnotation( Poppler::Annotation *
Poppler::MovieAnnotation * movieann = static_cast< Poppler::MovieAnnotation * >( ann );
Okular::MovieAnnotation * m = new Okular::MovieAnnotation();
annotation = m;
tieToOkularAnn = true;
*doDelete = false;
m->setMovie( createMovieFromPopplerMovie( movieann->movie() ) );
@ -79,6 +81,8 @@ Okular::Annotation* createAnnotationFromPopplerAnnotation( Poppler::Annotation *
Poppler::ScreenAnnotation * screenann = static_cast< Poppler::ScreenAnnotation * >( ann );
Okular::MovieAnnotation * m = new Okular::MovieAnnotation();
annotation = m;
tieToOkularAnn = true;
*doDelete = false;
m->setMovie( createMovieFromPopplerScreen( screenann->action() ) );

View file

@ -25,7 +25,6 @@ PopplerFormFieldButton::PopplerFormFieldButton( Poppler::FormFieldButton * field
if ( aAction )
{
setActivationAction( createLinkFromPopplerLink( aAction ) );
delete aAction;
}
}
@ -107,7 +106,6 @@ PopplerFormFieldText::PopplerFormFieldText( Poppler::FormFieldText * field )
if ( aAction )
{
setActivationAction( createLinkFromPopplerLink( aAction ) );
delete aAction;
}
}
@ -204,7 +202,6 @@ PopplerFormFieldChoice::PopplerFormFieldChoice( Poppler::FormFieldChoice * field
if ( aAction )
{
setActivationAction( createLinkFromPopplerLink( aAction ) );
delete aAction;
}
}

View file

@ -53,7 +53,9 @@
#include "formfields.h"
#include "popplerembeddedfile.h"
Q_DECLARE_METATYPE(Poppler::Annotation*)
Q_DECLARE_METATYPE(Poppler::FontInfo)
Q_DECLARE_METATYPE(const Poppler::LinkMovie*)
static const int PDFDebug = 4710;
static const int defaultPageWidth = 595;
@ -169,6 +171,9 @@ Okular::Movie* createMovieFromPopplerScreen( const Poppler::LinkRendition *poppl
}
#endif
/**
* Note: the function will take ownership of the popplerLink object.
*/
Okular::Action* createLinkFromPopplerLink(const Poppler::Link *popplerLink)
{
Okular::Action *link = 0;
@ -178,8 +183,13 @@ Okular::Action* createLinkFromPopplerLink(const Poppler::Link *popplerLink)
const Poppler::LinkAction *popplerLinkAction;
const Poppler::LinkSound *popplerLinkSound;
const Poppler::LinkJavaScript *popplerLinkJS;
#ifdef HAVE_POPPLER_0_20
const Poppler::LinkMovie *popplerLinkMovie;
#endif
Okular::DocumentViewport viewport;
bool deletePopplerLink = true;
switch(popplerLink->linkType())
{
case Poppler::Link::None:
@ -239,14 +249,47 @@ Okular::Action* createLinkFromPopplerLink(const Poppler::Link *popplerLink)
break;
#endif
#ifdef HAVE_POPPLER_0_20
case Poppler::Link::Movie:
// not implemented
{
deletePopplerLink = false; // we'll delete it inside resolveMovieLinkReferences() after we have resolved all references
popplerLinkMovie = static_cast<const Poppler::LinkMovie *>( popplerLink );
Okular::MovieAction::OperationType operation = Okular::MovieAction::Play;
switch ( popplerLinkMovie->operation() )
{
case Poppler::LinkMovie::Play:
operation = Okular::MovieAction::Play;
break;
case Poppler::LinkMovie::Stop:
operation = Okular::MovieAction::Stop;
break;
case Poppler::LinkMovie::Pause:
operation = Okular::MovieAction::Pause;
break;
case Poppler::LinkMovie::Resume:
operation = Okular::MovieAction::Resume;
break;
};
Okular::MovieAction *movieAction = new Okular::MovieAction( operation );
movieAction->setNativeId( QVariant::fromValue( popplerLinkMovie ) );
link = movieAction;
}
break;
#endif
}
if ( deletePopplerLink )
delete popplerLink;
return link;
}
/**
* Note: the function will take ownership of the popplerLink objects.
*/
static QLinkedList<Okular::ObjectRect*> generateLinks( const QList<Poppler::Link*> &popplerLinks )
{
QLinkedList<Okular::ObjectRect*> links;
@ -262,7 +305,6 @@ static QLinkedList<Okular::ObjectRect*> generateLinks( const QList<Poppler::Link
// add the ObjectRect to the container
links.push_front( rect );
}
qDeleteAll(popplerLinks);
return links;
}
@ -455,6 +497,8 @@ bool PDFGenerator::init(QVector<Okular::Page*> & pagesVector, const QString &wal
pagesVector.resize(pageCount);
rectsGenerated.fill(false, pageCount);
annotationsHash.clear();
loadPages(pagesVector, 0, false);
// update the configuration
@ -522,13 +566,11 @@ void PDFGenerator::loadPages(QVector<Okular::Page*> &pagesVector, int rotation,
if ( tmplink )
{
page->setPageAction( Okular::Page::Opening, createLinkFromPopplerLink( tmplink ) );
delete tmplink;
}
tmplink = p->action( Poppler::Page::Closing );
if ( tmplink )
{
page->setPageAction( Okular::Page::Closing, createLinkFromPopplerLink( tmplink ) );
delete tmplink;
}
page->setDuration( p->duration() );
page->setLabel( p->label() );
@ -814,6 +856,8 @@ QImage PDFGenerator::image( Okular::PixmapRequest * request )
// dead gp_outputdev.cpp on image extraction
page->setObjectRects( generateLinks(p->links()) );
rectsGenerated[ request->page()->number() ] = true;
resolveMovieLinkReferences( page );
}
// 3. UNLOCK [re-enables shared access]
@ -824,6 +868,49 @@ QImage PDFGenerator::image( Okular::PixmapRequest * request )
return img;
}
void PDFGenerator::resolveMovieLinkReference( Okular::Action *action, Okular::Page *page )
{
#ifdef HAVE_POPPLER_0_20
if ( !action )
return;
if ( action->actionType() != Okular::Action::Movie )
return;
Okular::MovieAction *movieAction = static_cast<Okular::MovieAction*>( action );
const Poppler::LinkMovie *linkMovie = movieAction->nativeId().value<const Poppler::LinkMovie*>();
QHashIterator<Okular::Annotation*, Poppler::Annotation*> it( annotationsHash );
while ( it.hasNext() )
{
it.next();
if ( it.key()->subType() == Okular::Annotation::AMovie )
{
const Poppler::MovieAnnotation *movieAnnotation = static_cast<const Poppler::MovieAnnotation*>( it.value() );
if ( linkMovie->isReferencedAnnotation( movieAnnotation ) )
{
movieAction->setAnnotation( static_cast<Okular::MovieAnnotation*>( it.key() ) );
movieAction->setNativeId( QVariant() );
delete linkMovie; // delete the associated Poppler::LinkMovie object, it's not needed anymore
break;
}
}
}
#endif
}
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::FormField *field, page->formFields() )
resolveMovieLinkReference( field->activationAction(), page );
}
Okular::TextPage* PDFGenerator::textPage( Okular::Page *page )
{
#ifdef PDFGENERATOR_DEBUG
@ -1279,6 +1366,9 @@ void PDFGenerator::addAnnotations( Poppler::Page * popplerPage, Okular::Page * p
// explicitly mark as external
newann->setFlags( newann->flags() | Okular::Annotation::External );
page->addAnnotation(newann);
if ( !doDelete )
annotationsHash.insert( newann, a );
}
if ( doDelete )
delete a;

View file

@ -123,6 +123,9 @@ class PDFGenerator : public Okular::Generator, public Okular::ConfigInterface, p
Okular::TextPage * abstractTextPage(const QList<Poppler::TextBox*> &text, double height, double width, int rot);
void resolveMovieLinkReferences( Okular::Page *page );
void resolveMovieLinkReference( Okular::Action *action, Okular::Page *page );
bool setDocumentRenderHints();
// poppler dependant stuff
@ -139,6 +142,7 @@ class PDFGenerator : public Okular::Generator, public Okular::ConfigInterface, p
int nextFontPage;
double dpiX;
double dpiY;
QHash<Okular::Annotation*, Poppler::Annotation*> annotationsHash;
QBitArray rectsGenerated;

View file

@ -363,6 +363,8 @@ PageView::PageView( QWidget *parent, Okular::Document *document )
d->leftClickTimer.setSingleShot( true );
connect( &d->leftClickTimer, SIGNAL(timeout()), this, SLOT(slotShowSizeAllCursor()) );
connect( d->document, SIGNAL(processMovieAction(const Okular::MovieAction*)), this, SLOT(slotProcessMovieAction(const Okular::MovieAction*)) );
// set a corner button to resize the view to the page size
// QPushButton * resizeButton = new QPushButton( viewport() );
// resizeButton->setPixmap( SmallIcon("crop") );
@ -4433,6 +4435,46 @@ void PageView::externalKeyPressEvent( QKeyEvent *e )
keyPressEvent( e );
}
void PageView::slotProcessMovieAction( const Okular::MovieAction *action )
{
const Okular::MovieAnnotation *movieAnnotation = action->annotation();
if ( !movieAnnotation )
return;
Okular::Movie *movie = movieAnnotation->movie();
if ( !movie )
return;
const int currentPage = d->document->viewport().pageNumber;
PageViewItem *item = d->items.at( currentPage );
if ( !item )
return;
VideoWidget *vw = item->videoWidgets().value( movie );
if ( !vw )
return;
vw->show();
switch ( action->operation() )
{
case Okular::MovieAction::Play:
vw->stop();
vw->play();
break;
case Okular::MovieAction::Stop:
vw->stop();
break;
case Okular::MovieAction::Pause:
vw->pause();
break;
case Okular::MovieAction::Resume:
vw->play();
break;
};
}
//END private SLOTS
#include "pageview.moc"

View file

@ -37,6 +37,7 @@ class Action;
class Document;
class DocumentViewport;
class Annotation;
class MovieAction;
}
class FormWidgetIface;
@ -244,6 +245,7 @@ Q_OBJECT
void slotAction( Okular::Action *action );
void externalKeyPressEvent( QKeyEvent *e );
void slotAnnotationWindowDestroyed( QObject *window );
void slotProcessMovieAction( const Okular::MovieAction *action );
};
#endif

View file

@ -219,6 +219,8 @@ PresentationWidget::PresentationWidget( QWidget * parent, Okular::Document * doc
m_nextPageTimer->setSingleShot( true );
connect( m_nextPageTimer, SIGNAL(timeout()), this, SLOT(slotNextPage()) );
connect( m_document, SIGNAL(processMovieAction(const Okular::MovieAction*)), this, SLOT(slotProcessMovieAction(const Okular::MovieAction*)) );
// handle cursor appearance as specified in configuration
if ( Okular::Settings::slidesCursor() == Okular::Settings::EnumSlidesCursor::HiddenDelay )
{
@ -1999,5 +2001,38 @@ void PresentationWidget::initTransition( const Okular::PageTransition *transitio
m_transitionTimer->start( 0 );
}
void PresentationWidget::slotProcessMovieAction( const Okular::MovieAction *action )
{
const Okular::MovieAnnotation *movieAnnotation = action->annotation();
if ( !movieAnnotation )
return;
Okular::Movie *movie = movieAnnotation->movie();
if ( !movie )
return;
VideoWidget *vw = m_frames[ m_frameIndex ]->videoWidgets.value( movieAnnotation->movie() );
if ( !vw )
return;
vw->show();
switch ( action->operation() )
{
case Okular::MovieAction::Play:
vw->stop();
vw->play();
break;
case Okular::MovieAction::Stop:
vw->stop();
break;
case Okular::MovieAction::Pause:
vw->pause();
break;
case Okular::MovieAction::Resume:
vw->play();
break;
};
}
#include "presentationwidget.moc"

View file

@ -31,6 +31,7 @@ namespace Okular {
class Action;
class Annotation;
class Document;
class MovieAction;
class Page;
}
@ -147,6 +148,7 @@ class PresentationWidget : public QWidget, public Okular::DocumentObserver
void screenResized( int );
void chooseScreen( QAction * );
void toggleBlackScreenMode( bool );
void slotProcessMovieAction( const Okular::MovieAction *action );
};
#endif