From b2a4c7f0142a48f60e7ec4fc5866917e3da8b7c3 Mon Sep 17 00:00:00 2001 From: Pierre Rossi Date: Fri, 2 Jul 2010 19:31:51 +0200 Subject: Fix an Assert in QTextTable The problem was caused by the fragment id being inserted in front of a cell spanning over several rows instead of the next logical cell (or fragment_end) in the cells structure. Task-number: QTBUG-11282 Reviewed-by: Simon Hausmann --- src/gui/text/qtexttable.cpp | 28 ++++++++++++++--- tests/auto/qtexttable/tst_qtexttable.cpp | 54 ++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 4 deletions(-) diff --git a/src/gui/text/qtexttable.cpp b/src/gui/text/qtexttable.cpp index 5100176..e3985ce 100644 --- a/src/gui/text/qtexttable.cpp +++ b/src/gui/text/qtexttable.cpp @@ -754,19 +754,39 @@ void QTextTable::insertColumns(int pos, int num) QTextFormatCollection *c = p->formatCollection(); p->beginEditBlock(); + QList extendedSpans; for (int i = 0; i < d->nRows; ++i) { int cell; if (i == d->nRows - 1 && pos == d->nCols) cell = d->fragment_end; else cell = d->grid[i*d->nCols + pos]; - QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), cell); - QTextCharFormat fmt = c->charFormat(it->format); if (pos > 0 && pos < d->nCols && cell == d->grid[i*d->nCols + pos - 1]) { // cell spans the insertion place, extend it - fmt.setTableCellColumnSpan(fmt.tableCellColumnSpan() + num); - p->setCharFormat(it.position(), 1, fmt); + if (!extendedSpans.contains(cell)) { + QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), cell); + QTextCharFormat fmt = c->charFormat(it->format); + fmt.setTableCellColumnSpan(fmt.tableCellColumnSpan() + num); + p->setCharFormat(it.position(), 1, fmt); + d->dirty = true; + extendedSpans << cell; + } } else { + /* If the next cell is spanned from the row above, we need to find the right position + to insert to */ + if (i > 0 && pos < d->nCols && cell == d->grid[(i-1) * d->nCols + pos]) { + int gridIndex = i*d->nCols + pos; + const int gridEnd = d->nRows * d->nCols - 1; + while (gridIndex < gridEnd && cell == d->grid[gridIndex]) { + ++gridIndex; + } + if (gridIndex == gridEnd) + cell = d->fragment_end; + else + cell = d->grid[gridIndex]; + } + QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), cell); + QTextCharFormat fmt = c->charFormat(it->format); fmt.setTableCellRowSpan(1); fmt.setTableCellColumnSpan(1); Q_ASSERT(fmt.objectIndex() == objectIndex()); diff --git a/tests/auto/qtexttable/tst_qtexttable.cpp b/tests/auto/qtexttable/tst_qtexttable.cpp index 2e6007e..b0cb34d 100644 --- a/tests/auto/qtexttable/tst_qtexttable.cpp +++ b/tests/auto/qtexttable/tst_qtexttable.cpp @@ -48,9 +48,14 @@ #include #include #include +#include +#include //TESTED_FILES= +typedef QList IntList; +Q_DECLARE_METATYPE(IntList) + QT_FORWARD_DECLARE_CLASS(QTextDocument) class tst_QTextTable : public QObject @@ -78,6 +83,7 @@ private slots: void insertRows(); void deleteInTable(); void mergeCells(); + void mergeAndInsert(); void splitCells(); void blocksForTableShouldHaveEmptyFormat(); void removeTableByRemoveRows(); @@ -93,6 +99,8 @@ private slots: void removeColumns3(); void removeColumns4(); void removeColumns5(); + void QTBUG11282_insertBeforeMergedEnding_data(); + void QTBUG11282_insertBeforeMergedEnding(); private: QTextTable *create2x2Table(); @@ -586,6 +594,16 @@ void tst_QTextTable::mergeCells() QVERIFY(table->cellAt(0, 1) == table->cellAt(1, 1)); } +void tst_QTextTable::mergeAndInsert() +{ + QTextTable *table = cursor.insertTable(4,3); + table->mergeCells(0,1,3,2); + table->mergeCells(3,0,1,3); + //Don't crash ! + table->insertColumns(1,2); + QCOMPARE(table->columns(), 5); +} + void tst_QTextTable::splitCells() { QTextTable *table = create4x4Table(); @@ -931,5 +949,41 @@ void tst_QTextTable::removeColumns5() QCOMPARE(table->cellAt(3, 2).firstPosition(), 11); } +void tst_QTextTable::QTBUG11282_insertBeforeMergedEnding_data() +{ + QTest::addColumn("rows"); + QTest::addColumn("columns"); + QTest::addColumn >("merge"); + QTest::addColumn >("insert"); + + QTest::newRow("2x3, merge two, insert one") << 2 << 3 << (QList() << 1 << 2 << 2) + << (QList() << 1 << 1) ; + QTest::newRow("3x4, merge three, insert one") << 3 << 4 << (QList() << 1 << 3 << 3) + << (QList() << 1 << 1) ; + QTest::newRow("4x3, merge two, insert two") << 4 << 3 << (QList() << 1 << 4 << 2) + << (QList() << 1 << 2) ; + QTest::newRow("4x4, merge middle two, insert one") << 4 << 4 << (QList() << 1 << 4 << 2) + << (QList() << 1 << 1) ; +} + +void tst_QTextTable::QTBUG11282_insertBeforeMergedEnding() +{ + QFETCH(int, rows); + QFETCH(int, columns); + QFETCH(QList, merge); + QFETCH(QList, insert); + QTextTable *table = cursor.insertTable(rows, columns); + QTextEdit *textEdit = new QTextEdit; + textEdit->setDocument(doc); + textEdit->show(); + QTest::qWaitForWindowShown(textEdit); + table->mergeCells(0,merge.at(0), merge.at(1), merge.at(2)); + //Don't crash ! + table->insertColumns(insert.at(0), insert.at(1)); + //Check that the final size is what we expected + QCOMPARE(table->rows(), rows); + QCOMPARE(table->columns(), columns + insert.at(1)); +} + QTEST_MAIN(tst_QTextTable) #include "tst_qtexttable.moc" -- cgit v0.12