mirror of
https://invent.kde.org/graphics/okular
synced 2024-08-27 11:40:07 +00:00
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:
parent
583fc0d81f
commit
3c6140b616
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 )
|
||||
|
|
190
tests/addremoveannotationtest.cpp
Normal file
190
tests/addremoveannotationtest.cpp
Normal 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"
|
519
tests/editannotationcontentstest.cpp
Normal file
519
tests/editannotationcontentstest.cpp
Normal 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"
|
138
tests/modifyannotationpropertiestest.cpp
Normal file
138
tests/modifyannotationpropertiestest.cpp
Normal 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
54
tests/testingutils.cpp
Normal 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
51
tests/testingutils.h
Normal 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
|
237
tests/translateannotationtest.cpp
Normal file
237
tests/translateannotationtest.cpp
Normal 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"
|
Loading…
Reference in a new issue