summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGabriel de Dietrich <gabriel.dietrich-de@nokia.com>2009-09-25 17:59:12 (GMT)
committerGabriel de Dietrich <gabriel.dietrich-de@nokia.com>2009-10-06 12:03:18 (GMT)
commit0d51611fa524091ddca3c6c11edb0eae8ffe3b02 (patch)
tree12d7a29651988a017758609208f9ad79cc8cf83d
parent6c14af1cdb02d1d6957ad23ec435e2b95dda5b4a (diff)
downloadQt-0d51611fa524091ddca3c6c11edb0eae8ffe3b02.zip
Qt-0d51611fa524091ddca3c6c11edb0eae8ffe3b02.tar.gz
Qt-0d51611fa524091ddca3c6c11edb0eae8ffe3b02.tar.bz2
Span update after row and column insertion and removal in QTableView.
The feature had not been implemented yet. Auto-test and benchmark included. As a bonus, single cell spans are no longer added to the span collection. Reviewed-by: Thierry Task-number: 245327 Task-number: QTBUG-3610
-rw-r--r--src/gui/itemviews/qtableview.cpp404
-rw-r--r--src/gui/itemviews/qtableview.h4
-rw-r--r--src/gui/itemviews/qtableview_p.h21
-rw-r--r--tests/auto/qtableview/tst_qtableview.cpp193
-rw-r--r--tests/benchmarks/qtableview/tst_qtableview.cpp174
5 files changed, 792 insertions, 4 deletions
diff --git a/src/gui/itemviews/qtableview.cpp b/src/gui/itemviews/qtableview.cpp
index f1ffaa6..15bd445 100644
--- a/src/gui/itemviews/qtableview.cpp
+++ b/src/gui/itemviews/qtableview.cpp
@@ -191,6 +191,359 @@ QList<QSpanCollection::Span *> QSpanCollection::spansInRect(int x, int y, int w,
return list.toList();
}
+#undef DEBUG_SPAN_UPDATE
+
+#ifdef DEBUG_SPAN_UPDATE
+QDebug operator<<(QDebug str, const QSpanCollection::Span &span)
+{
+ str << "(" << span.top() << "," << span.left() << "," << span.bottom() << "," << span.right() << ")";
+ return str;
+}
+#endif
+
+/** \internal
+* Updates the span collection after row insertion.
+*/
+void QSpanCollection::updateInsertedRows(int start, int end)
+{
+#ifdef DEBUG_SPAN_UPDATE
+ qDebug() << Q_FUNC_INFO;
+ qDebug() << start << end;
+ qDebug() << index;
+#endif
+ if (spans.isEmpty())
+ return;
+
+ int delta = end - start + 1;
+#ifdef DEBUG_SPAN_UPDATE
+ qDebug("Before");
+#endif
+ for (SpanList::iterator it = spans.begin(); it != spans.end(); ++it) {
+ Span *span = *it;
+#ifdef DEBUG_SPAN_UPDATE
+ qDebug() << span << *span;
+#endif
+ if (span->m_bottom < start)
+ continue;
+ if (span->m_top >= start)
+ span->m_top += delta;
+ span->m_bottom += delta;
+ }
+
+#ifdef DEBUG_SPAN_UPDATE
+ qDebug("After");
+ foreach (QSpanCollection::Span *span, spans)
+ qDebug() << span << *span;
+#endif
+
+ for (Index::iterator it_y = index.begin(); it_y != index.end(); ) {
+ int y = -it_y.key();
+ if (y < start) {
+ ++it_y;
+ continue;
+ }
+
+ index.insert(-y - delta, it_y.value());
+ it_y = index.erase(it_y);
+ }
+#ifdef DEBUG_SPAN_UPDATE
+ qDebug() << index;
+#endif
+}
+
+/** \internal
+* Updates the span collection after column insertion.
+*/
+void QSpanCollection::updateInsertedColumns(int start, int end)
+{
+#ifdef DEBUG_SPAN_UPDATE
+ qDebug() << Q_FUNC_INFO;
+ qDebug() << start << end;
+ qDebug() << index;
+#endif
+ if (spans.isEmpty())
+ return;
+
+ int delta = end - start + 1;
+#ifdef DEBUG_SPAN_UPDATE
+ qDebug("Before");
+#endif
+ for (SpanList::iterator it = spans.begin(); it != spans.end(); ++it) {
+ Span *span = *it;
+#ifdef DEBUG_SPAN_UPDATE
+ qDebug() << span << *span;
+#endif
+ if (span->m_right < start)
+ continue;
+ if (span->m_left >= start)
+ span->m_left += delta;
+ span->m_right += delta;
+ }
+
+#ifdef DEBUG_SPAN_UPDATE
+ qDebug("After");
+ foreach (QSpanCollection::Span *span, spans)
+ qDebug() << span << *span;
+#endif
+
+ for (Index::iterator it_y = index.begin(); it_y != index.end(); ++it_y) {
+ SubIndex &subindex = it_y.value();
+ for (SubIndex::iterator it = subindex.begin(); it != subindex.end(); ) {
+ int x = -it.key();
+ if (x < start) {
+ ++it;
+ continue;
+ }
+ subindex.insert(-x - delta, it.value());
+ it = subindex.erase(it);
+ }
+ }
+#ifdef DEBUG_SPAN_UPDATE
+ qDebug() << index;
+#endif
+}
+
+/** \internal
+* Cleans a subindex from to be deleted spans. The update argument is used
+* to move the spans inside the subindex, in case their anchor changed.
+* \return true if no span in this subindex starts at y, and should thus be deleted.
+*/
+bool QSpanCollection::cleanSpanSubIndex(QSpanCollection::SubIndex &subindex, int y, bool update)
+{
+ if (subindex.isEmpty())
+ return true;
+
+ bool should_be_deleted = true;
+ SubIndex::iterator it = subindex.end();
+ do {
+ --it;
+ int x = -it.key();
+ Span *span = it.value();
+ if (span->will_be_deleted) {
+ it = subindex.erase(it);
+ continue;
+ }
+ if (update && span->m_left != x) {
+ subindex.insert(-span->m_left, span);
+ it = subindex.erase(it);
+ }
+ if (should_be_deleted && span->m_top == y)
+ should_be_deleted = false;
+ } while (it != subindex.begin());
+
+ return should_be_deleted;
+}
+
+/** \internal
+* Updates the span collection after row removal.
+*/
+void QSpanCollection::updateRemovedRows(int start, int end)
+{
+#ifdef DEBUG_SPAN_UPDATE
+ qDebug() << Q_FUNC_INFO;
+ qDebug() << start << end;
+ qDebug() << index;
+#endif
+ if (spans.isEmpty())
+ return;
+
+ SpanList spansToBeDeleted;
+ int delta = end - start + 1;
+#ifdef DEBUG_SPAN_UPDATE
+ qDebug("Before");
+#endif
+ for (SpanList::iterator it = spans.begin(); it != spans.end(); ) {
+ Span *span = *it;
+#ifdef DEBUG_SPAN_UPDATE
+ qDebug() << span << *span;
+#endif
+ if (span->m_bottom < start) {
+ ++it;
+ continue;
+ }
+ if (span->m_top < start) {
+ if (span->m_bottom <= end)
+ span->m_bottom = start - 1;
+ else
+ span->m_bottom -= delta;
+ } else {
+ if (span->m_bottom > end) {
+ if (span->m_top <= end)
+ span->m_top = start;
+ else
+ span->m_top -= delta;
+ span->m_bottom -= delta;
+ } else {
+ span->will_be_deleted = true;
+ }
+ }
+ if (span->m_top == span->m_bottom && span->m_left == span->m_right)
+ span->will_be_deleted = true;
+ if (span->will_be_deleted) {
+ spansToBeDeleted.append(span);
+ it = spans.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+#ifdef DEBUG_SPAN_UPDATE
+ qDebug("After");
+ foreach (QSpanCollection::Span *span, spans)
+ qDebug() << span << *span;
+#endif
+ if (spans.isEmpty()) {
+ qDeleteAll(spansToBeDeleted);
+ index.clear();
+ return;
+ }
+
+ Index::iterator it_y = index.end();
+ do {
+ --it_y;
+ int y = -it_y.key();
+ SubIndex &subindex = it_y.value();
+ if (y < start) {
+ if (cleanSpanSubIndex(subindex, y))
+ it_y = index.erase(it_y);
+ } else if (y >= start && y <= end) {
+ bool span_at_start = false;
+ SubIndex spansToBeMoved;
+ for (SubIndex::iterator it = subindex.begin(); it != subindex.end(); ++it) {
+ Span *span = it.value();
+ if (span->will_be_deleted)
+ continue;
+ if (!span_at_start && span->m_top == start)
+ span_at_start = true;
+ spansToBeMoved.insert(it.key(), span);
+ }
+
+ if (y == start && span_at_start)
+ subindex.clear();
+ else
+ it_y = index.erase(it_y);
+
+ if (span_at_start) {
+ Index::iterator it_start;
+ if (y == start)
+ it_start = it_y;
+ else {
+ it_start = index.find(-start);
+ if (it_start == index.end())
+ it_start = index.insert(-start, SubIndex());
+ }
+ SubIndex &start_subindex = it_start.value();
+ for (SubIndex::iterator it = spansToBeMoved.begin(); it != spansToBeMoved.end(); ++it)
+ start_subindex.insert(it.key(), it.value());
+ }
+ } else {
+ if (y == end + 1) {
+ Index::iterator it_top = index.find(-y + delta);
+ if (it_top == index.end())
+ it_top = index.insert(-y + delta, SubIndex());
+ for (SubIndex::iterator it = subindex.begin(); it != subindex.end(); ) {
+ Span *span = it.value();
+ if (!span->will_be_deleted)
+ it_top.value().insert(it.key(), span);
+ ++it;
+ }
+ } else {
+ index.insert(-y + delta, subindex);
+ }
+ it_y = index.erase(it_y);
+ }
+ } while (it_y != index.begin());
+
+#ifdef DEBUG_SPAN_UPDATE
+ qDebug() << index;
+ qDebug("Deleted");
+ foreach (QSpanCollection::Span *span, spansToBeDeleted)
+ qDebug() << span << *span;
+#endif
+ qDeleteAll(spansToBeDeleted);
+}
+
+/** \internal
+* Updates the span collection after column removal.
+*/
+void QSpanCollection::updateRemovedColumns(int start, int end)
+{
+#ifdef DEBUG_SPAN_UPDATE
+ qDebug() << Q_FUNC_INFO;
+ qDebug() << start << end;
+ qDebug() << index;
+#endif
+ if (spans.isEmpty())
+ return;
+
+ SpanList toBeDeleted;
+ int delta = end - start + 1;
+#ifdef DEBUG_SPAN_UPDATE
+ qDebug("Before");
+#endif
+ for (SpanList::iterator it = spans.begin(); it != spans.end(); ) {
+ Span *span = *it;
+#ifdef DEBUG_SPAN_UPDATE
+ qDebug() << span << *span;
+#endif
+ if (span->m_right < start) {
+ ++it;
+ continue;
+ }
+ if (span->m_left < start) {
+ if (span->m_right <= end)
+ span->m_right = start - 1;
+ else
+ span->m_right -= delta;
+ } else {
+ if (span->m_right > end) {
+ if (span->m_left <= end)
+ span->m_left = start;
+ else
+ span->m_left -= delta;
+ span->m_right -= delta;
+ } else {
+ span->will_be_deleted = true;
+ }
+ }
+ if (span->m_top == span->m_bottom && span->m_left == span->m_right)
+ span->will_be_deleted = true;
+ if (span->will_be_deleted) {
+ toBeDeleted.append(span);
+ it = spans.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+#ifdef DEBUG_SPAN_UPDATE
+ qDebug("After");
+ foreach (QSpanCollection::Span *span, spans)
+ qDebug() << span << *span;
+#endif
+ if (spans.isEmpty()) {
+ qDeleteAll(toBeDeleted);
+ index.clear();
+ return;
+ }
+
+ for (Index::iterator it_y = index.begin(); it_y != index.end(); ) {
+ int y = -it_y.key();
+ if (cleanSpanSubIndex(it_y.value(), y, true))
+ it_y = index.erase(it_y);
+ else
+ ++it_y;
+ }
+
+#ifdef DEBUG_SPAN_UPDATE
+ qDebug() << index;
+ qDebug("Deleted");
+ foreach (QSpanCollection::Span *span, toBeDeleted)
+ qDebug() << span << *span;
+#endif
+ qDeleteAll(toBeDeleted);
+}
+
class QTableCornerButton : public QAbstractButton
{
Q_OBJECT
@@ -299,6 +652,9 @@ void QTableViewPrivate::setSpan(int row, int column, int rowSpan, int columnSpan
sp->m_right = column + columnSpan - 1;
spans.updateSpan(sp, old_height);
return;
+ } else if (rowSpan == 1 && columnSpan == 1) {
+ qWarning() << "QTableView::setSpan: single cell span won't be added";
+ return;
}
sp = new QSpanCollection::Span(row, column, rowSpan, columnSpan);
spans.addSpan(sp);
@@ -460,6 +816,46 @@ void QTableViewPrivate::drawAndClipSpans(const QRegion &area, QPainter *painter,
/*!
\internal
+ Updates spans after row insertion.
+*/
+void QTableViewPrivate::_q_updateSpanInsertedRows(const QModelIndex &parent, int start, int end)
+{
+ Q_UNUSED(parent)
+ spans.updateInsertedRows(start, end);
+}
+
+/*!
+ \internal
+ Updates spans after column insertion.
+*/
+void QTableViewPrivate::_q_updateSpanInsertedColumns(const QModelIndex &parent, int start, int end)
+{
+ Q_UNUSED(parent)
+ spans.updateInsertedColumns(start, end);
+}
+
+/*!
+ \internal
+ Updates spans after row removal.
+*/
+void QTableViewPrivate::_q_updateSpanRemovedRows(const QModelIndex &parent, int start, int end)
+{
+ Q_UNUSED(parent)
+ spans.updateRemovedRows(start, end);
+}
+
+/*!
+ \internal
+ Updates spans after column removal.
+*/
+void QTableViewPrivate::_q_updateSpanRemovedColumns(const QModelIndex &parent, int start, int end)
+{
+ Q_UNUSED(parent)
+ spans.updateRemovedColumns(start, end);
+}
+
+/*!
+ \internal
Draws a table cell.
*/
void QTableViewPrivate::drawCell(QPainter *painter, const QStyleOptionViewItemV4 &option, const QModelIndex &index)
@@ -629,6 +1025,14 @@ QTableView::~QTableView()
void QTableView::setModel(QAbstractItemModel *model)
{
Q_D(QTableView);
+ connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
+ this, SLOT(_q_updateSpanInsertedRows(QModelIndex,int,int)));
+ connect(model, SIGNAL(columnsInserted(QModelIndex,int,int)),
+ this, SLOT(_q_updateSpanInsertedColumns(QModelIndex,int,int)));
+ connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
+ this, SLOT(_q_updateSpanRemovedRows(QModelIndex,int,int)));
+ connect(model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
+ this, SLOT(_q_updateSpanRemovedColumns(QModelIndex,int,int)));
d->verticalHeader->setModel(model);
d->horizontalHeader->setModel(model);
QAbstractItemView::setModel(model);
diff --git a/src/gui/itemviews/qtableview.h b/src/gui/itemviews/qtableview.h
index a08d6a9..541c419 100644
--- a/src/gui/itemviews/qtableview.h
+++ b/src/gui/itemviews/qtableview.h
@@ -182,6 +182,10 @@ private:
Q_DISABLE_COPY(QTableView)
Q_PRIVATE_SLOT(d_func(), void _q_selectRow(int))
Q_PRIVATE_SLOT(d_func(), void _q_selectColumn(int))
+ Q_PRIVATE_SLOT(d_func(), void _q_updateSpanInsertedRows(QModelIndex,int,int))
+ Q_PRIVATE_SLOT(d_func(), void _q_updateSpanInsertedColumns(QModelIndex,int,int))
+ Q_PRIVATE_SLOT(d_func(), void _q_updateSpanRemovedRows(QModelIndex,int,int))
+ Q_PRIVATE_SLOT(d_func(), void _q_updateSpanRemovedColumns(QModelIndex,int,int))
};
#endif // QT_NO_TABLEVIEW
diff --git a/src/gui/itemviews/qtableview_p.h b/src/gui/itemviews/qtableview_p.h
index 36a3ece..c785bd7 100644
--- a/src/gui/itemviews/qtableview_p.h
+++ b/src/gui/itemviews/qtableview_p.h
@@ -54,6 +54,7 @@
//
#include <QtCore/QList>
+#include <QtCore/QLinkedList>
#include <QtCore/QMap>
#include <QtCore/QSet>
#include <QtCore/QDebug>
@@ -82,10 +83,11 @@ public:
int m_left;
int m_bottom;
int m_right;
+ bool will_be_deleted;
Span()
- : m_top(-1), m_left(-1), m_bottom(-1), m_right(-1) { }
+ : m_top(-1), m_left(-1), m_bottom(-1), m_right(-1), will_be_deleted(false) { }
Span(int row, int column, int rowCount, int columnCount)
- : m_top(row), m_left(column), m_bottom(row+rowCount-1), m_right(column+columnCount-1) { }
+ : m_top(row), m_left(column), m_bottom(row+rowCount-1), m_right(column+columnCount-1), will_be_deleted(false) { }
inline int top() const { return m_top; }
inline int left() const { return m_left; }
inline int bottom() const { return m_bottom; }
@@ -105,12 +107,20 @@ public:
void clear();
QList<Span *> spansInRect(int x, int y, int w, int h) const;
- QList<Span *> spans; //lists of all spans
+ void updateInsertedRows(int start, int end);
+ void updateInsertedColumns(int start, int end);
+ void updateRemovedRows(int start, int end);
+ void updateRemovedColumns(int start, int end);
+
+ typedef QLinkedList<Span *> SpanList;
+ SpanList spans; //lists of all spans
private:
//the indexes are negative so the QMap::lowerBound do what i need.
typedef QMap<int, Span *> SubIndex;
typedef QMap<int, SubIndex> Index;
Index index;
+
+ bool cleanSpanSubIndex(SubIndex &subindex, int end, bool update = false);
};
Q_DECLARE_TYPEINFO ( QSpanCollection::Span, Q_MOVABLE_TYPE);
@@ -227,6 +237,11 @@ public:
void selectRow(int row, bool anchor);
void selectColumn(int column, bool anchor);
+
+ void _q_updateSpanInsertedRows(const QModelIndex &parent, int start, int end);
+ void _q_updateSpanInsertedColumns(const QModelIndex &parent, int start, int end);
+ void _q_updateSpanRemovedRows(const QModelIndex &parent, int start, int end);
+ void _q_updateSpanRemovedColumns(const QModelIndex &parent, int start, int end);
};
QT_END_NAMESPACE
diff --git a/tests/auto/qtableview/tst_qtableview.cpp b/tests/auto/qtableview/tst_qtableview.cpp
index deb0b71..4bf7c2e 100644
--- a/tests/auto/qtableview/tst_qtableview.cpp
+++ b/tests/auto/qtableview/tst_qtableview.cpp
@@ -164,6 +164,10 @@ private slots:
void span();
void spans();
void spans_data();
+ void spansAfterRowInsertion();
+ void spansAfterColumnInsertion();
+ void spansAfterRowRemoval();
+ void spansAfterColumnRemoval();
void checkHeaderReset();
void checkHeaderMinSize();
@@ -268,6 +272,28 @@ public:
return QVariant();
}
+ bool insertRows(int start, int count, const QModelIndex &parent = QModelIndex())
+ {
+ if (start < 0 || start > row_count)
+ return false;
+
+ beginInsertRows(parent, start, start + count - 1);
+ row_count += count;
+ endInsertRows();
+ return true;
+ }
+
+ bool removeRows(int start, int count, const QModelIndex &parent = QModelIndex())
+ {
+ if (start < 0 || start >= row_count || row_count < count)
+ return false;
+
+ beginRemoveRows(parent, start, start + count - 1);
+ row_count -= count;
+ endRemoveRows();
+ return true;
+ }
+
void removeLastRow()
{
beginRemoveRows(QModelIndex(), row_count - 1, row_count - 1);
@@ -282,6 +308,28 @@ public:
endRemoveRows();
}
+ bool insertColumns(int start, int count, const QModelIndex &parent = QModelIndex())
+ {
+ if (start < 0 || start > column_count)
+ return false;
+
+ beginInsertColumns(parent, start, start + count - 1);
+ column_count += count;
+ endInsertColumns();
+ return true;
+ }
+
+ bool removeColumns(int start, int count, const QModelIndex &parent = QModelIndex())
+ {
+ if (start < 0 || start >= column_count || column_count < count)
+ return false;
+
+ beginRemoveColumns(parent, start, start + count - 1);
+ column_count -= count;
+ endRemoveColumns();
+ return true;
+ }
+
void removeLastColumn()
{
beginRemoveColumns(QModelIndex(), column_count - 1, column_count - 1);
@@ -2608,7 +2656,7 @@ void tst_QTableView::span_data()
<< -1 << -1
<< 6 << 6
<< 3 << 3
- << 3 << 3
+ << 2 << 3
<< true;
}
@@ -2797,6 +2845,149 @@ void tst_QTableView::spans()
QCOMPARE(view.rowSpan(pos.x(), pos.y()), expectedRowSpan);
}
+void tst_QTableView::spansAfterRowInsertion()
+{
+ QtTestTableModel model(10, 10);
+ QtTestTableView view;
+ view.setModel(&model);
+ view.setSpan(3, 3, 3, 3);
+ view.show();
+ QTest::qWait(50);
+
+ // Insertion before the span only shifts the span.
+ view.model()->insertRows(0, 2);
+ QCOMPARE(view.rowSpan(3, 3), 1);
+ QCOMPARE(view.columnSpan(3, 3), 1);
+ QCOMPARE(view.rowSpan(5, 3), 3);
+ QCOMPARE(view.columnSpan(5, 3), 3);
+
+ // Insertion happens before the given row, so it only shifts the span also.
+ view.model()->insertRows(5, 2);
+ QCOMPARE(view.rowSpan(5, 3), 1);
+ QCOMPARE(view.columnSpan(5, 3), 1);
+ QCOMPARE(view.rowSpan(7, 3), 3);
+ QCOMPARE(view.columnSpan(7, 3), 3);
+
+ // Insertion inside the span expands it.
+ view.model()->insertRows(8, 2);
+ QCOMPARE(view.rowSpan(7, 3), 5);
+ QCOMPARE(view.columnSpan(7, 3), 3);
+
+ // Insertion after the span does nothing to it.
+ view.model()->insertRows(12, 2);
+ QCOMPARE(view.rowSpan(7, 3), 5);
+ QCOMPARE(view.columnSpan(7, 3), 3);
+}
+
+void tst_QTableView::spansAfterColumnInsertion()
+{
+ QtTestTableModel model(10, 10);
+ QtTestTableView view;
+ view.setModel(&model);
+ view.setSpan(3, 3, 3, 3);
+ view.show();
+ QTest::qWait(50);
+
+ // Insertion before the span only shifts the span.
+ view.model()->insertColumns(0, 2);
+ QCOMPARE(view.rowSpan(3, 3), 1);
+ QCOMPARE(view.columnSpan(3, 3), 1);
+ QCOMPARE(view.rowSpan(3, 5), 3);
+ QCOMPARE(view.columnSpan(3, 5), 3);
+
+ // Insertion happens before the given column, so it only shifts the span also.
+ view.model()->insertColumns(5, 2);
+ QCOMPARE(view.rowSpan(3, 5), 1);
+ QCOMPARE(view.columnSpan(3, 5), 1);
+ QCOMPARE(view.rowSpan(3, 7), 3);
+ QCOMPARE(view.columnSpan(3, 7), 3);
+
+ // Insertion inside the span expands it.
+ view.model()->insertColumns(8, 2);
+ QCOMPARE(view.rowSpan(3, 7), 3);
+ QCOMPARE(view.columnSpan(3, 7), 5);
+
+ // Insertion after the span does nothing to it.
+ view.model()->insertColumns(12, 2);
+ QCOMPARE(view.rowSpan(3, 7), 3);
+ QCOMPARE(view.columnSpan(3, 7), 5);
+}
+
+void tst_QTableView::spansAfterRowRemoval()
+{
+ QtTestTableModel model(10, 10);
+ QtTestTableView view;
+ view.setModel(&model);
+
+ QList<QRect> spans;
+ spans << QRect(0, 1, 1, 2)
+ << QRect(1, 2, 1, 2)
+ << QRect(2, 2, 1, 5)
+ << QRect(2, 8, 1, 2)
+ << QRect(3, 4, 1, 2)
+ << QRect(4, 4, 1, 4)
+ << QRect(5, 6, 1, 3)
+ << QRect(6, 7, 1, 3);
+ foreach (QRect span, spans)
+ view.setSpan(span.top(), span.left(), span.height(), span.width());
+
+ view.show();
+ QTest::qWait(100);
+ view.model()->removeRows(3, 3);
+
+ QList<QRect> expectedSpans;
+ expectedSpans << QRect(0, 1, 1, 2)
+ << QRect(1, 2, 1, 1)
+ << QRect(2, 2, 1, 2)
+ << QRect(2, 5, 1, 2)
+ << QRect(3, 4, 1, 1)
+ << QRect(4, 3, 1, 2)
+ << QRect(5, 3, 1, 3)
+ << QRect(6, 4, 1, 3);
+ foreach (QRect span, expectedSpans) {
+ QCOMPARE(view.columnSpan(span.top(), span.left()), span.width());
+ QCOMPARE(view.rowSpan(span.top(), span.left()), span.height());
+ }
+}
+
+void tst_QTableView::spansAfterColumnRemoval()
+{
+ QtTestTableModel model(10, 10);
+ QtTestTableView view;
+ view.setModel(&model);
+
+ // Same set as above just swapping columns and rows.
+ QList<QRect> spans;
+ spans << QRect(0, 1, 1, 2)
+ << QRect(1, 2, 1, 2)
+ << QRect(2, 2, 1, 5)
+ << QRect(2, 8, 1, 2)
+ << QRect(3, 4, 1, 2)
+ << QRect(4, 4, 1, 4)
+ << QRect(5, 6, 1, 3)
+ << QRect(6, 7, 1, 3);
+ foreach (QRect span, spans)
+ view.setSpan(span.left(), span.top(), span.width(), span.height());
+
+ view.show();
+ QTest::qWait(100);
+ view.model()->removeColumns(3, 3);
+
+ QList<QRect> expectedSpans;
+ expectedSpans << QRect(0, 1, 1, 2)
+ << QRect(1, 2, 1, 1)
+ << QRect(2, 2, 1, 2)
+ << QRect(2, 5, 1, 2)
+ << QRect(3, 4, 1, 1)
+ << QRect(4, 3, 1, 2)
+ << QRect(5, 3, 1, 3)
+ << QRect(6, 4, 1, 3);
+ foreach (QRect span, expectedSpans) {
+ QCOMPARE(view.columnSpan(span.left(), span.top()), span.height());
+ QCOMPARE(view.rowSpan(span.left(), span.top()), span.width());
+ }
+}
+
class Model : public QAbstractTableModel {
Q_OBJECT
diff --git a/tests/benchmarks/qtableview/tst_qtableview.cpp b/tests/benchmarks/qtableview/tst_qtableview.cpp
index deeba3f..7247a23 100644
--- a/tests/benchmarks/qtableview/tst_qtableview.cpp
+++ b/tests/benchmarks/qtableview/tst_qtableview.cpp
@@ -75,6 +75,50 @@ public:
return QVariant();
}
+ bool insertRows(int start, int count, const QModelIndex &parent = QModelIndex())
+ {
+ if (start < 0 || start > row_count)
+ return false;
+
+ beginInsertRows(parent, start, start + count - 1);
+ row_count += count;
+ endInsertRows();
+ return true;
+ }
+
+ bool removeRows(int start, int count, const QModelIndex &parent = QModelIndex())
+ {
+ if (start < 0 || start >= row_count || row_count < count)
+ return false;
+
+ beginRemoveRows(parent, start, start + count - 1);
+ row_count -= count;
+ endRemoveRows();
+ return true;
+ }
+
+ bool insertColumns(int start, int count, const QModelIndex &parent = QModelIndex())
+ {
+ if (start < 0 || start > column_count)
+ return false;
+
+ beginInsertColumns(parent, start, start + count - 1);
+ column_count += count;
+ endInsertColumns();
+ return true;
+ }
+
+ bool removeColumns(int start, int count, const QModelIndex &parent = QModelIndex())
+ {
+ if (start < 0 || start >= column_count || column_count < count)
+ return false;
+
+ beginRemoveColumns(parent, start, start + count - 1);
+ column_count -= count;
+ endRemoveColumns();
+ return true;
+ }
+
int row_count;
int column_count;
};
@@ -99,6 +143,14 @@ private slots:
void spanDraw();
void spanSelectColumn();
void spanSelectAll();
+ void rowInsertion_data();
+ void rowInsertion();
+ void rowRemoval_data();
+ void rowRemoval();
+ void columnInsertion_data();
+ void columnInsertion();
+ void columnRemoval_data();
+ void columnRemoval();
private:
static inline void spanInit_helper(QTableView *);
};
@@ -189,5 +241,127 @@ void tst_QTableView::spanSelectColumn()
}
}
+typedef QVector<QRect> SpanList;
+Q_DECLARE_METATYPE(SpanList)
+
+void spansData()
+{
+ QTest::addColumn<SpanList>("spans");
+
+ QTest::newRow("Without spans")
+ << SpanList();
+
+ QTest::newRow("With spans")
+ << (SpanList()
+ << QRect(0, 1, 1, 2)
+ << QRect(1, 2, 1, 2)
+ << QRect(2, 2, 1, 5)
+ << QRect(2, 8, 1, 2)
+ << QRect(3, 4, 1, 2)
+ << QRect(4, 4, 1, 4)
+ << QRect(5, 6, 1, 3)
+ << QRect(6, 7, 1, 3));
+}
+
+void tst_QTableView::rowInsertion_data()
+{
+ spansData();
+}
+
+void tst_QTableView::rowInsertion()
+{
+ QFETCH(SpanList, spans);
+
+ QtTestTableModel model(10, 10);
+ QTableView view;
+ view.setModel(&model);
+
+ foreach (QRect span, spans)
+ view.setSpan(span.top(), span.left(), span.height(), span.width());
+ view.show();
+ QTest::qWait(50);
+
+ QBENCHMARK_ONCE {
+ view.model()->insertRows(0, 2);
+ view.model()->insertRows(5, 2);
+ view.model()->insertRows(8, 2);
+ view.model()->insertRows(12, 2);
+ }
+}
+
+void tst_QTableView::rowRemoval_data()
+{
+ spansData();
+}
+
+void tst_QTableView::rowRemoval()
+{
+ QFETCH(SpanList, spans);
+
+ QtTestTableModel model(10, 10);
+ QTableView view;
+ view.setModel(&model);
+
+ foreach (QRect span, spans)
+ view.setSpan(span.top(), span.left(), span.height(), span.width());
+ view.show();
+ QTest::qWait(50);
+
+ QBENCHMARK_ONCE {
+ view.model()->removeRows(3, 3);
+ }
+}
+
+void tst_QTableView::columnInsertion_data()
+{
+ spansData();
+}
+
+void tst_QTableView::columnInsertion()
+{
+ QFETCH(SpanList, spans);
+
+ QtTestTableModel model(10, 10);
+ QTableView view;
+ view.setModel(&model);
+
+ // Same set as for rowInsertion, just swapping columns and rows.
+ foreach (QRect span, spans)
+ view.setSpan(span.left(), span.top(), span.width(), span.height());
+ view.show();
+ QTest::qWait(50);
+
+ QBENCHMARK_ONCE {
+ view.model()->insertColumns(0, 2);
+ view.model()->insertColumns(5, 2);
+ view.model()->insertColumns(8, 2);
+ view.model()->insertColumns(12, 2);
+ }
+}
+
+void tst_QTableView::columnRemoval_data()
+{
+ spansData();
+}
+
+void tst_QTableView::columnRemoval()
+{
+ QFETCH(SpanList, spans);
+
+ QtTestTableModel model(10, 10);
+ QTableView view;
+ view.setModel(&model);
+
+ // Same set as for rowRemoval, just swapping columns and rows.
+ foreach (QRect span, spans)
+ view.setSpan(span.left(), span.top(), span.width(), span.height());
+ view.show();
+ QTest::qWait(50);
+
+ QBENCHMARK_ONCE {
+ view.model()->removeColumns(3, 3);
+ }
+}
+
QTEST_MAIN(tst_QTableView)
#include "tst_qtableview.moc"