Fix emission of QQmlListModel::rowsAboutToBeXxx() signals
Call beginInsertRows(), beginMoveRows() and beginRemoveRows() before the change to ensure that rowsAboutToBeInserted(), rowsAboutToBeMoved() and rowsAboutToBeRemoved() get emitted before the change as appropriate. NOTE: This patch solves the problem for the most common use case, when ListModel is used without WorkerScript. QQmlListModelWorkerAgent needs similar changes in order to fix the signals when ListModel is used with WorkerScript (QTBUG-39321). Task-number: QTBUG-39279 Change-Id: Idec5167d70b242f6f7d8b7cff008e130afc62505 Reviewed-by: Alan Alpert <aalpert@blackberry.com>
This commit is contained in:
parent
b5cab0515b
commit
0306626a4d
|
@ -1699,13 +1699,20 @@ void QQmlListModel::emitItemsChanged(int index, int count, const QVector<int> &r
|
|||
}
|
||||
}
|
||||
|
||||
void QQmlListModel::emitItemsAboutToBeRemoved(int index, int count)
|
||||
{
|
||||
if (count <= 0 || !m_mainThread)
|
||||
return;
|
||||
|
||||
beginRemoveRows(QModelIndex(), index, index + count - 1);
|
||||
}
|
||||
|
||||
void QQmlListModel::emitItemsRemoved(int index, int count)
|
||||
{
|
||||
if (count <= 0)
|
||||
return;
|
||||
|
||||
if (m_mainThread) {
|
||||
beginRemoveRows(QModelIndex(), index, index + count - 1);
|
||||
endRemoveRows();
|
||||
emit countChanged();
|
||||
} else {
|
||||
|
@ -1716,13 +1723,20 @@ void QQmlListModel::emitItemsRemoved(int index, int count)
|
|||
}
|
||||
}
|
||||
|
||||
void QQmlListModel::emitItemsAboutToBeInserted(int index, int count)
|
||||
{
|
||||
if (count <= 0 || !m_mainThread)
|
||||
return;
|
||||
|
||||
beginInsertRows(QModelIndex(), index, index + count - 1);
|
||||
}
|
||||
|
||||
void QQmlListModel::emitItemsInserted(int index, int count)
|
||||
{
|
||||
if (count <= 0)
|
||||
return;
|
||||
|
||||
if (m_mainThread) {
|
||||
beginInsertRows(QModelIndex(), index, index + count - 1);
|
||||
endInsertRows();
|
||||
emit countChanged();
|
||||
} else {
|
||||
|
@ -1731,13 +1745,20 @@ void QQmlListModel::emitItemsInserted(int index, int count)
|
|||
}
|
||||
}
|
||||
|
||||
void QQmlListModel::emitItemsAboutToBeMoved(int from, int to, int n)
|
||||
{
|
||||
if (n <= 0 || !m_mainThread)
|
||||
return;
|
||||
|
||||
beginMoveRows(QModelIndex(), from, from + n - 1, QModelIndex(), to > from ? to + n : to);
|
||||
}
|
||||
|
||||
void QQmlListModel::emitItemsMoved(int from, int to, int n)
|
||||
{
|
||||
if (n <= 0)
|
||||
return;
|
||||
|
||||
if (m_mainThread) {
|
||||
beginMoveRows(QModelIndex(), from, from + n - 1, QModelIndex(), to > from ? to + n : to);
|
||||
endMoveRows();
|
||||
} else {
|
||||
int uid = m_dynamicRoles ? getUid() : m_listModel->getUid();
|
||||
|
@ -1877,6 +1898,8 @@ void QQmlListModel::clear()
|
|||
{
|
||||
int cleared = count();
|
||||
|
||||
emitItemsAboutToBeRemoved(0, cleared);
|
||||
|
||||
if (m_dynamicRoles) {
|
||||
for (int i=0 ; i < m_modelObjects.count() ; ++i)
|
||||
delete m_modelObjects[i];
|
||||
|
@ -1909,6 +1932,8 @@ void QQmlListModel::remove(QQmlV4Function *args)
|
|||
return;
|
||||
}
|
||||
|
||||
emitItemsAboutToBeRemoved(index, removeCount);
|
||||
|
||||
if (m_dynamicRoles) {
|
||||
for (int i=0 ; i < removeCount ; ++i)
|
||||
delete m_modelObjects[index+i];
|
||||
|
@ -1957,6 +1982,7 @@ void QQmlListModel::insert(QQmlV4Function *args)
|
|||
QV4::ScopedObject argObject(scope);
|
||||
|
||||
int objectArrayLength = objectArray->getLength();
|
||||
emitItemsAboutToBeInserted(index, objectArrayLength);
|
||||
for (int i=0 ; i < objectArrayLength ; ++i) {
|
||||
argObject = objectArray->getIndexed(i);
|
||||
|
||||
|
@ -1968,6 +1994,8 @@ void QQmlListModel::insert(QQmlV4Function *args)
|
|||
}
|
||||
emitItemsInserted(index, objectArrayLength);
|
||||
} else if (argObject) {
|
||||
emitItemsAboutToBeInserted(index, 1);
|
||||
|
||||
if (m_dynamicRoles) {
|
||||
m_modelObjects.insert(index, DynamicRoleModelNode::create(args->engine()->variantMapFromJS(argObject), this));
|
||||
} else {
|
||||
|
@ -2006,6 +2034,8 @@ void QQmlListModel::move(int from, int to, int n)
|
|||
return;
|
||||
}
|
||||
|
||||
emitItemsAboutToBeMoved(from, to, n);
|
||||
|
||||
if (m_dynamicRoles) {
|
||||
|
||||
int realFrom = from;
|
||||
|
@ -2061,6 +2091,8 @@ void QQmlListModel::append(QQmlV4Function *args)
|
|||
int objectArrayLength = objectArray->getLength();
|
||||
|
||||
int index = count();
|
||||
emitItemsAboutToBeInserted(index, objectArrayLength);
|
||||
|
||||
for (int i=0 ; i < objectArrayLength ; ++i) {
|
||||
argObject = objectArray->getIndexed(i);
|
||||
|
||||
|
@ -2077,9 +2109,12 @@ void QQmlListModel::append(QQmlV4Function *args)
|
|||
|
||||
if (m_dynamicRoles) {
|
||||
index = m_modelObjects.count();
|
||||
emitItemsAboutToBeInserted(index, 1);
|
||||
m_modelObjects.append(DynamicRoleModelNode::create(args->engine()->variantMapFromJS(argObject), this));
|
||||
} else {
|
||||
index = m_listModel->append(argObject, args->engine());
|
||||
index = m_listModel->elementCount();
|
||||
emitItemsAboutToBeInserted(index, 1);
|
||||
m_listModel->append(argObject, args->engine());
|
||||
}
|
||||
|
||||
emitItemsInserted(index, 1);
|
||||
|
@ -2174,6 +2209,7 @@ void QQmlListModel::set(int index, const QQmlV4Handle &handle)
|
|||
|
||||
|
||||
if (index == count()) {
|
||||
emitItemsAboutToBeInserted(index, 1);
|
||||
|
||||
if (m_dynamicRoles) {
|
||||
m_modelObjects.append(DynamicRoleModelNode::create(engine()->variantMapFromJS(object), this));
|
||||
|
|
|
@ -144,8 +144,11 @@ private:
|
|||
static QQmlListModel *createWithOwner(QQmlListModel *newOwner);
|
||||
|
||||
void emitItemsChanged(int index, int count, const QVector<int> &roles);
|
||||
void emitItemsAboutToBeRemoved(int index, int count);
|
||||
void emitItemsRemoved(int index, int count);
|
||||
void emitItemsAboutToBeInserted(int index, int count);
|
||||
void emitItemsInserted(int index, int count);
|
||||
void emitItemsAboutToBeMoved(int from, int to, int n);
|
||||
void emitItemsMoved(int from, int to, int n);
|
||||
};
|
||||
|
||||
|
|
|
@ -132,6 +132,7 @@ private slots:
|
|||
void empty_element_warning_data();
|
||||
void datetime();
|
||||
void datetime_data();
|
||||
void about_to_be_signals();
|
||||
};
|
||||
|
||||
bool tst_qqmllistmodel::compareVariantList(const QVariantList &testList, QVariant object)
|
||||
|
@ -1306,6 +1307,134 @@ void tst_qqmllistmodel::datetime()
|
|||
QVERIFY(expected == dtResult);
|
||||
}
|
||||
|
||||
class RowTester : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
RowTester(QAbstractItemModel *model) : QObject(model), model(model)
|
||||
{
|
||||
reset();
|
||||
connect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), this, SLOT(rowsAboutToBeInserted()));
|
||||
connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(rowsInserted()));
|
||||
connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(rowsAboutToBeRemoved()));
|
||||
connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(rowsRemoved()));
|
||||
connect(model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)), this, SLOT(rowsAboutToBeMoved()));
|
||||
connect(model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), this, SLOT(rowsMoved()));
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
rowsAboutToBeInsertedCalls = 0;
|
||||
rowsAboutToBeInsertedCount = 0;
|
||||
rowsInsertedCalls = 0;
|
||||
rowsInsertedCount = 0;
|
||||
rowsAboutToBeRemovedCalls = 0;
|
||||
rowsAboutToBeRemovedCount = 0;
|
||||
rowsRemovedCalls = 0;
|
||||
rowsRemovedCount = 0;
|
||||
rowsAboutToBeMovedCalls = 0;
|
||||
rowsAboutToBeMovedData.clear();
|
||||
rowsMovedCalls = 0;
|
||||
rowsMovedData.clear();
|
||||
}
|
||||
|
||||
int rowsAboutToBeInsertedCalls;
|
||||
int rowsAboutToBeInsertedCount;
|
||||
int rowsInsertedCalls;
|
||||
int rowsInsertedCount;
|
||||
int rowsAboutToBeRemovedCalls;
|
||||
int rowsAboutToBeRemovedCount;
|
||||
int rowsRemovedCalls;
|
||||
int rowsRemovedCount;
|
||||
int rowsAboutToBeMovedCalls;
|
||||
QVariantList rowsAboutToBeMovedData;
|
||||
int rowsMovedCalls;
|
||||
QVariantList rowsMovedData;
|
||||
|
||||
private slots:
|
||||
void rowsAboutToBeInserted()
|
||||
{
|
||||
rowsAboutToBeInsertedCalls++;
|
||||
rowsAboutToBeInsertedCount = model->rowCount();
|
||||
}
|
||||
|
||||
void rowsInserted()
|
||||
{
|
||||
rowsInsertedCalls++;
|
||||
rowsInsertedCount = model->rowCount();
|
||||
}
|
||||
|
||||
void rowsAboutToBeRemoved()
|
||||
{
|
||||
rowsAboutToBeRemovedCalls++;
|
||||
rowsAboutToBeRemovedCount = model->rowCount();
|
||||
}
|
||||
|
||||
void rowsRemoved()
|
||||
{
|
||||
rowsRemovedCalls++;
|
||||
rowsRemovedCount = model->rowCount();
|
||||
}
|
||||
|
||||
void rowsAboutToBeMoved()
|
||||
{
|
||||
rowsAboutToBeMovedCalls++;
|
||||
for (int i = 0; i < model->rowCount(); ++i)
|
||||
rowsAboutToBeMovedData += model->data(model->index(i, 0), 0);
|
||||
}
|
||||
|
||||
void rowsMoved()
|
||||
{
|
||||
rowsMovedCalls++;
|
||||
for (int i = 0; i < model->rowCount(); ++i)
|
||||
rowsMovedData += model->data(model->index(i, 0), 0);
|
||||
}
|
||||
|
||||
private:
|
||||
QAbstractItemModel *model;
|
||||
};
|
||||
|
||||
void tst_qqmllistmodel::about_to_be_signals()
|
||||
{
|
||||
QQmlEngine engine;
|
||||
QQmlListModel model;
|
||||
QQmlEngine::setContextForObject(&model,engine.rootContext());
|
||||
|
||||
RowTester tester(&model);
|
||||
|
||||
QQmlExpression e1(engine.rootContext(), &model, "{append({'test':0})}");
|
||||
e1.evaluate();
|
||||
|
||||
QCOMPARE(tester.rowsAboutToBeInsertedCalls, 1);
|
||||
QCOMPARE(tester.rowsAboutToBeInsertedCount, 0);
|
||||
QCOMPARE(tester.rowsInsertedCalls, 1);
|
||||
QCOMPARE(tester.rowsInsertedCount, 1);
|
||||
|
||||
QQmlExpression e2(engine.rootContext(), &model, "{append({'test':1})}");
|
||||
e2.evaluate();
|
||||
|
||||
QCOMPARE(tester.rowsAboutToBeInsertedCalls, 2);
|
||||
QCOMPARE(tester.rowsAboutToBeInsertedCount, 1);
|
||||
QCOMPARE(tester.rowsInsertedCalls, 2);
|
||||
QCOMPARE(tester.rowsInsertedCount, 2);
|
||||
|
||||
QQmlExpression e3(engine.rootContext(), &model, "{move(0, 1, 1)}");
|
||||
e3.evaluate();
|
||||
|
||||
QCOMPARE(tester.rowsAboutToBeMovedCalls, 1);
|
||||
QCOMPARE(tester.rowsAboutToBeMovedData, QVariantList() << 0.0 << 1.0);
|
||||
QCOMPARE(tester.rowsMovedCalls, 1);
|
||||
QCOMPARE(tester.rowsMovedData, QVariantList() << 1.0 << 0.0);
|
||||
|
||||
QQmlExpression e4(engine.rootContext(), &model, "{remove(0, 2)}");
|
||||
e4.evaluate();
|
||||
|
||||
QCOMPARE(tester.rowsAboutToBeRemovedCalls, 1);
|
||||
QCOMPARE(tester.rowsAboutToBeRemovedCount, 2);
|
||||
QCOMPARE(tester.rowsRemovedCalls, 1);
|
||||
QCOMPARE(tester.rowsRemovedCount, 0);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_qqmllistmodel)
|
||||
|
||||
#include "tst_qqmllistmodel.moc"
|
||||
|
|
Loading…
Reference in New Issue