diff --git a/libs/textlayout/tests/MockRootAreaProvider.h b/libs/textlayout/tests/MockRootAreaProvider.h --- a/libs/textlayout/tests/MockRootAreaProvider.h +++ b/libs/textlayout/tests/MockRootAreaProvider.h @@ -23,6 +23,7 @@ #include "KoTextLayoutRootAreaProvider.h" #include +#include class MockRootAreaProvider : public KoTextLayoutRootAreaProvider { @@ -39,7 +40,10 @@ void setSuggestedRect(QRectF rect); - KoTextLayoutRootArea *m_area; + KoTextLayoutRootArea *area(int pos = 0) const; + + int maxPosition; + QMap m_areas; QRectF m_suggestedRect; bool m_askedForMoreThenOneArea; }; diff --git a/libs/textlayout/tests/MockRootAreaProvider.cpp b/libs/textlayout/tests/MockRootAreaProvider.cpp --- a/libs/textlayout/tests/MockRootAreaProvider.cpp +++ b/libs/textlayout/tests/MockRootAreaProvider.cpp @@ -21,23 +21,28 @@ #include "KoTextLayoutRootArea.h" +#include + MockRootAreaProvider::MockRootAreaProvider() - : m_area(0), - m_suggestedRect(QRectF(100, 100, 200,1000)), - m_askedForMoreThenOneArea(false) + : maxPosition(0) + , m_suggestedRect(QRectF(100, 100, 200, 1000)) + , m_askedForMoreThenOneArea(false) { } -KoTextLayoutRootArea *MockRootAreaProvider::provide(KoTextDocumentLayout *documentLayout, const RootAreaConstraint &, int requestedPosition, bool *isNewRootArea) +KoTextLayoutRootArea *MockRootAreaProvider::provide(KoTextDocumentLayout *documentLayout, const RootAreaConstraint &constraint, int requestedPosition, bool *isNewRootArea) { - if(m_area == 0) { - m_area = new KoTextLayoutRootArea(documentLayout); - *isNewRootArea = true; - return m_area; + if (maxPosition > 0 && requestedPosition > maxPosition) { + qInfo()<<"To many area requests:"< 1); + *isNewRootArea = !m_areas.contains(requestedPosition); + if (!m_areas.contains(requestedPosition)) { + m_areas.insert(requestedPosition, new KoTextLayoutRootArea(documentLayout)); + qInfo()<<"New area provided:"< 0; - return requestedPosition == 0 ? m_area : 0; + return m_areas.value(requestedPosition); } void MockRootAreaProvider::doPostLayout(KoTextLayoutRootArea *rootArea, bool isNewRootArea) @@ -55,9 +60,8 @@ Q_UNUSED(afterThis); } -QRectF MockRootAreaProvider::suggestRect(KoTextLayoutRootArea *rootArea) +QRectF MockRootAreaProvider::suggestRect(KoTextLayoutRootArea */*rootArea*/) { - Q_UNUSED(rootArea); return m_suggestedRect; } @@ -72,3 +76,8 @@ QList obstructions; return obstructions; } + +KoTextLayoutRootArea *MockRootAreaProvider::area(int pos) const +{ + return m_areas.value(pos); +} diff --git a/libs/textlayout/tests/TestDocumentLayout.cpp b/libs/textlayout/tests/TestDocumentLayout.cpp --- a/libs/textlayout/tests/TestDocumentLayout.cpp +++ b/libs/textlayout/tests/TestDocumentLayout.cpp @@ -101,30 +101,30 @@ m_layout->layout(); MockRootAreaProvider *p = dynamic_cast(m_layout->provider()); - QVERIFY(p->m_area); + QVERIFY(p->area()); QCOMPARE(lines, 8); /* Following is device-/font-dependent and therefore can be different on other computers // outside text - QCOMPARE(p->m_area->hitTest(QPointF(0, 0), Qt::FuzzyHit).position, 0); - QCOMPARE(p->m_area->hitTest(QPointF(0, 0), Qt::ExactHit).position, -1); - QCOMPARE(p->m_area->hitTest(QPointF(19, 49), Qt::ExactHit).position, 51); - QCOMPARE(p->m_area->hitTest(QPointF(71, 0), Qt::ExactHit).position, -1); - QCOMPARE(p->m_area->hitTest(QPointF(71, 51), Qt::ExactHit).position, 62); + QCOMPARE(p->area()->hitTest(QPointF(0, 0), Qt::FuzzyHit).position, 0); + QCOMPARE(p->area()->hitTest(QPointF(0, 0), Qt::ExactHit).position, -1); + QCOMPARE(p->area()->hitTest(QPointF(19, 49), Qt::ExactHit).position, 51); + QCOMPARE(p->area()->hitTest(QPointF(71, 0), Qt::ExactHit).position, -1); + QCOMPARE(p->area()->hitTest(QPointF(71, 51), Qt::ExactHit).position, 62); // first char - QCOMPARE(p->m_area->hitTest(QPointF(20, 51), Qt::ExactHit).position, 52); - QCOMPARE(p->m_area->hitTest(QPointF(20, 50), Qt::ExactHit).position, 52); + QCOMPARE(p->area()->hitTest(QPointF(20, 51), Qt::ExactHit).position, 52); + QCOMPARE(p->area()->hitTest(QPointF(20, 50), Qt::ExactHit).position, 52); // below line 1 - //QCOMPARE(p->m_area->hitTest(QPointF(20, 51 + lineHeight), Qt::ExactHit).position, -1); - //QVERIFY(p->m_area->hitTest(QPointF(20, 51 + lineHeight), Qt::FuzzyHit).position > 0); // line 2 + //QCOMPARE(p->area()->hitTest(QPointF(20, 51 + lineHeight), Qt::ExactHit).position, -1); + //QVERIFY(p->area()->hitTest(QPointF(20, 51 + lineHeight), Qt::FuzzyHit).position > 0); // line 2 // parag2 - QCOMPARE(p->m_area->hitTest(QPointF(20, paragOffets[1]), Qt::ExactHit).position, 139); - QCOMPARE(p->m_area->hitTest(QPointF(20, paragOffets[1]), Qt::FuzzyHit).position, 139); - QVERIFY(p->m_area->hitTest(QPointF(20, paragOffets[1] + 20), Qt::FuzzyHit).position >= 139); + QCOMPARE(p->area()->hitTest(QPointF(20, paragOffets[1]), Qt::ExactHit).position, 139); + QCOMPARE(p->area()->hitTest(QPointF(20, paragOffets[1]), Qt::FuzzyHit).position, 139); + QVERIFY(p->area()->hitTest(QPointF(20, paragOffets[1] + 20), Qt::FuzzyHit).position >= 139); */ Q_UNUSED(lineHeight); // used in the above commented piece of code Q_UNUSED(paragOffets); // used in the above commented piece of code @@ -140,15 +140,15 @@ m_layout->layout(); QVERIFY(!provider->m_askedForMoreThenOneArea); - QVERIFY(provider->m_area); - QVERIFY(!provider->m_area->isDirty()); - QVERIFY(!provider->m_area->virginPage()); - QVERIFY(provider->m_area->nextStartOfArea()); - QVERIFY(!provider->m_area->isStartingAt(provider->m_area->nextStartOfArea())); - QCOMPARE(provider->m_area->boundingRect().topLeft(), QPointF(10.,10.)); - //QCOMPARE(provider->m_area->boundingRect().height(), qreal(14.4)); - QCOMPARE(provider->m_area->referenceRect().topLeft(), QPointF(10.,10.)); - //QCOMPARE(provider->m_area->referenceRect().bottomLeft(), QPointF(0.,14.4)); + QVERIFY(provider->area()); + QVERIFY(!provider->area()->isDirty()); + QVERIFY(!provider->area()->virginPage()); + QVERIFY(provider->area()->nextStartOfArea()); + QVERIFY(!provider->area()->isStartingAt(provider->area()->nextStartOfArea())); + QCOMPARE(provider->area()->boundingRect().topLeft(), QPointF(10.,10.)); + //QCOMPARE(provider->area()->boundingRect().height(), qreal(14.4)); + QCOMPARE(provider->area()->referenceRect().topLeft(), QPointF(10.,10.)); + //QCOMPARE(provider->area()->referenceRect().bottomLeft(), QPointF(0.,14.4)); } void TestDocumentLayout::testRootAreaZeroHeight() @@ -161,13 +161,13 @@ m_layout->layout(); QVERIFY(!provider->m_askedForMoreThenOneArea); // we add the text anyways even if it does not match in height - QVERIFY(provider->m_area); - QVERIFY(!provider->m_area->isDirty()); - QVERIFY(!provider->m_area->virginPage()); // should not be virigin any longer cause we added text - QVERIFY(provider->m_area->nextStartOfArea()); - QVERIFY(!provider->m_area->isStartingAt(provider->m_area->nextStartOfArea())); // start- and end-iterator should not be equal cause we added text - QCOMPARE(provider->m_area->boundingRect(), QRectF(10.,10.,200.,0.)); - QCOMPARE(provider->m_area->referenceRect(), QRectF(10.,10.,200.,0.)); + QVERIFY(provider->area()); + QVERIFY(!provider->area()->isDirty()); + QVERIFY(!provider->area()->virginPage()); // should not be virigin any longer cause we added text + QVERIFY(provider->area()->nextStartOfArea()); + QVERIFY(!provider->area()->isStartingAt(provider->area()->nextStartOfArea())); // start- and end-iterator should not be equal cause we added text + QCOMPARE(provider->area()->boundingRect(), QRectF(10.,10.,200.,0.)); + QCOMPARE(provider->area()->referenceRect(), QRectF(10.,10.,200.,0.)); } void TestDocumentLayout::testRootAreaZeroWidthAndHeight() @@ -180,15 +180,15 @@ m_layout->layout(); QVERIFY(!provider->m_askedForMoreThenOneArea); - QVERIFY(provider->m_area); - QVERIFY(!provider->m_area->isDirty()); - QVERIFY(!provider->m_area->virginPage()); - QVERIFY(provider->m_area->nextStartOfArea()); - QVERIFY(!provider->m_area->isStartingAt(provider->m_area->nextStartOfArea())); - QCOMPARE(provider->m_area->boundingRect().topLeft(), QPointF(10.,10.)); - QCOMPARE(provider->m_area->boundingRect().height(), qreal(0.)); - //QCOMPARE(provider->m_area->boundingRect().width(), qreal(6.67188)); - QCOMPARE(provider->m_area->referenceRect(), QRectF(10.,10.,0.,0.)); + QVERIFY(provider->area()); + QVERIFY(!provider->area()->isDirty()); + QVERIFY(!provider->area()->virginPage()); + QVERIFY(provider->area()->nextStartOfArea()); + QVERIFY(!provider->area()->isStartingAt(provider->area()->nextStartOfArea())); + QCOMPARE(provider->area()->boundingRect().topLeft(), QPointF(10.,10.)); + QCOMPARE(provider->area()->boundingRect().height(), qreal(0.)); + //QCOMPARE(provider->area()->boundingRect().width(), qreal(6.67188)); + QCOMPARE(provider->area()->referenceRect(), QRectF(10.,10.,0.,0.)); } QTEST_MAIN(TestDocumentLayout) diff --git a/libs/textlayout/tests/TestTableLayout.h b/libs/textlayout/tests/TestTableLayout.h --- a/libs/textlayout/tests/TestTableLayout.h +++ b/libs/textlayout/tests/TestTableLayout.h @@ -55,7 +55,6 @@ * exactly this case. */ void testMergedCells(); - /** * If no column-width is defined then the available width should be distributed among * the available columns. Since the provided rootArea's have a width of 200 and we @@ -98,9 +97,17 @@ */ void testRowHeightMinimum(); + void testOneTableNeedsTwoRootAreas(); + void testTwoTablesNeedsTwoRootAreas(); + void testMergedRowsSpansAreas(); + void testMergedRowsSpansAreas2(); + void testTwoTablesMergedRowsSpansAreas(); + void testTwoTablesMergedRowsSpansThreeAreas(); + private: QTextCursor setupTest(); void setupTest(const QString &mergedText, const QString &topRightText, const QString &midRightText, const QString &bottomLeftText, const QString &bottomMidText, const QString &bottomRightText, KoTableStyle* tableStyle = 0); + QTextTable *addTable(QTextCursor cursor, int rows, int columns, KoTableStyle* tableStyle = 0); private: QTextDocument *m_doc; diff --git a/libs/textlayout/tests/TestTableLayout.cpp b/libs/textlayout/tests/TestTableLayout.cpp --- a/libs/textlayout/tests/TestTableLayout.cpp +++ b/libs/textlayout/tests/TestTableLayout.cpp @@ -33,7 +33,10 @@ #include #include #include +#include #include +#include +#include #include #include @@ -55,6 +58,7 @@ void TestTableLayout::cleanupTestCase() { delete m_doc; + m_doc = 0; } QTextCursor TestTableLayout::setupTest() @@ -201,7 +205,15 @@ m_layout->layout(); - QVERIFY(!dynamic_cast(m_layout->provider())->m_askedForMoreThenOneArea); + MockRootAreaProvider *provider = dynamic_cast(m_layout->provider()); + QVERIFY(!provider->m_askedForMoreThenOneArea); + // check if table is layed out + for (int i = 0; i < provider->m_areas.count(); ++i) { + qInfo()<<"area:"<area(i)->referenceRect(); + } + QPointF point = provider->area(0)->referenceRect().topLeft() + QPointF(0., 20.); + KoPointedAt p = provider->area(0)->hitTest(point, Qt::FuzzyHit); + QVERIFY2(m_table == p.table, "m_table not found in area 0"); } void TestTableLayout::testColumnWidthUndefined() @@ -369,4 +381,240 @@ //QVERIFY(qAbs(mergedCellBlock().layout()->lineAt(0).height() - 14) < ROUNDING); } +QTextTable *TestTableLayout::addTable(QTextCursor cursor, int rows, int columns, KoTableStyle* tableStyle) +{ + KoParagraphStyle style; + style.setStyleId(101); // needed to do manually since we don't use the stylemanager + style.applyStyle(m_block); + QTextTableFormat tableFormat; + if (tableStyle) { + tableStyle->applyStyle(tableFormat); + } + QTextTable *table = cursor.insertTable(rows, columns, tableFormat); + for (int r = 0; r < table->rows(); ++r) { + for (int c = 0; c < table->columns(); ++c) { + QString s = QString("Cell %1, %2").arg(r, c); + table->cellAt(r,c).firstCursorPosition().insertText(s); + QTextBlock b2 = table->cellAt(r,c).firstCursorPosition().block(); + while (b2.isValid()) { + style.applyStyle(b2); + b2 = b2.next(); + } + } + } + return table; +} + +void TestTableLayout::testOneTableNeedsTwoRootAreas() +{ + QTextCursor c = setupTest(); + QTextTable *table1 = addTable(c, 6, 3); + + MockRootAreaProvider *provider = dynamic_cast(m_layout->provider()); + QVERIFY(provider); + provider->setSuggestedRect(QRect(100, 100, 200, 90)); + provider->maxPosition = 10; // guard against loop + + m_layout->layout(); + + QCOMPARE(provider->m_areas.count(), 2); + + QPointF point = provider->area(0)->referenceRect().topLeft() + QPointF(0., 20.); + KoPointedAt p = provider->area(0)->hitTest(point, Qt::FuzzyHit); + QVERIFY2(table1 == p.table, "table1 not found in area 0"); + + // table2 starts in first area and continues into second area + point = provider->area(1)->referenceRect().topLeft() + QPointF(0., 10.); + p = provider->area(1)->hitTest(point, Qt::FuzzyHit); + QVERIFY2(table1 == p.table, "table1 not found in area 1"); +} + +void TestTableLayout::testTwoTablesNeedsTwoRootAreas() +{ + QTextCursor c = setupTest(); + QTextTable *table1 = addTable(c, 2, 3); + QTextTable *table2 = addTable(c, 3, 3); + + MockRootAreaProvider *provider = dynamic_cast(m_layout->provider()); + QVERIFY(provider); + provider->setSuggestedRect(QRect(100, 100, 200, 90)); + + m_layout->layout(); + + for (int i = 0; i < provider->m_areas.count(); ++i) { + qInfo()<<"area:"<area(i)->referenceRect(); + } + + QCOMPARE(provider->m_areas.count(), 2); + + QPointF point = provider->area(0)->referenceRect().topLeft() + QPointF(0., 20.); + KoPointedAt p = provider->area(0)->hitTest(point, Qt::FuzzyHit); + QVERIFY2(table1 == p.table, "table1 not found in area 0"); + + // table2 starts in first area and continues into second area + point = provider->area(1)->referenceRect().topLeft() + QPointF(0., 10.); + p = provider->area(1)->hitTest(point, Qt::FuzzyHit); + QVERIFY2(table2 == p.table, "table2 not found in area 1"); +} + +void TestTableLayout::testMergedRowsSpansAreas() +{ + QTextCursor c = setupTest(); + QTextTable *table1 = addTable(c, 6, 3); + + MockRootAreaProvider *provider = dynamic_cast(m_layout->provider()); + QVERIFY(provider); + provider->setSuggestedRect(QRect(100, 100, 200, 90)); + provider->maxPosition = 10; // guard against loop + + table1->mergeCells(0,0,2,1); + table1->mergeCells(0,1,2,1); + table1->mergeCells(0,2,2,1); + + table1->mergeCells(2,0,2,1); + table1->mergeCells(2,1,2,1); + table1->mergeCells(2,2,2,1); + + table1->mergeCells(4,0,2,1); + table1->mergeCells(4,1,2,1); + table1->mergeCells(4,2,2,1); + + m_layout->layout(); + + for (int i = 0; i < provider->m_areas.count(); ++i) { + qInfo()<<"area:"<area(i)->referenceRect(); + } + // should be room in two areas (it is if cells are not merged) + QCOMPARE(provider->m_areas.count(), 2); + + QPointF point = provider->area(0)->referenceRect().topLeft() + QPointF(0., 20.); + KoPointedAt p = provider->area(0)->hitTest(point, Qt::FuzzyHit); + QVERIFY2(table1 == p.table, "table1 not found in area 0"); + + point = provider->area(1)->referenceRect().topLeft() + QPointF(0., 10.); + p = provider->area(1)->hitTest(point, Qt::FuzzyHit); + QVERIFY2(table1 == p.table, "table1 not found in area 1"); +} + +void TestTableLayout::testMergedRowsSpansAreas2() +{ + QTextCursor c = setupTest(); + QTextTable *table1 = addTable(c, 10, 3); + + MockRootAreaProvider *provider = dynamic_cast(m_layout->provider()); + QVERIFY(provider); + provider->setSuggestedRect(QRect(100, 100, 200, 110)); + provider->maxPosition = 10; // guard against loop + + table1->mergeCells(0,0,2,1); + table1->mergeCells(0,1,2,1); + table1->mergeCells(0,2,2,1); + + table1->mergeCells(2,0,2,1); + table1->mergeCells(2,1,2,1); + table1->mergeCells(2,2,2,1); + + table1->mergeCells(4,0,2,1); + table1->mergeCells(4,1,2,1); + table1->mergeCells(4,2,2,1); + + table1->mergeCells(6,0,2,1); + table1->mergeCells(6,1,2,1); + table1->mergeCells(6,2,2,1); + + table1->mergeCells(8,0,2,1); + table1->mergeCells(8,1,2,1); + table1->mergeCells(8,2,2,1); + + m_layout->layout(); + + for (int i = 0; i < provider->m_areas.count(); ++i) { + qInfo()<<"area:"<area(i)->referenceRect(); + } + QVERIFY2(provider->m_areas.count() <= 5, "Table should fit in max 5 areas, possibly in 3"); + + // check if table is layed out at all + QPointF point = provider->area(0)->referenceRect().topLeft() + QPointF(0., 20.); + KoPointedAt p = provider->area(0)->hitTest(point, Qt::FuzzyHit); + QVERIFY2(table1 == p.table, "table1 not found in area 0"); +} + +void TestTableLayout::testTwoTablesMergedRowsSpansAreas() +{ + QTextCursor c = setupTest(); + QTextTable *table1 = addTable(c, 4, 3); + QTextTable *table2 = addTable(c, 3, 3); + + MockRootAreaProvider *provider = dynamic_cast(m_layout->provider()); + QVERIFY(provider); + provider->setSuggestedRect(QRect(100, 100, 200, 90)); + provider->maxPosition = 10; // guard against loop + + table2->mergeCells(0,0,2,1); + table2->mergeCells(0,1,2,1); + table2->mergeCells(0,2,2,1); + + m_layout->layout(); + + for (int i = 0; i < provider->m_areas.count(); ++i) { + qInfo()<<"area:"<area(i)->referenceRect(); + } + + QCOMPARE(provider->m_areas.count(), 2); + + QPointF point = provider->area(0)->referenceRect().topLeft() + QPointF(0., 20.); + KoPointedAt p = provider->area(0)->hitTest(point, Qt::FuzzyHit); + QVERIFY2(table1 == p.table, "table1 not found in area 0"); + + // intention: there should not be room left for another row in area 0, so table2 should start in next area + point = provider->area(0)->referenceRect().bottomLeft() + QPointF(0., -10.); + p = provider->area(0)->hitTest(point, Qt::FuzzyHit); + QVERIFY2(table2 != p.table, "table2 found in area 0, possibly due font size"); + + point = provider->area(1)->referenceRect().topLeft() + QPointF(0., 20.); + p = provider->area(1)->hitTest(point, Qt::FuzzyHit); + QVERIFY2(table2 == p.table, "table2 not found in area 1"); +} + +void TestTableLayout::testTwoTablesMergedRowsSpansThreeAreas() +{ + QTextCursor c = setupTest(); + QTextTable *table1 = addTable(c, 4, 3); + QTextTable *table2 = addTable(c, 8, 3); // should need 2 areas + + MockRootAreaProvider *provider = dynamic_cast(m_layout->provider()); + QVERIFY(provider); + provider->setSuggestedRect(QRect(100, 100, 200, 90)); + provider->maxPosition = 10; // guard against loop + + table2->mergeCells(0,0,2,1); + table2->mergeCells(0,1,2,1); + table2->mergeCells(0,2,2,1); + + m_layout->layout(); + + for (int i = 0; i < provider->m_areas.count(); ++i) { + qInfo()<<"area:"<area(i)->referenceRect(); + } + + QCOMPARE(provider->m_areas.count(), 3); + + QPointF point = provider->area(0)->referenceRect().topLeft() + QPointF(0., 20.); + KoPointedAt p = provider->area(0)->hitTest(point, Qt::FuzzyHit); + QVERIFY2(table1 == p.table, "table1 not found in area 0"); + + // intention: there should not be room left for another row in area 0, so table2 should start in next area + point = provider->area(0)->referenceRect().bottomLeft() + QPointF(0., -10.); + p = provider->area(0)->hitTest(point, Qt::FuzzyHit); + QVERIFY2(table2 != p.table, "table2 found in area 0, possibly due font size"); + + point = provider->area(1)->referenceRect().topLeft() + QPointF(0., 20.); + p = provider->area(1)->hitTest(point, Qt::FuzzyHit); + QVERIFY2(table2 == p.table, "table2 not found in area 1"); + + point = provider->area(2)->referenceRect().topLeft() + QPointF(0., 20.); + p = provider->area(2)->hitTest(point, Qt::FuzzyHit); + QVERIFY2(table2 == p.table, "table2 not found in area 2"); +} + QTEST_MAIN(TestTableLayout)