diff options
author | Qt Continuous Integration System <qt-info@nokia.com> | 2010-09-17 13:32:20 (GMT) |
---|---|---|
committer | Qt Continuous Integration System <qt-info@nokia.com> | 2010-09-17 13:32:20 (GMT) |
commit | 2046037499830506ec24097c9b7a739bb7c78566 (patch) | |
tree | 1af518306ce87b7fb1fc7803a4d6d2f663b2506c /src | |
parent | cb3b83e64154e9725c0c050ea32a4a632ad9f041 (diff) | |
parent | 39dcbf66fd482bc49a475ec056f90e8a123cd4a8 (diff) | |
download | Qt-2046037499830506ec24097c9b7a739bb7c78566.zip Qt-2046037499830506ec24097c9b7a739bb7c78566.tar.gz Qt-2046037499830506ec24097c9b7a739bb7c78566.tar.bz2 |
Merge branch '4.7' of scm.dev.nokia.troll.no:qt/qt-qml into 4.7-integration
* '4.7' of scm.dev.nokia.troll.no:qt/qt-qml:
Fix example after changes to font.letterSpacing.
Autotest and small fix for QDeclarativeFontLoader.
Improve error messages
Changes to objects returned from get() should emit itemsChanged() so
Make it clear that private ListModel constructor is only for worker
Remove duplicated move() implementations
Doc changes
Fix QDeclarativeXmlQuery mutex locking and don't wait for new jobs if the query has already quit
PathView didn't accept mouse events, preventing it from working in a Flickable.
Moving items in a PathView caused PathView.onPath to be set to false.
Fix worker agent to emit ListModel itemsChanged() correctly when set()
Diffstat (limited to 'src')
-rw-r--r-- | src/declarative/graphicsitems/qdeclarativepathview.cpp | 191 | ||||
-rw-r--r-- | src/declarative/graphicsitems/qdeclarativepathview_p_p.h | 4 | ||||
-rw-r--r-- | src/declarative/util/qdeclarativefontloader.cpp | 6 | ||||
-rw-r--r-- | src/declarative/util/qdeclarativelistmodel.cpp | 400 | ||||
-rw-r--r-- | src/declarative/util/qdeclarativelistmodel_p.h | 12 | ||||
-rw-r--r-- | src/declarative/util/qdeclarativelistmodel_p_p.h | 123 | ||||
-rw-r--r-- | src/declarative/util/qdeclarativelistmodelworkeragent.cpp | 33 | ||||
-rw-r--r-- | src/declarative/util/qdeclarativelistmodelworkeragent_p.h | 4 | ||||
-rw-r--r-- | src/declarative/util/qdeclarativexmllistmodel.cpp | 8 |
9 files changed, 598 insertions, 183 deletions
diff --git a/src/declarative/graphicsitems/qdeclarativepathview.cpp b/src/declarative/graphicsitems/qdeclarativepathview.cpp index dad547f..d134929 100644 --- a/src/declarative/graphicsitems/qdeclarativepathview.cpp +++ b/src/declarative/graphicsitems/qdeclarativepathview.cpp @@ -141,11 +141,13 @@ void QDeclarativePathViewPrivate::releaseItem(QDeclarativeItem *item) { if (!item || !model) return; - if (QDeclarativePathViewAttached *att = attached(item)) - att->setOnPath(false); QDeclarativeItemPrivate *itemPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(item)); itemPrivate->removeItemChangeListener(this, QDeclarativeItemPrivate::Geometry); - model->release(item); + if (model->release(item) == 0) { + // item was not destroyed, and we no longer reference it. + if (QDeclarativePathViewAttached *att = attached(item)) + att->setOnPath(false); + } } QDeclarativePathViewAttached *QDeclarativePathViewPrivate::attached(QDeclarativeItem *item) @@ -1033,103 +1035,138 @@ QPointF QDeclarativePathViewPrivate::pointNear(const QPointF &point, qreal *near return nearPoint; } - void QDeclarativePathView::mousePressEvent(QGraphicsSceneMouseEvent *event) { Q_D(QDeclarativePathView); - if (!d->interactive || !d->items.count()) + if (d->interactive) { + d->handleMousePressEvent(event); + event->accept(); + } else { + QDeclarativeItem::mousePressEvent(event); + } +} + +void QDeclarativePathViewPrivate::handleMousePressEvent(QGraphicsSceneMouseEvent *event) +{ + Q_Q(QDeclarativePathView); + if (!interactive || !items.count()) return; - QPointF scenePoint = mapToScene(event->pos()); + QPointF scenePoint = q->mapToScene(event->pos()); int idx = 0; - for (; idx < d->items.count(); ++idx) { - QRectF rect = d->items.at(idx)->boundingRect(); - rect = d->items.at(idx)->mapToScene(rect).boundingRect(); + for (; idx < items.count(); ++idx) { + QRectF rect = items.at(idx)->boundingRect(); + rect = items.at(idx)->mapToScene(rect).boundingRect(); if (rect.contains(scenePoint)) break; } - if (idx == d->items.count() && d->dragMargin == 0.) // didn't click on an item + if (idx == items.count() && dragMargin == 0.) // didn't click on an item return; - d->startPoint = d->pointNear(event->pos(), &d->startPc); - if (idx == d->items.count()) { - qreal distance = qAbs(event->pos().x() - d->startPoint.x()) + qAbs(event->pos().y() - d->startPoint.y()); - if (distance > d->dragMargin) + startPoint = pointNear(event->pos(), &startPc); + if (idx == items.count()) { + qreal distance = qAbs(event->pos().x() - startPoint.x()) + qAbs(event->pos().y() - startPoint.y()); + if (distance > dragMargin) return; } - if (d->tl.isActive() && d->flicking) - d->stealMouse = true; // If we've been flicked then steal the click. + if (tl.isActive() && flicking) + stealMouse = true; // If we've been flicked then steal the click. else - d->stealMouse = false; + stealMouse = false; - d->lastElapsed = 0; - d->lastDist = 0; - QDeclarativeItemPrivate::start(d->lastPosTime); - d->tl.clear(); + lastElapsed = 0; + lastDist = 0; + QDeclarativeItemPrivate::start(lastPosTime); + tl.clear(); } void QDeclarativePathView::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { Q_D(QDeclarativePathView); - if (!d->interactive || !d->lastPosTime.isValid()) + if (d->interactive) { + d->handleMouseMoveEvent(event); + if (d->stealMouse) + setKeepMouseGrab(true); + event->accept(); + } else { + QDeclarativeItem::mouseMoveEvent(event); + } +} + +void QDeclarativePathViewPrivate::handleMouseMoveEvent(QGraphicsSceneMouseEvent *event) +{ + Q_Q(QDeclarativePathView); + if (!interactive || !lastPosTime.isValid()) return; - if (!d->stealMouse) { - QPointF delta = event->pos() - d->startPoint; + if (!stealMouse) { + QPointF delta = event->pos() - startPoint; if (qAbs(delta.x()) > QApplication::startDragDistance() || qAbs(delta.y()) > QApplication::startDragDistance()) - d->stealMouse = true; + stealMouse = true; } - if (d->stealMouse) { - d->moveReason = QDeclarativePathViewPrivate::Mouse; + if (stealMouse) { + moveReason = QDeclarativePathViewPrivate::Mouse; qreal newPc; - d->pointNear(event->pos(), &newPc); - qreal diff = (newPc - d->startPc)*d->modelCount*d->mappedRange; + pointNear(event->pos(), &newPc); + qreal diff = (newPc - startPc)*modelCount*mappedRange; if (diff) { - setOffset(d->offset + diff); + setOffset(offset + diff); - if (diff > d->modelCount/2) - diff -= d->modelCount; - else if (diff < -d->modelCount/2) - diff += d->modelCount; + if (diff > modelCount/2) + diff -= modelCount; + else if (diff < -modelCount/2) + diff += modelCount; - d->lastElapsed = QDeclarativeItemPrivate::restart(d->lastPosTime); - d->lastDist = diff; - d->startPc = newPc; + lastElapsed = QDeclarativeItemPrivate::restart(lastPosTime); + lastDist = diff; + startPc = newPc; } - if (!d->moving) { - d->moving = true; - emit movingChanged(); - emit movementStarted(); + if (!moving) { + moving = true; + emit q->movingChanged(); + emit q->movementStarted(); } } } -void QDeclarativePathView::mouseReleaseEvent(QGraphicsSceneMouseEvent *) +void QDeclarativePathView::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { Q_D(QDeclarativePathView); - d->stealMouse = false; - setKeepMouseGrab(false); - if (!d->interactive || !d->lastPosTime.isValid()) + if (d->interactive) { + d->handleMouseReleaseEvent(event); + event->accept(); + ungrabMouse(); + } else { + QDeclarativeItem::mouseReleaseEvent(event); + } +} + +void QDeclarativePathViewPrivate::handleMouseReleaseEvent(QGraphicsSceneMouseEvent *) +{ + Q_Q(QDeclarativePathView); + stealMouse = false; + q->setKeepMouseGrab(false); + if (!interactive || !lastPosTime.isValid()) return; - qreal elapsed = qreal(d->lastElapsed + QDeclarativeItemPrivate::elapsed(d->lastPosTime)) / 1000.; - qreal velocity = elapsed > 0. ? d->lastDist / elapsed : 0; - if (d->model && d->modelCount && qAbs(velocity) > 1.) { - qreal count = d->pathItems == -1 ? d->modelCount : d->pathItems; + qreal elapsed = qreal(lastElapsed + QDeclarativeItemPrivate::elapsed(lastPosTime)) / 1000.; + qreal velocity = elapsed > 0. ? lastDist / elapsed : 0; + if (model && modelCount && qAbs(velocity) > 1.) { + qreal count = pathItems == -1 ? modelCount : pathItems; if (qAbs(velocity) > count * 2) // limit velocity velocity = (velocity > 0 ? count : -count) * 2; // Calculate the distance to be travelled qreal v2 = velocity*velocity; - qreal accel = d->deceleration/10; + qreal accel = deceleration/10; // + 0.25 to encourage moving at least one item in the flick direction - qreal dist = qMin(qreal(d->modelCount-1), qreal(v2 / (accel * 2.0) + 0.25)); - if (d->haveHighlightRange && d->highlightRangeMode == QDeclarativePathView::StrictlyEnforceRange) { + qreal dist = qMin(qreal(modelCount-1), qreal(v2 / (accel * 2.0) + 0.25)); + if (haveHighlightRange && highlightRangeMode == QDeclarativePathView::StrictlyEnforceRange) { // round to nearest item. if (velocity > 0.) - dist = qRound(dist + d->offset) - d->offset; + dist = qRound(dist + offset) - offset; else - dist = qRound(dist - d->offset) + d->offset; + dist = qRound(dist - offset) + offset; // Calculate accel required to stop on item boundary if (dist <= 0.) { dist = 0.; @@ -1138,23 +1175,22 @@ void QDeclarativePathView::mouseReleaseEvent(QGraphicsSceneMouseEvent *) accel = v2 / (2.0f * qAbs(dist)); } } - d->offsetAdj = 0.0; - d->moveOffset.setValue(d->offset); - d->tl.accel(d->moveOffset, velocity, accel, dist); - d->tl.callback(QDeclarativeTimeLineCallback(&d->moveOffset, d->fixOffsetCallback, d)); - if (!d->flicking) { - d->flicking = true; - emit flickingChanged(); - emit flickStarted(); + offsetAdj = 0.0; + moveOffset.setValue(offset); + tl.accel(moveOffset, velocity, accel, dist); + tl.callback(QDeclarativeTimeLineCallback(&moveOffset, fixOffsetCallback, this)); + if (!flicking) { + flicking = true; + emit q->flickingChanged(); + emit q->flickStarted(); } } else { - d->fixOffset(); + fixOffset(); } - d->lastPosTime.invalidate(); - ungrabMouse(); - if (!d->tl.isActive()) - movementEnding(); + lastPosTime.invalidate(); + if (!tl.isActive()) + q->movementEnding(); } bool QDeclarativePathView::sendMouseEvent(QGraphicsSceneMouseEvent *event) @@ -1164,7 +1200,8 @@ bool QDeclarativePathView::sendMouseEvent(QGraphicsSceneMouseEvent *event) QRectF myRect = mapToScene(QRectF(0, 0, width(), height())).boundingRect(); QGraphicsScene *s = scene(); QDeclarativeItem *grabber = s ? qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem()) : 0; - if ((d->stealMouse || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab())) { + bool stealThisEvent = d->stealMouse; + if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab())) { mouseEvent.setAccepted(false); for (int i = 0x1; i <= 0x10; i <<= 1) { if (event->buttons() & i) { @@ -1179,25 +1216,28 @@ bool QDeclarativePathView::sendMouseEvent(QGraphicsSceneMouseEvent *event) switch(mouseEvent.type()) { case QEvent::GraphicsSceneMouseMove: - mouseMoveEvent(&mouseEvent); + d->handleMouseMoveEvent(&mouseEvent); break; case QEvent::GraphicsSceneMousePress: - mousePressEvent(&mouseEvent); + d->handleMousePressEvent(&mouseEvent); + stealThisEvent = d->stealMouse; // Update stealThisEvent in case changed by function call above break; case QEvent::GraphicsSceneMouseRelease: - mouseReleaseEvent(&mouseEvent); + d->handleMouseReleaseEvent(&mouseEvent); break; default: break; } grabber = qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem()); - if (grabber && d->stealMouse && !grabber->keepMouseGrab() && grabber != this) + if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this) grabMouse(); return d->stealMouse; } else if (d->lastPosTime.isValid()) { d->lastPosTime.invalidate(); } + if (mouseEvent.type() == QEvent::GraphicsSceneMouseRelease) + d->stealMouse = false; return false; } @@ -1211,12 +1251,7 @@ bool QDeclarativePathView::sceneEventFilter(QGraphicsItem *i, QEvent *e) case QEvent::GraphicsSceneMousePress: case QEvent::GraphicsSceneMouseMove: case QEvent::GraphicsSceneMouseRelease: - { - bool ret = sendMouseEvent(static_cast<QGraphicsSceneMouseEvent *>(e)); - if (e->type() == QEvent::GraphicsSceneMouseRelease) - return ret; - break; - } + return sendMouseEvent(static_cast<QGraphicsSceneMouseEvent *>(e)); default: break; } diff --git a/src/declarative/graphicsitems/qdeclarativepathview_p_p.h b/src/declarative/graphicsitems/qdeclarativepathview_p_p.h index dfebe35..b217216 100644 --- a/src/declarative/graphicsitems/qdeclarativepathview_p_p.h +++ b/src/declarative/graphicsitems/qdeclarativepathview_p_p.h @@ -123,6 +123,10 @@ public: return model && model->count() > 0 && model->isValid() && path; } + void handleMousePressEvent(QGraphicsSceneMouseEvent *event); + void handleMouseMoveEvent(QGraphicsSceneMouseEvent *event); + void handleMouseReleaseEvent(QGraphicsSceneMouseEvent *); + int calcCurrentIndex(); void updateCurrent(); static void fixOffsetCallback(void*); diff --git a/src/declarative/util/qdeclarativefontloader.cpp b/src/declarative/util/qdeclarativefontloader.cpp index 91588b7..6879494 100644 --- a/src/declarative/util/qdeclarativefontloader.cpp +++ b/src/declarative/util/qdeclarativefontloader.cpp @@ -210,11 +210,7 @@ void QDeclarativeFontLoader::setSource(const QUrl &url) updateFontInfo(QString(), Error); } } else { - QDeclarativeFontObject *fo = d->fonts[d->url]; - d->name = QFontDatabase::applicationFontFamilies(fo->id).at(0); - emit nameChanged(); - d->status = QDeclarativeFontLoader::Ready; - emit statusChanged(); + updateFontInfo(QFontDatabase::applicationFontFamilies(d->fonts[d->url]->id).at(0), Ready); } } else #endif diff --git a/src/declarative/util/qdeclarativelistmodel.cpp b/src/declarative/util/qdeclarativelistmodel.cpp index cf2eada..2d8b946 100644 --- a/src/declarative/util/qdeclarativelistmodel.cpp +++ b/src/declarative/util/qdeclarativelistmodel.cpp @@ -58,6 +58,28 @@ Q_DECLARE_METATYPE(QListModelInterface *) QT_BEGIN_NAMESPACE +template<typename T> +void qdeclarativelistmodel_move(int from, int to, int n, T *items) +{ + if (n == 1) { + items->move(from, to); + } else { + T replaced; + int i=0; + typename T::ConstIterator it=items->begin(); it += from+n; + for (; i<to-from; ++i,++it) + replaced.append(*it); + i=0; + it=items->begin(); it += from; + for (; i<n; ++i,++it) + replaced.append(*it); + typename T::ConstIterator f=replaced.begin(); + typename T::Iterator t=items->begin(); t += from; + for (; f != replaced.end(); ++f, ++t) + *t = *f; + } +} + QDeclarativeListModelParser::ListInstruction *QDeclarativeListModelParser::ListModelData::instructions() const { return (QDeclarativeListModelParser::ListInstruction *)((char *)this + sizeof(ListModelData)); @@ -154,10 +176,10 @@ QDeclarativeListModelParser::ListInstruction *QDeclarativeListModelParser::ListM handler. You must call sync() or else the changes made to the list from the external thread will not be reflected in the list model in the main thread. - \section1 Limitations + \section1 Restrictions - If a list model is to be accessed from a WorkerScript, it \bold cannot - contain list data. So, the following model cannot be used from a WorkerScript + If a list model is to be accessed from a WorkerScript, it cannot + contain list-type data. So, the following model cannot be used from a WorkerScript because of the list contained in the "attributes" property: \code @@ -174,7 +196,7 @@ QDeclarativeListModelParser::ListInstruction *QDeclarativeListModelParser::ListM } \endcode - In addition, the WorkerScript cannot add any list data to the model. + In addition, the WorkerScript cannot add list-type data to the model. \sa {qmlmodels}{Data Models}, {declarative/threading/threadedlistmodel}{Threaded ListModel example}, QtDeclarative */ @@ -195,17 +217,25 @@ QDeclarativeListModelParser::ListInstruction *QDeclarativeListModelParser::ListM */ QDeclarativeListModel::QDeclarativeListModel(QObject *parent) -: QListModelInterface(parent), m_agent(0), m_nested(new NestedListModel(this)), m_flat(0), m_isWorkerCopy(false) +: QListModelInterface(parent), m_agent(0), m_nested(new NestedListModel(this)), m_flat(0) { } -QDeclarativeListModel::QDeclarativeListModel(bool workerCopy, QObject *parent) -: QListModelInterface(parent), m_agent(0), m_nested(0), m_flat(0), m_isWorkerCopy(workerCopy) +QDeclarativeListModel::QDeclarativeListModel(const QDeclarativeListModel *orig, QDeclarativeListModelWorkerAgent *parent) +: QListModelInterface(parent), m_agent(0), m_nested(0), m_flat(0) { - if (workerCopy) - m_flat = new FlatListModel(this); - else - m_nested = new NestedListModel(this); + m_flat = new FlatListModel(this); + m_flat->m_parentAgent = parent; + + if (orig->m_flat) { + m_flat->m_roles = orig->m_flat->m_roles; + m_flat->m_strings = orig->m_flat->m_strings; + m_flat->m_values = orig->m_flat->m_values; + + m_flat->m_nodeData.reserve(m_flat->m_values.count()); + for (int i=0; i<m_flat->m_values.count(); i++) + m_flat->m_nodeData << 0; + } } QDeclarativeListModel::~QDeclarativeListModel() @@ -241,19 +271,28 @@ bool QDeclarativeListModel::flatten() flat->m_strings.insert(s, roles[i]); } + flat->m_nodeData.reserve(flat->m_values.count()); + for (int i=0; i<flat->m_values.count(); i++) + flat->m_nodeData << 0; + m_flat = flat; delete m_nested; m_nested = 0; return true; } +bool QDeclarativeListModel::inWorkerThread() const +{ + return m_flat && m_flat->m_parentAgent; +} + QDeclarativeListModelWorkerAgent *QDeclarativeListModel::agent() { if (m_agent) return m_agent; if (!flatten()) { - qmlInfo(this) << "List contains nested list values and cannot be used from a worker script"; + qmlInfo(this) << "List contains list-type data and cannot be used from a worker script"; return 0; } @@ -311,7 +350,7 @@ void QDeclarativeListModel::clear() else m_nested->clear(); - if (!m_isWorkerCopy) { + if (!inWorkerThread()) { emit itemsRemoved(0, cleared); emit countChanged(); } @@ -336,7 +375,7 @@ void QDeclarativeListModel::remove(int index) else m_nested->remove(index); - if (!m_isWorkerCopy) { + if (!inWorkerThread()) { emit itemsRemoved(index, 1); emit countChanged(); } @@ -370,7 +409,7 @@ void QDeclarativeListModel::insert(int index, const QScriptValue& valuemap) } bool ok = m_flat ? m_flat->insert(index, valuemap) : m_nested->insert(index, valuemap); - if (ok && !m_isWorkerCopy) { + if (ok && !inWorkerThread()) { emit itemsInserted(index, 1); emit countChanged(); } @@ -394,7 +433,7 @@ void QDeclarativeListModel::move(int from, int to, int n) { if (n==0 || from==to) return; - if (from+n > count() || to+n > count() || from < 0 || to < 0 || n < 0) { + if (!canMove(from, to, n)) { qmlInfo(this) << tr("move: out of range"); return; } @@ -416,7 +455,7 @@ void QDeclarativeListModel::move(int from, int to, int n) else m_nested->move(from, to, n); - if (!m_isWorkerCopy) + if (!inWorkerThread()) emit itemsMoved(origfrom, origto, orign); } @@ -445,11 +484,15 @@ void QDeclarativeListModel::append(const QScriptValue& valuemap) /*! \qmlmethod object ListModel::get(int index) - Returns the item at \a index in the list model. + Returns the item at \a index in the list model. This allows the item + data to be accessed or modified from JavaScript: \code - fruitModel.append({"cost": 5.95, "name":"Jackfruit"}) - fruitModel.get(0).cost + Component.onCompleted: { + fruitModel.append({"cost": 5.95, "name":"Jackfruit"}); + console.log(fruitModel.get(0).cost); + fruitModel.get(0).cost = 10.95; + } \endcode The \a index must be an element in the list. @@ -464,6 +507,9 @@ void QDeclarativeListModel::append(const QScriptValue& valuemap) fruitModel.get(0).attributes.get(1).value; // == "green" \endcode + \warning The returned object is not guaranteed to remain valid. It + should not be used in \l{Property Binding}{property bindings}. + \sa append() */ QScriptValue QDeclarativeListModel::get(int index) const @@ -507,7 +553,7 @@ void QDeclarativeListModel::set(int index, const QScriptValue& valuemap) else m_nested->set(index, valuemap, &roles); - if (!m_isWorkerCopy) + if (!inWorkerThread()) emit itemsChanged(index, 1, roles); } } @@ -538,7 +584,7 @@ void QDeclarativeListModel::setProperty(int index, const QString& property, cons else m_nested->setProperty(index, property, value, &roles); - if (!m_isWorkerCopy) + if (!inWorkerThread()) emit itemsChanged(index, 1, roles); } @@ -705,7 +751,7 @@ void QDeclarativeListModelParser::setCustomData(QObject *obj, const QByteArray & { QDeclarativeListModel *rv = static_cast<QDeclarativeListModel *>(obj); - ModelNode *root = new ModelNode; + ModelNode *root = new ModelNode(rv->m_nested); rv->m_nested->_root = root; QStack<ModelNode *> nodes; nodes << root; @@ -722,7 +768,7 @@ void QDeclarativeListModelParser::setCustomData(QObject *obj, const QByteArray & case ListInstruction::Push: { ModelNode *n = nodes.top(); - ModelNode *n2 = new ModelNode; + ModelNode *n2 = new ModelNode(rv->m_nested); n->values << qVariantFromValue(n2); nodes.push(n2); if (processingSet) @@ -761,7 +807,7 @@ void QDeclarativeListModelParser::setCustomData(QObject *obj, const QByteArray & case ListInstruction::Set: { ModelNode *n = nodes.top(); - ModelNode *n2 = new ModelNode; + ModelNode *n2 = new ModelNode(rv->m_nested); n->properties.insert(QString::fromUtf8(data + instr.dataIdx), n2); nodes.push(n2); processingSet = true; @@ -769,6 +815,13 @@ void QDeclarativeListModelParser::setCustomData(QObject *obj, const QByteArray & break; } } + + ModelNode *rootNode = rv->m_nested->_root; + for (int i=0; i<rootNode->values.count(); ++i) { + ModelNode *node = qvariant_cast<ModelNode *>(rootNode->values[i]); + node->listIndex = i; + node->updateListIndexes(); + } } bool QDeclarativeListModelParser::definesEmptyList(const QString &s) @@ -783,6 +836,7 @@ bool QDeclarativeListModelParser::definesEmptyList(const QString &s) return false; } + /*! \qmlclass ListElement QDeclarativeListElement \ingroup qml-working-with-data @@ -826,12 +880,13 @@ bool QDeclarativeListModelParser::definesEmptyList(const QString &s) */ FlatListModel::FlatListModel(QDeclarativeListModel *base) - : m_scriptEngine(0), m_listModel(base) + : m_scriptEngine(0), m_listModel(base), m_scriptClass(0), m_parentAgent(0) { } FlatListModel::~FlatListModel() { + qDeleteAll(m_nodeData); } QHash<int,QVariant> FlatListModel::data(int index, const QList<int> &roles) const @@ -875,11 +930,15 @@ int FlatListModel::count() const void FlatListModel::clear() { m_values.clear(); + + qDeleteAll(m_nodeData); + m_nodeData.clear(); } void FlatListModel::remove(int index) { m_values.removeAt(index); + removedNode(index); } bool FlatListModel::append(const QScriptValue &value) @@ -896,6 +955,8 @@ bool FlatListModel::insert(int index, const QScriptValue &value) return false; m_values.insert(index, row); + insertedNode(index); + return true; } @@ -909,13 +970,17 @@ QScriptValue FlatListModel::get(int index) const if (index < 0 || index >= m_values.count()) return scriptEngine->undefinedValue(); - QScriptValue rv = scriptEngine->newObject(); + FlatListModel *that = const_cast<FlatListModel*>(this); + if (!m_scriptClass) + that->m_scriptClass = new FlatListScriptClass(that, scriptEngine); - QHash<int, QVariant> row = m_values.at(index); - for (QHash<int, QVariant>::ConstIterator iter = row.begin(); iter != row.end(); ++iter) - rv.setProperty(m_roles.value(iter.key()), qScriptValueFromValue(scriptEngine, iter.value())); + FlatNodeData *data = m_nodeData.value(index); + if (!data) { + data = new FlatNodeData(index); + that->m_nodeData.replace(index, data); + } - return rv; + return QScriptDeclarativeClass::newObject(scriptEngine, m_scriptClass, new FlatNodeObjectData(data)); } void FlatListModel::set(int index, const QScriptValue &value, QList<int> *roles) @@ -947,23 +1012,8 @@ void FlatListModel::setProperty(int index, const QString& property, const QVaria void FlatListModel::move(int from, int to, int n) { - if (n == 1) { - m_values.move(from, to); - } else { - QList<QHash<int, QVariant> > replaced; - int i=0; - QList<QHash<int, QVariant> >::ConstIterator it=m_values.begin(); it += from+n; - for (; i<to-from; ++i,++it) - replaced.append(*it); - i=0; - it=m_values.begin(); it += from; - for (; i<n; ++i,++it) - replaced.append(*it); - QList<QHash<int, QVariant> >::ConstIterator f=replaced.begin(); - QList<QHash<int, QVariant> >::Iterator t=m_values.begin(); t += from; - for (; f != replaced.end(); ++f, ++t) - *t = *f; - } + qdeclarativelistmodel_move<QList<QHash<int, QVariant> > >(from, to, n, &m_values); + moveNodes(from, to, n); } bool FlatListModel::addValue(const QScriptValue &value, QHash<int, QVariant> *row, QList<int> *roles) @@ -973,7 +1023,7 @@ bool FlatListModel::addValue(const QScriptValue &value, QHash<int, QVariant> *ro it.next(); QScriptValue value = it.value(); if (!value.isVariant() && !value.isRegExp() && !value.isDate() && value.isObject()) { - qmlInfo(m_listModel) << "Cannot add nested list values when modifying or after modification from a worker script"; + qmlInfo(m_listModel) << "Cannot add list-type data when modifying or after modification from a worker script"; return false; } @@ -993,6 +1043,139 @@ bool FlatListModel::addValue(const QScriptValue &value, QHash<int, QVariant> *ro return true; } +void FlatListModel::insertedNode(int index) +{ + if (index >= 0 && index <= m_values.count()) { + m_nodeData.insert(index, 0); + + for (int i=index + 1; i<m_nodeData.count(); i++) { + if (m_nodeData[i]) + m_nodeData[i]->index = i; + } + } +} + +void FlatListModel::removedNode(int index) +{ + if (index >= 0 && index < m_nodeData.count()) { + delete m_nodeData.takeAt(index); + + for (int i=index; i<m_nodeData.count(); i++) { + if (m_nodeData[i]) + m_nodeData[i]->index = i; + } + } +} + +void FlatListModel::moveNodes(int from, int to, int n) +{ + if (!m_listModel->canMove(from, to, n)) + return; + + qdeclarativelistmodel_move<QList<FlatNodeData *> >(from, to, n, &m_nodeData); + + for (int i=from; i<from + (to-from); i++) { + if (m_nodeData[i]) + m_nodeData[i]->index = i; + } +} + + + +FlatNodeData::~FlatNodeData() +{ + for (QSet<FlatNodeObjectData *>::Iterator iter = objects.begin(); iter != objects.end(); ++iter) { + FlatNodeObjectData *data = *iter; + data->nodeData = 0; + } +} + +void FlatNodeData::addData(FlatNodeObjectData *data) +{ + objects.insert(data); +} + +void FlatNodeData::removeData(FlatNodeObjectData *data) +{ + objects.remove(data); +} + + +FlatListScriptClass::FlatListScriptClass(FlatListModel *model, QScriptEngine *seng) + : QScriptDeclarativeClass(seng), + m_model(model) +{ +} + +QScriptDeclarativeClass::Value FlatListScriptClass::property(Object *obj, const Identifier &name) +{ + FlatNodeObjectData *objData = static_cast<FlatNodeObjectData*>(obj); + if (!objData->nodeData) // item at this index has been deleted + return QScriptDeclarativeClass::Value(engine(), engine()->undefinedValue()); + + int index = objData->nodeData->index; + QString propName = toString(name); + int role = m_model->m_strings.value(propName, -1); + + if (role >= 0 && index >=0 ) { + const QHash<int, QVariant> &row = m_model->m_values[index]; + QScriptValue sv = engine()->toScriptValue<QVariant>(row[role]); + return QScriptDeclarativeClass::Value(engine(), sv); + } + + return QScriptDeclarativeClass::Value(engine(), engine()->undefinedValue()); +} + +void FlatListScriptClass::setProperty(Object *obj, const Identifier &name, const QScriptValue &value) +{ + if (!value.isVariant() && !value.isRegExp() && !value.isDate() && value.isObject()) { + qmlInfo(m_model->m_listModel) << "Cannot add list-type data when modifying or after modification from a worker script"; + return; + } + + FlatNodeObjectData *objData = static_cast<FlatNodeObjectData*>(obj); + if (!objData->nodeData) // item at this index has been deleted + return; + + int index = objData->nodeData->index; + QString propName = toString(name); + + int role = m_model->m_strings.value(propName, -1); + if (role >= 0 && index >= 0) { + QHash<int, QVariant> &row = m_model->m_values[index]; + row[role] = value.toVariant(); + + if (m_model->m_parentAgent) { + // This is the list in the worker thread, so tell the agent to + // emit itemsChanged() later + m_model->m_parentAgent->changedData(index, 1); + } else { + // This is the list in the main thread, so emit itemsChanged() + QList<int> roles; + roles << role; + emit m_model->m_listModel->itemsChanged(index, 1, roles); + } + } +} + +QScriptClass::QueryFlags FlatListScriptClass::queryProperty(Object *, const Identifier &, QScriptClass::QueryFlags) +{ + return (QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess); +} + +bool FlatListScriptClass::compare(Object *obj1, Object *obj2) +{ + FlatNodeObjectData *data1 = static_cast<FlatNodeObjectData*>(obj1); + FlatNodeObjectData *data2 = static_cast<FlatNodeObjectData*>(obj2); + + if (!data1->nodeData || !data2->nodeData) + return false; + + return data1->nodeData->index == data2->nodeData->index; +} + + + NestedListModel::NestedListModel(QDeclarativeListModel *base) : _root(0), m_ownsRoot(false), m_listModel(base), _rolesOk(false) { @@ -1118,11 +1301,12 @@ void NestedListModel::remove(int index) bool NestedListModel::insert(int index, const QScriptValue& valuemap) { if (!_root) { - _root = new ModelNode; + _root = new ModelNode(this); m_ownsRoot = true; } - ModelNode *mn = new ModelNode; + ModelNode *mn = new ModelNode(this); + mn->listIndex = index; mn->setObjectValue(valuemap); _root->values.insert(index,qVariantFromValue(mn)); return true; @@ -1130,34 +1314,19 @@ bool NestedListModel::insert(int index, const QScriptValue& valuemap) void NestedListModel::move(int from, int to, int n) { - if (n==1) { - _root->values.move(from,to); - } else { - QList<QVariant> replaced; - int i=0; - QVariantList::const_iterator it=_root->values.begin(); it += from+n; - for (; i<to-from; ++i,++it) - replaced.append(*it); - i=0; - it=_root->values.begin(); it += from; - for (; i<n; ++i,++it) - replaced.append(*it); - QVariantList::const_iterator f=replaced.begin(); - QVariantList::iterator t=_root->values.begin(); t += from; - for (; f != replaced.end(); ++f, ++t) - *t = *f; - } + if (!_root) + return; + qdeclarativelistmodel_move<QVariantList>(from, to, n, &_root->values); } bool NestedListModel::append(const QScriptValue& valuemap) { if (!_root) { - _root = new ModelNode; + _root = new ModelNode(this); m_ownsRoot = true; } - ModelNode *mn = new ModelNode; - mn->setObjectValue(valuemap); - _root->values << qVariantFromValue(mn); + + insert(count(), valuemap); return true; } @@ -1252,8 +1421,8 @@ QString NestedListModel::toString(int role) const } -ModelNode::ModelNode() -: modelCache(0), objectCache(0), isArray(false) +ModelNode::ModelNode(NestedListModel *model) +: modelCache(0), objectCache(0), isArray(false), m_model(model), listIndex(-1) { } @@ -1277,18 +1446,18 @@ void ModelNode::clear() properties.clear(); } -void ModelNode::setObjectValue(const QScriptValue& valuemap) { +void ModelNode::setObjectValue(const QScriptValue& valuemap, bool writeToCache) { QScriptValueIterator it(valuemap); while (it.hasNext()) { it.next(); - ModelNode *value = new ModelNode; + ModelNode *value = new ModelNode(m_model); QScriptValue v = it.value(); if (v.isArray()) { value->isArray = true; value->setListValue(v); } else { value->values << v.toVariant(); - if (objectCache) + if (writeToCache && objectCache) objectCache->setValue(it.name().toUtf8(), value->values.last()); } if (properties.contains(it.name())) @@ -1301,14 +1470,16 @@ void ModelNode::setListValue(const QScriptValue& valuelist) { values.clear(); int size = valuelist.property(QLatin1String("length")).toInt32(); for (int i=0; i<size; i++) { - ModelNode *value = new ModelNode; + ModelNode *value = new ModelNode(m_model); QScriptValue v = valuelist.property(i); if (v.isArray()) { value->isArray = true; value->setListValue(v); } else if (v.isObject()) { + value->listIndex = i; value->setObjectValue(v); } else { + value->listIndex = i; value->values << v.toVariant(); } values.append(qVariantFromValue(value)); @@ -1320,7 +1491,7 @@ void ModelNode::setProperty(const QString& prop, const QVariant& val) { if (it != properties.end()) { (*it)->values[0] = val; } else { - ModelNode *n = new ModelNode; + ModelNode *n = new ModelNode(m_model); n->values << val; properties.insert(prop,n); } @@ -1328,6 +1499,40 @@ void ModelNode::setProperty(const QString& prop, const QVariant& val) { objectCache->setValue(prop.toUtf8(), val); } +void ModelNode::updateListIndexes() +{ + for (QHash<QString, ModelNode *>::ConstIterator iter = properties.begin(); iter != properties.end(); ++iter) { + ModelNode *node = iter.value(); + if (node->isArray) { + for (int i=0; i<node->values.count(); ++i) { + ModelNode *subNode = qvariant_cast<ModelNode *>(node->values.at(i)); + if (subNode) + subNode->listIndex = i; + } + } + node->updateListIndexes(); + } +} + +/* + Need to call this to emit itemsChanged() for modifications outside of set() + and setProperty(), i.e. if an item returned from get() is modified +*/ +void ModelNode::changedProperty(const QString &name) const +{ + if (listIndex < 0) + return; + + m_model->checkRoles(); + QList<int> roles; + int role = m_model->roleStrings.indexOf(name); + if (role < 0) + roles = m_model->roles(); + else + roles << role; + emit m_model->m_listModel->itemsChanged(listIndex, 1, roles); +} + void ModelNode::dump(ModelNode *node, int ind) { QByteArray indentBa(ind * 4, ' '); @@ -1349,16 +1554,47 @@ void ModelNode::dump(ModelNode *node, int ind) } } -ModelObject::ModelObject() -: _mo(new QDeclarativeOpenMetaObject(this)) +ModelObject::ModelObject(ModelNode *node, NestedListModel *model, QScriptEngine *seng) + : m_model(model), + m_node(node), + m_meta(new ModelNodeMetaObject(seng, this)) { } void ModelObject::setValue(const QByteArray &name, const QVariant &val) { - _mo->setValue(name, val); + m_meta->setValue(name, val); setProperty(name.constData(), val); } +void ModelObject::setNodeUpdatesEnabled(bool enable) +{ + m_meta->m_enabled = enable; +} + + +ModelNodeMetaObject::ModelNodeMetaObject(QScriptEngine *seng, ModelObject *object) + : QDeclarativeOpenMetaObject(object), + m_enabled(false), + m_seng(seng), + m_obj(object) +{ +} + +void ModelNodeMetaObject::propertyWritten(int index) +{ + if (!m_enabled) + return; + + QString propName = QString::fromUtf8(name(index)); + QVariant value = operator[](index); + + QScriptValue sv = m_seng->newObject(); + sv.setProperty(propName, m_seng->newVariant(value)); + m_obj->m_node->setObjectValue(sv, false); + + m_obj->m_node->changedProperty(propName); +} + QT_END_NAMESPACE diff --git a/src/declarative/util/qdeclarativelistmodel_p.h b/src/declarative/util/qdeclarativelistmodel_p.h index 6aff9c6..fe42ef6 100644 --- a/src/declarative/util/qdeclarativelistmodel_p.h +++ b/src/declarative/util/qdeclarativelistmodel_p.h @@ -63,6 +63,7 @@ class FlatListModel; class NestedListModel; class QDeclarativeListModelWorkerAgent; struct ModelNode; +class FlatListScriptClass; class Q_DECLARATIVE_EXPORT QDeclarativeListModel : public QListModelInterface { Q_OBJECT @@ -96,16 +97,21 @@ Q_SIGNALS: private: friend class QDeclarativeListModelParser; friend class QDeclarativeListModelWorkerAgent; + friend class FlatListModel; + friend class FlatListScriptClass; friend struct ModelNode; - QDeclarativeListModel(bool workerCopy, QObject *parent=0); + // Constructs a flat list model for a worker agent + QDeclarativeListModel(const QDeclarativeListModel *orig, QDeclarativeListModelWorkerAgent *parent); + bool flatten(); - bool modifyCheck(); + bool inWorkerThread() const; + + inline bool canMove(int from, int to, int n) const { return !(from+n > count() || to+n > count() || from < 0 || to < 0 || n < 0); } QDeclarativeListModelWorkerAgent *m_agent; NestedListModel *m_nested; FlatListModel *m_flat; - bool m_isWorkerCopy; }; // ### FIXME diff --git a/src/declarative/util/qdeclarativelistmodel_p_p.h b/src/declarative/util/qdeclarativelistmodel_p_p.h index 8231414..acf4f3e 100644 --- a/src/declarative/util/qdeclarativelistmodel_p_p.h +++ b/src/declarative/util/qdeclarativelistmodel_p_p.h @@ -54,9 +54,11 @@ // #include "private/qdeclarativelistmodel_p.h" - -#include "qdeclarative.h" #include "private/qdeclarativeengine_p.h" +#include "private/qdeclarativeopenmetaobject_p.h" +#include "qdeclarative.h" + +#include <private/qscriptdeclarativeclass_p.h> QT_BEGIN_HEADER @@ -68,6 +70,8 @@ class QDeclarativeOpenMetaObject; class QScriptEngine; class QDeclarativeListModelWorkerAgent; struct ModelNode; +class FlatListScriptClass; +class FlatNodeData; class FlatListModel { @@ -94,16 +98,82 @@ public: private: friend class QDeclarativeListModelWorkerAgent; friend class QDeclarativeListModel; + friend class FlatListScriptClass; + friend class FlatNodeData; bool addValue(const QScriptValue &value, QHash<int, QVariant> *row, QList<int> *roles); + void insertedNode(int index); + void removedNode(int index); + void moveNodes(int from, int to, int n); QScriptEngine *m_scriptEngine; QHash<int, QString> m_roles; QHash<QString, int> m_strings; QList<QHash<int, QVariant> > m_values; QDeclarativeListModel *m_listModel; + + FlatListScriptClass *m_scriptClass; + QList<FlatNodeData *> m_nodeData; + QDeclarativeListModelWorkerAgent *m_parentAgent; +}; + + +/* + Created when get() is called on a FlatListModel. This allows changes to the + object returned by get() to be tracked, and passed onto the model. +*/ +class FlatListScriptClass : public QScriptDeclarativeClass +{ +public: + FlatListScriptClass(FlatListModel *model, QScriptEngine *seng); + + Value property(Object *, const Identifier &); + void setProperty(Object *, const Identifier &name, const QScriptValue &); + QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, QScriptClass::QueryFlags flags); + bool compare(Object *, Object *); + +private: + FlatListModel *m_model; +}; + +/* + FlatNodeData and FlatNodeObjectData allow objects returned by get() to still + point to the correct list index if move(), insert() or remove() are called. +*/ +struct FlatNodeObjectData; +class FlatNodeData +{ +public: + FlatNodeData(int i) + : index(i) {} + + ~FlatNodeData(); + + void addData(FlatNodeObjectData *data); + void removeData(FlatNodeObjectData *data); + + int index; + +private: + QSet<FlatNodeObjectData*> objects; }; +struct FlatNodeObjectData : public QScriptDeclarativeClass::Object +{ + FlatNodeObjectData(FlatNodeData *data) : nodeData(data) { + nodeData->addData(this); + } + + ~FlatNodeObjectData() { + if (nodeData) + nodeData->removeData(this); + } + + FlatNodeData *nodeData; +}; + + + class NestedListModel { public: @@ -134,25 +204,50 @@ public: QDeclarativeListModel *m_listModel; private: + friend struct ModelNode; mutable QStringList roleStrings; mutable bool _rolesOk; }; +class ModelNodeMetaObject; class ModelObject : public QObject { Q_OBJECT public: - ModelObject(); + ModelObject(ModelNode *node, NestedListModel *model, QScriptEngine *seng); void setValue(const QByteArray &name, const QVariant &val); + void setNodeUpdatesEnabled(bool enable); + + NestedListModel *m_model; + ModelNode *m_node; + +private: + ModelNodeMetaObject *m_meta; +}; + +class ModelNodeMetaObject : public QDeclarativeOpenMetaObject +{ +public: + ModelNodeMetaObject(QScriptEngine *seng, ModelObject *object); + + bool m_enabled; + +protected: + void propertyWritten(int index); private: - QDeclarativeOpenMetaObject *_mo; + QScriptEngine *m_seng; + ModelObject *m_obj; }; + +/* + A ModelNode is created for each item in a NestedListModel. +*/ struct ModelNode { - ModelNode(); + ModelNode(NestedListModel *model); ~ModelNode(); QList<QVariant> values; @@ -165,30 +260,44 @@ struct ModelNode modelCache = new QDeclarativeListModel; QDeclarativeEngine::setContextForObject(modelCache,QDeclarativeEngine::contextForObject(model->m_listModel)); modelCache->m_nested->_root = this; // ListModel defaults to nestable model + + for (int i=0; i<values.count(); ++i) { + ModelNode *subNode = qvariant_cast<ModelNode *>(values.at(i)); + if (subNode) + subNode->m_model = modelCache->m_nested; + } } return modelCache; } ModelObject *object(const NestedListModel *model) { if (!objectCache) { - objectCache = new ModelObject(); + objectCache = new ModelObject(this, + const_cast<NestedListModel*>(model), + QDeclarativeEnginePrivate::getScriptEngine(qmlEngine(model->m_listModel))); QHash<QString, ModelNode *>::iterator it; for (it = properties.begin(); it != properties.end(); ++it) { objectCache->setValue(it.key().toUtf8(), model->valueForNode(*it)); } + objectCache->setNodeUpdatesEnabled(true); } return objectCache; } - void setObjectValue(const QScriptValue& valuemap); + void setObjectValue(const QScriptValue& valuemap, bool writeToCache = true); void setListValue(const QScriptValue& valuelist); void setProperty(const QString& prop, const QVariant& val); + void changedProperty(const QString &name) const; + void updateListIndexes(); static void dump(ModelNode *node, int ind); QDeclarativeListModel *modelCache; ModelObject *objectCache; bool isArray; + + NestedListModel *m_model; + int listIndex; // only used for top-level nodes within a list }; diff --git a/src/declarative/util/qdeclarativelistmodelworkeragent.cpp b/src/declarative/util/qdeclarativelistmodelworkeragent.cpp index d9df169..6804d4a 100644 --- a/src/declarative/util/qdeclarativelistmodelworkeragent.cpp +++ b/src/declarative/util/qdeclarativelistmodelworkeragent.cpp @@ -83,11 +83,11 @@ void QDeclarativeListModelWorkerAgent::Data::changedChange(int index, int count) } QDeclarativeListModelWorkerAgent::QDeclarativeListModelWorkerAgent(QDeclarativeListModel *model) -: m_engine(0), m_ref(1), m_orig(model), m_copy(new QDeclarativeListModel(true, this)) + : m_engine(0), + m_ref(1), + m_orig(model), + m_copy(new QDeclarativeListModel(model, this)) { - m_copy->m_flat->m_roles = m_orig->m_flat->m_roles; - m_copy->m_flat->m_strings = m_orig->m_flat->m_strings; - m_copy->m_flat->m_values = m_orig->m_flat->m_values; } QDeclarativeListModelWorkerAgent::~QDeclarativeListModelWorkerAgent() @@ -194,6 +194,11 @@ void QDeclarativeListModelWorkerAgent::sync() mutex.unlock(); } +void QDeclarativeListModelWorkerAgent::changedData(int index, int count) +{ + data.changedChange(index, count); +} + bool QDeclarativeListModelWorkerAgent::event(QEvent *e) { if (e->type() == QEvent::User) { @@ -216,6 +221,24 @@ bool QDeclarativeListModelWorkerAgent::event(QEvent *e) orig->m_strings = copy->m_strings; orig->m_values = copy->m_values; + // update the orig->m_nodeData list + for (int ii = 0; ii < changes.count(); ++ii) { + const Change &change = changes.at(ii); + switch (change.type) { + case Change::Inserted: + orig->insertedNode(change.index); + break; + case Change::Removed: + orig->removedNode(change.index); + break; + case Change::Moved: + orig->moveNodes(change.index, change.to, change.count); + break; + case Change::Changed: + break; + } + } + syncDone.wakeAll(); locker.unlock(); @@ -232,7 +255,7 @@ bool QDeclarativeListModelWorkerAgent::event(QEvent *e) emit m_orig->itemsMoved(change.index, change.to, change.count); break; case Change::Changed: - emit m_orig->itemsChanged(change.index, change.to, orig->m_roles.keys()); + emit m_orig->itemsChanged(change.index, change.count, orig->m_roles.keys()); break; } } diff --git a/src/declarative/util/qdeclarativelistmodelworkeragent_p.h b/src/declarative/util/qdeclarativelistmodelworkeragent_p.h index 01da374..10c3bca 100644 --- a/src/declarative/util/qdeclarativelistmodelworkeragent_p.h +++ b/src/declarative/util/qdeclarativelistmodelworkeragent_p.h @@ -67,6 +67,7 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) class QDeclarativeListModel; +class FlatListScriptClass; class QDeclarativeListModelWorkerAgent : public QObject { @@ -115,6 +116,7 @@ protected: private: friend class QDeclarativeWorkerScriptEnginePrivate; + friend class FlatListScriptClass; QScriptEngine *m_engine; struct Change { @@ -141,6 +143,8 @@ private: QDeclarativeListModel *list; }; + void changedData(int index, int count); + QAtomicInt m_ref; QDeclarativeListModel *m_orig; QDeclarativeListModel *m_copy; diff --git a/src/declarative/util/qdeclarativexmllistmodel.cpp b/src/declarative/util/qdeclarativexmllistmodel.cpp index 47b502d..f0ed80b 100644 --- a/src/declarative/util/qdeclarativexmllistmodel.cpp +++ b/src/declarative/util/qdeclarativexmllistmodel.cpp @@ -209,8 +209,9 @@ Q_SIGNALS: protected: void run() { + m_mutex.lock(); + while (!m_quit) { - m_mutex.lock(); if (!m_jobs.isEmpty()) m_currentJob = m_jobs.dequeue(); m_mutex.unlock(); @@ -230,12 +231,13 @@ protected: m_mutex.lock(); if (m_currentJob.queryId != -1 && m_abortQueryId != m_currentJob.queryId) emit queryCompleted(r); - if (m_jobs.isEmpty()) + if (m_jobs.isEmpty() && !m_quit) m_condition.wait(&m_mutex); m_currentJob.queryId = -1; m_abortQueryId = -1; - m_mutex.unlock(); } + + m_mutex.unlock(); } private: |