Only emit headerDataChanged for valid proxy intervals.
authorStephen Kelly <stephen.kelly@kdab.com>
Wed, 8 Aug 2012 12:56:14 +0000 (14:56 +0200)
committerQt by Nokia <qt-info@nokia.com>
Wed, 15 Aug 2012 13:04:11 +0000 (15:04 +0200)
Modeltest asserts before the patch, and passes afterward.

Task-number: QTBUG-26515

Change-Id: I08a89cd5c9c59613badcddbd056a3d0b8fbbca13
Reviewed-by: Marc Mutz <marc.mutz@kdab.com>
Reviewed-by: Stephen Kelly <stephen.kelly@kdab.com>
src/corelib/itemmodels/qsortfilterproxymodel.cpp
tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp
tests/auto/other/modeltest/modeltest.cpp
tests/auto/other/modeltest/modeltest.h

index fb84dce..7863dc6 100644 (file)
@@ -1226,15 +1226,43 @@ void QSortFilterProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &sourc
 void QSortFilterProxyModelPrivate::_q_sourceHeaderDataChanged(Qt::Orientation orientation,
                                                            int start, int end)
 {
+    Q_ASSERT(start <= end);
+
     Q_Q(QSortFilterProxyModel);
     Mapping *m = create_mapping(QModelIndex()).value();
-    int proxy_start = (orientation == Qt::Vertical
-                       ? m->proxy_rows.at(start)
-                       : m->proxy_columns.at(start));
-    int proxy_end = (orientation == Qt::Vertical
-                     ? m->proxy_rows.at(end)
-                     : m->proxy_columns.at(end));
-    emit q->headerDataChanged(orientation, proxy_start, proxy_end);
+
+    const QVector<int> &source_to_proxy = (orientation == Qt::Vertical) ? m->proxy_rows : m->proxy_columns;
+
+    QVector<int> proxy_positions;
+    proxy_positions.reserve(end - start + 1);
+    {
+        Q_ASSERT(source_to_proxy.size() > end);
+        QVector<int>::const_iterator it = source_to_proxy.constBegin() + start;
+        const QVector<int>::const_iterator endIt = source_to_proxy.constBegin() + end + 1;
+        for ( ; it != endIt; ++it) {
+            if (*it != -1)
+                proxy_positions.push_back(*it);
+        }
+    }
+
+    qSort(proxy_positions);
+
+    int last_index = 0;
+    const int numItems = proxy_positions.size();
+    while (last_index < numItems) {
+        const int proxyStart = proxy_positions.at(last_index);
+        int proxyEnd = proxyStart;
+        ++last_index;
+        for (int i = last_index; i < numItems; ++i) {
+            if (proxy_positions.at(i) == proxyEnd + 1) {
+                ++last_index;
+                ++proxyEnd;
+            } else {
+                break;
+            }
+        }
+        emit q->headerDataChanged(orientation, proxyStart, proxyEnd);
+    }
 }
 
 void QSortFilterProxyModelPrivate::_q_sourceAboutToBeReset()
index 3770abb..444d26c 100644 (file)
@@ -140,6 +140,7 @@ private slots:
     void testMultipleProxiesWithSelection();
     void mapSelectionFromSource();
     void filteredColumns();
+    void headerDataChanged();
 
     void testParentLayoutChanged();
     void moveSourceRows();
@@ -3155,6 +3156,40 @@ void tst_QSortFilterProxyModel::filteredColumns()
     insertCommand->doCommand();
 }
 
