From 83c9ebbd6692cde99ee692e6549c591100f12545 Mon Sep 17 00:00:00 2001 From: Mark Brand Date: Mon, 23 Apr 2012 01:06:17 +0200 Subject: QSqlQueryModel::setQuery() don't use deprecated reset() Previously the method attempted to reset only as a last resort. Now reset() is deprecated and resetting must happen between emitting modelAboutToBeReset() and modelReset(). Since this suffices in all cases to notify views that they must reinterrogate the model, it is no longer necessary to signal explicitly row removals and insertions within the scope of the reset. Additionally, fetchMore() is now called within the scope of the reset so insert signals do not have to be emitted here either. This improved handling of resetting in QSqlQueryModel also allows the cache in QSqlTableModel to be cleared directly at select(). This change may actually allow views to operate more efficiently since they no longer have to react to separate row removal and insert signals. Views can avoid pointless deallocation and reallocation by considering row count only after the reset is finished. The cost is that the columns and horizontal headers must be considered in the view at each setQuery() call. In any case, it is not clear that trying to be smart about this in the model justifies additional complexity. Tests had to be adjusted where they expected explicit row removal and insert signals. Change-Id: I4f7eac1419824361d7d9bdcc6a87092b33e80d7a Task-Id: QTBUG-25419 Reviewed-by: Andy Shaw Reviewed-by: Olivier Goffart Reviewed-by: Honglei Zhang --- src/sql/models/qsqlquerymodel.cpp | 85 ++++++++++++++++++++++----------------- src/sql/models/qsqlquerymodel.h | 2 + src/sql/models/qsqlquerymodel_p.h | 3 +- src/sql/models/qsqltablemodel.cpp | 17 +++----- 4 files changed, 57 insertions(+), 50 deletions(-) (limited to 'src/sql/models') diff --git a/src/sql/models/qsqlquerymodel.cpp b/src/sql/models/qsqlquerymodel.cpp index 7b884edab8..85869e41ac 100644 --- a/src/sql/models/qsqlquerymodel.cpp +++ b/src/sql/models/qsqlquerymodel.cpp @@ -78,9 +78,11 @@ void QSqlQueryModelPrivate::prefetch(int limit) atEnd = true; // this is the end. } if (newBottom.row() >= 0 && newBottom.row() > bottom.row()) { - q->beginInsertRows(QModelIndex(), bottom.row() + 1, newBottom.row()); + if (!resetting) + q->beginInsertRows(QModelIndex(), bottom.row() + 1, newBottom.row()); bottom = newBottom; - q->endInsertRows(); + if (!resetting) + q->endInsertRows(); } else { bottom = newBottom; } @@ -208,6 +210,28 @@ bool QSqlQueryModel::canFetchMore(const QModelIndex &parent) const return (!parent.isValid() && !d->atEnd); } +/*! \reimp + */ +void QSqlQueryModel::beginResetModel() +{ + Q_D(QSqlQueryModel); + if (!d->resetting) { + QAbstractTableModel::beginResetModel(); + d->resetting = true; + } +} + +/*! \reimp + */ +void QSqlQueryModel::endResetModel() +{ + Q_D(QSqlQueryModel); + if (d->resetting) { + d->resetting = false; + QAbstractTableModel::endResetModel(); + } +} + /*! \fn int QSqlQueryModel::rowCount(const QModelIndex &parent) const \since 4.1 @@ -317,60 +341,47 @@ void QSqlQueryModel::queryChange() void QSqlQueryModel::setQuery(const QSqlQuery &query) { Q_D(QSqlQueryModel); + beginResetModel(); + QSqlRecord newRec = query.record(); bool columnsChanged = (newRec != d->rec); - bool hasQuerySize = query.driver()->hasFeature(QSqlDriver::QuerySize); - bool hasNewData = (newRec != QSqlRecord()) || !query.lastError().isValid(); if (d->colOffsets.size() != newRec.count() || columnsChanged) d->initColOffsets(newRec.count()); - bool mustClearModel = d->bottom.isValid(); - if (mustClearModel) { - d->atEnd = true; - beginRemoveRows(QModelIndex(), 0, qMax(d->bottom.row(), 0)); - d->bottom = QModelIndex(); - } - + d->bottom = QModelIndex(); d->error = QSqlError(); d->query = query; d->rec = newRec; + d->atEnd = true; - if (mustClearModel) - endRemoveRows(); - - d->atEnd = false; - - if (columnsChanged && hasNewData) - reset(); + if (query.isForwardOnly()) { + d->error = QSqlError(QLatin1String("Forward-only queries " + "cannot be used in a data model"), + QString(), QSqlError::ConnectionError); + endResetModel(); + return; + } - if (!query.isActive() || query.isForwardOnly()) { - d->atEnd = true; - d->bottom = QModelIndex(); - if (query.isForwardOnly()) - d->error = QSqlError(QLatin1String("Forward-only queries " - "cannot be used in a data model"), - QString(), QSqlError::ConnectionError); - else - d->error = query.lastError(); + if (!query.isActive()) { + d->error = query.lastError(); + endResetModel(); return; } - QModelIndex newBottom; - if (hasQuerySize && d->query.size() > 0) { - newBottom = createIndex(d->query.size() - 1, d->rec.count() - 1); - beginInsertRows(QModelIndex(), 0, qMax(0, newBottom.row())); - d->bottom = createIndex(d->query.size() - 1, columnsChanged ? 0 : d->rec.count() - 1); - d->atEnd = true; - endInsertRows(); + + if (query.driver()->hasFeature(QSqlDriver::QuerySize) && d->query.size() > 0) { + d->bottom = createIndex(d->query.size() - 1, d->rec.count() - 1); } else { - newBottom = createIndex(-1, d->rec.count() - 1); + d->bottom = createIndex(-1, d->rec.count() - 1); + d->atEnd = false; } - d->bottom = newBottom; - queryChange(); // fetchMore does the rowsInserted stuff for incremental models fetchMore(); + + endResetModel(); + queryChange(); } /*! \overload diff --git a/src/sql/models/qsqlquerymodel.h b/src/sql/models/qsqlquerymodel.h index b5e1a7a746..89b72c8222 100644 --- a/src/sql/models/qsqlquerymodel.h +++ b/src/sql/models/qsqlquerymodel.h @@ -90,6 +90,8 @@ public: bool canFetchMore(const QModelIndex &parent = QModelIndex()) const; protected: + void beginResetModel(); + void endResetModel(); virtual void queryChange(); virtual QModelIndex indexInQuery(const QModelIndex &item) const; diff --git a/src/sql/models/qsqlquerymodel_p.h b/src/sql/models/qsqlquerymodel_p.h index 6e0349f032..3288d311a4 100644 --- a/src/sql/models/qsqlquerymodel_p.h +++ b/src/sql/models/qsqlquerymodel_p.h @@ -67,7 +67,7 @@ class QSqlQueryModelPrivate: public QAbstractItemModelPrivate { Q_DECLARE_PUBLIC(QSqlQueryModel) public: - QSqlQueryModelPrivate() : atEnd(false) {} + QSqlQueryModelPrivate() : atEnd(false), resetting(false) {} ~QSqlQueryModelPrivate(); void prefetch(int); @@ -80,6 +80,7 @@ public: uint atEnd : 1; QVector > headers; QVarLengthArray colOffsets; // used to calculate indexInQuery of columns + bool resetting; }; // helpers for building SQL expressions diff --git a/src/sql/models/qsqltablemodel.cpp b/src/sql/models/qsqltablemodel.cpp index f7198978dd..40315da204 100644 --- a/src/sql/models/qsqltablemodel.cpp +++ b/src/sql/models/qsqltablemodel.cpp @@ -364,18 +364,9 @@ bool QSqlTableModel::select() if (query.isEmpty()) return false; - QSqlTableModelPrivate::CacheMap::Iterator it = d->cache.end(); - while (it != d->cache.constBegin()) { - --it; - // rows must be accounted for - if (it.value().insert()) { - beginRemoveRows(QModelIndex(), it.key(), it.key()); - it = d->cache.erase(it); - endRemoveRows(); - } else { - it = d->cache.erase(it); - } - } + beginResetModel(); + + d->clearCache(); QSqlQuery qu(query, d->db); setQuery(qu); @@ -383,8 +374,10 @@ bool QSqlTableModel::select() if (!qu.isActive() || lastError().isValid()) { // something went wrong - revert to non-select state d->initRecordAndPrimaryIndex(); + endResetModel(); return false; } + endResetModel(); return true; } -- cgit v1.2.3