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