+class ChangableHeaderData : public QStringListModel
+{
+    Q_OBJECT
+public:
+    explicit ChangableHeaderData(QObject *parent = 0)
+      : QStringListModel(parent)
+    {
+
+    }
+
+    void emitHeaderDataChanged()
+    {
+        headerDataChanged(Qt::Vertical, 0, rowCount() - 1);
+    }
+};
+
+
+void tst_QSortFilterProxyModel::headerDataChanged()
+{
+    ChangableHeaderData *model = new ChangableHeaderData(this);
+
+    QStringList numbers;
+    for (int i = 0; i < 10; ++i)
+        numbers.append(QString::number(i));
+    model->setStringList(numbers);
+
+    QSortFilterProxyModel *proxy = new QSortFilterProxyModel(this);
+    proxy->setSourceModel(model);
+
+    new ModelTest(proxy, this);
+
+    model->emitHeaderDataChanged();
+}
+
 void tst_QSortFilterProxyModel::resetInvalidate_data()
 {
     QTest::addColumn<int>("test");
index 98f6600..c204a74 100644 (file)
@@ -80,7 +80,7 @@ ModelTest::ModelTest ( QAbstractItemModel *_model, QObject *parent ) : QObject (
     connect ( model, SIGNAL ( rowsRemoved ( const QModelIndex &, int, int ) ),
               this, SLOT ( runAllTests() ) );
 
-    // Special checks for inserting/removing
+    // Special checks for changes
     connect ( model, SIGNAL ( layoutAboutToBeChanged() ),
               this, SLOT ( layoutAboutToBeChanged() ) );
     connect ( model, SIGNAL ( layoutChanged() ),
@@ -94,6 +94,10 @@ ModelTest::ModelTest ( QAbstractItemModel *_model, QObject *parent ) : QObject (
               this, SLOT ( rowsInserted ( const QModelIndex &, int, int ) ) );
     connect ( model, SIGNAL ( rowsRemoved ( const QModelIndex &, int, int ) ),
               this, SLOT ( rowsRemoved ( const QModelIndex &, int, int ) ) );
+    connect ( model, SIGNAL ( dataChanged ( const QModelIndex &, const QModelIndex & ) ),
+              this, SLOT ( dataChanged ( const QModelIndex &, const QModelIndex & ) ) );
+    connect ( model, SIGNAL ( headerDataChanged ( Qt::Orientation, int, int ) ),
+              this, SLOT ( headerDataChanged ( Qt::Orientation, int, int ) ) );
 
     runAllTests();
 }
@@ -561,4 +565,27 @@ void ModelTest::rowsRemoved ( const QModelIndex & parent, int start, int end )
     QVERIFY( c.next == model->data ( model->index ( start, 0, c.parent ) ) );
 }
 
+void ModelTest::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
+{
+    QVERIFY(topLeft.isValid());
+    QVERIFY(bottomRight.isValid());
+    QModelIndex commonParent = bottomRight.parent();
+    QVERIFY(topLeft.parent() == commonParent);
+    QVERIFY(topLeft.row() <= bottomRight.row());
+    QVERIFY(topLeft.column() <= bottomRight.column());
+    int rowCount = model->rowCount(commonParent);
+    int columnCount = model->columnCount(commonParent);
+    QVERIFY(bottomRight.row() < rowCount);
+    QVERIFY(bottomRight.column() < columnCount);
+}
+
+void ModelTest::headerDataChanged(Qt::Orientation orientation, int start, int end)
+{
+    QVERIFY(start >= 0);
+    QVERIFY(end >= 0);
+    QVERIFY(start <= end);
+    int itemCount = orientation == Qt::Vertical ? model->rowCount() : model->columnCount();
+    QVERIFY(start < itemCount);
+    QVERIFY(end < itemCount);
+}
 
index 1b254a4..9c828db 100644 (file)
@@ -71,6 +71,8 @@ protected Q_SLOTS:
   void rowsInserted( const QModelIndex & parent, int start, int end );
   void rowsAboutToBeRemoved( const QModelIndex &parent, int start, int end );
   void rowsRemoved( const QModelIndex & parent, int start, int end );
+  void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
+  void headerDataChanged(Qt::Orientation orientation, int start, int end);
 
 private:
   void checkChildren( const QModelIndex &parent, int currentDepth = 0 );