QSqlQueryModel: fix nested beginResetModel/endResetModel
Follow-up to83c9ebbd66
. Consider the case where calls to the reset methods on the same object are nested as in the following sequence: 1. beginResetModel() 2. beginResetModel() 3. endResetModel() 4. endResetModel() In such cases, only the outermost calls, i.e., 1) and 4), should emit signals. After83c9ebbd66
, 1) and 3) emitted the signals, which is wrong. This is corrected by keeping track of the nesting level. Such sequences can come about when a base class calls the begin/end methods between the calls made by the subclass. QSqlTableModel::select() is an example of this. Test included. Change-Id: Ia62b45cb1abaab00a32bb8357de4a958bcff83e5 Reviewed-by: Andy Shaw <andy.shaw@digia.com> Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
This commit is contained in:
parent
98c663acd9
commit
c194b7f345
@ -78,10 +78,10 @@ void QSqlQueryModelPrivate::prefetch(int limit)
|
||||
atEnd = true; // this is the end.
|
||||
}
|
||||
if (newBottom.row() >= 0 && newBottom.row() > bottom.row()) {
|
||||
if (!resetting)
|
||||
if (!nestedResetLevel)
|
||||
q->beginInsertRows(QModelIndex(), bottom.row() + 1, newBottom.row());
|
||||
bottom = newBottom;
|
||||
if (!resetting)
|
||||
if (!nestedResetLevel)
|
||||
q->endInsertRows();
|
||||
} else {
|
||||
bottom = newBottom;
|
||||
@ -215,10 +215,9 @@ bool QSqlQueryModel::canFetchMore(const QModelIndex &parent) const
|
||||
void QSqlQueryModel::beginResetModel()
|
||||
{
|
||||
Q_D(QSqlQueryModel);
|
||||
if (!d->resetting) {
|
||||
if (!d->nestedResetLevel)
|
||||
QAbstractTableModel::beginResetModel();
|
||||
d->resetting = true;
|
||||
}
|
||||
++d->nestedResetLevel;
|
||||
}
|
||||
|
||||
/*! \internal
|
||||
@ -226,10 +225,9 @@ void QSqlQueryModel::beginResetModel()
|
||||
void QSqlQueryModel::endResetModel()
|
||||
{
|
||||
Q_D(QSqlQueryModel);
|
||||
if (d->resetting) {
|
||||
d->resetting = false;
|
||||
--d->nestedResetLevel;
|
||||
if (!d->nestedResetLevel)
|
||||
QAbstractTableModel::endResetModel();
|
||||
}
|
||||
}
|
||||
|
||||
/*! \fn int QSqlQueryModel::rowCount(const QModelIndex &parent) const
|
||||
|
@ -67,7 +67,7 @@ class QSqlQueryModelPrivate: public QAbstractItemModelPrivate
|
||||
{
|
||||
Q_DECLARE_PUBLIC(QSqlQueryModel)
|
||||
public:
|
||||
QSqlQueryModelPrivate() : atEnd(false), resetting(false) {}
|
||||
QSqlQueryModelPrivate() : atEnd(false), nestedResetLevel(0) {}
|
||||
~QSqlQueryModelPrivate();
|
||||
|
||||
void prefetch(int);
|
||||
@ -80,7 +80,7 @@ public:
|
||||
uint atEnd : 1;
|
||||
QVector<QHash<int, QVariant> > headers;
|
||||
QVarLengthArray<int, 56> colOffsets; // used to calculate indexInQuery of columns
|
||||
bool resetting;
|
||||
int nestedResetLevel;
|
||||
};
|
||||
|
||||
// helpers for building SQL expressions
|
||||
|
@ -91,6 +91,8 @@ private slots:
|
||||
void setQuerySignalEmission();
|
||||
void setQueryWithNoRowsInResultSet_data() { generic_data(); }
|
||||
void setQueryWithNoRowsInResultSet();
|
||||
void nestedResets_data() { generic_data(); }
|
||||
void nestedResets();
|
||||
|
||||
void task_180617();
|
||||
void task_180617_data() { generic_data(); }
|
||||
@ -585,6 +587,61 @@ void tst_QSqlQueryModel::setQueryWithNoRowsInResultSet()
|
||||
QCOMPARE(modelRowsInsertedSpy.count(), 0);
|
||||
}
|
||||
|
||||
class NestedResetsTest: public QSqlQueryModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
NestedResetsTest(QObject* parent = 0) : QSqlQueryModel(parent), gotAboutToBeReset(false), gotReset(false)
|
||||
{
|
||||
connect(this, SIGNAL(modelAboutToBeReset()), this, SLOT(modelAboutToBeResetSlot()));
|
||||
connect(this, SIGNAL(modelReset()), this, SLOT(modelResetSlot()));
|
||||
}
|
||||
|
||||
void testme()
|
||||
{
|
||||
// Only the outermost beginResetModel/endResetModel should
|
||||
// emit signals.
|
||||
gotAboutToBeReset = gotReset = false;
|
||||
beginResetModel();
|
||||
QCOMPARE(gotAboutToBeReset, true);
|
||||
QCOMPARE(gotReset, false);
|
||||
|
||||
gotAboutToBeReset = gotReset = false;
|
||||
beginResetModel();
|
||||
QCOMPARE(gotAboutToBeReset, false);
|
||||
QCOMPARE(gotReset, false);
|
||||
|
||||
gotAboutToBeReset = gotReset = false;
|
||||
endResetModel();
|
||||
QCOMPARE(gotAboutToBeReset, false);
|
||||
QCOMPARE(gotReset, false);
|
||||
|
||||
gotAboutToBeReset = gotReset = false;
|
||||
endResetModel();
|
||||
QCOMPARE(gotAboutToBeReset, false);
|
||||
QCOMPARE(gotReset, true);
|
||||
}
|
||||
|
||||
private slots:
|
||||
void modelAboutToBeResetSlot() { gotAboutToBeReset = true; }
|
||||
void modelResetSlot() { gotReset = true; }
|
||||
|
||||
private:
|
||||
bool gotAboutToBeReset;
|
||||
bool gotReset;
|
||||
};
|
||||
|
||||
void tst_QSqlQueryModel::nestedResets()
|
||||
{
|
||||
QFETCH(QString, dbName);
|
||||
QSqlDatabase db = QSqlDatabase::database(dbName);
|
||||
CHECK_DATABASE(db);
|
||||
|
||||
NestedResetsTest t;
|
||||
t.testme();
|
||||
}
|
||||
|
||||
// For task 180617
|
||||
// According to the task, several specific duplicate SQL queries would cause
|
||||
// multiple empty grid lines to be visible in the view
|
||||
|
Loading…
Reference in New Issue
Block a user