Fix Undo / Redo of annotation creation doesn't properly handle page rotation and adds undo unit tests

BUG: 318091
REVIEW: 109989
This commit is contained in:
Jon Mease 2013-04-13 22:54:47 +02:00 committed by Albert Astals Cid
parent 583fc0d81f
commit 3c6140b616
9 changed files with 1207 additions and 1 deletions

View file

@ -2404,6 +2404,8 @@ void Document::closeDocument()
d->m_documentInfo = 0;
AudioPlayer::instance()->d->m_currentDocument = KUrl();
d->m_undoStack->clear();
}
void Document::addObserver( DocumentObserver * pObserver )
@ -2896,6 +2898,10 @@ void DocumentPrivate::notifyAnnotationChanges( int page )
void Document::addPageAnnotation( int page, Annotation * annotation )
{
// Transform annotation's base boundary rectangle into unrotated coordinates
Page *p = d->m_pagesVector[page];
QTransform t = p->d->rotationMatrix();
annotation->d_ptr->baseTransform(t.inverted());
QUndoCommand *uc = new AddAnnotationCommand(this->d, annotation, page);
d->m_undoStack->push(uc);
}

View file

@ -641,7 +641,6 @@ void Page::addAnnotation( Annotation * annotation )
// Rotate the annotation on the page.
const QTransform matrix = d->rotationMatrix();
annotation->d_ptr->baseTransform( matrix.inverted() );
annotation->d_ptr->annotationTransform( matrix );
m_rects.append( rect );

View file

