From 43246c563b2682417e11dd7a853779d40f55ed30 Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Sun, 29 Dec 2013 23:27:30 +0100 Subject: [PATCH] Viewport transition refinements for Find and Undo/Redo actions REVIEW: 114060 This patch introduces viewport transitions for undo/redo actions on annotations and forms. When an annotation/form action is undone/redone but the associated annotation/form is not currently visible, the viewport is updated to center on the undo/redo action. If the annotation/form is visible, the viewport is not updated. The viewport transitions for the Find action have also been updated to this same algorithm. Previously the viewport was moved to center on each matching search term even if the search term was already visible in the viewport. This lead to unnecessary viewport transitions if the search term matched several items in a single paragraph for example. These proposed changes to the viewport transition behavior are consistent with the find and undo behavior of many existing applications including Kate, Open Office, and Foxit PDF Reader. --- core/document.cpp | 37 +++++++++++-- core/document_p.h | 6 +++ core/documentcommands.cpp | 108 +++++++++++++++++++++++++++++++------- core/documentcommands_p.h | 19 +++---- core/page.cpp | 20 +------ core/utils.cpp | 22 ++++++++ core/utils_p.h | 5 ++ 7 files changed, 166 insertions(+), 51 deletions(-) diff --git a/core/document.cpp b/core/document.cpp index 10cd238c0..6990bc309 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -1699,8 +1699,16 @@ void DocumentPrivate::doProcessSearchMatch( RegularAreaRect *match, RunningSearc // ..queue page for notifying changes.. pagesToNotify->insert( currentPage ); + // Create a normalized rectangle around the search match that includes a 5% buffer on all sides. + const Okular::NormalizedRect matchRectWithBuffer = Okular::NormalizedRect( match->first().left - 0.05, + match->first().top - 0.05, + match->first().right + 0.05, + match->first().bottom + 0.05 ); + + const bool matchRectFullyVisible = isNormalizedRectangleFullyVisible( matchRectWithBuffer, currentPage ); + // ..move the viewport to show the first of the searched word sequence centered - if ( moveViewport ) + if ( moveViewport && !matchRectFullyVisible ) { DocumentViewport searchViewport( currentPage ); searchViewport.rePos.enabled = true; @@ -1999,6 +2007,25 @@ QVariant DocumentPrivate::documentMetaData( const QString &key, const QVariant & return QVariant(); }; +bool DocumentPrivate::isNormalizedRectangleFullyVisible( const Okular::NormalizedRect & rectOfInterest, int rectPage ) +{ + bool rectFullyVisible = false; + const QVector & visibleRects = m_parent->visiblePageRects(); + QVector::const_iterator vEnd = visibleRects.end(); + QVector::const_iterator vIt = visibleRects.begin(); + + for ( ; ( vIt != vEnd ) && !rectFullyVisible; ++vIt ) + { + if ( (*vIt)->pageNumber == rectPage && + (*vIt)->rect.contains( rectOfInterest.left, rectOfInterest.top ) && + (*vIt)->rect.contains( rectOfInterest.right, rectOfInterest.bottom ) ) + { + rectFullyVisible = true; + } + } + return rectFullyVisible; +} + Document::Document( QWidget *widget ) : QObject( 0 ), d( new DocumentPrivate( this ) ) { @@ -3445,7 +3472,7 @@ void Document::editFormText( int pageNumber, int prevCursorPos, int prevAnchorPos ) { - QUndoCommand *uc = new EditFormTextCommand( this, form, pageNumber, newContents, newCursorPos, form->text(), prevCursorPos, prevAnchorPos ); + QUndoCommand *uc = new EditFormTextCommand( this->d, form, pageNumber, newContents, newCursorPos, form->text(), prevCursorPos, prevAnchorPos ); d->m_undoStack->push( uc ); } @@ -3454,7 +3481,7 @@ void Document::editFormList( int pageNumber, const QList< int > & newChoices ) { const QList< int > prevChoices = form->currentChoices(); - QUndoCommand *uc = new EditFormListCommand( this, form, pageNumber, newChoices, prevChoices ); + QUndoCommand *uc = new EditFormListCommand( this->d, form, pageNumber, newChoices, prevChoices ); d->m_undoStack->push( uc ); } @@ -3476,13 +3503,13 @@ void Document::editFormCombo( int pageNumber, prevText = form->choices()[form->currentChoices()[0]]; } - QUndoCommand *uc = new EditFormComboCommand( this, form, pageNumber, newText, newCursorPos, prevText, prevCursorPos, prevAnchorPos ); + QUndoCommand *uc = new EditFormComboCommand( this->d, form, pageNumber, newText, newCursorPos, prevText, prevCursorPos, prevAnchorPos ); d->m_undoStack->push( uc ); } void Document::editFormButtons( int pageNumber, const QList< FormFieldButton* >& formButtons, const QList< bool >& newButtonStates ) { - QUndoCommand *uc = new EditFormButtonsCommand( this, pageNumber, formButtons, newButtonStates ); + QUndoCommand *uc = new EditFormButtonsCommand( this->d, pageNumber, formButtons, newButtonStates ); d->m_undoStack->push( uc ); } diff --git a/core/document_p.h b/core/document_p.h index 3a257de42..ef2516974 100644 --- a/core/document_p.h +++ b/core/document_p.h @@ -183,6 +183,12 @@ class DocumentPrivate */ QVariant documentMetaData( const QString &key, const QVariant &option ) const; + /** + * Return whether the normalized rectangle @p rectOfInterest on page number @p rectPage + * is fully visible. + */ + bool isNormalizedRectangleFullyVisible( const Okular::NormalizedRect & rectOfInterest, int rectPage ); + // member variables Document *m_parent; QPointer m_widget; diff --git a/core/documentcommands.cpp b/core/documentcommands.cpp index 7799bb0d4..065042d26 100644 --- a/core/documentcommands.cpp +++ b/core/documentcommands.cpp @@ -13,11 +13,49 @@ #include "debug_p.h" #include "document_p.h" #include "form.h" +#include "utils_p.h" +#include "page.h" #include namespace Okular { +void moveViewportIfBoundingRectNotFullyVisible( Okular::NormalizedRect boundingRect, + DocumentPrivate *docPriv, + int pageNumber ) +{ + const Rotation pageRotation = docPriv->m_parent->page( pageNumber )->rotation(); + const QTransform rotationMatrix = Okular::buildRotationMatrix( pageRotation ); + boundingRect.transform( rotationMatrix ); + if ( !docPriv->isNormalizedRectangleFullyVisible( boundingRect, pageNumber ) ) + { + DocumentViewport searchViewport( pageNumber ); + searchViewport.rePos.enabled = true; + searchViewport.rePos.normalizedX = ( boundingRect.left + boundingRect.right ) / 2.0; + searchViewport.rePos.normalizedY = ( boundingRect.top + boundingRect.bottom ) / 2.0; + docPriv->m_parent->setViewport( searchViewport, 0, true ); + } +} + +Okular::NormalizedRect buildBoundingRectangleForButtons( const QList & formButtons ) +{ + // Initialize coordinates of the bounding rect + double left = 1.0; + double top = 1.0; + double right = 0.0; + double bottom = 0.0; + + foreach( FormFieldButton* formButton, formButtons ) + { + left = qMin( left, formButton->rect().left ); + top = qMin( top, formButton->rect().top ); + right = qMax( right, formButton->rect().right ); + bottom = qMax( bottom, formButton->rect().bottom ); + } + Okular::NormalizedRect boundingRect( left, top, right, bottom ); + return boundingRect; +} + AddAnnotationCommand::AddAnnotationCommand( Okular::DocumentPrivate * docPriv, Okular::Annotation* annotation, int pageNumber ) : m_docPriv( docPriv ), m_annotation( annotation ), @@ -37,19 +75,21 @@ AddAnnotationCommand::~AddAnnotationCommand() void AddAnnotationCommand::undo() { + moveViewportIfBoundingRectNotFullyVisible( m_annotation->boundingRectangle(), m_docPriv, m_pageNumber ); m_docPriv->performRemovePageAnnotation( m_pageNumber, m_annotation ); m_done = false; } void AddAnnotationCommand::redo() { + moveViewportIfBoundingRectNotFullyVisible( m_annotation->boundingRectangle(), m_docPriv, m_pageNumber ); m_docPriv->performAddPageAnnotation( m_pageNumber, m_annotation ); m_done = true; } RemoveAnnotationCommand::RemoveAnnotationCommand(Okular::DocumentPrivate * doc, Okular::Annotation* annotation, int pageNumber) - : m_doc( doc ), + : m_docPriv( doc ), m_annotation( annotation ), m_pageNumber( pageNumber ), m_done( false ) @@ -67,12 +107,14 @@ RemoveAnnotationCommand::~RemoveAnnotationCommand() void RemoveAnnotationCommand::undo() { - m_doc->performAddPageAnnotation( m_pageNumber, m_annotation ); + moveViewportIfBoundingRectNotFullyVisible( m_annotation->boundingRectangle(), m_docPriv, m_pageNumber ); + m_docPriv->performAddPageAnnotation( m_pageNumber, m_annotation ); m_done = false; } void RemoveAnnotationCommand::redo(){ - m_doc->performRemovePageAnnotation( m_pageNumber, m_annotation ); + moveViewportIfBoundingRectNotFullyVisible( m_annotation->boundingRectangle(), m_docPriv, m_pageNumber ); + m_docPriv->performRemovePageAnnotation( m_pageNumber, m_annotation ); m_done = true; } @@ -93,12 +135,14 @@ ModifyAnnotationPropertiesCommand::ModifyAnnotationPropertiesCommand( DocumentPr void ModifyAnnotationPropertiesCommand::undo() { + moveViewportIfBoundingRectNotFullyVisible( m_annotation->boundingRectangle(), m_docPriv, m_pageNumber ); m_annotation->setAnnotationProperties( m_prevProperties ); m_docPriv->performModifyPageAnnotation( m_pageNumber, m_annotation, true ); } void ModifyAnnotationPropertiesCommand::redo() { + moveViewportIfBoundingRectNotFullyVisible( m_annotation->boundingRectangle(), m_docPriv, m_pageNumber ); m_annotation->setAnnotationProperties( m_newProperties ); m_docPriv->performModifyPageAnnotation( m_pageNumber, m_annotation, true ); } @@ -119,12 +163,14 @@ TranslateAnnotationCommand::TranslateAnnotationCommand( DocumentPrivate* docPriv void TranslateAnnotationCommand::undo() { + moveViewportIfBoundingRectNotFullyVisible(translateBoundingRectangle( minusDelta() ), m_docPriv, m_pageNumber ); m_annotation->translate( minusDelta() ); m_docPriv->performModifyPageAnnotation( m_pageNumber, m_annotation, true ); } void TranslateAnnotationCommand::redo() { + moveViewportIfBoundingRectNotFullyVisible(translateBoundingRectangle( m_delta ), m_docPriv, m_pageNumber ); m_annotation->translate( m_delta ); m_docPriv->performModifyPageAnnotation( m_pageNumber, m_annotation, true ); } @@ -155,6 +201,16 @@ Okular::NormalizedPoint TranslateAnnotationCommand::minusDelta() return Okular::NormalizedPoint( -m_delta.x, -m_delta.y ); } +Okular::NormalizedRect TranslateAnnotationCommand::translateBoundingRectangle( const Okular::NormalizedPoint & delta ) +{ + Okular::NormalizedRect annotBoundingRect = m_annotation->boundingRectangle(); + double left = qMin( annotBoundingRect.left, annotBoundingRect.left + delta.x ); + double right = qMax( annotBoundingRect.right, annotBoundingRect.right + delta.x ); + double top = qMin( annotBoundingRect.top, annotBoundingRect.top + delta.y ); + double bottom = qMax( annotBoundingRect.bottom, annotBoundingRect.bottom + delta.y ); + Okular::NormalizedRect boundingRect( left, top, right, bottom ); + return boundingRect; +} EditTextCommand::EditTextCommand( const QString & newContents, int newCursorPos, @@ -260,12 +316,14 @@ EditAnnotationContentsCommand::EditAnnotationContentsCommand( DocumentPrivate* d void EditAnnotationContentsCommand::undo() { + moveViewportIfBoundingRectNotFullyVisible( m_annotation->boundingRectangle(), m_docPriv, m_pageNumber ); m_docPriv->performSetAnnotationContents( m_prevContents, m_annotation, m_pageNumber ); emit m_docPriv->m_parent->annotationContentsChangedByUndoRedo( m_annotation, m_prevContents, m_prevCursorPos, m_prevAnchorPos ); } void EditAnnotationContentsCommand::redo() { + moveViewportIfBoundingRectNotFullyVisible( m_annotation->boundingRectangle(), m_docPriv, m_pageNumber ); m_docPriv->performSetAnnotationContents( m_newContents, m_annotation, m_pageNumber ); emit m_docPriv->m_parent->annotationContentsChangedByUndoRedo( m_annotation, m_newContents, m_newCursorPos, m_newCursorPos ); } @@ -289,7 +347,7 @@ bool EditAnnotationContentsCommand::mergeWith(const QUndoCommand* uc) } } -EditFormTextCommand::EditFormTextCommand( Okular::Document* doc, +EditFormTextCommand::EditFormTextCommand( Okular::DocumentPrivate* docPriv, Okular::FormFieldText* form, int pageNumber, const QString & newContents, @@ -298,7 +356,7 @@ EditFormTextCommand::EditFormTextCommand( Okular::Document* doc, int prevCursorPos, int prevAnchorPos ) : EditTextCommand( newContents, newCursorPos, prevContents, prevCursorPos, prevAnchorPos ), - m_doc ( doc ), + m_docPriv ( docPriv ), m_form( form ), m_pageNumber( pageNumber ) { @@ -307,14 +365,16 @@ EditFormTextCommand::EditFormTextCommand( Okular::Document* doc, void EditFormTextCommand::undo() { + moveViewportIfBoundingRectNotFullyVisible( m_form->rect(), m_docPriv, m_pageNumber ); m_form->setText( m_prevContents ); - m_doc->formTextChangedByUndoRedo( m_pageNumber, m_form, m_prevContents, m_prevCursorPos, m_prevAnchorPos ); + m_docPriv->m_parent->formTextChangedByUndoRedo( m_pageNumber, m_form, m_prevContents, m_prevCursorPos, m_prevAnchorPos ); } void EditFormTextCommand::redo() { + moveViewportIfBoundingRectNotFullyVisible( m_form->rect(), m_docPriv, m_pageNumber ); m_form->setText( m_newContents ); - m_doc->formTextChangedByUndoRedo( m_pageNumber, m_form, m_newContents, m_newCursorPos, m_newCursorPos ); + m_docPriv->m_parent->formTextChangedByUndoRedo( m_pageNumber, m_form, m_newContents, m_newCursorPos, m_newCursorPos ); } int EditFormTextCommand::id() const @@ -336,12 +396,12 @@ bool EditFormTextCommand::mergeWith(const QUndoCommand* uc) } } -EditFormListCommand::EditFormListCommand( Okular::Document* doc, +EditFormListCommand::EditFormListCommand( Okular::DocumentPrivate* docPriv, FormFieldChoice* form, int pageNumber, const QList< int > & newChoices, const QList< int > & prevChoices ) -: m_doc( doc ), +: m_docPriv( docPriv ), m_form( form ), m_pageNumber( pageNumber ), m_newChoices( newChoices ), @@ -352,17 +412,19 @@ EditFormListCommand::EditFormListCommand( Okular::Document* doc, void EditFormListCommand::undo() { + moveViewportIfBoundingRectNotFullyVisible( m_form->rect(), m_docPriv, m_pageNumber ); m_form->setCurrentChoices( m_prevChoices ); - m_doc->formListChangedByUndoRedo( m_pageNumber, m_form, m_prevChoices ); + m_docPriv->m_parent->formListChangedByUndoRedo( m_pageNumber, m_form, m_prevChoices ); } void EditFormListCommand::redo() { + moveViewportIfBoundingRectNotFullyVisible( m_form->rect(), m_docPriv, m_pageNumber ); m_form->setCurrentChoices( m_newChoices ); - m_doc->formListChangedByUndoRedo( m_pageNumber, m_form, m_newChoices ); + m_docPriv->m_parent->formListChangedByUndoRedo( m_pageNumber, m_form, m_newChoices ); } -EditFormComboCommand::EditFormComboCommand( Okular::Document* doc, +EditFormComboCommand::EditFormComboCommand( Okular::DocumentPrivate* docPriv, FormFieldChoice* form, int pageNumber, const QString & newContents, @@ -371,7 +433,7 @@ EditFormComboCommand::EditFormComboCommand( Okular::Document* doc, int prevCursorPos, int prevAnchorPos ) : EditTextCommand( newContents, newCursorPos, prevContents, prevCursorPos, prevAnchorPos ), - m_doc( doc ), + m_docPriv( docPriv ), m_form( form ), m_pageNumber( pageNumber ), m_newIndex( -1 ), @@ -404,7 +466,8 @@ void EditFormComboCommand::undo() { m_form->setEditChoice( m_prevContents ); } - m_doc->formComboChangedByUndoRedo( m_pageNumber, m_form, m_prevContents, m_prevCursorPos, m_prevAnchorPos ); + moveViewportIfBoundingRectNotFullyVisible( m_form->rect(), m_docPriv, m_pageNumber ); + m_docPriv->m_parent->formComboChangedByUndoRedo( m_pageNumber, m_form, m_prevContents, m_prevCursorPos, m_prevAnchorPos ); } void EditFormComboCommand::redo() @@ -417,7 +480,8 @@ void EditFormComboCommand::redo() { m_form->setEditChoice( m_newContents ); } - m_doc->formComboChangedByUndoRedo( m_pageNumber, m_form, m_newContents, m_newCursorPos, m_newCursorPos ); + moveViewportIfBoundingRectNotFullyVisible( m_form->rect(), m_docPriv, m_pageNumber ); + m_docPriv->m_parent->formComboChangedByUndoRedo( m_pageNumber, m_form, m_newContents, m_newCursorPos, m_newCursorPos ); } int EditFormComboCommand::id() const @@ -444,11 +508,11 @@ bool EditFormComboCommand::mergeWith( const QUndoCommand *uc ) } } -EditFormButtonsCommand::EditFormButtonsCommand( Okular::Document* doc, +EditFormButtonsCommand::EditFormButtonsCommand( Okular::DocumentPrivate* docPriv, int pageNumber, const QList< FormFieldButton* > & formButtons, const QList< bool > & newButtonStates ) -: m_doc( doc ), +: m_docPriv( docPriv ), m_pageNumber( pageNumber ), m_formButtons( formButtons ), m_newButtonStates( newButtonStates ), @@ -470,7 +534,10 @@ void EditFormButtonsCommand::undo() if ( checked ) m_formButtons.at( i )->setState( checked ); } - m_doc->formButtonsChangedByUndoRedo( m_pageNumber, m_formButtons ); + + Okular::NormalizedRect boundingRect = buildBoundingRectangleForButtons( m_formButtons ); + moveViewportIfBoundingRectNotFullyVisible( boundingRect, m_docPriv, m_pageNumber ); + m_docPriv->m_parent->formButtonsChangedByUndoRedo( m_pageNumber, m_formButtons ); } void EditFormButtonsCommand::redo() @@ -482,7 +549,10 @@ void EditFormButtonsCommand::redo() if ( checked ) m_formButtons.at( i )->setState( checked ); } - m_doc->formButtonsChangedByUndoRedo( m_pageNumber, m_formButtons ); + + Okular::NormalizedRect boundingRect = buildBoundingRectangleForButtons( m_formButtons ); + moveViewportIfBoundingRectNotFullyVisible( boundingRect, m_docPriv, m_pageNumber ); + m_docPriv->m_parent->formButtonsChangedByUndoRedo( m_pageNumber, m_formButtons ); } void EditFormButtonsCommand::clearFormButtonStates() diff --git a/core/documentcommands_p.h b/core/documentcommands_p.h index fe1c577dd..17394f2a2 100644 --- a/core/documentcommands_p.h +++ b/core/documentcommands_p.h @@ -51,7 +51,7 @@ class RemoveAnnotationCommand : public QUndoCommand virtual void redo(); private: - Okular::DocumentPrivate * m_doc; + Okular::DocumentPrivate * m_docPriv; Okular::Annotation* m_annotation; int m_pageNumber; bool m_done; @@ -90,6 +90,7 @@ class TranslateAnnotationCommand : public QUndoCommand virtual int id() const; virtual bool mergeWith(const QUndoCommand *uc); Okular::NormalizedPoint minusDelta(); + Okular::NormalizedRect translateBoundingRectangle( const Okular::NormalizedPoint & delta ); private: Okular::DocumentPrivate * m_docPriv; @@ -164,7 +165,7 @@ class EditAnnotationContentsCommand : public EditTextCommand class EditFormTextCommand : public EditTextCommand { public: - EditFormTextCommand( Okular::Document* doc, + EditFormTextCommand( Okular::DocumentPrivate* docPriv, Okular::FormFieldText* form, int pageNumber, const QString & newContents, @@ -177,7 +178,7 @@ class EditFormTextCommand : public EditTextCommand virtual int id() const; virtual bool mergeWith( const QUndoCommand *uc ); private: - Okular::Document* m_doc; + Okular::DocumentPrivate* m_docPriv; Okular::FormFieldText* m_form; int m_pageNumber; }; @@ -185,7 +186,7 @@ class EditFormTextCommand : public EditTextCommand class EditFormListCommand : public QUndoCommand { public: - EditFormListCommand( Okular::Document* doc, + EditFormListCommand( Okular::DocumentPrivate* docPriv, FormFieldChoice* form, int pageNumber, const QList< int > & newChoices, @@ -196,7 +197,7 @@ class EditFormListCommand : public QUndoCommand virtual void redo(); private: - Okular::Document* m_doc; + Okular::DocumentPrivate* m_docPriv; FormFieldChoice* m_form; int m_pageNumber; QList< int > m_newChoices; @@ -206,7 +207,7 @@ class EditFormListCommand : public QUndoCommand class EditFormComboCommand : public EditTextCommand { public: - EditFormComboCommand( Okular::Document* doc, + EditFormComboCommand( Okular::DocumentPrivate* docPriv, FormFieldChoice* form, int pageNumber, const QString & newText, @@ -222,7 +223,7 @@ class EditFormComboCommand : public EditTextCommand virtual bool mergeWith( const QUndoCommand *uc ); private: - Okular::Document* m_doc; + Okular::DocumentPrivate* m_docPriv; FormFieldChoice* m_form; int m_pageNumber; int m_newIndex; @@ -232,7 +233,7 @@ class EditFormComboCommand : public EditTextCommand class EditFormButtonsCommand : public QUndoCommand { public: - EditFormButtonsCommand( Okular::Document* doc, + EditFormButtonsCommand( Okular::DocumentPrivate* docPriv, int pageNumber, const QList< FormFieldButton* > & formButtons, const QList< bool > & newButtonStates @@ -245,7 +246,7 @@ class EditFormButtonsCommand : public QUndoCommand void clearFormButtonStates(); private: - Okular::Document* m_doc; + Okular::DocumentPrivate* m_docPriv; int m_pageNumber; QList< FormFieldButton* > m_formButtons; QList< bool > m_newButtonStates; diff --git a/core/page.cpp b/core/page.cpp index 0bafa997e..e19452323 100644 --- a/core/page.cpp +++ b/core/page.cpp @@ -40,6 +40,7 @@ #include "textpage_p.h" #include "tile.h" #include "tilesmanager_p.h" +#include "utils_p.h" #include @@ -118,24 +119,7 @@ void PagePrivate::imageRotationDone( RotationJob * job ) QTransform PagePrivate::rotationMatrix() const { - QTransform matrix; - matrix.rotate( (int)m_rotation * 90 ); - - switch ( m_rotation ) - { - case Rotation90: - matrix.translate( 0, -1 ); - break; - case Rotation180: - matrix.translate( -1, -1 ); - break; - case Rotation270: - matrix.translate( -1, 0 ); - break; - default: ; - } - - return matrix; + return Okular::buildRotationMatrix( m_rotation ); } /** class Page **/ diff --git a/core/utils.cpp b/core/utils.cpp index 5dd84484f..08923cf77 100644 --- a/core/utils.cpp +++ b/core/utils.cpp @@ -259,3 +259,25 @@ void Okular::copyQIODevice( QIODevice *from, QIODevice *to ) break; } } + +QTransform Okular::buildRotationMatrix(Rotation rotation) +{ + QTransform matrix; + matrix.rotate( (int)rotation * 90 ); + + switch ( rotation ) + { + case Rotation90: + matrix.translate( 0, -1 ); + break; + case Rotation180: + matrix.translate( -1, -1 ); + break; + case Rotation270: + matrix.translate( -1, 0 ); + break; + default: ; + } + + return matrix; +} diff --git a/core/utils_p.h b/core/utils_p.h index df82fe1da..3b3f51179 100644 --- a/core/utils_p.h +++ b/core/utils_p.h @@ -17,6 +17,11 @@ namespace Okular void copyQIODevice( QIODevice *from, QIODevice *to ); +/** + * Return a rotation matrix corresponding to the @p rotation enumeration. + */ +QTransform buildRotationMatrix( Rotation rotation ); + } #endif