@ -11,3 +11,15 @@ target_link_libraries( searchtest ${KDE4_KDECORE_LIBS} ${QT_QTGUI_LIBRARY} ${QT_
kde4_add_unit_test( urldetecttest urldetecttest.cpp )
target_link_libraries( urldetecttest ${KDE4_KDECORE_LIBS} ${QT_QTTEST_LIBRARY} )
kde4_add_unit_test( editannotationcontentstest editannotationcontentstest.cpp testingutils.cpp)
target_link_libraries( editannotationcontentstest ${KDE4_KDECORE_LIBS} ${QT_QTGUI_LIBRARY} ${QT_QTTEST_LIBRARY} ${QT_QTXML_LIBRARY} okularcore )
kde4_add_unit_test( addremoveannotationtest addremoveannotationtest.cpp testingutils.cpp)
target_link_libraries( addremoveannotationtest ${KDE4_KDECORE_LIBS} ${QT_QTGUI_LIBRARY} ${QT_QTTEST_LIBRARY} ${QT_QTXML_LIBRARY} okularcore )
kde4_add_unit_test( translateannotationtest translateannotationtest.cpp testingutils.cpp)
target_link_libraries( translateannotationtest ${KDE4_KDECORE_LIBS} ${QT_QTGUI_LIBRARY} ${QT_QTTEST_LIBRARY} ${QT_QTXML_LIBRARY} okularcore )
kde4_add_unit_test( modifyannotationpropertiestest modifyannotationpropertiestest.cpp testingutils.cpp)
target_link_libraries( modifyannotationpropertiestest ${KDE4_KDECORE_LIBS} ${QT_QTGUI_LIBRARY} ${QT_QTTEST_LIBRARY} ${QT_QTXML_LIBRARY} okularcore )

View file

@ -0,0 +1,190 @@
/***************************************************************************
* Copyright (C) 2013 by Jon Mease <jon.mease@gmail.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
***************************************************************************/
#include <qtest_kde.h>
#include "../core/document.h"
#include "../core/page.h"
#include "../core/annotations.h"
#include "../settings_core.h"
#include "testingutils.h"
class AddRemoveAnnotationTest : public QObject
{
Q_OBJECT
private slots:
void initTestCase();
void init();
void cleanup();
void testAddAnnotations();
void testAddAnnotationUndoWithRotate_Bug318091();
void testRemoveAnnotations();
private:
Okular::Document *m_document;
};
void AddRemoveAnnotationTest::initTestCase()
{
Okular::SettingsCore::instance( "addannotationtest" );
m_document = new Okular::Document( 0 );
}
void AddRemoveAnnotationTest::init()
{
const QString testFile = KDESRCDIR "data/file1.pdf";
const KMimeType::Ptr mime = KMimeType::findByPath( testFile );
m_document->openDocument(testFile, KUrl(), mime);
}
void AddRemoveAnnotationTest::cleanup()
{
m_document->closeDocument();
}
void AddRemoveAnnotationTest::testAddAnnotations()
{
// Undo and Redo should be unavailable when docuemnt is first opened.
QVERIFY( !m_document->canUndo() );
QVERIFY( !m_document->canRedo() );
// Create two distinct text annotations
Okular::Annotation *annot1 = new Okular::TextAnnotation();
annot1->setBoundingRectangle( Okular::NormalizedRect( 0.1, 0.1, 0.15, 0.15 ) );
annot1->setContents( "annot contents" );
Okular::Annotation *annot2 = new Okular::TextAnnotation();
annot2->setBoundingRectangle( Okular::NormalizedRect( 0.2, 0.2, 0.3, 0.4 ) );
annot2->setContents( "annot contents" );
// The two annotations shold have different properties XML strings
QVERIFY( TestingUtils::getAnnotationXml( annot1 ) != TestingUtils::getAnnotationXml( annot2 ) );
// We start with no annotations in the docuemnt
QVERIFY( m_document->page( 0 )->annotations().size() == 0 );
// After adding annot1 we should have one annotation in the page and it should be annot1.
m_document->addPageAnnotation( 0, annot1 );
QVERIFY( m_document->page( 0 )->annotations().size() == 1 );
QCOMPARE( annot1, m_document->page( 0 )->annotations().first() );
// Record the properties and name of annot1 just after insertion for later comparisons
QString origLine1Xml = TestingUtils::getAnnotationXml( annot1 );
QString annot1Name = annot1->uniqueName();
QVERIFY( !annot1Name.isEmpty() );
// Now undo the addition of annot1 and verify that annot1's properties haven't changed
m_document->undo();
QVERIFY( m_document->page( 0 )->annotations().empty() );
QVERIFY( !m_document->canUndo() );
QVERIFY( m_document->canRedo() );
QCOMPARE( TestingUtils::getAnnotationXml( annot1 ), origLine1Xml );
// redo addition of annot1
m_document->redo();
QVERIFY( m_document->page( 0 )->annotations().size() == 1 );
QVERIFY( annot1 == m_document->page( 0 )->annotations().first() );
QCOMPARE( TestingUtils::getAnnotationXml( annot1 ), origLine1Xml );
// undo once more
m_document->undo();
QVERIFY( m_document->page( 0 )->annotations().empty() );
QVERIFY( !m_document->canUndo() );
QVERIFY( m_document->canRedo() );
QCOMPARE( TestingUtils::getAnnotationXml( annot1 ), origLine1Xml );
// Set AnnotationDisposeWatcher dispose function on annot1 so we can detect
// when it is deleted
annot1->setDisposeDataFunction( TestingUtils::AnnotationDisposeWatcher::disposeAnnotation );
TestingUtils::AnnotationDisposeWatcher::resetDisposedAnnotationName();
QCOMPARE( TestingUtils::AnnotationDisposeWatcher::disposedAnnotationName(), QString() );
// now add annot2
m_document->addPageAnnotation( 0, annot2 );
QString annot2Name = annot2->uniqueName();
QVERIFY( !annot2Name.isEmpty() );
QVERIFY( annot1Name != annot2Name );
QVERIFY( m_document->page( 0 )->annotations().size() == 1 );
QCOMPARE( annot2, m_document->page( 0 )->annotations().first() );
// Check that adding annot2 while annot1 was in the unadded state triggered the deletion of annot1
QVERIFY( TestingUtils::AnnotationDisposeWatcher::disposedAnnotationName() == annot1Name );
}
void AddRemoveAnnotationTest::testAddAnnotationUndoWithRotate_Bug318091()
{
Okular::Annotation *annot = new Okular::TextAnnotation();
annot->setBoundingRectangle( Okular::NormalizedRect( 0.1, 0.1, 0.15, 0.15 ) );
annot->setContents( "annot contents" );
m_document->addPageAnnotation( 0, annot );
QString origAnnotXml = TestingUtils::getAnnotationXml( annot );
// Now undo annotation addition, rotate the page, and redo to annotation addition
m_document->undo();
m_document->setRotation( 1 );
m_document->redo();
// Verify that annotation's properties remain unchanged
// In Bug318091 the bounding rectangle was being rotated upon each redo
QString newAnnotXml = TestingUtils::getAnnotationXml( annot );
QCOMPARE( origAnnotXml, newAnnotXml );
}
void AddRemoveAnnotationTest::testRemoveAnnotations()
{
// Undo and Redo should be unavailable when docuemnt is first opened.
QVERIFY( !m_document->canUndo() );
QVERIFY( !m_document->canRedo() );
// Create two distinct text annotations
Okular::Annotation *annot1 = new Okular::TextAnnotation();
annot1->setBoundingRectangle( Okular::NormalizedRect( 0.1, 0.1, 0.15, 0.15 ) );
annot1->setContents( "annot contents" );
Okular::Annotation *annot2 = new Okular::TextAnnotation();
annot2->setBoundingRectangle( Okular::NormalizedRect( 0.2, 0.2, 0.3, 0.4 ) );
annot2->setContents( "annot contents" );
// Add annot1 and annot2 to document
m_document->addPageAnnotation( 0, annot1 );
m_document->addPageAnnotation( 0, annot2 );
QVERIFY( m_document->page( 0 )->annotations().size() == 2 );
QVERIFY( m_document->page( 0 )->annotations().contains(annot1) );
QVERIFY( m_document->page( 0 )->annotations().contains(annot2) );
// Now remove annot1
m_document->removePageAnnotation( 0, annot1 );
QVERIFY( m_document->page( 0 )->annotations().size() == 1 );
QVERIFY( m_document->page( 0 )->annotations().contains(annot2) );
// Undo removal of annot1
m_document->undo();
QVERIFY( m_document->page( 0 )->annotations().size() == 2 );
QVERIFY( m_document->page( 0 )->annotations().contains(annot1) );
QVERIFY( m_document->page( 0 )->annotations().contains(annot2) );
// Redo removal
m_document->redo();
QVERIFY( m_document->page( 0 )->annotations().size() == 1 );
QVERIFY( m_document->page( 0 )->annotations().contains(annot2) );
// Verify that annot1 is disposed of if document is closed with annot1 in removed state
QString annot1Name = annot1->uniqueName();
annot1->setDisposeDataFunction( TestingUtils::AnnotationDisposeWatcher::disposeAnnotation );
TestingUtils::AnnotationDisposeWatcher::resetDisposedAnnotationName();
QVERIFY( TestingUtils::AnnotationDisposeWatcher::disposedAnnotationName() == QString() );
m_document->closeDocument();
QVERIFY( TestingUtils::AnnotationDisposeWatcher::disposedAnnotationName() == annot1Name );
}
QTEST_KDEMAIN( AddRemoveAnnotationTest, GUI )
#include "addremoveannotationtest.moc"

View file

@ -0,0 +1,519 @@
/***************************************************************************
* Copyright (C) 2013 by Jon Mease <jon.mease@gmail.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
***************************************************************************/
#include <qtest_kde.h>
#include <kmimetype.h>
#include "../settings_core.h"
#include "core/annotations.h"
#include "core/document.h"
class MockEditor;
class EditAnnotationContentsTest : public QObject
{
Q_OBJECT
private slots:
void initTestCase();
void cleanupTestCase();
void init();
void cleanup();
void testConsecutiveCharBackspacesMerged();
void testConsecutiveNewlineBackspacesNotMerged();
void testConsecutiveCharInsertionsMerged();
void testConsecutiveNewlineInsertionsNotMerged();
void testConsecutiveCharDeletesMerged();
void testConsecutiveNewlineDeletesNotMerged();
void testConsecutiveEditsNotMergedAcrossDifferentAnnotations();
void testInsertWithSelection();
void testCombinations();
private:
Okular::Document *m_document;
Okular::TextAnnotation *m_annot1;
Okular::TextAnnotation *m_annot2;
MockEditor *m_editor1;
MockEditor *m_editor2;
};
/*
* Simple class that receives the Document::annotationContentsChangedByUndoRedo
* signal that would normally be directed to an annotation's
* contents editor (For example AnnotWindow)
*/
class MockEditor: public QObject
{
Q_OBJECT
public:
MockEditor( Okular::Annotation *annot, Okular::Document *doc);
QString contents() { return m_contents; }
int cursorPos() { return m_cursorPos; }
int anchorPos() { return m_anchorPos; }
private slots:
void slotAnnotationContentsChangedByUndoRedo( Okular::Annotation* annotation, const QString & contents, int cursorPos, int anchorPos );
private:
Okular::Document *m_document;
Okular::Annotation *m_annot;
QString m_contents;
int m_cursorPos;
int m_anchorPos;
};
MockEditor::MockEditor( Okular::Annotation *annot, Okular::Document *doc )
{
m_annot = annot;
m_document = doc;
connect( m_document, SIGNAL(annotationContentsChangedByUndoRedo(Okular::Annotation*,QString,int,int)),
this, SLOT(slotAnnotationContentsChangedByUndoRedo(Okular::Annotation*,QString,int,int)));
m_cursorPos = 0;
m_anchorPos = 0;
m_contents = annot->contents();
}
void MockEditor::slotAnnotationContentsChangedByUndoRedo(Okular::Annotation* annotation, const QString& contents, int cursorPos, int anchorPos)
{
if( annotation == m_annot )
{
m_contents = contents;
m_cursorPos = cursorPos;
m_anchorPos = anchorPos;
}
}
void EditAnnotationContentsTest::initTestCase()
{
Okular::SettingsCore::instance( "editannotationcontentstest" );
m_document = new Okular::Document( 0 );
}
void EditAnnotationContentsTest::cleanupTestCase()
{
delete m_document;
}
void EditAnnotationContentsTest::init()
{
const QString testFile = KDESRCDIR "data/file1.pdf";
const KMimeType::Ptr mime = KMimeType::findByPath( testFile );
m_document->openDocument(testFile, KUrl(), mime);
// Undo and Redo should be unavailable when docuemnt is first opened.
QVERIFY( !m_document->canUndo() );
QVERIFY( !m_document->canRedo() );
// Create two distinct text annotations
m_annot1 = new Okular::TextAnnotation();
m_annot1->setBoundingRectangle( Okular::NormalizedRect( 0.1, 0.1, 0.15, 0.15 ) );
m_annot1->setContents( QString( "Hello, World" ) );
m_document->addPageAnnotation( 0, m_annot1 );
m_annot2 = new Okular::TextAnnotation();
m_annot2->setBoundingRectangle( Okular::NormalizedRect( 0.1, 0.1, 0.15, 0.15 ) );
m_annot2->setContents( QString( "Hello, World" ) );
m_document->addPageAnnotation( 0, m_annot2 );
// setup editors
m_editor1 = new MockEditor( m_annot1, m_document );
m_editor2 = new MockEditor( m_annot2, m_document );
}
void EditAnnotationContentsTest::cleanup()
{
m_document->closeDocument();
delete m_editor1;
delete m_editor2;
// m_annot1 and m_annot2 are deleted when document is closed
}
void EditAnnotationContentsTest::testConsecutiveCharBackspacesMerged()
{
// Hello, World| -> Hello, Worl|
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Hello, Worl" ), 11, 12, 12 );
QCOMPARE( QString( "Hello, Worl" ), m_annot1->contents() );
// Hello, Worl| -> Hello, Wor|
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Hello, Wor" ), 10, 11, 11 );
QCOMPARE( QString( "Hello, Wor" ), m_annot1->contents() );
// undo and verify that consecutive backspace operations are merged together
m_document->undo();
QCOMPARE( QString( "Hello, World" ), m_annot1->contents() );
QCOMPARE( QString( "Hello, World" ), m_editor1->contents() );
QCOMPARE( 12, m_editor1->cursorPos() );
QCOMPARE( 12, m_editor1->anchorPos() );
m_document->redo();
QCOMPARE( QString( "Hello, Wor" ), m_annot1->contents() );
QCOMPARE( QString( "Hello, Wor" ), m_editor1->contents() );
QCOMPARE( 10, m_editor1->cursorPos() );
QCOMPARE( 10, m_editor1->anchorPos() );
// Hello, Wor| -> Hello, Wo|
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Hello, Wo" ), 9, 10, 10 );
QCOMPARE( QString( "Hello, Wo" ), m_annot1->contents() );
// Hello, Wo| -> Hello, W|
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Hello, W" ), 8, 9, 9 );
QCOMPARE( QString( "Hello, W" ), m_annot1->contents() );
// Hello, W| -> Hello, |
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Hello, " ), 7, 8, 8 );
QCOMPARE( QString( "Hello, " ), m_annot1->contents() );
// undo and verify that consecutive backspace operations are merged together
m_document->undo();
QCOMPARE( QString( "Hello, World" ), m_annot1->contents() );
QCOMPARE( QString( "Hello, World" ), m_editor1->contents() );
QCOMPARE( 12, m_editor1->cursorPos() );
QCOMPARE( 12, m_editor1->anchorPos() );
m_document->redo();
QCOMPARE( QString( "Hello, " ), m_annot1->contents() );
QCOMPARE( QString( "Hello, " ), m_editor1->contents() );
QCOMPARE( 7, m_editor1->cursorPos() );
QCOMPARE( 7, m_editor1->anchorPos() );
}
void EditAnnotationContentsTest::testConsecutiveNewlineBackspacesNotMerged()
{
// Set contents to Hello, \n\n|World
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Hello, \n\nWorld" ), 0, 0, 0 );
QCOMPARE( QString( "Hello, \n\nWorld" ), m_annot1->contents() );
// Hello, \n\n|World -> Hello, \n|World
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Hello, \nWorld" ), 8, 9, 9 );
QCOMPARE( QString( "Hello, \nWorld" ), m_annot1->contents() );
// Hello, \n|World -> Hello, |World
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Hello, World" ), 7, 8, 8 );
QCOMPARE( QString( "Hello, World" ), m_annot1->contents() );
// Hello, |World -> Hello,|World
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Hello,World" ), 6, 7, 7 );
QCOMPARE( QString( "Hello,World" ), m_annot1->contents() );
// Hello,|World -> Hello|World
m_document->editPageAnnotationContents( 0, m_annot1, QString( "HelloWorld" ), 5, 6, 6 );
QCOMPARE( QString( "HelloWorld" ), m_annot1->contents() );
// Backspace operations of non-newline characters should be merged
m_document->undo();
QCOMPARE( QString( "Hello, World" ), m_annot1->contents() );
QCOMPARE( QString( "Hello, World" ), m_editor1->contents() );
QCOMPARE( 7, m_editor1->cursorPos() );
QCOMPARE( 7, m_editor1->anchorPos() );
// Backspace operations on newline characters should not be merged
m_document->undo();
QCOMPARE( QString( "Hello, \nWorld" ), m_annot1->contents() );
QCOMPARE( QString( "Hello, \nWorld" ), m_editor1->contents() );
QCOMPARE( 8, m_editor1->cursorPos() );
QCOMPARE( 8, m_editor1->anchorPos() );
m_document->undo();
QCOMPARE( QString( "Hello, \n\nWorld" ), m_annot1->contents() );
QCOMPARE( QString( "Hello, \n\nWorld" ), m_editor1->contents() );
QCOMPARE( 9, m_editor1->cursorPos() );
QCOMPARE( 9, m_editor1->anchorPos() );
}
void EditAnnotationContentsTest::testConsecutiveCharInsertionsMerged()
{
// Hello, |World -> Hello, B|World
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Hello, BWorld" ), 8, 7, 7 );
QCOMPARE( QString( "Hello, BWorld" ), m_annot1->contents() );
// Hello, l| -> Hello, li|
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Hello, BiWorld" ), 9, 8, 8 );
QCOMPARE( QString( "Hello, BiWorld" ), m_annot1->contents() );
// Hello, li| -> Hello, lin|
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Hello, BigWorld" ), 10, 9, 9 );
QCOMPARE( QString( "Hello, BigWorld" ), m_annot1->contents() );
// Hello, lin| -> Hello, line|
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Hello, Big World" ), 11, 10, 10 );
QCOMPARE( QString( "Hello, Big World" ), m_annot1->contents() );
// Verify undo/redo operations merged
m_document->undo();
QCOMPARE( QString( "Hello, World" ), m_annot1->contents() );
QCOMPARE( QString( "Hello, World" ), m_editor1->contents() );
QCOMPARE( 7, m_editor1->cursorPos() );
QCOMPARE( 7, m_editor1->anchorPos() );
m_document->redo();
QCOMPARE( QString( "Hello, Big World" ), m_annot1->contents() );
QCOMPARE( QString( "Hello, Big World" ), m_editor1->contents() );
QCOMPARE( 11, m_editor1->cursorPos() );
QCOMPARE( 11, m_editor1->anchorPos() );
}
void EditAnnotationContentsTest::testConsecutiveNewlineInsertionsNotMerged()
{
// Hello, |World -> Hello, \n|World
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Hello, \nWorld" ), 8, 7, 7 );
QCOMPARE( QString( "Hello, \nWorld" ), m_annot1->contents() );
// Hello, |World -> Hello, \n|World
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Hello, \n\nWorld" ), 9, 8, 8 );
QCOMPARE( QString( "Hello, \n\nWorld" ), m_annot1->contents() );
m_document->undo();
QCOMPARE( QString( "Hello, \nWorld" ), m_annot1->contents() );
QCOMPARE( QString( "Hello, \nWorld" ), m_editor1->contents() );
QCOMPARE( 8, m_editor1->cursorPos() );
QCOMPARE( 8, m_editor1->anchorPos() );
m_document->undo();
QCOMPARE( QString( "Hello, World" ), m_annot1->contents() );
QCOMPARE( QString( "Hello, World" ), m_editor1->contents() );
QCOMPARE( 7, m_editor1->cursorPos() );
QCOMPARE( 7, m_editor1->anchorPos() );
m_document->redo();
QCOMPARE( QString( "Hello, \nWorld" ), m_annot1->contents() );
QCOMPARE( QString( "Hello, \nWorld" ), m_editor1->contents() );
QCOMPARE( 8, m_editor1->cursorPos() );
QCOMPARE( 8, m_editor1->anchorPos() );
m_document->redo();
QCOMPARE( QString( "Hello, \n\nWorld" ), m_annot1->contents() );
QCOMPARE( QString( "Hello, \n\nWorld" ), m_editor1->contents() );
QCOMPARE( 9, m_editor1->cursorPos() );
QCOMPARE( 9, m_editor1->anchorPos() );
}
void EditAnnotationContentsTest::testConsecutiveCharDeletesMerged()
{
// Hello, |World -> Hello, |orld
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Hello, orld" ), 7, 7, 7 );
QCOMPARE( QString( "Hello, orld" ), m_annot1->contents() );
// Hello, |orld -> Hello, |rld
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Hello, rld" ), 7, 7, 7 );
QCOMPARE( QString( "Hello, rld" ), m_annot1->contents() );
// Hello, |rld -> Hello, |ld
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Hello, ld" ), 7, 7, 7 );
QCOMPARE( QString( "Hello, ld" ), m_annot1->contents() );
// Hello, |ld -> Hello, |d
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Hello, d" ), 7, 7, 7 );
QCOMPARE( QString( "Hello, d" ), m_annot1->contents() );
// Hello, | -> Hello, |
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Hello, " ), 7, 7, 7 );
QCOMPARE( QString( "Hello, " ), m_annot1->contents() );
// Verify undo/redo operations merged
m_document->undo();
QCOMPARE( QString( "Hello, World" ), m_annot1->contents() );
QCOMPARE( QString( "Hello, World" ), m_editor1->contents() );
QCOMPARE( 7, m_editor1->cursorPos() );
QCOMPARE( 7, m_editor1->anchorPos() );
m_document->redo();
QCOMPARE( QString( "Hello, " ), m_annot1->contents() );
QCOMPARE( QString( "Hello, " ), m_editor1->contents() );
QCOMPARE( 7, m_editor1->cursorPos() );
QCOMPARE( 7, m_editor1->anchorPos() );
}
void EditAnnotationContentsTest::testConsecutiveNewlineDeletesNotMerged()
{
// Set contents to Hello, \n\n|World
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Hello, \n\nWorld" ), 0, 0, 0 );
QCOMPARE( QString( "Hello, \n\nWorld" ), m_annot1->contents() );
// He|llo, \n\nWorld -> He|lo, \n\nWorld
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Helo, \n\nWorld" ), 2, 2, 2 );
QCOMPARE( QString( "Helo, \n\nWorld" ), m_annot1->contents() );
// He|lo, \n\nWorld -> He|o, \n\nWorld
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Heo, \n\nWorld" ), 2, 2, 2 );
QCOMPARE( QString( "Heo, \n\nWorld" ), m_annot1->contents() );
// He|o, \n\nWorld -> He|, \n\nWorld
m_document->editPageAnnotationContents( 0, m_annot1, QString( "He, \n\nWorld" ), 2, 2, 2 );
QCOMPARE( QString( "He, \n\nWorld" ), m_annot1->contents() );
// He|, \n\nWorld -> He| \n\nWorld
m_document->editPageAnnotationContents( 0, m_annot1, QString( "He \n\nWorld" ), 2, 2, 2 );
QCOMPARE( QString( "He \n\nWorld" ), m_annot1->contents() );
// He| \n\nWorld -> He|\n\nWorld
m_document->editPageAnnotationContents( 0, m_annot1, QString( "He\n\nWorld" ), 2, 2, 2 );
QCOMPARE( QString( "He\n\nWorld" ), m_annot1->contents() );
// He|\n\nWorld -> He|\nWorld
m_document->editPageAnnotationContents( 0, m_annot1, QString( "He\nWorld" ), 2, 2, 2 );
QCOMPARE( QString( "He\nWorld" ), m_annot1->contents() );
// He|\nWorld -> He|World
m_document->editPageAnnotationContents( 0, m_annot1, QString( "HeWorld" ), 2, 2, 2 );
QCOMPARE( QString( "HeWorld" ), m_annot1->contents() );
// Verify that deletions of newlines are not merged, but deletions of other characters are
m_document->undo();
QCOMPARE( QString( "He\nWorld" ), m_annot1->contents() );
QCOMPARE( QString( "He\nWorld" ), m_editor1->contents() );
QCOMPARE( 2, m_editor1->cursorPos() );
QCOMPARE( 2, m_editor1->anchorPos() );
m_document->undo();
QCOMPARE( QString( "He\n\nWorld" ), m_annot1->contents() );
QCOMPARE( QString( "He\n\nWorld" ), m_editor1->contents() );
QCOMPARE( 2, m_editor1->cursorPos() );
QCOMPARE( 2, m_editor1->anchorPos() );
m_document->undo();
QCOMPARE( QString( "Hello, \n\nWorld" ), m_annot1->contents() );
QCOMPARE( QString( "Hello, \n\nWorld" ), m_editor1->contents() );
QCOMPARE( 2, m_editor1->cursorPos() );
QCOMPARE( 2, m_editor1->anchorPos() );
}
void EditAnnotationContentsTest::testConsecutiveEditsNotMergedAcrossDifferentAnnotations()
{
// Annot1: Hello, World| -> Hello, Worl|
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Hello, Worl" ), 11, 12, 12 );
QCOMPARE( QString( "Hello, Worl" ), m_annot1->contents() );
// Annot1: Hello, Worl| -> Hello, Wor|
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Hello, Wor" ), 10, 11, 11 );
QCOMPARE( QString( "Hello, Wor" ), m_annot1->contents() );
// Annot2: Hello, World| -> Hello, Worl|
m_document->editPageAnnotationContents( 0, m_annot2, QString( "Hello, Worl" ), 11, 12, 12 );
QCOMPARE( QString( "Hello, Worl" ), m_annot2->contents() );
// Annot2: Hello, Worl| -> Hello, Wor|
m_document->editPageAnnotationContents( 0, m_annot2, QString( "Hello, Wor" ), 10, 11, 11 );
QCOMPARE( QString( "Hello, Wor" ), m_annot2->contents() );
// Annot1: Hello, Wor| -> Hello, Wo|
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Hello, Wo" ), 9, 10, 10 );
QCOMPARE( QString( "Hello, Wo" ), m_annot1->contents() );
// Annot1: Hello, Wo| -> Hello, W|
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Hello, W" ), 8, 9, 9 );
QCOMPARE( QString( "Hello, W" ), m_annot1->contents() );
// Annot1: Hello, W| -> Hello, |
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Hello, " ), 7, 8, 8 );
QCOMPARE( QString( "Hello, " ), m_annot1->contents() );
// Annot2: Hello, Wor| -> Hello, Wo|
m_document->editPageAnnotationContents( 0, m_annot2, QString( "Hello, Wo" ), 9, 10, 10 );
QCOMPARE( QString( "Hello, Wo" ), m_annot2->contents() );
// Annot2: Hello, Wo| -> Hello, W|
m_document->editPageAnnotationContents( 0, m_annot2, QString( "Hello, W" ), 8, 9, 9 );
QCOMPARE( QString( "Hello, W" ), m_annot2->contents() );
// Annot2: Hello, W| -> Hello, |
m_document->editPageAnnotationContents( 0, m_annot2, QString( "Hello, " ), 7, 8, 8 );
QCOMPARE( QString( "Hello, " ), m_annot2->contents() );
// undo and verify that consecutive backspace operations are merged together
// m_annot2 -> "Hello, Wor|"
m_document->undo();
QCOMPARE( QString( "Hello, Wor" ), m_annot2->contents() );
QCOMPARE( QString( "Hello, " ), m_editor1->contents() );
QCOMPARE( QString( "Hello, Wor" ), m_editor2->contents() );
QCOMPARE( 10, m_editor2->cursorPos() );
QCOMPARE( 10, m_editor2->anchorPos() );
// m_annot1 -> "Hello, Wor|"
m_document->undo();
QCOMPARE( QString( "Hello, Wor" ), m_annot1->contents() );
QCOMPARE( QString( "Hello, Wor" ), m_editor1->contents() );
QCOMPARE( QString( "Hello, Wor" ), m_editor2->contents() );
QCOMPARE( 10, m_editor1->cursorPos() );
QCOMPARE( 10, m_editor1->anchorPos() );
// m_annot2 -> "Hello, World|"
m_document->undo();
QCOMPARE( QString( "Hello, World" ), m_annot2->contents() );
QCOMPARE( QString( "Hello, Wor" ), m_editor1->contents() );
QCOMPARE( QString( "Hello, World" ), m_editor2->contents() );
QCOMPARE( 12, m_editor2->cursorPos() );
QCOMPARE( 12, m_editor2->anchorPos() );
// m_annot1 -> "Hello, World|"
m_document->undo();
QCOMPARE( QString( "Hello, World" ), m_annot1->contents() );
QCOMPARE( QString( "Hello, World" ), m_editor1->contents() );
QCOMPARE( QString( "Hello, World" ), m_editor2->contents() );
QCOMPARE( 12, m_editor1->cursorPos() );
QCOMPARE( 12, m_editor1->anchorPos() );
}
void EditAnnotationContentsTest::testInsertWithSelection()
{
// Annot1: |Hello|, World -> H|, World
m_document->editPageAnnotationContents( 0, m_annot1, QString( "H, World" ), 1, 0, 5 );
QCOMPARE( QString( "H, World" ), m_annot1->contents() );
// Annot1: H|, World -> Hi|, World
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Hi, World" ), 2, 1, 1 );
QCOMPARE( QString( "Hi, World" ), m_annot1->contents() );
m_document->undo();
QCOMPARE( QString( "H, World" ), m_annot1->contents() );
QCOMPARE( QString( "H, World" ), m_editor1->contents() );
QCOMPARE( 1, m_editor1->cursorPos() );
QCOMPARE( 1, m_editor1->anchorPos() );
m_document->undo();
QCOMPARE( QString( "Hello, World" ), m_annot1->contents() );
QCOMPARE( QString( "Hello, World" ), m_editor1->contents() );
QCOMPARE( 0, m_editor1->cursorPos() );
QCOMPARE( 5, m_editor1->anchorPos() );
}
void EditAnnotationContentsTest::testCombinations()
{
// Annot1: Hello, World| -> Hello, Worl|
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Hello, Worl" ), 11, 12, 12 );
QCOMPARE( QString( "Hello, Worl" ), m_annot1->contents() );
// Annot1: Hello, Worl| -> Hello, Wor|
m_document->editPageAnnotationContents( 0, m_annot1, QString( "Hello, Wor" ), 10, 11, 11 );
QCOMPARE( QString( "Hello, Wor" ), m_annot1->contents() );
// Annot1: |He|llo, Wor -> |llo, Wor
m_document->editPageAnnotationContents( 0, m_annot1, QString( "llo, Wor" ), 0, 2, 0 );
QCOMPARE( QString( "llo, Wor" ), m_annot1->contents() );
// Annot1: |llo, Wor -> |lo, Wor
m_document->editPageAnnotationContents( 0, m_annot1, QString( "lo, Wor" ), 0, 0, 0 );
QCOMPARE( QString( "lo, Wor" ), m_annot1->contents() );
m_document->undo();
QCOMPARE( QString( "llo, Wor" ), m_annot1->contents() );
QCOMPARE( QString( "llo, Wor" ), m_editor1->contents() );
QCOMPARE( 0, m_editor1->cursorPos() );
QCOMPARE( 0, m_editor1->anchorPos() );
m_document->undo();
QCOMPARE( QString( "Hello, Wor" ), m_annot1->contents() );
QCOMPARE( QString( "Hello, Wor" ), m_editor1->contents() );
QCOMPARE( 2, m_editor1->cursorPos() );
QCOMPARE( 0, m_editor1->anchorPos() );
m_document->undo();
QCOMPARE( QString( "Hello, World" ), m_annot1->contents() );
QCOMPARE( QString( "Hello, World" ), m_editor1->contents() );
QCOMPARE( 12, m_editor1->cursorPos() );
QCOMPARE( 12, m_editor1->anchorPos() );
}
QTEST_KDEMAIN( EditAnnotationContentsTest, GUI )
#include "editannotationcontentstest.moc"

View file

@ -0,0 +1,138 @@
/***************************************************************************
* Copyright (C) 2013 by Jon Mease <jon.mease@gmail.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
***************************************************************************/
#include <qtest_kde.h>
#include <kmimetype.h>
#include "../settings_core.h"
#include <core/area.h>
#include <core/annotations.h>
#include "core/document.h"
#include "testingutils.h"
static const QColor RED = QColor(255, 0, 0);
static const QColor GREEN = QColor(0, 255, 0.0);
static const QColor BLUE = QColor(0, 0, 255);
class ModifyAnnotationPropertiesTest : public QObject
{
Q_OBJECT
private slots:
void initTestCase();
void cleanupTestCase();
void init();
void cleanup();
void testModifyAnnotationProperties();
void testModifyDefaultAnnotationProperties();
private:
Okular::Document *m_document;
Okular::TextAnnotation *m_annot1;
};
void ModifyAnnotationPropertiesTest::initTestCase()
{
Okular::SettingsCore::instance( "editannotationcontentstest" );
m_document = new Okular::Document( 0 );
}
void ModifyAnnotationPropertiesTest::cleanupTestCase()
{
delete m_document;
}
void ModifyAnnotationPropertiesTest::init()
{
const QString testFile = KDESRCDIR "data/file1.pdf";
const KMimeType::Ptr mime = KMimeType::findByPath( testFile );
m_document->openDocument(testFile, KUrl(), mime);
// Undo and Redo should be unavailable when docuemnt is first opened.
QVERIFY( !m_document->canUndo() );
QVERIFY( !m_document->canRedo() );
// Create two distinct text annotations
m_annot1 = new Okular::TextAnnotation();
m_annot1->setBoundingRectangle( Okular::NormalizedRect( 0.1, 0.1, 0.15, 0.15 ) );
m_annot1->setContents( QString( "Hello, World" ) );
m_annot1->setAuthor( "Jon Mease" );
m_annot1->style().setColor( RED );
m_annot1->style().setWidth( 4.0 );
m_document->addPageAnnotation( 0, m_annot1 );
}
void ModifyAnnotationPropertiesTest::cleanup()
{
m_document->closeDocument();
// m_annot1 and m_annot2 are deleted when document is closed
}
void ModifyAnnotationPropertiesTest::testModifyAnnotationProperties()
{
// Add m_annot1 to document and record its properties XML string
QString origLine1Xml = TestingUtils::getAnnotationXml( m_annot1 );
// Tell document we're going to modify m_annot1's properties
m_document->prepareToModifyAnnotationProperties( m_annot1 );
// Now modify m_annot1's properties and record properties XML string
m_annot1->style().setWidth( 8.0 );
m_annot1->style().setColor( GREEN );
m_document->modifyPageAnnotationProperties( 0, m_annot1 );
QString m_annot1XmlA = TestingUtils::getAnnotationXml( m_annot1 );
QCOMPARE( 8.0, m_annot1->style().width() );
QCOMPARE( GREEN, m_annot1->style().color() );
// undo modification and check that original properties have been restored
m_document->undo();
QCOMPARE( 4.0, m_annot1->style().width() );
QCOMPARE( RED, m_annot1->style().color() );
QCOMPARE( origLine1Xml, TestingUtils::getAnnotationXml( m_annot1 ) );
// redo modification and verify that new properties have been restored
m_document->redo();
QCOMPARE( 8.0, m_annot1->style().width() );
QCOMPARE( GREEN, m_annot1->style().color() );
QCOMPARE( m_annot1XmlA, TestingUtils::getAnnotationXml( m_annot1 ) );
// Verify that default values are properly restored. (We haven't explicitly set opacity yet)
QCOMPARE( 1.0, m_annot1->style().opacity() );
m_document->prepareToModifyAnnotationProperties( m_annot1 );
m_annot1->style().setOpacity( 0.5 );
m_document->modifyPageAnnotationProperties( 0, m_annot1 );
QCOMPARE( 0.5, m_annot1->style().opacity() );
m_document->undo();
QCOMPARE( 1.0, m_annot1->style().opacity() );
QCOMPARE( m_annot1XmlA, TestingUtils::getAnnotationXml( m_annot1 ) );
// And finally undo back to original properties
m_document->undo();
QCOMPARE( 4.0, m_annot1->style().width() );
QCOMPARE( RED, m_annot1->style().color() );
QCOMPARE( origLine1Xml, TestingUtils::getAnnotationXml( m_annot1 ) );
}
void ModifyAnnotationPropertiesTest::testModifyDefaultAnnotationProperties()
{
QString origLine1Xml = TestingUtils::getAnnotationXml( m_annot1 );
// Verify that default values are properly restored. (We haven't explicitly set opacity yet)
QCOMPARE( 1.0, m_annot1->style().opacity() );
m_document->prepareToModifyAnnotationProperties( m_annot1 );
m_annot1->style().setOpacity( 0.5 );
m_document->modifyPageAnnotationProperties( 0, m_annot1 );
QCOMPARE( 0.5, m_annot1->style().opacity() );
m_document->undo();
QCOMPARE( 1.0, m_annot1->style().opacity() );
QCOMPARE( origLine1Xml, TestingUtils::getAnnotationXml( m_annot1 ) );
}
QTEST_KDEMAIN( ModifyAnnotationPropertiesTest, GUI )
#include "modifyannotationpropertiestest.moc"

54
tests/testingutils.cpp Normal file
View file

@ -0,0 +1,54 @@
/***************************************************************************
* Copyright (C) 2013 by Jon Mease <jon.mease@gmail.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
***************************************************************************/
#include "testingutils.h"
#include "core/annotations.h"
#include <qtest_kde.h>
namespace TestingUtils
{
QString getAnnotationXml(const Okular::Annotation* annotation)
{
QString annotXmlString;
QTextStream stream(&annotXmlString, QIODevice::Append);
annotation->getAnnotationPropertiesDomNode().save(stream, 0);
return annotXmlString;
}
bool pointListsAlmostEqual( QLinkedList< Okular::NormalizedPoint > points1, QLinkedList< Okular::NormalizedPoint > points2 ) {
QLinkedListIterator<Okular::NormalizedPoint> it1( points1 );
QLinkedListIterator<Okular::NormalizedPoint> it2( points2 );
while ( it1.hasNext() && it2.hasNext() )
{
const Okular::NormalizedPoint& p1 = it1.next();
const Okular::NormalizedPoint& p2 = it2.next();
if ( !qFuzzyCompare( p1.x, p2.x ) || !qFuzzyCompare( p1.y, p2.y ) ) {
return false;
}
}
return !it1.hasNext() && !it2.hasNext();
}
QString AnnotationDisposeWatcher::m_disposedAnnotationName = QString();
QString AnnotationDisposeWatcher::disposedAnnotationName() {
return m_disposedAnnotationName;
}
void AnnotationDisposeWatcher::resetDisposedAnnotationName()
{
m_disposedAnnotationName = QString();
}
void AnnotationDisposeWatcher::disposeAnnotation( const Okular::Annotation *ann )
{
m_disposedAnnotationName = ann->uniqueName();
}
}

51
tests/testingutils.h Normal file
View file

@ -0,0 +1,51 @@
/***************************************************************************
* Copyright (C) 2013 by Jon Mease <jon.mease@gmail.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
***************************************************************************/
#ifndef OKULAR_TESTINGUTILS_H
#define OKULAR_TESTINGUTILS_H
template<class T >
class QLinkedList;
class QString;
namespace Okular {
class NormalizedPoint;
class Annotation;
}
namespace TestingUtils
{
/**
* Return the XML string associated with an annotation's properties
*/
QString getAnnotationXml(const Okular::Annotation* annotation);
/**
* Returns true if the pairwise comparison coordinates of points in @p points1 and @p points2 are almost
* equal (according to qFuzzyCompare)
*/
bool pointListsAlmostEqual( QLinkedList< Okular::NormalizedPoint > points1, QLinkedList< Okular::NormalizedPoint > points2 );
/*
* The AnnotationDisposeWatcher class provides a static disposeAnnotation function
* that may be assigned to an annotation with Annotation::setDisposeDataFunction in order to
* determine when an annotation has been disposed of.
*/
class AnnotationDisposeWatcher {
private:
static QString m_disposedAnnotationName;
public:
static QString disposedAnnotationName();
static void resetDisposedAnnotationName();
static void disposeAnnotation( const Okular::Annotation *ann );
};
}
#endif

View file

@ -0,0 +1,237 @@
/***************************************************************************
* Copyright (C) 2013 by Jon Mease <jon.mease@gmail.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
***************************************************************************/
#include <qtest_kde.h>
#include <kmimetype.h>
#include "../settings_core.h"
#include "core/annotations.h"
#include "core/document.h"
#include "testingutils.h"
Okular::LineAnnotation* getNewLineAnnotation(double startX, double startY, double endX, double endY)
{
Okular::LineAnnotation *line = new Okular::LineAnnotation;
line->setLinePoints( QLinkedList< Okular::NormalizedPoint >()
<< Okular::NormalizedPoint( startX, startY )
<< Okular::NormalizedPoint( endX, endY )
);
double left = qMin(startX, endX);
double top = qMin(startY, endY);
double right = qMax(startX, endX);
double bottom = qMax(startY, endY);
line->setBoundingRectangle( Okular::NormalizedRect(left, top, right, bottom) );
return line;
}
class TranslateAnnotationTest : public QObject
{
Q_OBJECT
private slots:
void initTestCase();
void cleanupTestCase();
void init();
void cleanup();
void testTranslateAnnotation();
void testSequentialTranslationsMergedIfBeingMovedIsSet();
void testSequentialTranslationsNotMergedIfBeingMovedIsNotSet();
void testAlternateTranslationsNotMerged();
private:
Okular::Document *m_document;
Okular::LineAnnotation *m_annot1;
Okular::LineAnnotation *m_annot2;
Okular::NormalizedPoint m_deltaA;
Okular::NormalizedPoint m_deltaB;
QLinkedList< Okular::NormalizedPoint > m_origPoints1;
QLinkedList< Okular::NormalizedPoint > m_origPoints2;
QLinkedList< Okular::NormalizedPoint > m_points1DeltaA;
QLinkedList< Okular::NormalizedPoint > m_points1DeltaAB;
QLinkedList< Okular::NormalizedPoint > m_points2DeltaA;
QLinkedList< Okular::NormalizedPoint > m_points2DeltaAB;
};
void TranslateAnnotationTest::initTestCase()
{
Okular::SettingsCore::instance( "editannotationcontentstest" );
m_document = new Okular::Document( 0 );
// translate m_annot1
m_deltaA = Okular::NormalizedPoint(0.05, 0.1);
m_deltaB = Okular::NormalizedPoint(0.1, 0.2);
// Build lists of expected points for various states
m_origPoints1 = QLinkedList< Okular::NormalizedPoint >()
<< Okular::NormalizedPoint( 0.1, 0.1 )
<< Okular::NormalizedPoint( 0.2, 0.3 );
m_points1DeltaA = QLinkedList< Okular::NormalizedPoint >()
<< Okular::NormalizedPoint( 0.15, 0.2 )
<< Okular::NormalizedPoint( 0.25, 0.4 );
m_points1DeltaAB = QLinkedList< Okular::NormalizedPoint >()
<< Okular::NormalizedPoint( 0.25, 0.4 )
<< Okular::NormalizedPoint( 0.35, 0.6 );
m_origPoints2 = QLinkedList< Okular::NormalizedPoint >()
<< Okular::NormalizedPoint( 0.1, 0.1 )
<< Okular::NormalizedPoint( 0.3, 0.4 );
m_points2DeltaA = QLinkedList< Okular::NormalizedPoint >()
<< Okular::NormalizedPoint( 0.15, 0.2 )
<< Okular::NormalizedPoint( 0.35, 0.5 );
m_points2DeltaAB = QLinkedList< Okular::NormalizedPoint >()
<< Okular::NormalizedPoint( 0.25, 0.4 )
<< Okular::NormalizedPoint( 0.45, 0.7 );
}
void TranslateAnnotationTest::cleanupTestCase()
{
delete m_document;
}
void TranslateAnnotationTest::init()
{
const QString testFile = KDESRCDIR "data/file1.pdf";
const KMimeType::Ptr mime = KMimeType::findByPath( testFile );
m_document->openDocument(testFile, KUrl(), mime);
// Undo and Redo should be unavailable when docuemnt is first opened.
QVERIFY( !m_document->canUndo() );
QVERIFY( !m_document->canRedo() );
// Create two distinct line annotations and add them to the document
m_annot1 = getNewLineAnnotation( m_origPoints1.first().x,
m_origPoints1.first().y,
m_origPoints1.last().x,
m_origPoints1.last().y );
m_document->addPageAnnotation( 0, m_annot1 );
m_annot2 = getNewLineAnnotation( m_origPoints2.first().x,
m_origPoints2.first().y,
m_origPoints2.last().x,
m_origPoints2.last().y );
m_document->addPageAnnotation( 0, m_annot2 );
}
void TranslateAnnotationTest::cleanup()
{
m_document->closeDocument();
// m_annot1 and m_annot2 are deleted when document is closed
}
void TranslateAnnotationTest::testTranslateAnnotation()
{
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot1->linePoints(), m_origPoints1 ) );
m_document->translatePageAnnotation( 0, m_annot1, m_deltaA );
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot1->linePoints(), m_points1DeltaA ) );
// undo and ensure m_annot1 is back to where it started
m_document->undo();
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot1->linePoints(), m_origPoints1 ) );
// redo then translate m_annot1 by m_deltaB
m_document->redo();
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot1->linePoints(), m_points1DeltaA ) );
}
void TranslateAnnotationTest::testSequentialTranslationsMergedIfBeingMovedIsSet()
{
// mark m_annot1 as BeingMoved but not m_annot2
m_annot1->setFlags( m_annot1->flags() | Okular::Annotation::BeingMoved );
// Verify initial positions
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot1->linePoints(), m_origPoints1 ) );
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot2->linePoints(), m_origPoints2 ) );
// Translate m_annot1 by m_deltaA then m_deltaB
m_document->translatePageAnnotation( 0, m_annot1, m_deltaA );
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot1->linePoints(), m_points1DeltaA ) );
m_document->translatePageAnnotation( 0, m_annot1, m_deltaB );
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot1->linePoints(), m_points1DeltaAB ) );
// Now undo and verify that these two translations were merged into one undo command
m_document->undo();
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot1->linePoints(), m_origPoints1 ) );
}
void TranslateAnnotationTest::testSequentialTranslationsNotMergedIfBeingMovedIsNotSet()
{
// mark m_annot1 as not BeingMoved
m_annot1->setFlags( m_annot1->flags() & ~Okular::Annotation::BeingMoved );
// Verify initial positions
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot1->linePoints(), m_origPoints1 ) );
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot2->linePoints(), m_origPoints2 ) );
// Translate m_annot1 by m_deltaA then m_deltaB
m_document->translatePageAnnotation( 0, m_annot1, m_deltaA );
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot1->linePoints(), m_points1DeltaA ) );
m_document->translatePageAnnotation( 0, m_annot1, m_deltaB );
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot1->linePoints(), m_points1DeltaAB ) );
// Now undo and verify that these two translations were NOT merged into one undo command
m_document->undo();
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot1->linePoints(), m_points1DeltaA ) );
m_document->undo();
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot1->linePoints(), m_origPoints1 ) );
}
void TranslateAnnotationTest::testAlternateTranslationsNotMerged()
{
// Set both m_annot1 and m_annot2 to BeingMoved
m_annot1->setFlags( m_annot1->flags() | Okular::Annotation::BeingMoved );
m_annot2->setFlags( m_annot2->flags() | Okular::Annotation::BeingMoved );
m_document->translatePageAnnotation( 0, m_annot1, m_deltaA );
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot1->linePoints(), m_points1DeltaA ) );
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot2->linePoints(), m_origPoints2 ) );
m_document->translatePageAnnotation( 0, m_annot2, m_deltaA );
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot1->linePoints(), m_points1DeltaA ) );
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot2->linePoints(), m_points2DeltaA ) );
m_document->translatePageAnnotation( 0, m_annot1, m_deltaB );
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot1->linePoints(), m_points1DeltaAB ) );
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot2->linePoints(), m_points2DeltaA ) );
m_document->translatePageAnnotation( 0, m_annot2, m_deltaB );
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot1->linePoints(), m_points1DeltaAB ) );
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot2->linePoints(), m_points2DeltaAB ) );
// First undo should move only m_annot2 back by m_deltaB
m_document->undo();
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot1->linePoints(), m_points1DeltaAB ) );
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot2->linePoints(), m_points2DeltaA ) );
// Next undo should move only m_annot1 back by m_deltaB
m_document->undo();
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot1->linePoints(), m_points1DeltaA ) );
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot2->linePoints(), m_points2DeltaA ) );
// Next Undo should move only m_annot2 back to its original location
m_document->undo();
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot1->linePoints(), m_points1DeltaA ) );
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot2->linePoints(), m_origPoints2 ) );
// Next undo should move m_annot1 back to its original location
m_document->undo();
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot1->linePoints(), m_origPoints1 ) );
QVERIFY( TestingUtils::pointListsAlmostEqual( m_annot2->linePoints(), m_origPoints2 ) );
}
QTEST_KDEMAIN( TranslateAnnotationTest, GUI )
#include "translateannotationtest.moc"