aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Jones <martin.jones@nokia.com>2011-11-03 15:52:13 +1000
committerQt by Nokia <qt-info@nokia.com>2011-12-01 01:14:53 +0100
commit5f5aba5b6e690ca54e66f41b93474f7e67e83c8b (patch)
tree874c9944c5a2b5b0b717da2bd8b018ce291a0ff7
parent01479573b98747b39833ab09e2cd9ee618ad2a0f (diff)
Non-blocking view delegate instantiation.
Task-number: QTBUG-21792 Change-Id: I29a4028cd24eb55d4768aacaa3abbd1786061398 Reviewed-by: Andrew den Exter <andrew.den-exter@nokia.com>
-rw-r--r--src/declarative/items/qquickgridview.cpp75
-rw-r--r--src/declarative/items/qquickitemview.cpp136
-rw-r--r--src/declarative/items/qquickitemview_p.h4
-rw-r--r--src/declarative/items/qquickitemview_p_p.h7
-rw-r--r--src/declarative/items/qquicklistview.cpp49
-rw-r--r--src/declarative/items/qquickloader.cpp30
-rw-r--r--src/declarative/items/qquickpathview.cpp207
-rw-r--r--src/declarative/items/qquickpathview_p.h4
-rw-r--r--src/declarative/items/qquickpathview_p_p.h11
-rw-r--r--src/declarative/items/qquickrepeater.cpp94
-rw-r--r--src/declarative/items/qquickrepeater_p.h1
-rw-r--r--src/declarative/items/qquickrepeater_p_p.h10
-rw-r--r--src/declarative/items/qquickvisualdatamodel.cpp425
-rw-r--r--src/declarative/items/qquickvisualdatamodel_p.h4
-rw-r--r--src/declarative/items/qquickvisualitemmodel.cpp12
-rw-r--r--src/declarative/items/qquickvisualitemmodel_p.h9
-rw-r--r--tests/auto/declarative/qquickgridview/data/asyncloader.qml36
-rw-r--r--tests/auto/declarative/qquickgridview/data/gridview1.qml2
-rw-r--r--tests/auto/declarative/qquickgridview/tst_qquickgridview.cpp147
-rw-r--r--tests/auto/declarative/qquicklistview/data/asyncloader.qml36
-rw-r--r--tests/auto/declarative/qquicklistview/data/listviewtest.qml2
-rw-r--r--tests/auto/declarative/qquicklistview/tst_qquicklistview.cpp132
-rw-r--r--tests/auto/declarative/qquickpathview/data/asyncloader.qml71
-rw-r--r--tests/auto/declarative/qquickpathview/tst_qquickpathview.cpp60
-rw-r--r--tests/auto/declarative/qquickrepeater/data/asyncloader.qml32
-rw-r--r--tests/auto/declarative/qquickrepeater/tst_qquickrepeater.cpp59
26 files changed, 1232 insertions, 423 deletions
diff --git a/src/declarative/items/qquickgridview.cpp b/src/declarative/items/qquickgridview.cpp
index 51131ab742..44e1f14c6f 100644
--- a/src/declarative/items/qquickgridview.cpp
+++ b/src/declarative/items/qquickgridview.cpp
@@ -294,7 +294,10 @@ qreal QQuickGridViewPrivate::colPosAt(int modelIndex) const
if (FxViewItem *item = visibleItem(modelIndex))
return static_cast<FxGridItemSG*>(item)->colPos();
if (!visibleItems.isEmpty()) {
- if (modelIndex < visibleIndex) {
+ if (modelIndex == visibleIndex) {
+ FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.first());
+ return firstItem->colPos();
+ } else if (modelIndex < visibleIndex) {
int count = (visibleIndex - modelIndex) % columns;
int col = static_cast<FxGridItemSG*>(visibleItems.first())->colPos() / colSize();
col = (columns - count + col) % columns;
@@ -312,7 +315,10 @@ qreal QQuickGridViewPrivate::rowPosAt(int modelIndex) const
if (FxViewItem *item = visibleItem(modelIndex))
return static_cast<FxGridItemSG*>(item)->rowPos();
if (!visibleItems.isEmpty()) {
- if (modelIndex < visibleIndex) {
+ if (modelIndex == visibleIndex) {
+ FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.first());
+ return firstItem->rowPos();
+ } else if (modelIndex < visibleIndex) {
FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.first());
int firstCol = firstItem->colPos() / colSize();
int col = visibleIndex - modelIndex + (columns - firstCol - 1);
@@ -438,10 +444,11 @@ bool QQuickGridViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, bool d
bool changed = false;
while (modelIndex < model->count() && rowPos <= fillTo + rowSize()*(columns - colNum)/(columns+1)) {
-// qDebug() << "refill: append item" << modelIndex;
- if (!(item = static_cast<FxGridItemSG*>(createItem(modelIndex))))
+// qDebug() << "refill: append item" << modelIndex << colPos << rowPos;
+ if (!(item = static_cast<FxGridItemSG*>(createItem(modelIndex, doBuffer))))
break;
item->setPosition(colPos, rowPos);
+ item->item->setVisible(!doBuffer);
visibleItems.append(item);
if (++colNum >= columns) {
colNum = 0;
@@ -450,8 +457,6 @@ bool QQuickGridViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, bool d
colPos = colNum * colSize();
++modelIndex;
changed = true;
- if (doBuffer) // never buffer more than one item per frame
- break;
}
// Find first column
@@ -471,10 +476,11 @@ bool QQuickGridViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, bool d
colPos = colNum * colSize();
while (visibleIndex > 0 && rowPos + rowSize() - 1 >= fillFrom - rowSize()*(colNum+1)/(columns+1)){
// qDebug() << "refill: prepend item" << visibleIndex-1 << "top pos" << rowPos << colPos;
- if (!(item = static_cast<FxGridItemSG*>(createItem(visibleIndex-1))))
+ if (!(item = static_cast<FxGridItemSG*>(createItem(visibleIndex-1, doBuffer))))
break;
--visibleIndex;
item->setPosition(colPos, rowPos);
+ item->item->setVisible(!doBuffer);
visibleItems.prepend(item);
if (--colNum < 0) {
colNum = columns-1;
@@ -482,8 +488,6 @@ bool QQuickGridViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, bool d
}
colPos = colNum * colSize();
changed = true;
- if (doBuffer) // never buffer more than one item per frame
- break;
}
return changed;
@@ -491,6 +495,7 @@ bool QQuickGridViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, bool d
bool QQuickGridViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal bufferTo)
{
+ Q_Q(QQuickGridView);
FxGridItemSG *item = 0;
bool changed = false;
@@ -499,7 +504,7 @@ bool QQuickGridViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal buffer
&& item->rowPos()+rowSize()-1 < bufferFrom - rowSize()*(item->colPos()/colSize()+1)/(columns+1)) {
if (item->attached->delayRemove())
break;
-// qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endRowPos();
+// qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endRowPos();
if (item->index != -1)
visibleIndex++;
visibleItems.removeFirst();
@@ -511,7 +516,7 @@ bool QQuickGridViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal buffer
&& item->rowPos() > bufferTo + rowSize()*(columns - item->colPos()/colSize())/(columns+1)) {
if (item->attached->delayRemove())
break;
-// qDebug() << "refill: remove last" << visibleIndex+visibleItems.count()-1;
+// qDebug() << "refill: remove last" << visibleIndex+visibleItems.count()-1;
visibleItems.removeLast();
releaseItem(item);
changed = true;
@@ -1341,11 +1346,16 @@ void QQuickGridView::setHighlightFollowsCurrentItem(bool autoHighlight)
This property determines whether delegates are retained outside the
visible area of the view.
- If non-zero the view will keep as many delegates
+ If non-zero the view may keep as many delegates
instantiated as will fit within the buffer specified. For example,
- if in a vertical view the delegate is 20 pixels high and \c cacheBuffer is
- set to 40, then up to 2 delegates above and 2 delegates below the visible
- area may be retained.
+ if in a vertical view the delegate is 20 pixels high, there are 3
+ columns and \c cacheBuffer is
+ set to 40, then up to 6 delegates above and 6 delegates below the visible
+ area may be created/retained. The buffered delegates are created asynchronously,
+ allowing creation to occur across multiple frames and reducing the
+ likelihood of skipping frames. In order to improve painting performance
+ delegates outside the visible area have their \l visible property set to
+ false until they are moved into the visible area.
Note that cacheBuffer is not a pixel buffer - it only maintains additional
instantiated delegates.
@@ -1507,22 +1517,21 @@ void QQuickGridView::viewportMoved()
return;
d->inViewportMoved = true;
- d->lazyRelease = true;
- if (d->hData.flicking || d->vData.flicking) {
- if (yflick()) {
- if (d->vData.velocity > 0)
- d->bufferMode = QQuickGridViewPrivate::BufferBefore;
- else if (d->vData.velocity < 0)
- d->bufferMode = QQuickGridViewPrivate::BufferAfter;
- }
-
- if (xflick()) {
- if (d->hData.velocity > 0)
- d->bufferMode = QQuickGridViewPrivate::BufferBefore;
- else if (d->hData.velocity < 0)
- d->bufferMode = QQuickGridViewPrivate::BufferAfter;
- }
+ // Set visibility of items to eliminate cost of items outside the visible area.
+ qreal from = d->isContentFlowReversed() ? -d->position()-d->size() : d->position();
+ qreal to = d->isContentFlowReversed() ? -d->position() : d->position()+d->size();
+ for (int i = 0; i < d->visibleItems.count(); ++i) {
+ FxGridItemSG *item = static_cast<FxGridItemSG*>(d->visibleItems.at(i));
+ item->item->setVisible(item->rowPos() + d->rowSize() >= from && item->rowPos() <= to);
}
+
+ if (yflick())
+ d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferBefore : QQuickItemViewPrivate::BufferAfter;
+ else if (d->isRightToLeftTopToBottom())
+ d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferAfter : QQuickItemViewPrivate::BufferBefore;
+ else
+ d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferBefore : QQuickItemViewPrivate::BufferAfter;
+
d->refill();
if (d->hData.flicking || d->vData.flicking || d->hData.moving || d->vData.moving)
d->moveReason = QQuickGridViewPrivate::Mouse;
@@ -1815,7 +1824,10 @@ bool QQuickGridViewPrivate::applyInsertionChange(const QDeclarativeChangeSet::In
}
if (!item)
item = createItem(modelIndex + i);
+ if (!item)
+ return false;
+ item->item->setVisible(true);
visibleItems.insert(insertionIdx, item);
if (!change.isMove()) {
insertResult->addedItems.append(item);
@@ -1843,7 +1855,10 @@ bool QQuickGridViewPrivate::applyInsertionChange(const QDeclarativeChangeSet::In
}
if (!item)
item = createItem(modelIndex + i);
+ if (!item)
+ return false;
+ item->item->setVisible(true);
visibleItems.insert(index, item);
if (!change.isMove())
insertResult->addedItems.append(item);
diff --git a/src/declarative/items/qquickitemview.cpp b/src/declarative/items/qquickitemview.cpp
index 63855ae7cb..c329cd525e 100644
--- a/src/declarative/items/qquickitemview.cpp
+++ b/src/declarative/items/qquickitemview.cpp
@@ -178,6 +178,7 @@ void QQuickItemView::setModel(const QVariant &model)
if (d->model) {
disconnect(d->model, SIGNAL(modelUpdated(QDeclarativeChangeSet,bool)),
this, SLOT(modelUpdated(QDeclarativeChangeSet,bool)));
+ disconnect(d->model, SIGNAL(initItem(int,QQuickItem*)), this, SLOT(initItem(int,QQuickItem*)));
disconnect(d->model, SIGNAL(createdItem(int,QQuickItem*)), this, SLOT(createdItem(int,QQuickItem*)));
disconnect(d->model, SIGNAL(destroyingItem(QQuickItem*)), this, SLOT(destroyingItem(QQuickItem*)));
}
@@ -212,6 +213,9 @@ void QQuickItemView::setModel(const QVariant &model)
if (d->model) {
d->bufferMode = QQuickItemViewPrivate::BufferBefore | QQuickItemViewPrivate::BufferAfter;
+ connect(d->model, SIGNAL(createdItem(int,QQuickItem*)), this, SLOT(createdItem(int,QQuickItem*)));
+ connect(d->model, SIGNAL(initItem(int,QQuickItem*)), this, SLOT(initItem(int,QQuickItem*)));
+ connect(d->model, SIGNAL(destroyingItem(QQuickItem*)), this, SLOT(destroyingItem(QQuickItem*)));
if (isComponentComplete()) {
updateSections();
d->refill();
@@ -231,8 +235,6 @@ void QQuickItemView::setModel(const QVariant &model)
}
connect(d->model, SIGNAL(modelUpdated(QDeclarativeChangeSet,bool)),
this, SLOT(modelUpdated(QDeclarativeChangeSet,bool)));
- connect(d->model, SIGNAL(createdItem(int,QQuickItem*)), this, SLOT(createdItem(int,QQuickItem*)));
- connect(d->model, SIGNAL(destroyingItem(QQuickItem*)), this, SLOT(destroyingItem(QQuickItem*)));
emit countChanged();
}
emit modelChanged();
@@ -785,26 +787,11 @@ void QQuickItemView::modelUpdated(const QDeclarativeChangeSet &changeSet, bool r
}
}
-void QQuickItemView::createdItem(int index, QQuickItem *item)
-{
- Q_D(QQuickItemView);
- if (d->requestedIndex != index) {
- item->setParentItem(contentItem());
- d->unrequestedItems.insert(item, index);
- d->repositionPackageItemAt(item, index);
- }
-}
-
-void QQuickItemView::destroyingItem(QQuickItem *item)
-{
- Q_D(QQuickItemView);
- d->unrequestedItems.remove(item);
-}
-
void QQuickItemView::animStopped()
{
Q_D(QQuickItemView);
- d->bufferMode = QQuickItemViewPrivate::NoBuffer;
+ d->bufferMode = QQuickItemViewPrivate::BufferBefore | QQuickItemViewPrivate::BufferAfter;
+ d->refill();
if (d->haveHighlightRange && d->highlightRange == QQuickItemView::StrictlyEnforceRange)
d->updateHighlight();
}
@@ -1104,16 +1091,17 @@ QQuickItemViewPrivate::QQuickItemViewPrivate()
, moveReason(Other)
, visibleIndex(0)
, currentIndex(-1), currentItem(0)
- , trackedItem(0), requestedIndex(-1)
+ , trackedItem(0), requestedIndex(-1), requestedItem(0)
, highlightComponent(0), highlight(0)
, highlightRange(QQuickItemView::NoHighlightRange)
, highlightRangeStart(0), highlightRangeEnd(0)
, highlightMoveDuration(150)
, headerComponent(0), header(0), footerComponent(0), footer(0)
, minExtent(0), maxExtent(0)
- , ownModel(false), wrap(false), lazyRelease(false), deferredRelease(false)
+ , ownModel(false), wrap(false), deferredRelease(false)
, inApplyModelChanges(false), inViewportMoved(false), forceLayout(false), currentIndexCleared(false)
, haveHighlightRange(false), autoHighlight(true), highlightRangeStartValid(false), highlightRangeEndValid(false)
+ , fillCacheBuffer(false), inRequest(false), requestedAsync(false)
{
}
@@ -1229,6 +1217,7 @@ void QQuickItemViewPrivate::updateCurrent(int modelIndex)
currentItem = 0;
currentIndex = modelIndex;
emit q->currentIndexChanged();
+ emit q->currentItemChanged();
updateHighlight();
} else if (currentIndex != modelIndex) {
currentIndex = modelIndex;
@@ -1243,8 +1232,9 @@ void QQuickItemViewPrivate::updateCurrent(int modelIndex)
}
FxViewItem *oldCurrentItem = currentItem;
+ int oldCurrentIndex = currentIndex;
currentIndex = modelIndex;
- currentItem = createItem(modelIndex);
+ currentItem = createItem(modelIndex, false);
if (oldCurrentItem && (!currentItem || oldCurrentItem->item != currentItem->item))
oldCurrentItem->attached->setIsCurrentItem(false);
if (currentItem) {
@@ -1254,7 +1244,10 @@ void QQuickItemViewPrivate::updateCurrent(int modelIndex)
}
updateHighlight();
- emit q->currentIndexChanged();
+ if (oldCurrentIndex != currentIndex)
+ emit q->currentIndexChanged();
+ if (oldCurrentItem != currentItem)
+ emit q->currentItemChanged();
releaseItem(oldCurrentItem);
}
@@ -1318,7 +1311,7 @@ void QQuickItemViewPrivate::refill(qreal from, qreal to, bool doBuffer)
bool changed = addVisibleItems(fillFrom, fillTo, doBuffer);
- if (!lazyRelease || !changed || deferredRelease) { // avoid destroying items in the same frame that we create
+ if (!changed || deferredRelease) { // avoid destroying items in the same frame that we create
if (removeNonVisibleItems(bufferFrom, bufferTo))
changed = true;
deferredRelease = false;
@@ -1333,7 +1326,11 @@ void QQuickItemViewPrivate::refill(qreal from, qreal to, bool doBuffer)
refill(from, to, true);
}
- lazyRelease = false;
+ if (!q->isMoving() && changed) {
+ fillCacheBuffer = true;
+ q->polish();
+ }
+
if (prevCount != itemCount)
emit q->countChanged();
}
@@ -1380,8 +1377,11 @@ void QQuickItemViewPrivate::layout()
return;
}
- if (!applyModelChanges() && !forceLayout)
+ if (!applyModelChanges() && !forceLayout) {
+ if (fillCacheBuffer)
+ refill();
return;
+ }
forceLayout = false;
layoutVisibleItems();
@@ -1407,6 +1407,7 @@ bool QQuickItemViewPrivate::applyModelChanges()
Q_Q(QQuickItemView);
if (!q->isComponentComplete() || !currentChanges.hasPendingChanges() || inApplyModelChanges)
return false;
+
inApplyModelChanges = true;
updateUnrequestedIndexes();
@@ -1557,38 +1558,87 @@ bool QQuickItemViewPrivate::applyModelChanges()
return visibleAffected;
}
-FxViewItem *QQuickItemViewPrivate::createItem(int modelIndex)
+/*
+ This may return 0 if the item is being created asynchronously.
+ When the item becomes available, refill() will be called and the item
+ will be returned on the next call to createItem().
+*/
+FxViewItem *QQuickItemViewPrivate::createItem(int modelIndex, bool asynchronous)
{
Q_Q(QQuickItemView);
+ if (requestedIndex == modelIndex && (asynchronous || requestedAsync == asynchronous))
+ return 0;
+
+ if (requestedIndex != -1 && requestedIndex != modelIndex) {
+ delete requestedItem;
+ requestedItem = 0;
+ }
requestedIndex = modelIndex;
- FxViewItem *viewItem = 0;
+ requestedAsync = asynchronous;
+ inRequest = true;
- if (QQuickItem *item = model->item(modelIndex, false)) {
- viewItem = newViewItem(modelIndex, item);
+ if (QQuickItem *item = model->item(modelIndex, asynchronous)) {
+ item->setParentItem(q->contentItem());
+ QDeclarative_setParent_noEvent(item, q->contentItem());
+ requestedIndex = -1;
+ fillCacheBuffer = false;
+ FxViewItem *viewItem = requestedItem;
+ if (!viewItem)
+ viewItem = newViewItem(modelIndex, item); // already in cache, so viewItem not initialized in initItem()
if (viewItem) {
viewItem->index = modelIndex;
- if (model->completePending()) {
- // complete
- viewItem->item->setZ(1);
- QDeclarative_setParent_noEvent(viewItem->item, q->contentItem());
- viewItem->item->setParentItem(q->contentItem());
- model->completeItem();
- } else {
- QDeclarative_setParent_noEvent(viewItem->item, q->contentItem());
- viewItem->item->setParentItem(q->contentItem());
- }
// do other set up for the new item that should not happen
// until after bindings are evaluated
initializeViewItem(viewItem);
+ unrequestedItems.remove(item);
+ }
+ requestedItem = 0;
+ inRequest = false;
+ return viewItem;
+ }
+
+ inRequest = false;
+ return 0;
+}
- unrequestedItems.remove(viewItem->item);
+void QQuickItemView::createdItem(int index, QQuickItem *item)
+{
+ Q_D(QQuickItemView);
+ if (d->requestedIndex != index) {
+ item->setParentItem(contentItem());
+ d->unrequestedItems.insert(item, index);
+ item->setVisible(false);
+ d->repositionPackageItemAt(item, index);
+ } else {
+ d->requestedIndex = -1;
+ if (!d->inRequest) {
+ if (index == d->currentIndex)
+ d->updateCurrent(index);
+ d->refill();
+ } else {
+ d->fillCacheBuffer = true;
+ polish();
}
}
- requestedIndex = -1;
- return viewItem;
}
+void QQuickItemView::initItem(int index, QQuickItem *item)
+{
+ Q_D(QQuickItemView);
+ item->setZ(1);
+ if (d->requestedIndex == index) {
+ item->setParentItem(contentItem());
+ QDeclarative_setParent_noEvent(item, contentItem());
+ d->requestedItem = d->newViewItem(index, item);
+ }
+}
+
+void QQuickItemView::destroyingItem(QQuickItem *item)
+{
+ Q_D(QQuickItemView);
+ d->unrequestedItems.remove(item);
+}
void QQuickItemViewPrivate::releaseItem(FxViewItem *item)
{
diff --git a/src/declarative/items/qquickitemview_p.h b/src/declarative/items/qquickitemview_p.h
index 8bb63539b4..b8e27e4741 100644
--- a/src/declarative/items/qquickitemview_p.h
+++ b/src/declarative/items/qquickitemview_p.h
@@ -63,7 +63,7 @@ class Q_AUTOTEST_EXPORT QQuickItemView : public QQuickFlickable
Q_PROPERTY(int count READ count NOTIFY countChanged)
Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged)
- Q_PROPERTY(QQuickItem *currentItem READ currentItem NOTIFY currentIndexChanged)
+ Q_PROPERTY(QQuickItem *currentItem READ currentItem NOTIFY currentItemChanged)
Q_PROPERTY(bool keyNavigationWraps READ isWrapEnabled WRITE setWrapEnabled NOTIFY keyNavigationWrapsChanged)
Q_PROPERTY(int cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged)
@@ -161,6 +161,7 @@ signals:
void delegateChanged();
void countChanged();
void currentIndexChanged();
+ void currentItemChanged();
void keyNavigationWrapsChanged();
void cacheBufferChanged();
@@ -194,6 +195,7 @@ protected slots:
virtual void updateSections() {}
void destroyRemoved();
void createdItem(int index, QQuickItem *item);
+ void initItem(int index, QQuickItem *item);
void modelUpdated(const QDeclarativeChangeSet &changeSet, bool reset);
void destroyingItem(QQuickItem *item);
void animStopped();
diff --git a/src/declarative/items/qquickitemview_p_p.h b/src/declarative/items/qquickitemview_p_p.h
index ca4c0ceba9..4db274e045 100644
--- a/src/declarative/items/qquickitemview_p_p.h
+++ b/src/declarative/items/qquickitemview_p_p.h
@@ -133,7 +133,7 @@ public:
void refill(qreal from, qreal to, bool doBuffer = false);
void mirrorChange();
- FxViewItem *createItem(int modelIndex);
+ FxViewItem *createItem(int modelIndex, bool asynchronous = false);
virtual void releaseItem(FxViewItem *item);
QQuickItem *createHighlightItem();
@@ -173,6 +173,7 @@ public:
FxViewItem *trackedItem;
QHash<QQuickItem*,int> unrequestedItems;
int requestedIndex;
+ FxViewItem *requestedItem;
QQuickItemViewChangeSet currentChanges;
// XXX split into struct
@@ -193,7 +194,6 @@ public:
bool ownModel : 1;
bool wrap : 1;
- bool lazyRelease : 1;
bool deferredRelease : 1;
bool inApplyModelChanges : 1;
bool inViewportMoved : 1;
@@ -203,6 +203,9 @@ public:
bool autoHighlight : 1;
bool highlightRangeStartValid : 1;
bool highlightRangeEndValid : 1;
+ bool fillCacheBuffer : 1;
+ bool inRequest : 1;
+ bool requestedAsync : 1;
protected:
virtual Qt::Orientation layoutOrientation() const = 0;
diff --git a/src/declarative/items/qquicklistview.cpp b/src/declarative/items/qquicklistview.cpp
index 60164d51c5..86af39075a 100644
--- a/src/declarative/items/qquicklistview.cpp
+++ b/src/declarative/items/qquicklistview.cpp
@@ -603,27 +603,25 @@ bool QQuickListViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, bool d
qreal pos = itemEnd;
while (modelIndex < model->count() && pos <= fillTo) {
// qDebug() << "refill: append item" << modelIndex << "pos" << pos;
- if (!(item = static_cast<FxListItemSG*>(createItem(modelIndex))))
+ if (!(item = static_cast<FxListItemSG*>(createItem(modelIndex, doBuffer))))
break;
item->setPosition(pos);
+ item->item->setVisible(!doBuffer);
pos += item->size() + spacing;
visibleItems.append(item);
++modelIndex;
changed = true;
- if (doBuffer) // never buffer more than one item per frame
- break;
}
- while (visibleIndex > 0 && visibleIndex <= model->count() && visiblePos >= fillFrom) {
+ while (visibleIndex > 0 && visibleIndex <= model->count() && visiblePos > fillFrom) {
// qDebug() << "refill: prepend item" << visibleIndex-1 << "current top pos" << visiblePos;
- if (!(item = static_cast<FxListItemSG*>(createItem(visibleIndex-1))))
+ if (!(item = static_cast<FxListItemSG*>(createItem(visibleIndex-1, doBuffer))))
break;
--visibleIndex;
visiblePos -= item->size() + spacing;
item->setPosition(visiblePos);
+ item->item->setVisible(!doBuffer);
visibleItems.prepend(item);
changed = true;
- if (doBuffer) // never buffer more than one item per frame
- break;
}
return changed;
@@ -640,7 +638,7 @@ bool QQuickListViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal buffer
// over by refill().
int index = 0;
while (visibleItems.count() > 1 && index < visibleItems.count()
- && (item = visibleItems.at(index)) && item->endPosition() <= bufferFrom) {
+ && (item = visibleItems.at(index)) && item->endPosition() < bufferFrom) {
if (item->attached->delayRemove())
break;
if (item->size() > 0) {
@@ -665,7 +663,7 @@ bool QQuickListViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal buffer
while (visibleItems.count() > 1 && (item = visibleItems.last()) && item->position() > bufferTo) {
if (item->attached->delayRemove())
break;
-// qDebug() << "refill: remove last" << visibleIndex+visibleItems.count()-1 << item->position();
+// qDebug() << "refill: remove last" << visibleIndex+visibleItems.count()-1 << item->position();
visibleItems.removeLast();
releaseItem(item);
changed = true;
@@ -1916,11 +1914,15 @@ void QQuickListView::setOrientation(QQuickListView::Orientation orientation)
This property determines whether delegates are retained outside the
visible area of the view.
- If this value is non-zero, the view keeps as many delegates
+ If this value is non-zero, the view may keep as many delegates
instantiated as it can fit within the buffer specified. For example,
if in a vertical view the delegate is 20 pixels high and \c cacheBuffer is
set to 40, then up to 2 delegates above and 2 delegates below the visible
- area may be retained.
+ area may be created/retained. The buffered delegates are created asynchronously,
+ allowing creation to occur across multiple frames and reducing the
+ likelihood of skipping frames. In order to improve painting performance
+ delegates outside the visible area have their \l visible property set to
+ false until they are moved into the visible area.
Note that cacheBuffer is not a pixel buffer - it only maintains additional
instantiated delegates.
@@ -2163,7 +2165,22 @@ void QQuickListView::viewportMoved()
if (d->inViewportMoved)
return;
d->inViewportMoved = true;
- d->lazyRelease = true;
+
+ // Set visibility of items to eliminate cost of items outside the visible area.
+ qreal from = d->isContentFlowReversed() ? -d->position()-d->size() : d->position();
+ qreal to = d->isContentFlowReversed() ? -d->position() : d->position()+d->size();
+ for (int i = 0; i < d->visibleItems.count(); ++i) {
+ FxViewItem *item = static_cast<FxListItemSG*>(d->visibleItems.at(i));
+ item->item->setVisible(item->endPosition() >= from && item->position() <= to);
+ }
+
+ if (yflick())
+ d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter;
+ else if (d->isRightToLeft())
+ d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferAfter : QQuickListViewPrivate::BufferBefore;
+ else
+ d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter;
+
d->refill();
if (d->hData.flicking || d->vData.flicking || d->hData.moving || d->vData.moving)
d->moveReason = QQuickListViewPrivate::Mouse;
@@ -2201,13 +2218,11 @@ void QQuickListView::viewportMoved()
if ((minY - d->vData.move.value() < height()/2 || d->vData.flickTarget - d->vData.move.value() < height()/2)
&& minY != d->vData.flickTarget)
d->flickY(-d->vData.smoothVelocity.value());
- d->bufferMode = QQuickListViewPrivate::BufferBefore;
} else if (d->vData.velocity < 0) {
const qreal maxY = maxYExtent();
if ((d->vData.move.value() - maxY < height()/2 || d->vData.move.value() - d->vData.flickTarget < height()/2)
&& maxY != d->vData.flickTarget)
d->flickY(-d->vData.smoothVelocity.value());
- d->bufferMode = QQuickListViewPrivate::BufferAfter;
}
}
@@ -2217,13 +2232,11 @@ void QQuickListView::viewportMoved()
if ((minX - d->hData.move.value() < width()/2 || d->hData.flickTarget - d->hData.move.value() < width()/2)
&& minX != d->hData.flickTarget)
d->flickX(-d->hData.smoothVelocity.value());
- d->bufferMode = d->isRightToLeft() ? QQuickListViewPrivate::BufferAfter : QQuickListViewPrivate::BufferBefore;
} else if (d->hData.velocity < 0) {
const qreal maxX = maxXExtent();
if ((d->hData.move.value() - maxX < width()/2 || d->hData.move.value() - d->hData.flickTarget < width()/2)
&& maxX != d->hData.flickTarget)
d->flickX(-d->hData.smoothVelocity.value());
- d->bufferMode = d->isRightToLeft() ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter;
}
}
d->inFlickCorrection = false;
@@ -2398,6 +2411,8 @@ bool QQuickListViewPrivate::applyInsertionChange(const QDeclarativeChangeSet::In
}
if (!item)
item = createItem(modelIndex + i);
+ if (!item)
+ return false;
visibleItems.insert(insertionIdx, item);
if (!change.isMove()) {
@@ -2420,6 +2435,8 @@ bool QQuickListViewPrivate::applyInsertionChange(const QDeclarativeChangeSet::In
}
if (!item)
item = createItem(modelIndex + i);
+ if (!item)
+ return false;
visibleItems.insert(index, item);
if (!change.isMove())
diff --git a/src/declarative/items/qquickloader.cpp b/src/declarative/items/qquickloader.cpp
index 242d9f3d7f..f9fd9148ee 100644
--- a/src/declarative/items/qquickloader.cpp
+++ b/src/declarative/items/qquickloader.cpp
@@ -576,6 +576,7 @@ void QQuickLoaderPrivate::incubatorStateChanged(QDeclarativeIncubator::Status st
itemContext = 0;
delete obj;
}
+ incubator->clear();
} else if (status == QDeclarativeIncubator::Error) {
if (!incubator->errors().isEmpty())
QDeclarativeEnginePrivate::warning(qmlEngine(q), incubator->errors());
@@ -616,19 +617,12 @@ void QQuickLoaderPrivate::_q_sourceLoaded()
itemContext = new QDeclarativeContext(creationContext);
itemContext->setContextObject(q);
- if (incubator) {
- bool async = incubator->incubationMode() == QDeclarativeIncubator::Asynchronous;
- if (asynchronous != async) {
- delete incubator;
- incubator = 0;
- }
- }
- if (!incubator)
- incubator = new QQuickLoaderIncubator(this, asynchronous ? QDeclarativeIncubator::Asynchronous : QDeclarativeIncubator::AsynchronousIfNested);
+ delete incubator;
+ incubator = new QQuickLoaderIncubator(this, asynchronous ? QDeclarativeIncubator::Asynchronous : QDeclarativeIncubator::AsynchronousIfNested);
component->create(*incubator, itemContext);
- if (incubator->status() == QDeclarativeIncubator::Loading)
+ if (incubator && incubator->status() == QDeclarativeIncubator::Loading)
emit q->statusChanged();
}
@@ -756,6 +750,22 @@ qreal QQuickLoader::progress() const
This property holds whether the component will be instantiated asynchronously.
+Loading asynchronously creates the objects declared by the component
+across multiple frames, and reduces the
+likelihood of glitches in animation. When loading asynchronously the status
+will change to Loader.Loading. Once the entire component has been created, the
+\l item will be available and the status will change to Loader.Ready.
+
+To avoid seeing the items loading progressively set \c visible appropriately, e.g.
+
+\code
+Loader {
+ source: "mycomponent.qml"
+ asynchronous: true
+ visible: status == Loader.Ready
+}
+\endcode
+
Note that this property affects object instantiation only; it is unrelated to
loading a component asynchronously via a network.
*/
diff --git a/src/declarative/items/qquickpathview.cpp b/src/declarative/items/qquickpathview.cpp
index 1963307a1e..f262562edf 100644
--- a/src/declarative/items/qquickpathview.cpp
+++ b/src/declarative/items/qquickpathview.cpp
@@ -106,34 +106,71 @@ void QQuickPathViewPrivate::init()
FAST_CONNECT(&tl, SIGNAL(completed()), q, SLOT(movementEnding()))
}
-QQuickItem *QQuickPathViewPrivate::getItem(int modelIndex, bool onPath)
+QQuickItem *QQuickPathViewPrivate::getItem(int modelIndex, qreal z, bool onPath)
{
Q_Q(QQuickPathView);
requestedIndex = modelIndex;
+ requestedOnPath = onPath;
+ requestedZ = z;
+ inRequest = true;
QQuickItem *item = model->item(modelIndex, false);
if (item) {
- if (!attType) {
- // pre-create one metatype to share with all attached objects
- attType = new QDeclarativeOpenMetaObjectType(&QQuickPathViewAttached::staticMetaObject, qmlEngine(q));
- foreach (const QString &attr, path->attributes())
- attType->createProperty(attr.toUtf8());
- }
+ QDeclarative_setParent_noEvent(item, q);
+ item->setParentItem(q);
+ requestedIndex = -1;
qPathViewAttachedType = attType;
QQuickPathViewAttached *att = static_cast<QQuickPathViewAttached *>(qmlAttachedPropertiesObject<QQuickPathView>(item));
qPathViewAttachedType = 0;
- if (att) {
- att->m_view = q;
+ if (att)
att->setOnPath(onPath);
- }
- QDeclarative_setParent_noEvent(item, q);
- item->setParentItem(q);
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
itemPrivate->addItemChangeListener(this, QQuickItemPrivate::Geometry);
}
- requestedIndex = -1;
+ inRequest = false;
return item;
}
+void QQuickPathView::createdItem(int index, QQuickItem *item)
+{
+ Q_D(QQuickPathView);
+ if (d->requestedIndex != index) {
+ qPathViewAttachedType = d->attachedType();
+ QQuickPathViewAttached *att = static_cast<QQuickPathViewAttached *>(qmlAttachedPropertiesObject<QQuickPathView>(item));
+ qPathViewAttachedType = 0;
+ if (att) {
+ att->m_view = this;
+ att->setOnPath(false);
+ }
+ item->setParentItem(this);
+ QDeclarative_setParent_noEvent(item, this);
+ d->updateItem(item, index < d->firstIndex ? 0.0 : 1.0);
+ } else {
+ d->requestedIndex = -1;
+ if (!d->inRequest)
+ refill();
+ }
+}
+
+void QQuickPathView::initItem(int index, QQuickItem *item)
+{
+ Q_D(QQuickPathView);
+ if (d->requestedIndex == index) {
+ item->setParentItem(this);
+ qPathViewAttachedType = d->attachedType();
+ QQuickPathViewAttached *att = static_cast<QQuickPathViewAttached *>(qmlAttachedPropertiesObject<QQuickPathView>(item));
+ qPathViewAttachedType = 0;
+ if (att) {
+ att->m_view = this;
+ qreal percent = d->positionOfIndex(index);
+ foreach (const QString &attr, d->path->attributes())
+ att->setValue(attr.toUtf8(), d->path->attributeAt(attr, percent));
+ item->setZ(d->requestedZ);
+ if (att)
+ att->setOnPath(d->requestedOnPath);
+ }
+ }
+}
+
void QQuickPathViewPrivate::releaseItem(QQuickItem *item)
{
if (!item || !model)
@@ -152,6 +189,19 @@ QQuickPathViewAttached *QQuickPathViewPrivate::attached(QQuickItem *item)
return static_cast<QQuickPathViewAttached *>(qmlAttachedPropertiesObject<QQuickPathView>(item, false));
}
+QDeclarativeOpenMetaObjectType *QQuickPathViewPrivate::attachedType()
+{
+ Q_Q(QQuickPathView);
+ if (!attType) {
+ // pre-create one metatype to share with all attached objects
+ attType = new QDeclarativeOpenMetaObjectType(&QQuickPathViewAttached::staticMetaObject, qmlEngine(q));
+ foreach (const QString &attr, path->attributes())
+ attType->createProperty(attr.toUtf8());
+ }
+
+ return attType;
+}
+
void QQuickPathViewPrivate::clear()
{
if (currentItem) {
@@ -493,6 +543,7 @@ void QQuickPathView::setModel(const QVariant &model)
disconnect(d->model, SIGNAL(modelUpdated(QDeclarativeChangeSet,bool)),
this, SLOT(modelUpdated(QDeclarativeChangeSet,bool)));
disconnect(d->model, SIGNAL(createdItem(int,QQuickItem*)), this, SLOT(createdItem(int,QQuickItem*)));
+ disconnect(d->model, SIGNAL(initItem(int,QQuickItem*)), this, SLOT(initItem(int,QQuickItem*)));
for (int i=0; i<d->items.count(); i++){
QQuickItem *p = d->items[i];
d->releaseItem(p);
@@ -524,6 +575,7 @@ void QQuickPathView::setModel(const QVariant &model)
connect(d->model, SIGNAL(modelUpdated(QDeclarativeChangeSet,bool)),
this, SLOT(modelUpdated(QDeclarativeChangeSet,bool)));
connect(d->model, SIGNAL(createdItem(int,QQuickItem*)), this, SLOT(createdItem(int,QQuickItem*)));
+ connect(d->model, SIGNAL(initItem(int,QQuickItem*)), this, SLOT(initItem(int,QQuickItem*)));
d->modelCount = d->model->count();
if (d->model->count())
d->offset = qmlMod(d->offset, qreal(d->model->count()));
@@ -595,36 +647,28 @@ void QQuickPathView::setCurrentIndex(int idx)
Q_D(QQuickPathView);
if (d->model && d->modelCount)
idx = qAbs(idx % d->modelCount);
- if (d->model && idx != d->currentIndex) {
+ if (d->model && (idx != d->currentIndex || !d->currentItem)) {
if (d->currentItem) {
if (QQuickPathViewAttached *att = d->attached(d->currentItem))
att->setIsCurrentItem(false);
d->releaseItem(d->currentItem);
}
+ int oldCurrentIdx = d->currentIndex;
+ QQuickItem *oldCurrentItem = d->currentItem;
d->currentItem = 0;
d->moveReason = QQuickPathViewPrivate::SetIndex;
d->currentIndex = idx;
if (d->modelCount) {
- int itemIndex = (idx - d->firstIndex + d->modelCount) % d->modelCount;
- if (itemIndex < d->items.count()) {
- d->currentItem = d->model->item(d->currentIndex, true);
- d->currentItem->setFocus(true);
- if (QQuickPathViewAttached *att = d->attached(d->currentItem))
- att->setIsCurrentItem(true);
- } else {
- d->currentItem = d->getItem(d->currentIndex, false);
- d->updateItem(d->currentItem, d->currentIndex < d->firstIndex ? 0.0 : 1.0);
- if (QQuickPathViewAttached *att = d->attached(d->currentItem))
- att->setIsCurrentItem(true);
- if (d->model->completePending())
- d->model->completeItem();
- }
+ d->createCurrentItem();
if (d->haveHighlightRange && d->highlightRangeMode == QQuickPathView::StrictlyEnforceRange)
d->snapToCurrent();
d->currentItemOffset = d->positionOfIndex(d->currentIndex);
d->updateHighlight();
}
- emit currentIndexChanged();
+ if (oldCurrentIdx != d->currentIndex)
+ emit currentIndexChanged();
+ if (oldCurrentItem != d->currentItem)
+ emit currentItemChanged();
}
}
@@ -1392,6 +1436,7 @@ void QQuickPathView::refill()
if (!d->items.count())
d->firstIndex = -1;
+ bool waiting = false;
if (d->modelCount) {
// add items to beginning and end
int count = d->pathItems == -1 ? d->modelCount : qMin(d->pathItems, d->modelCount);
@@ -1406,10 +1451,12 @@ void QQuickPathView::refill()
}
qreal pos = d->positionOfIndex(idx);
while ((pos > startPos || !d->items.count()) && d->items.count() < count) {
- // qDebug() << "append" << idx;
- QQuickItem *item = d->getItem(idx);
- if (d->model->completePending())
- item->setZ(idx+1);
+// qDebug() << "append" << idx;
+ QQuickItem *item = d->getItem(idx, idx+1);
+ if (!item) {
+ waiting = true;
+ break;
+ }
if (d->currentIndex == idx) {
currentVisible = true;
d->currentItemOffset = pos;
@@ -1418,8 +1465,6 @@ void QQuickPathView::refill()
d->firstIndex = idx;
d->items.append(item);
d->updateItem(item, pos);
- if (d->model->completePending())
- d->model->completeItem();
++idx;
if (idx >= d->modelCount)
idx = 0;
@@ -1430,19 +1475,19 @@ void QQuickPathView::refill()
if (idx < 0)
idx = d->modelCount - 1;
pos = d->positionOfIndex(idx);
- while ((pos >= 0.0 && pos < startPos) && d->items.count() < count) {
- // qDebug() << "prepend" << idx;
- QQuickItem *item = d->getItem(idx);
- if (d->model->completePending())
- item->setZ(idx+1);
+ while (!waiting && (pos >= 0.0 && pos < startPos) && d->items.count() < count) {
+// qDebug() << "prepend" << idx;
+ QQuickItem *item = d->getItem(idx, idx+1);
+ if (!item) {
+ waiting = true;
+ break;
+ }
if (d->currentIndex == idx) {
currentVisible = true;
d->currentItemOffset = pos;
}
d->items.prepend(item);
d->updateItem(item, pos);
- if (d->model->completePending())
- d->model->completeItem();
d->firstIndex = idx;
idx = d->firstIndex - 1;
if (idx < 0)
@@ -1457,19 +1502,19 @@ void QQuickPathView::refill()
if (d->currentItem) {
if (QQuickPathViewAttached *att = d->attached(d->currentItem))
att->setOnPath(false);
- } else if (d->currentIndex >= 0 && d->currentIndex < d->modelCount) {
- d->currentItem = d->getItem(d->currentIndex, false);
- d->updateItem(d->currentItem, d->currentIndex < d->firstIndex ? 0.0 : 1.0);
+ } else if (!waiting && d->currentIndex >= 0 && d->currentIndex < d->modelCount) {
+ if (d->currentItem = d->getItem(d->currentIndex, d->currentIndex, false)) {
+ d->updateItem(d->currentItem, d->currentIndex < d->firstIndex ? 0.0 : 1.0);
+ if (QQuickPathViewAttached *att = d->attached(d->currentItem))
+ att->setIsCurrentItem(true);
+ }
+ }
+ } else if (!waiting && !d->currentItem) {
+ if (d->currentItem = d->getItem(d->currentIndex, d->currentIndex, true)) {
+ d->currentItem->setFocus(true);
if (QQuickPathViewAttached *att = d->attached(d->currentItem))
att->setIsCurrentItem(true);
- if (d->model->completePending())
- d->model->completeItem();
}
- } else if (!d->currentItem) {
- d->currentItem = d->model->item(d->currentIndex, true);
- d->currentItem->setFocus(true);
- if (QQuickPathViewAttached *att = d->attached(d->currentItem))
- att->setIsCurrentItem(true);
}
if (d->highlightItem && d->haveHighlightRange && d->highlightRangeMode == QQuickPathView::StrictlyEnforceRange) {
@@ -1582,29 +1627,6 @@ void QQuickPathView::modelUpdated(const QDeclarativeChangeSet &changeSet, bool r
emit countChanged();
}
-void QQuickPathView::createdItem(int index, QQuickItem *item)
-{
- Q_D(QQuickPathView);
- if (d->requestedIndex != index) {
- if (!d->attType) {
- // pre-create one metatype to share with all attached objects
- d->attType = new QDeclarativeOpenMetaObjectType(&QQuickPathViewAttached::staticMetaObject, qmlEngine(this));
- foreach (const QString &attr, d->path->attributes())
- d->attType->createProperty(attr.toUtf8());
- }
- qPathViewAttachedType = d->attType;
- QQuickPathViewAttached *att = static_cast<QQuickPathViewAttached *>(qmlAttachedPropertiesObject<QQuickPathView>(item));
- qPathViewAttachedType = 0;
- if (att) {
- att->m_view = this;
- att->setOnPath(false);
- }
- QDeclarative_setParent_noEvent(item, this);
- item->setParentItem(this);
- d->updateItem(item, index < d->firstIndex ? 0.0 : 1.0);
- }
-}
-
void QQuickPathView::destroyingItem(QQuickItem *item)
{
Q_UNUSED(item);
@@ -1646,6 +1668,26 @@ int QQuickPathViewPrivate::calcCurrentIndex()
return current;
}
+void QQuickPathViewPrivate::createCurrentItem()
+{
+ if (requestedIndex != -1)
+ return;
+ int itemIndex = (currentIndex - firstIndex + modelCount) % modelCount;
+ if (itemIndex < items.count()) {
+ if (currentItem = getItem(currentIndex, currentIndex, true)) {
+ currentItem->setFocus(true);
+ if (QQuickPathViewAttached *att = attached(currentItem))
+ att->setIsCurrentItem(true);
+ }
+ } else if (currentIndex >= 0 && currentIndex < modelCount) {
+ if (currentItem = getItem(currentIndex, currentIndex, false)) {
+ updateItem(currentItem, currentIndex < firstIndex ? 0.0 : 1.0);
+ if (QQuickPathViewAttached *att = attached(currentItem))
+ att->setIsCurrentItem(true);
+ }
+ }
+}
+
void QQuickPathViewPrivate::updateCurrent()
{
Q_Q(QQuickPathView);
@@ -1663,20 +1705,7 @@ void QQuickPathViewPrivate::updateCurrent()
}
currentIndex = idx;
currentItem = 0;
- int itemIndex = (idx - firstIndex + modelCount) % modelCount;
- if (itemIndex < items.count()) {
- currentItem = model->item(currentIndex, true);
- currentItem->setFocus(true);
- if (QQuickPathViewAttached *att = attached(currentItem))
- att->setIsCurrentItem(true);
- } else if (currentIndex >= 0 && currentIndex < modelCount) {
- currentItem = getItem(currentIndex, false);
- updateItem(currentItem, currentIndex < firstIndex ? 0.0 : 1.0);
- if (QQuickPathViewAttached *att = attached(currentItem))
- att->setIsCurrentItem(true);
- if (model->completePending())
- model->completeItem();
- }
+ createCurrentItem();
emit q->currentIndexChanged();
}
}
diff --git a/src/declarative/items/qquickpathview_p.h b/src/declarative/items/qquickpathview_p.h
index 657d721ae6..ebc1587b09 100644
--- a/src/declarative/items/qquickpathview_p.h
+++ b/src/declarative/items/qquickpathview_p.h
@@ -64,7 +64,7 @@ class Q_AUTOTEST_EXPORT QQuickPathView : public QQuickItem
Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged)
Q_PROPERTY(QDeclarativePath *path READ path WRITE setPath NOTIFY pathChanged)
Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged)
- Q_PROPERTY(QQuickItem *currentItem READ currentItem NOTIFY currentIndexChanged)
+ Q_PROPERTY(QQuickItem *currentItem READ currentItem NOTIFY currentItemChanged)
Q_PROPERTY(qreal offset READ offset WRITE setOffset NOTIFY offsetChanged)
Q_PROPERTY(QDeclarativeComponent *highlight READ highlight WRITE setHighlight NOTIFY highlightChanged)
@@ -151,6 +151,7 @@ public Q_SLOTS:
Q_SIGNALS:
void currentIndexChanged();
+ void currentItemChanged();
void offsetChanged();
void modelChanged();
void countChanged();
@@ -190,6 +191,7 @@ private Q_SLOTS:
void movementEnding();
void modelUpdated(const QDeclarativeChangeSet &changeSet, bool reset);
void createdItem(int index, QQuickItem *item);
+ void initItem(int index, QQuickItem *item);
void destroyingItem(QQuickItem *item);
void pathUpdated();
diff --git a/src/declarative/items/qquickpathview_p_p.h b/src/declarative/items/qquickpathview_p_p.h
index 87d9313645..9bf329dab5 100644
--- a/src/declarative/items/qquickpathview_p_p.h
+++ b/src/declarative/items/qquickpathview_p_p.h
@@ -80,10 +80,10 @@ public:
, lastElapsed(0), offset(0.0), offsetAdj(0.0), mappedRange(1.0)
, stealMouse(false), ownModel(false), interactive(true), haveHighlightRange(true)
, autoHighlight(true), highlightUp(false), layoutScheduled(false)
- , moving(false), flicking(false)
+ , moving(false), flicking(false), requestedOnPath(false), inRequest(false)
, dragMargin(0), deceleration(100)
, moveOffset(this, &QQuickPathViewPrivate::setAdjustedOffset)
- , firstIndex(-1), pathItems(-1), requestedIndex(-1)
+ , firstIndex(-1), pathItems(-1), requestedIndex(-1), requestedZ(0)
, moveReason(Other), moveDirection(Shortest), attType(0), highlightComponent(0), highlightItem(0)
, moveHighlight(this, &QQuickPathViewPrivate::setHighlightPosition)
, highlightPosition(0)
@@ -112,9 +112,10 @@ public:
}
}
- QQuickItem *getItem(int modelIndex, bool onPath = true);
+ QQuickItem *getItem(int modelIndex, qreal z = 0, bool onPath=true);
void releaseItem(QQuickItem *item);
QQuickPathViewAttached *attached(QQuickItem *item);
+ QDeclarativeOpenMetaObjectType *attachedType();
void clear();
void updateMappedRange();
qreal positionOfIndex(qreal index) const;
@@ -130,6 +131,7 @@ public:
void handleMouseReleaseEvent(QMouseEvent *);
int calcCurrentIndex();
+ void createCurrentItem();
void updateCurrent();
static void fixOffsetCallback(void*);
void fixOffset();
@@ -160,6 +162,8 @@ public:
bool layoutScheduled : 1;
bool moving : 1;
bool flicking : 1;
+ bool requestedOnPath : 1;
+ bool inRequest : 1;
QElapsedTimer lastPosTime;
QPointF lastPos;
qreal dragMargin;
@@ -169,6 +173,7 @@ public:
int firstIndex;
int pathItems;
int requestedIndex;
+ qreal requestedZ;
QList<QQuickItem *> items;
QList<QQuickItem *> itemCache;
QDeclarativeGuard<QQuickVisualModel> model;
diff --git a/src/declarative/items/qquickrepeater.cpp b/src/declarative/items/qquickrepeater.cpp
index 48632efe83..f207afdcae 100644
--- a/src/declarative/items/qquickrepeater.cpp
+++ b/src/declarative/items/qquickrepeater.cpp
@@ -51,7 +51,7 @@
QT_BEGIN_NAMESPACE
QQuickRepeaterPrivate::QQuickRepeaterPrivate()
-: model(0), ownModel(false)
+ : model(0), ownModel(false), inRequest(false), itemCount(0), createFrom(-1)
{
}
@@ -188,10 +188,8 @@ void QQuickRepeater::setModel(const QVariant &model)
if (d->model) {
disconnect(d->model, SIGNAL(modelUpdated(QDeclarativeChangeSet,bool)),
this, SLOT(modelUpdated(QDeclarativeChangeSet,bool)));
- /*
disconnect(d->model, SIGNAL(createdItem(int,QQuickItem*)), this, SLOT(createdItem(int,QQuickItem*)));
- disconnect(d->model, SIGNAL(destroyingItem(QQuickItem*)), this, SLOT(destroyingItem(QQuickItem*)));
- */
+// disconnect(d->model, SIGNAL(destroyingItem(QQuickItem*)), this, SLOT(destroyingItem(QQuickItem*)));
}
d->dataSource = model;
QObject *object = qvariant_cast<QObject*>(model);
@@ -215,10 +213,8 @@ void QQuickRepeater::setModel(const QVariant &model)
if (d->model) {
connect(d->model, SIGNAL(modelUpdated(QDeclarativeChangeSet,bool)),
this, SLOT(modelUpdated(QDeclarativeChangeSet,bool)));
- /*
connect(d->model, SIGNAL(createdItem(int,QQuickItem*)), this, SLOT(createdItem(int,QQuickItem*)));
- connect(d->model, SIGNAL(destroyingItem(QQuickItem*)), this, SLOT(destroyingItem(QQuickItem*)));
- */
+// connect(d->model, SIGNAL(destroyingItem(QQuickItem*)), this, SLOT(destroyingItem(QQuickItem*)));
regenerate();
}
emit modelChanged();
@@ -339,14 +335,15 @@ void QQuickRepeater::clear()
bool complete = isComponentComplete();
if (d->model) {
- while (d->deletables.count() > 0) {
- QQuickItem *item = d->deletables.takeLast();
+ for (int i = 0; i < d->deletables.count(); ++i) {
+ QQuickItem *item = d->deletables.at(i);
if (complete)
- emit itemRemoved(d->deletables.count()-1, item);
+ emit itemRemoved(i, item);
d->model->release(item);
}
}
d->deletables.clear();
+ d->itemCount = 0;
}
void QQuickRepeater::regenerate()
@@ -360,16 +357,51 @@ void QQuickRepeater::regenerate()
if (!d->model || !d->model->count() || !d->model->isValid() || !parentItem() || !isComponentComplete())
return;
- for (int ii = 0; ii < count(); ++ii) {
- QQuickItem *item = d->model->item(ii);
- if (item) {
- QDeclarative_setParent_noEvent(item, parentItem());
- item->setParentItem(parentItem());
- item->stackBefore(this);
- d->deletables << item;
- emit itemAdded(ii, item);
+ d->itemCount = count();
+ d->deletables.resize(d->itemCount);
+ d->createFrom = 0;
+ d->createItems();
+}
+
+void QQuickRepeaterPrivate::createItems()
+{
+ Q_Q(QQuickRepeater);
+ if (createFrom == -1)
+ return;
+ inRequest = true;
+ for (int ii = createFrom; ii < itemCount; ++ii) {
+ if (!deletables.at(ii)) {
+ QQuickItem *item = model->item(ii, false);
+ if (!item) {
+ createFrom = ii;
+ break;
+ }
+ deletables[ii] = item;
+ QDeclarative_setParent_noEvent(item, q->parentItem());
+ item->setParentItem(q->parentItem());
+ if (ii > 0 && deletables.at(ii-1)) {
+ item->stackAfter(deletables.at(ii-1));
+ } else {
+ QQuickItem *after = q;
+ for (int si = ii+1; si < itemCount; ++si) {
+ if (deletables.at(si)) {
+ after = deletables.at(si);
+ break;
+ }
+ }
+ item->stackBefore(after);
+ }
+ emit q->itemAdded(ii, item);
}
}
+ inRequest = false;
+}
+
+void QQuickRepeater::createdItem(int index, QQuickItem *item)
+{
+ Q_D(QQuickRepeater);
+ if (!d->inRequest)
+ d->createItems();
}
void QQuickRepeater::modelUpdated(const QDeclarativeChangeSet &changeSet, bool reset)
@@ -385,7 +417,7 @@ void QQuickRepeater::modelUpdated(const QDeclarativeChangeSet &changeSet, bool r
}
int difference = 0;
- QHash<int, QList<QPointer<QQuickItem> > > moved;
+ QHash<int, QVector<QPointer<QQuickItem> > > moved;
foreach (const QDeclarativeChangeSet::Remove &remove, changeSet.removes()) {
int index = qMin(remove.index, d->deletables.count());
int count = qMin(remove.index + remove.count, d->deletables.count()) - index;
@@ -395,19 +427,22 @@ void QQuickRepeater::modelUpdated(const QDeclarativeChangeSet &changeSet, bool r
d->deletables.begin() + index,
d->deletables.begin() + index + count);
} else while (count--) {
- QQuickItem *item = d->deletables.takeAt(index);
+ QQuickItem *item = d->deletables.at(index);
+ d->deletables.remove(index);
emit itemRemoved(index, item);
if (item)
d->model->release(item);
+ --d->itemCount;
}
difference -= remove.count;
}
+ d->createFrom = -1;
foreach (const QDeclarativeChangeSet::Insert &insert, changeSet.inserts()) {
int index = qMin(insert.index, d->deletables.count());
if (insert.isMove()) {
- QList<QPointer<QQuickItem> > items = moved.value(insert.moveId);
+ QVector<QPointer<QQuickItem> > items = moved.value(insert.moveId);
d->deletables = d->deletables.mid(0, index) + items + d->deletables.mid(index);
QQuickItem *stackBefore = index + items.count() < d->deletables.count()
? d->deletables.at(index + items.count())
@@ -416,21 +451,16 @@ void QQuickRepeater::modelUpdated(const QDeclarativeChangeSet &changeSet, bool r
d->deletables.at(i)->stackBefore(stackBefore);
} else for (int i = 0; i < insert.count; ++i) {
int modelIndex = index + i;
- QQuickItem *item = d->model->item(modelIndex);
- if (item) {
- QDeclarative_setParent_noEvent(item, parentItem());
- item->setParentItem(parentItem());
- if (modelIndex < d->deletables.count())
- item->stackBefore(d->deletables.at(modelIndex));
- else
- item->stackBefore(this);
- d->deletables.insert(modelIndex, item);
- emit itemAdded(modelIndex, item);
- }
+ ++d->itemCount;
+ d->deletables.insert(modelIndex, 0);
+ if (d->createFrom == -1)
+ d->createFrom = modelIndex;
}
difference += insert.count;
}
+ d->createItems();
+
if (difference != 0)
emit countChanged();
}
diff --git a/src/declarative/items/qquickrepeater_p.h b/src/declarative/items/qquickrepeater_p.h
index 66e583e406..6da6adb989 100644
--- a/src/declarative/items/qquickrepeater_p.h
+++ b/src/declarative/items/qquickrepeater_p.h
@@ -94,6 +94,7 @@ protected:
void itemChange(ItemChange change, const ItemChangeData &value);
private Q_SLOTS:
+ void createdItem(int index, QQuickItem *item);
void modelUpdated(const QDeclarativeChangeSet &changeSet, bool reset);
private:
diff --git a/src/declarative/items/qquickrepeater_p_p.h b/src/declarative/items/qquickrepeater_p_p.h
index a1ec15960a..962d177494 100644
--- a/src/declarative/items/qquickrepeater_p_p.h
+++ b/src/declarative/items/qquickrepeater_p_p.h
@@ -71,11 +71,17 @@ public:
QQuickRepeaterPrivate();
~QQuickRepeaterPrivate();
+private:
+ void createItems();
+
QQuickVisualModel *model;
QVariant dataSource;
- bool ownModel;
+ bool ownModel : 1;
+ bool inRequest : 1;
+ int itemCount;
+ int createFrom;
- QList<QPointer<QQuickItem> > deletables;
+ QVector<QPointer<QQuickItem> > deletables;
};
QT_END_NAMESPACE
diff --git a/src/declarative/items/qquickvisualdatamodel.cpp b/src/declarative/items/qquickvisualdatamodel.cpp
index ce8548456e..649ca6f96b 100644
--- a/src/declarative/items/qquickvisualdatamodel.cpp
+++ b/src/declarative/items/qquickvisualdatamodel.cpp
@@ -47,6 +47,7 @@
#include <QtDeclarative/qdeclarativeengine.h>
#include <QtDeclarative/qdeclarativeexpression.h>
#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtDeclarative/qdeclarativeincubator.h>
#include <private/qdeclarativecontext_p.h>
#include <private/qdeclarativepackage_p.h>
@@ -62,6 +63,7 @@
#include <private/qdeclarativechangeset_p.h>
#include <private/qdeclarativelistcompositor_p.h>
#include <private/qdeclarativeengine_p.h>
+#include <private/qquickitem_p.h>
#include <private/qobject_p.h>
#include <QtCore/qhash.h>
@@ -71,11 +73,33 @@ QT_BEGIN_NAMESPACE
typedef QDeclarativeListCompositor Compositor;
+class QQuickVisualDataModelPrivate;
+class QVDMIncubationTask : public QDeclarativeIncubator
+{
+public:
+ QVDMIncubationTask(QQuickVisualDataModelPrivate *l, IncubationMode mode)
+ : QDeclarativeIncubator(mode)
+ , incubating(0)
+ , incubatingContext(0)
+ , vdm(l) {}
+
+ virtual void statusChanged(Status);
+ virtual void setInitialState(QObject *);
+
+ QQuickVisualDataModelCacheItem *incubating;
+ QDeclarativeContext *incubatingContext;
+
+private:
+ QQuickVisualDataModelPrivate *vdm;
+};
+
+
class QQuickVisualDataGroupEmitter
{
public:
virtual void emitModelUpdated(const QDeclarativeChangeSet &changeSet, bool reset) = 0;
virtual void createdPackage(int, QDeclarativePackage *) {}
+ virtual void initPackage(int, QDeclarativePackage *) {}
virtual void destroyingPackage(QDeclarativePackage *) {}
QIntrusiveListNode emitterNode;
@@ -100,6 +124,7 @@ public:
void emitModelUpdated(bool reset);
void createdPackage(int index, QDeclarativePackage *package);
+ void initPackage(int index, QDeclarativePackage *package);
void destroyingPackage(QDeclarativePackage *package);
bool parseGroupArgs(QDeclarativeV8Function *args, int *index, int *count, int *groups) const;
@@ -118,11 +143,78 @@ class QQuickVisualDataModelCacheItem;
class QQuickVisualDataModelCacheMetaType;
class QQuickVisualDataModelParts;
+class QQuickVisualDataModelCacheMetaType : public QDeclarativeRefCount
+{
+public:
+ QQuickVisualDataModelCacheMetaType(QV8Engine *engine, QQuickVisualDataModel *model, const QStringList &groupNames);
+ ~QQuickVisualDataModelCacheMetaType();
+
+ int parseGroups(const QStringList &groupNames) const;
+ int parseGroups(QV8Engine *engine, const v8::Local<v8::Value> &groupNames) const;
+
+ static v8::Handle<v8::Value> get_model(v8::Local<v8::String>, const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> get_groups(v8::Local<v8::String>, const v8::AccessorInfo &info);
+ static void set_groups(
+ v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> get_member(v8::Local<v8::String>, const v8::AccessorInfo &info);
+ static void set_member(
+ v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> get_index(v8::Local<v8::String>, const v8::AccessorInfo &info);
+
+ QDeclarativeGuard<QQuickVisualDataModel> model;
+ const int groupCount;
+ const int memberPropertyOffset;
+ const int indexPropertyOffset;
+ QV8Engine * const v8Engine;
+ QMetaObject *metaObject;
+ const QStringList groupNames;
+ v8::Persistent<v8::Function> constructor;
+};
+
+class QQuickVisualDataModelCacheItem : public QV8ObjectResource
+{
+ V8_RESOURCE_TYPE(VisualDataItemType)
+public:
+ QQuickVisualDataModelCacheItem(QQuickVisualDataModelCacheMetaType *metaType)
+ : QV8ObjectResource(metaType->v8Engine)
+ , metaType(metaType)
+ , object(0)
+ , attached(0)
+ , objectRef(0)
+ , scriptRef(0)
+ , groups(0)
+ , incubationTask(0)
+ {
+ metaType->addref();
+ }
+
+ ~QQuickVisualDataModelCacheItem();
+
+ void referenceObject() { ++objectRef; }
+ bool releaseObject() { return --objectRef == 0 && !(groups & Compositor::PersistedFlag); }
+ bool isObjectReferenced() const { return objectRef == 0 && !(groups & Compositor::PersistedFlag); }
+
+ bool isReferenced() const { return objectRef || scriptRef || (groups & Compositor::PersistedFlag) || incubationTask; }
+
+ void Dispose();
+
+ QQuickVisualDataModelCacheMetaType * const metaType;
+ QDeclarativeGuard<QObject> object;
+ QQuickVisualDataModelAttached *attached;
+ int objectRef;
+ int scriptRef;
+ int groups;
+ int index[Compositor::MaximumGroupCount];
+ QVDMIncubationTask *incubationTask;
+};
+
+
class QQuickVisualDataModelPrivate : public QObjectPrivate, public QQuickVisualDataGroupEmitter
{
Q_DECLARE_PUBLIC(QQuickVisualDataModel)
public:
QQuickVisualDataModelPrivate(QDeclarativeContext *);
+ ~QQuickVisualDataModelPrivate();
static QQuickVisualDataModelPrivate *get(QQuickVisualDataModel *m) {
return static_cast<QQuickVisualDataModelPrivate *>(QObjectPrivate::get(m));
@@ -131,14 +223,17 @@ public:
void init();
void connectModel(QQuickVisualAdaptorModel *model);
- QObject *object(Compositor::Group group, int index, bool complete, bool reference);
+ QObject *object(Compositor::Group group, int index, bool asynchronous, bool reference);
void destroy(QObject *object);
QQuickVisualDataModel::ReleaseFlags release(QObject *object);
QString stringValue(Compositor::Group group, int index, const QString &name);
int cacheIndexOf(QObject *object) const;
- void emitCreatedPackage(Compositor::iterator at, QDeclarativePackage *package);
- void emitCreatedItem(Compositor::iterator at, QQuickItem *item) {
- emit q_func()->createdItem(at.index[m_compositorGroup], item); }
+ void emitCreatedPackage(QQuickVisualDataModelCacheItem *cacheItem, QDeclarativePackage *package);
+ void emitInitPackage(QQuickVisualDataModelCacheItem *cacheItem, QDeclarativePackage *package);
+ void emitCreatedItem(QQuickVisualDataModelCacheItem *cacheItem, QQuickItem *item) {
+ emit q_func()->createdItem(cacheItem->index[m_compositorGroup], item); }
+ void emitInitItem(QQuickVisualDataModelCacheItem *cacheItem, QQuickItem *item) {
+ emit q_func()->initItem(cacheItem->index[m_compositorGroup], item); }
void emitDestroyingPackage(QDeclarativePackage *package);
void emitDestroyingItem(QQuickItem *item) { emit q_func()->destroyingItem(item); }
@@ -170,6 +265,10 @@ public:
static int group_count(QDeclarativeListProperty<QQuickVisualDataGroup> *property);
static QQuickVisualDataGroup *group_at(QDeclarativeListProperty<QQuickVisualDataGroup> *property, int index);
+ void releaseIncubator(QVDMIncubationTask *incubationTask);
+ void incubatorStatusChanged(QVDMIncubationTask *incubationTask, QDeclarativeIncubator::Status status);
+ void setInitialState(QVDMIncubationTask *incubationTask, QObject *o);
+
QQuickVisualAdaptorModel *m_adaptorModel;
QDeclarativeComponent *m_delegate;
QQuickVisualDataModelCacheMetaType *m_cacheMetaType;
@@ -183,9 +282,9 @@ public:
QDeclarativeListCompositor::Group m_compositorGroup;
bool m_complete : 1;
bool m_delegateValidated : 1;
- bool m_completePending : 1;
bool m_reset : 1;
bool m_transaction : 1;
+ bool m_incubatorCleanupScheduled : 1;
QString m_filterGroup;
QList<QByteArray> watchedRoles;
@@ -199,6 +298,8 @@ public:
QQuickVisualDataGroup *m_groups[Compositor::MaximumGroupCount];
};
int m_groupCount;
+
+ QList<QVDMIncubationTask *> m_finishedIncubating;
};
//---------------------------------------------------------------------------
@@ -219,10 +320,8 @@ public:
int count() const;
bool isValid() const;
- QQuickItem *item(int index, bool complete=true);
+ QQuickItem *item(int index, bool asynchronous=false);
ReleaseFlags release(QQuickItem *item);
- bool completePending() const;
- void completeItem();
QString stringValue(int index, const QString &role);
void setWatchedRoles(QList<QByteArray> roles);
@@ -231,6 +330,7 @@ public:
void emitModelUpdated(const QDeclarativeChangeSet &changeSet, bool reset);
void createdPackage(int index, QDeclarativePackage *package);
+ void initPackage(int index, QDeclarativePackage *package);
void destroyingPackage(QDeclarativePackage *package);
Q_SIGNALS:
@@ -286,78 +386,6 @@ QQuickVisualDataModelParts::QQuickVisualDataModelParts(QQuickVisualDataModel *pa
new QQuickVisualDataModelPartsMetaObject(this);
}
-//---------------------------------------------------------------------------
-
-class QQuickVisualDataModelCacheMetaType : public QDeclarativeRefCount
-{
-public:
- QQuickVisualDataModelCacheMetaType(QV8Engine *engine, QQuickVisualDataModel *model, const QStringList &groupNames);
- ~QQuickVisualDataModelCacheMetaType();
-
- int parseGroups(const QStringList &groupNames) const;
- int parseGroups(QV8Engine *engine, const v8::Local<v8::Value> &groupNames) const;
-
- static v8::Handle<v8::Value> get_model(v8::Local<v8::String>, const v8::AccessorInfo &info);
- static v8::Handle<v8::Value> get_groups(v8::Local<v8::String>, const v8::AccessorInfo &info);
- static void set_groups(
- v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info);
- static v8::Handle<v8::Value> get_member(v8::Local<v8::String>, const v8::AccessorInfo &info);
- static void set_member(
- v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info);
- static v8::Handle<v8::Value> get_index(v8::Local<v8::String>, const v8::AccessorInfo &info);
-
- QDeclarativeGuard<QQuickVisualDataModel> model;
- const int groupCount;
- const int memberPropertyOffset;
- const int indexPropertyOffset;
- QV8Engine * const v8Engine;
- QMetaObject *metaObject;
- const QStringList groupNames;
- v8::Persistent<v8::Function> constructor;
-};
-
-class QQuickVisualDataModelCacheItem : public QV8ObjectResource
-{
- V8_RESOURCE_TYPE(VisualDataItemType)
-public:
- QQuickVisualDataModelCacheItem(QQuickVisualDataModelCacheMetaType *metaType)
- : QV8ObjectResource(metaType->v8Engine)
- , metaType(metaType)
- , object(0)
- , attached(0)
- , objectRef(0)
- , scriptRef(0)
- , groups(0)
- {
- metaType->addref();
- }
-
- ~QQuickVisualDataModelCacheItem()
- {
- Q_ASSERT(scriptRef == 0);
- Q_ASSERT(objectRef == 0);
- Q_ASSERT(!object);
-
- metaType->release();
- }
-
- void referenceObject() { ++objectRef; }
- bool releaseObject() { return --objectRef == 0 && !(groups & Compositor::PersistedFlag); }
- bool isObjectReferenced() const { return objectRef == 0 && !(groups & Compositor::PersistedFlag); }
-
- bool isReferenced() const { return objectRef || scriptRef || (groups & Compositor::PersistedFlag); }
-
- void Dispose();
-
- QQuickVisualDataModelCacheMetaType * const metaType;
- QDeclarativeGuard<QObject> object;
- QQuickVisualDataModelAttached *attached;
- int objectRef;
- int scriptRef;
- int groups;
- int index[Compositor::MaximumGroupCount];
-};
-
class QQuickVisualDataModelAttachedMetaObject : public QAbstractDynamicMetaObject
{
public:
@@ -405,9 +433,9 @@ QQuickVisualDataModelPrivate::QQuickVisualDataModelPrivate(QDeclarativeContext *
, m_compositorGroup(Compositor::Cache)
, m_complete(false)
, m_delegateValidated(false)
- , m_completePending(false)
, m_reset(false)
, m_transaction(false)
+ , m_incubatorCleanupScheduled(false)
, m_filterGroup(QStringLiteral("items"))
, m_cacheItems(0)
, m_items(0)
@@ -415,6 +443,11 @@ QQuickVisualDataModelPrivate::QQuickVisualDataModelPrivate(QDeclarativeContext *
{
}
+QQuickVisualDataModelPrivate::~QQuickVisualDataModelPrivate()
+{
+ qDeleteAll(m_finishedIncubating);
+}
+
void QQuickVisualDataModelPrivate::connectModel(QQuickVisualAdaptorModel *model)
{
Q_Q(QQuickVisualDataModel);
@@ -714,6 +747,8 @@ QQuickVisualDataModel::ReleaseFlags QQuickVisualDataModelPrivate::release(QObjec
QQuickVisualDataModelCacheItem *cacheItem = m_cache.at(cacheIndex);
if (cacheItem->releaseObject()) {
destroy(object);
+ if (QQuickItem *item = qobject_cast<QQuickItem *>(object))
+ emitDestroyingItem(item);
cacheItem->object = 0;
stat |= QQuickVisualModel::Destroyed;
if (!cacheItem->isReferenced()) {
@@ -944,10 +979,16 @@ QObject *QQuickVisualDataModel::parts()
return d->m_parts;
}
-void QQuickVisualDataModelPrivate::emitCreatedPackage(Compositor::iterator at, QDeclarativePackage *package)
+void QQuickVisualDataModelPrivate::emitCreatedPackage(QQuickVisualDataModelCacheItem *cacheItem, QDeclarativePackage *package)
{
for (int i = 1; i < m_groupCount; ++i)
- QQuickVisualDataGroupPrivate::get(m_groups[i])->createdPackage(at.index[i], package);
+ QQuickVisualDataGroupPrivate::get(m_groups[i])->createdPackage(cacheItem->index[i], package);
+}
+
+void QQuickVisualDataModelPrivate::emitInitPackage(QQuickVisualDataModelCacheItem *cacheItem, QDeclarativePackage *package)
+{
+ for (int i = 1; i < m_groupCount; ++i)
+ QQuickVisualDataGroupPrivate::get(m_groups[i])->initPackage(cacheItem->index[i], package);
}
void QQuickVisualDataModelPrivate::emitDestroyingPackage(QDeclarativePackage *package)
@@ -956,13 +997,87 @@ void QQuickVisualDataModelPrivate::emitDestroyingPackage(QDeclarativePackage *pa
QQuickVisualDataGroupPrivate::get(m_groups[i])->destroyingPackage(package);
}
-QObject *QQuickVisualDataModelPrivate::object(Compositor::Group group, int index, bool complete, bool reference)
+void QVDMIncubationTask::statusChanged(Status status)
+{
+ vdm->incubatorStatusChanged(this, status);
+}
+
+void QQuickVisualDataModelPrivate::releaseIncubator(QVDMIncubationTask *incubationTask)
+{
+ Q_Q(QQuickVisualDataModel);
+ if (!incubationTask->isError())
+ incubationTask->clear();
+ m_finishedIncubating.append(incubationTask);
+ if (!m_incubatorCleanupScheduled) {
+ m_incubatorCleanupScheduled = true;
+ QCoreApplication::postEvent(q, new QEvent(QEvent::User));
+ }
+}
+
+void QQuickVisualDataModelPrivate::incubatorStatusChanged(QVDMIncubationTask *incubationTask, QDeclarativeIncubator::Status status)
+{
+ Q_Q(QQuickVisualDataModel);
+ if (status != QDeclarativeIncubator::Ready && status != QDeclarativeIncubator::Error)
+ return;
+
+ QQuickVisualDataModelCacheItem *cacheItem = incubationTask->incubating;
+ cacheItem->incubationTask = 0;
+
+ if (status == QDeclarativeIncubator::Ready) {
+ incubationTask->incubating = 0;
+ releaseIncubator(incubationTask);
+ if (QDeclarativePackage *package = qobject_cast<QDeclarativePackage *>(cacheItem->object))
+ emitCreatedPackage(cacheItem, package);
+ else if (QQuickItem *item = qobject_cast<QQuickItem *>(cacheItem->object))
+ emitCreatedItem(cacheItem, item);
+ } else if (status == QDeclarativeIncubator::Error) {
+ delete incubationTask->incubatingContext;
+ incubationTask->incubatingContext = 0;
+ if (!cacheItem->isReferenced()) {
+ int cidx = m_cache.indexOf(cacheItem);
+ m_compositor.clearFlags(Compositor::Cache, cidx, 1, Compositor::CacheFlag);
+ m_cache.removeAt(cidx);
+ delete cacheItem;
+ Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
+ }
+ releaseIncubator(incubationTask);
+ qmlInfo(q, m_delegate->errors()) << "Error creating delegate";
+ }
+}
+
+void QVDMIncubationTask::setInitialState(QObject *o)
+{
+ vdm->setInitialState(this, o);
+}
+
+void QQuickVisualDataModelPrivate::setInitialState(QVDMIncubationTask *incubationTask, QObject *o)
+{
+ QQuickVisualDataModelCacheItem *cacheItem = incubationTask->incubating;
+ cacheItem->object = o;
+ QDeclarative_setParent_noEvent(incubationTask->incubatingContext, cacheItem->object);
+ incubationTask->incubatingContext = 0;
+
+ cacheItem->attached = QQuickVisualDataModelAttached::properties(cacheItem->object);
+ cacheItem->attached->m_cacheItem = cacheItem;
+ new QQuickVisualDataModelAttachedMetaObject(cacheItem->attached, m_cacheMetaType);
+ cacheItem->attached->emitChanges();
+
+ if (QDeclarativePackage *package = qobject_cast<QDeclarativePackage *>(cacheItem->object))
+ emitInitPackage(cacheItem, package);
+ else if (QQuickItem *item = qobject_cast<QQuickItem *>(cacheItem->object))
+ emitInitItem(cacheItem, item);
+}
+
+QObject *QQuickVisualDataModelPrivate::object(Compositor::Group group, int index, bool asynchronous, bool reference)
{
Q_Q(QQuickVisualDataModel);
+ if (!m_delegate || index < 0 || index >= m_compositor.count(group)) {
+ qWarning() << "VisualDataModel::item: index out range" << index << m_compositor.count(group);
+ return 0;
+ }
Compositor::iterator it = m_compositor.find(group, index);
QQuickVisualDataModelCacheItem *cacheItem = it->inCache() ? m_cache.at(it.cacheIndex) : 0;
-
if (!cacheItem) {
cacheItem = new QQuickVisualDataModelCacheItem(m_cacheMetaType);
for (int i = 0; i < m_groupCount; ++i)
@@ -970,8 +1085,24 @@ QObject *QQuickVisualDataModelPrivate::object(Compositor::Group group, int index
cacheItem->groups = it->flags & Compositor::GroupMask;
}
- if (!cacheItem->object) {
- QObject *data = m_adaptorModel->data(it.modelIndex());
+ int modelIndex = it.modelIndex();
+
+ if (!it->inCache()) {
+ m_cache.insert(it.cacheIndex, cacheItem);
+ m_compositor.setFlags(it, 1, Compositor::CacheFlag);
+ Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
+ }
+
+ if (cacheItem->incubationTask) {
+ if (!asynchronous) {
+ // previously requested async - now needed immediately
+ cacheItem->incubationTask->forceCompletion();
+ }
+ } else if (!cacheItem->object) {
+ QVDMIncubationTask *incubator = new QVDMIncubationTask(this, asynchronous ? QDeclarativeIncubator::Asynchronous : QDeclarativeIncubator::AsynchronousIfNested);
+ cacheItem->incubationTask = incubator;
+
+ QObject *data = m_adaptorModel->data(modelIndex);
QDeclarativeContext *creationContext = m_delegate->creationContext();
QDeclarativeContext *rootContext = new QDeclarativeContext(
@@ -988,49 +1119,27 @@ QObject *QQuickVisualDataModelPrivate::object(Compositor::Group group, int index
ctxt->setContextProperty(QLatin1String("model"), data);
ctxt->setContextObject(data);
- m_completePending = false;
- cacheItem->object = m_delegate->beginCreate(ctxt);
-
- if (cacheItem->object) {
- QDeclarative_setParent_noEvent(rootContext, cacheItem->object);
- if (!it->inCache()) {
- m_cache.insert(it.cacheIndex, cacheItem);
- m_compositor.setFlags(it, 1, Compositor::CacheFlag);
- Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
- }
-
- cacheItem->attached = QQuickVisualDataModelAttached::properties(cacheItem->object);
- cacheItem->attached->setCacheItem(cacheItem);
- new QQuickVisualDataModelAttachedMetaObject(cacheItem->attached, m_cacheMetaType);
- cacheItem->attached->emitChanges();
-
- if (QDeclarativePackage *package = qobject_cast<QDeclarativePackage *>(cacheItem->object)) {
- emitCreatedPackage(it, package);
- } else if (!reference) {
- if (QQuickItem *item = qobject_cast<QQuickItem *>(cacheItem->object))
- emitCreatedItem(it, item);
- }
-
- m_completePending = !complete;
- if (complete)
- m_delegate->completeCreate();
- } else {
- delete rootContext;
- if (!it->inCache())
- delete cacheItem;
- qmlInfo(q, m_delegate->errors()) << "Error creating delegate";
- return 0;
- }
+ incubator->incubating = cacheItem;
+ incubator->incubatingContext = rootContext;
+ m_delegate->create(*incubator, ctxt, m_context);
}
if (index == m_compositor.count(group) - 1 && m_adaptorModel->canFetchMore())
QCoreApplication::postEvent(q, new QEvent(QEvent::UpdateRequest));
- if (reference)
+ if (cacheItem->object && reference)
cacheItem->referenceObject();
return cacheItem->object;
}
-QQuickItem *QQuickVisualDataModel::item(int index, bool complete)
+/*
+ If asynchronous is true or the component is being loaded asynchronously due
+ to an ancestor being loaded asynchronously, item() may return 0. In this
+ case itemCreated() will be emitted when the item is available. The item
+ at this stage does not have any references, so item() must be called again
+ to ensure a reference is held. Any call to item() which returns a valid item
+ must be matched by a call to release() in order to destroy the item.
+*/
+QQuickItem *QQuickVisualDataModel::item(int index, bool asynchronous)
{
Q_D(QQuickVisualDataModel);
if (!d->m_delegate || index < 0 || index >= d->m_compositor.count(d->m_compositorGroup)) {
@@ -1038,11 +1147,13 @@ QQuickItem *QQuickVisualDataModel::item(int index, bool complete)
return 0;
}
- QObject *object = d->object(d->m_compositorGroup, index, complete, true);
+ QObject *object = d->object(d->m_compositorGroup, index, asynchronous, true);
+ if (!object)
+ return 0;
+
if (QQuickItem *item = qobject_cast<QQuickItem *>(object))
return item;
- if (d->m_completePending)
- completeItem();
+
d->release(object);
if (!d->m_delegateValidated) {
if (object)
@@ -1052,19 +1163,6 @@ QQuickItem *QQuickVisualDataModel::item(int index, bool complete)
return 0;
}
-bool QQuickVisualDataModel::completePending() const
-{
- Q_D(const QQuickVisualDataModel);
- return d->m_completePending;
-}
-
-void QQuickVisualDataModel::completeItem()
-{
- Q_D(QQuickVisualDataModel);
- d->m_delegate->completeCreate();
- d->m_completePending = false;
-}
-
QString QQuickVisualDataModelPrivate::stringValue(Compositor::Group group, int index, const QString &name)
{
Compositor::iterator it = m_compositor.find(group, index);
@@ -1138,8 +1236,13 @@ void QQuickVisualDataModelPrivate::setGroups(Compositor::Group group, int index,
bool QQuickVisualDataModel::event(QEvent *e)
{
Q_D(QQuickVisualDataModel);
- if (e->type() == QEvent::UpdateRequest)
+ if (e->type() == QEvent::UpdateRequest) {
d->m_adaptorModel->fetchMore();
+ } else if (e->type() == QEvent::User) {
+ d->m_incubatorCleanupScheduled = false;
+ qDeleteAll(d->m_finishedIncubating);
+ d->m_finishedIncubating.clear();
+ }
return QQuickVisualModel::event(e);
}
@@ -1436,7 +1539,7 @@ void QQuickVisualDataModelPrivate::emitChanges()
QQuickVisualDataGroupPrivate::get(m_groups[i])->emitModelUpdated(reset);
foreach (QQuickVisualDataModelCacheItem *cacheItem, m_cache) {
- if (cacheItem->object)
+ if (cacheItem->object && cacheItem->attached)
cacheItem->attached->emitChanges();
}
}
@@ -1664,6 +1767,17 @@ v8::Handle<v8::Value> QQuickVisualDataModelCacheMetaType::get_index(
//---------------------------------------------------------------------------
+QQuickVisualDataModelCacheItem::~QQuickVisualDataModelCacheItem()
+{
+ Q_ASSERT(scriptRef == 0);
+ Q_ASSERT(objectRef == 0);
+ Q_ASSERT(!object);
+ if (incubationTask && metaType->model)
+ QQuickVisualDataModelPrivate::get(metaType->model)->releaseIncubator(incubationTask);
+
+ metaType->release();
+}
+
void QQuickVisualDataModelCacheItem::Dispose()
{
--scriptRef;
@@ -1892,6 +2006,12 @@ void QQuickVisualDataGroupPrivate::createdPackage(int index, QDeclarativePackage
it->createdPackage(index, package);
}
+void QQuickVisualDataGroupPrivate::initPackage(int index, QDeclarativePackage *package)
+{
+ for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
+ it->initPackage(index, package);
+}
+
void QQuickVisualDataGroupPrivate::destroyingPackage(QDeclarativePackage *package)
{
for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
@@ -2068,7 +2188,7 @@ QObject *QQuickVisualDataGroup::create(int index)
return 0;
}
- QObject *object = model->object(d->group, index, true, false);
+ QObject *object = model->object(d->group, index, false, false);
if (object)
model->addGroups(d->group, index, 1, Compositor::PersistedFlag);
return object;
@@ -2438,7 +2558,7 @@ bool QQuickVisualPartsModel::isValid() const
return m_model->isValid();
}
-QQuickItem *QQuickVisualPartsModel::item(int index, bool complete)
+QQuickItem *QQuickVisualPartsModel::item(int index, bool asynchronous)
{
QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
@@ -2447,7 +2567,7 @@ QQuickItem *QQuickVisualPartsModel::item(int index, bool complete)
return 0;
}
- QObject *object = model->object(m_compositorGroup, index, complete, true);
+ QObject *object = model->object(m_compositorGroup, index, asynchronous, true);
if (QDeclarativePackage *package = qobject_cast<QDeclarativePackage *>(object)) {
QObject *part = package->part(m_part);
@@ -2459,8 +2579,6 @@ QQuickItem *QQuickVisualPartsModel::item(int index, bool complete)
}
}
- if (m_model->completePending())
- m_model->completeItem();
model->release(object);
if (!model->m_delegateValidated) {
if (object)
@@ -2478,6 +2596,7 @@ QQuickVisualModel::ReleaseFlags QQuickVisualPartsModel::release(QQuickItem *item
QHash<QObject *, QDeclarativePackage *>::iterator it = m_packaged.find(item);
if (it != m_packaged.end()) {
QDeclarativePackage *package = *it;
+ QDeclarative_setParent_noEvent(item, package);
QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
flags = model->release(package);
m_packaged.erase(it);
@@ -2491,16 +2610,6 @@ QQuickVisualModel::ReleaseFlags QQuickVisualPartsModel::release(QQuickItem *item
return flags;
}
-bool QQuickVisualPartsModel::completePending() const
-{
- return m_model->completePending();
-}
-
-void QQuickVisualPartsModel::completeItem()
-{
- m_model->completeItem();
-}
-
QString QQuickVisualPartsModel::stringValue(int index, const QString &role)
{
return QQuickVisualDataModelPrivate::get(m_model)->stringValue(m_compositorGroup, index, role);
@@ -2532,6 +2641,12 @@ void QQuickVisualPartsModel::createdPackage(int index, QDeclarativePackage *pack
emit createdItem(index, item);
}
+void QQuickVisualPartsModel::initPackage(int index, QDeclarativePackage *package)
+{
+ if (QQuickItem *item = qobject_cast<QQuickItem *>(package->part(m_part)))
+ emit initItem(index, item);
+}
+
void QQuickVisualPartsModel::destroyingPackage(QDeclarativePackage *package)
{
if (QQuickItem *item = qobject_cast<QQuickItem *>(package->part(m_part))) {
diff --git a/src/declarative/items/qquickvisualdatamodel_p.h b/src/declarative/items/qquickvisualdatamodel_p.h
index 60b04ab9f2..a5a384f67b 100644
--- a/src/declarative/items/qquickvisualdatamodel_p.h
+++ b/src/declarative/items/qquickvisualdatamodel_p.h
@@ -107,10 +107,8 @@ public:
int count() const;
bool isValid() const { return delegate() != 0; }
- QQuickItem *item(int index, bool complete=true);
+ QQuickItem *item(int index, bool asynchronous=false);
ReleaseFlags release(QQuickItem *item);
- bool completePending() const;
- void completeItem();
virtual QString stringValue(int index, const QString &role);
virtual void setWatchedRoles(QList<QByteArray> roles);
diff --git a/src/declarative/items/qquickvisualitemmodel.cpp b/src/declarative/items/qquickvisualitemmodel.cpp
index 31d06f68c8..78c4f8868b 100644
--- a/src/declarative/items/qquickvisualitemmodel.cpp
+++ b/src/declarative/items/qquickvisualitemmodel.cpp
@@ -193,6 +193,8 @@ QQuickItem *QQuickVisualItemModel::item(int index, bool)
Q_D(QQuickVisualItemModel);
QQuickVisualItemModelPrivate::Item &item = d->children[index];
item.addRef();
+ emit initItem(index, item.item);
+ emit createdItem(index, item.item);
return item.item;
}
@@ -210,16 +212,6 @@ QQuickVisualModel::ReleaseFlags QQuickVisualItemModel::release(QQuickItem *item)
return 0;
}
-bool QQuickVisualItemModel::completePending() const
-{
- return false;
-}
-
-void QQuickVisualItemModel::completeItem()
-{
- // Nothing to do
-}
-
QString QQuickVisualItemModel::stringValue(int index, const QString &name)
{
Q_D(QQuickVisualItemModel);
diff --git a/src/declarative/items/qquickvisualitemmodel_p.h b/src/declarative/items/qquickvisualitemmodel_p.h
index 9fc3d5767c..3d9610abe9 100644
--- a/src/declarative/items/qquickvisualitemmodel_p.h
+++ b/src/declarative/items/qquickvisualitemmodel_p.h
@@ -69,10 +69,8 @@ public:
virtual int count() const = 0;
virtual bool isValid() const = 0;
- virtual QQuickItem *item(int index, bool complete=true) = 0;
+ virtual QQuickItem *item(int index, bool asynchronous=false) = 0;
virtual ReleaseFlags release(QQuickItem *item) = 0;
- virtual bool completePending() const = 0;
- virtual void completeItem() = 0;
virtual QString stringValue(int, const QString &) = 0;
virtual void setWatchedRoles(QList<QByteArray> roles) = 0;
@@ -82,6 +80,7 @@ Q_SIGNALS:
void countChanged();
void modelUpdated(const QDeclarativeChangeSet &changeSet, bool reset);
void createdItem(int index, QQuickItem *item);
+ void initItem(int index, QQuickItem *item);
void destroyingItem(QQuickItem *item);
protected:
@@ -108,10 +107,8 @@ public:
virtual int count() const;
virtual bool isValid() const;
- virtual QQuickItem *item(int index, bool complete=true);
+ virtual QQuickItem *item(int index, bool asynchronous=false);
virtual ReleaseFlags release(QQuickItem *item);
- virtual bool completePending() const;
- virtual void completeItem();
virtual QString stringValue(int index, const QString &role);
virtual void setWatchedRoles(QList<QByteArray>) {}
diff --git a/tests/auto/declarative/qquickgridview/data/asyncloader.qml b/tests/auto/declarative/qquickgridview/data/asyncloader.qml
new file mode 100644
index 0000000000..ab66f20a1e
--- /dev/null
+++ b/tests/auto/declarative/qquickgridview/data/asyncloader.qml
@@ -0,0 +1,36 @@
+
+import QtQuick 2.0
+
+Rectangle {
+ id: root
+ width: 300; height: 400
+ color: "#2200FF00"
+
+ Loader {
+ asynchronous: true
+ sourceComponent: viewComp
+ anchors.fill: parent
+ }
+
+ Component {
+ id: viewComp
+ GridView {
+ objectName: "view"
+ width: 300; height: 400
+ model: 40
+ delegate: aDelegate
+
+ highlight: Rectangle { color: "lightsteelblue" }
+ }
+ }
+ // The delegate for each list
+ Component {
+ id: aDelegate
+ Item {
+ objectName: "wrapper"
+ width: 100
+ height: 100
+ Text { text: 'Index: ' + index }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qquickgridview/data/gridview1.qml b/tests/auto/declarative/qquickgridview/data/gridview1.qml
index e6a3923532..4bf6f0b952 100644
--- a/tests/auto/declarative/qquickgridview/data/gridview1.qml
+++ b/tests/auto/declarative/qquickgridview/data/gridview1.qml
@@ -5,6 +5,7 @@ Rectangle {
property int count: grid.count
property bool showHeader: false
property bool showFooter: false
+ property real cacheBuffer: 0
property int added: -1
property variant removed
@@ -63,5 +64,6 @@ Rectangle {
delegate: myDelegate
header: root.showHeader ? headerFooter : null
footer: root.showFooter ? headerFooter : null
+ cacheBuffer: root.cacheBuffer
}
}
diff --git a/tests/auto/declarative/qquickgridview/tst_qquickgridview.cpp b/tests/auto/declarative/qquickgridview/tst_qquickgridview.cpp
index 9cd39fcdc9..3370b721d7 100644
--- a/tests/auto/declarative/qquickgridview/tst_qquickgridview.cpp
+++ b/tests/auto/declarative/qquickgridview/tst_qquickgridview.cpp
@@ -46,6 +46,7 @@
#include <QtDeclarative/qdeclarativecomponent.h>
#include <QtDeclarative/qdeclarativecontext.h>
#include <QtDeclarative/qdeclarativeexpression.h>
+#include <QtDeclarative/qdeclarativeincubator.h>
#include <QtDeclarative/private/qquickitem_p.h>
#include <QtDeclarative/private/qlistmodelinterface_p.h>
#include <QtDeclarative/private/qquickgridview_p.h>
@@ -117,6 +118,8 @@ private slots:
void snapToRow_data();
void snapToRow();
void unaligned();
+ void cacheBuffer();
+ void asynchronous();
private:
QQuickView *createView();
@@ -3524,6 +3527,150 @@ void tst_QQuickGridView::flick(QQuickView *canvas, const QPoint &from, const QPo
QTest::mouseRelease(canvas, Qt::LeftButton, 0, to);
}
+void tst_QQuickGridView::cacheBuffer()
+{
+ QQuickView *canvas = createView();
+
+ TestModel model;
+ for (int i = 0; i < 90; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+ ctxt->setContextProperty("testRightToLeft", QVariant(false));
+ ctxt->setContextProperty("testTopToBottom", QVariant(false));
+
+ canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml")));
+ canvas->show();
+ qApp->processEvents();
+
+ QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid");
+ QVERIFY(gridview != 0);
+
+ QQuickItem *contentItem = gridview->contentItem();
+ QVERIFY(contentItem != 0);
+ QVERIFY(gridview->delegate() != 0);
+ QVERIFY(gridview->model() != 0);
+
+ // Confirm items positioned correctly
+ int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ for (int i = 0; i < model.count() && i < itemCount; ++i) {
+ QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
+ QTRY_COMPARE(item->x(), (i%3)*80.0);
+ QTRY_COMPARE(item->y(), (i/3)*60.0);
+ }
+
+ QDeclarativeIncubationController controller;
+ canvas->engine()->setIncubationController(&controller);
+
+ canvas->rootObject()->setProperty("cacheBuffer", 200);
+ QTRY_VERIFY(gridview->cacheBuffer() == 200);
+
+ // items will be created one at a time
+ for (int i = itemCount; i < qMin(itemCount+9,model.count()); ++i) {
+ QVERIFY(findItem<QQuickItem>(gridview, "wrapper", i) == 0);
+ QQuickItem *item = 0;
+ while (!item) {
+ bool b = false;
+ controller.incubateWhile(&b);
+ item = findItem<QQuickItem>(gridview, "wrapper", i);
+ }
+ }
+
+ {
+ bool b = true;
+ controller.incubateWhile(&b);
+ }
+
+ int newItemCount = 0;
+ newItemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+
+ // Confirm items positioned correctly
+ for (int i = 0; i < model.count() && i < newItemCount; ++i) {
+ QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
+ QVERIFY(item);
+ QTRY_COMPARE(item->x(), (i%3)*80.0);
+ QTRY_COMPARE(item->y(), (i/3)*60.0);
+ }
+
+ // move view and confirm items in view are visible immediately and outside are created async
+ gridview->setContentY(300);
+
+ for (int i = 15; i < 34; ++i) { // 34 due to staggered item creation
+ QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
+ QVERIFY(item);
+ QTRY_COMPARE(item->x(), (i%3)*80.0);
+ QTRY_COMPARE(item->y(), (i/3)*60.0);
+ }
+
+ QVERIFY(findItem<QQuickItem>(gridview, "wrapper", 34) == 0);
+
+ // ensure buffered items are created
+ for (int i = 34; i < qMin(44,model.count()); ++i) {
+ QQuickItem *item = 0;
+ while (!item) {
+ qGuiApp->processEvents(); // allow refill to happen
+ bool b = false;
+ controller.incubateWhile(&b);
+ item = findItem<QQuickItem>(gridview, "wrapper", i);
+ }
+ }
+
+ {
+ bool b = true;
+ controller.incubateWhile(&b);
+ }
+
+ delete canvas;
+}
+
+void tst_QQuickGridView::asynchronous()
+{
+ QQuickView *canvas = createView();
+ canvas->show();
+ QDeclarativeIncubationController controller;
+ canvas->engine()->setIncubationController(&controller);
+
+ canvas->setSource(TESTDATA("asyncloader.qml"));
+
+ QQuickItem *rootObject = qobject_cast<QQuickItem*>(canvas->rootObject());
+ QVERIFY(rootObject);
+
+ QQuickGridView *gridview = 0;
+ while (!gridview) {
+ bool b = false;
+ controller.incubateWhile(&b);
+ gridview = rootObject->findChild<QQuickGridView*>("view");
+ }
+
+ // items will be created one at a time
+ for (int i = 0; i < 12; ++i) {
+ QVERIFY(findItem<QQuickItem>(gridview, "wrapper", i) == 0);
+ QQuickItem *item = 0;
+ while (!item) {
+ bool b = false;
+ controller.incubateWhile(&b);
+ item = findItem<QQuickItem>(gridview, "wrapper", i);
+ }
+ }
+
+ {
+ bool b = true;
+ controller.incubateWhile(&b);
+ }
+
+ // verify positioning
+ QQuickItem *contentItem = gridview->contentItem();
+ for (int i = 0; i < 12; ++i) {
+ QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QVERIFY(item->x() == (i%3)*100);
+ QVERIFY(item->y() == (i/3)*100);
+ }
+
+ delete canvas;
+}
+
/*
Find an item with the specified objectName. If index is supplied then the
item must also evaluate the {index} expression equal to index
diff --git a/tests/auto/declarative/qquicklistview/data/asyncloader.qml b/tests/auto/declarative/qquicklistview/data/asyncloader.qml
new file mode 100644
index 0000000000..f038f0960c
--- /dev/null
+++ b/tests/auto/declarative/qquicklistview/data/asyncloader.qml
@@ -0,0 +1,36 @@
+
+import QtQuick 2.0
+
+Rectangle {
+ id: root
+ width: 300; height: 400
+ color: "#2200FF00"
+
+ Loader {
+ asynchronous: true
+ sourceComponent: viewComp
+ anchors.fill: parent
+ }
+
+ Component {
+ id: viewComp
+ ListView {
+ objectName: "view"
+ width: 300; height: 400
+ model: 20
+ delegate: aDelegate
+
+ highlight: Rectangle { color: "lightsteelblue" }
+ }
+ }
+ // The delegate for each list
+ Component {
+ id: aDelegate
+ Item {
+ objectName: "wrapper"
+ width: 300
+ height: 50
+ Text { text: 'Index: ' + index }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qquicklistview/data/listviewtest.qml b/tests/auto/declarative/qquicklistview/data/listviewtest.qml
index 0202de1546..47b341c1fc 100644
--- a/tests/auto/declarative/qquicklistview/data/listviewtest.qml
+++ b/tests/auto/declarative/qquicklistview/data/listviewtest.qml
@@ -64,7 +64,7 @@ Rectangle {
x: 200
text: wrapper.y
}
- color: ListView.isCurrentItem ? "lightsteelblue" : "white"
+ color: ListView.isCurrentItem ? "lightsteelblue" : "#EEEEEE"
}
},
Component {
diff --git a/tests/auto/declarative/qquicklistview/tst_qquicklistview.cpp b/tests/auto/declarative/qquicklistview/tst_qquicklistview.cpp
index b12bf3eb50..3b41600eb6 100644
--- a/tests/auto/declarative/qquicklistview/tst_qquicklistview.cpp
+++ b/tests/auto/declarative/qquicklistview/tst_qquicklistview.cpp
@@ -45,6 +45,7 @@
#include <QtDeclarative/qdeclarativeengine.h>
#include <QtDeclarative/qdeclarativecontext.h>
#include <QtDeclarative/qdeclarativeexpression.h>
+#include <QtDeclarative/qdeclarativeincubator.h>
#include <QtDeclarative/private/qquickitem_p.h>
#include <QtDeclarative/private/qquicklistview_p.h>
#include <QtDeclarative/private/qquicktext_p.h>
@@ -147,6 +148,8 @@ private slots:
void QTBUG_11105();
void QTBUG_21742();
+ void asynchronous();
+
private:
template <class T> void items();
template <class T> void changed();
@@ -1049,8 +1052,8 @@ void tst_QQuickListView::removed(bool /* animated */)
// Confirm items positioned correctly
itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
- QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i+2);
- if (!item) qWarning() << "Item" << i+2 << "not found";
+ QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i+1);
+ if (!item) qWarning() << "Item" << i+1 << "not found";
QTRY_VERIFY(item);
QTRY_COMPARE(item->y(),80+i*20.0);
}
@@ -2067,33 +2070,33 @@ void tst_QQuickListView::sectionsPositioning()
QTRY_COMPARE(item->y(), qreal(i*20*6));
}
- QTRY_VERIFY(topItem = findVisibleChild(contentItem, "sect_aaa")); // section header
- QCOMPARE(topItem->y(), 120.);
QVERIFY(topItem = findVisibleChild(contentItem, "sect_1"));
- QTRY_COMPARE(topItem->y(), 140.);
+ QTRY_COMPARE(topItem->y(), 120.);
// Change the next section
listview->setContentY(0);
bottomItem = findVisibleChild(contentItem, "sect_3"); // section footer
QVERIFY(bottomItem);
- QTRY_COMPARE(bottomItem->y(), 320.);
+ QTRY_COMPARE(bottomItem->y(), 300.);
model.modifyItem(14, "New", "new");
QTRY_VERIFY(bottomItem = findVisibleChild(contentItem, "sect_new")); // section footer
- QTRY_COMPARE(bottomItem->y(), 320.);
+ QTRY_COMPARE(bottomItem->y(), 300.);
// Turn sticky footer off
- listview->setContentY(50);
+ listview->setContentY(40);
canvas->rootObject()->setProperty("sectionPositioning", QVariant(int(QQuickViewSection::InlineLabels | QQuickViewSection::CurrentLabelAtStart)));
item = findVisibleChild(contentItem, "sect_new"); // inline label restored
+ QVERIFY(item);
QCOMPARE(item->y(), 360.);
// Turn sticky header off
- listview->setContentY(50);
+ listview->setContentY(30);
canvas->rootObject()->setProperty("sectionPositioning", QVariant(int(QQuickViewSection::InlineLabels)));
item = findVisibleChild(contentItem, "sect_aaa"); // inline label restored
- QCOMPARE(item->y(), 20.);
+ QVERIFY(item);
+ QCOMPARE(item->y(), 0.);
delete canvas;
}
@@ -2119,7 +2122,7 @@ void tst_QQuickListView::currentIndex_delayedItemCreation()
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != 0);
- QSignalSpy spy(listview, SIGNAL(currentIndexChanged()));
+ QSignalSpy spy(listview, SIGNAL(currentItemChanged()));
QCOMPARE(listview->currentIndex(), 0);
QTRY_COMPARE(spy.count(), 1);
@@ -2355,7 +2358,7 @@ void tst_QQuickListView::cacheBuffer()
QQuickView *canvas = createView();
TestModel model;
- for (int i = 0; i < 30; i++)
+ for (int i = 0; i < 90; i++)
model.addItem("Item" + QString::number(i), "");
QDeclarativeContext *ctxt = canvas->rootContext();
@@ -2365,6 +2368,7 @@ void tst_QQuickListView::cacheBuffer()
ctxt->setContextProperty("testObject", testObject);
canvas->setSource(QUrl::fromLocalFile(TESTDATA("listviewtest.qml")));
+ canvas->show();
qApp->processEvents();
QQuickListView *listview = findItem<QQuickListView>(canvas->rootObject(), "list");
@@ -2385,11 +2389,30 @@ void tst_QQuickListView::cacheBuffer()
QTRY_VERIFY(item->y() == i*20);
}
- testObject->setCacheBuffer(400);
- QTRY_VERIFY(listview->cacheBuffer() == 400);
+ QDeclarativeIncubationController controller;
+ canvas->engine()->setIncubationController(&controller);
+
+ testObject->setCacheBuffer(200);
+ QTRY_VERIFY(listview->cacheBuffer() == 200);
- int newItemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
- QTRY_VERIFY(newItemCount > itemCount);
+ // items will be created one at a time
+ for (int i = itemCount; i < qMin(itemCount+10,model.count()); ++i) {
+ QVERIFY(findItem<QQuickItem>(listview, "wrapper", i) == 0);
+ QQuickItem *item = 0;
+ while (!item) {
+ bool b = false;
+ controller.incubateWhile(&b);
+ item = findItem<QQuickItem>(listview, "wrapper", i);
+ }
+ }
+
+ {
+ bool b = true;
+ controller.incubateWhile(&b);
+ }
+
+ int newItemCount = 0;
+ newItemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
// Confirm items positioned correctly
for (int i = 0; i < model.count() && i < newItemCount; ++i) {
@@ -2399,6 +2422,34 @@ void tst_QQuickListView::cacheBuffer()
QTRY_VERIFY(item->y() == i*20);
}
+ // move view and confirm items in view are visible immediately and outside are created async
+ listview->setContentY(300);
+
+ for (int i = 15; i < 32; ++i) {
+ QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
+ if (!item) qWarning() << "Item" << i << "not found";
+ QVERIFY(item);
+ QVERIFY(item->y() == i*20);
+ }
+
+ QVERIFY(findItem<QQuickItem>(listview, "wrapper", 32) == 0);
+
+ // ensure buffered items are created
+ for (int i = 32; i < qMin(41,model.count()); ++i) {
+ QQuickItem *item = 0;
+ while (!item) {
+ qGuiApp->processEvents(); // allow refill to happen
+ bool b = false;
+ controller.incubateWhile(&b);
+ item = findItem<QQuickItem>(listview, "wrapper", i);
+ }
+ }
+
+ {
+ bool b = true;
+ controller.incubateWhile(&b);
+ }
+
delete canvas;
delete testObject;
}
@@ -3590,9 +3641,10 @@ void tst_QQuickListView::resizeFirstDelegate()
listview->setCurrentIndex(19);
qApp->processEvents();
- // items 0-3 should have been deleted
- for (int i=0; i<4; i++)
+ // items 0-2 should have been deleted
+ for (int i=0; i<3; i++) {
QTRY_VERIFY(!findItem<QQuickItem>(contentItem, "wrapper", i));
+ }
delete testObject;
delete canvas;
@@ -4202,6 +4254,50 @@ void tst_QQuickListView::flick(QQuickView *canvas, const QPoint &from, const QPo
QTest::mouseRelease(canvas, Qt::LeftButton, 0, to);
}
+void tst_QQuickListView::asynchronous()
+{
+ QQuickView *canvas = createView();
+ canvas->show();
+ QDeclarativeIncubationController controller;
+ canvas->engine()->setIncubationController(&controller);
+
+ canvas->setSource(TESTDATA("asyncloader.qml"));
+
+ QQuickItem *rootObject = qobject_cast<QQuickItem*>(canvas->rootObject());
+ QVERIFY(rootObject);
+
+ QQuickListView *listview = 0;
+ while (!listview) {
+ bool b = false;
+ controller.incubateWhile(&b);
+ listview = rootObject->findChild<QQuickListView*>("view");
+ }
+
+ // items will be created one at a time
+ for (int i = 0; i < 8; ++i) {
+ QVERIFY(findItem<QQuickItem>(listview, "wrapper", i) == 0);
+ QQuickItem *item = 0;
+ while (!item) {
+ bool b = false;
+ controller.incubateWhile(&b);
+ item = findItem<QQuickItem>(listview, "wrapper", i);
+ }
+ }
+
+ {
+ bool b = true;
+ controller.incubateWhile(&b);
+ }
+
+ // verify positioning
+ QQuickItem *contentItem = listview->contentItem();
+ for (int i = 0; i < 8; ++i) {
+ QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
+ QTRY_COMPARE(item->y(), i*50.0);
+ }
+
+ delete canvas;
+}
QQuickItem *tst_QQuickListView::findVisibleChild(QQuickItem *parent, const QString &objectName)
{
diff --git a/tests/auto/declarative/qquickpathview/data/asyncloader.qml b/tests/auto/declarative/qquickpathview/data/asyncloader.qml
new file mode 100644
index 0000000000..94f560f3e7
--- /dev/null
+++ b/tests/auto/declarative/qquickpathview/data/asyncloader.qml
@@ -0,0 +1,71 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: root
+ property real delegateWidth: 60
+ property real delegateHeight: 20
+ property real delegateScale: 1.0
+ width: 240
+ height: 320
+ color: "#ffffff"
+
+ Loader {
+ asynchronous: true
+ sourceComponent: viewComponent
+ anchors.fill: parent
+ }
+
+ Component {
+ id: adelegate
+ Rectangle {
+ objectName: "wrapper"
+ property bool onPath: PathView.onPath
+ height: root.delegateHeight
+ width: root.delegateWidth
+ scale: root.delegateScale
+ color: PathView.isCurrentItem ? "lightsteelblue" : "white"
+ border.color: "black"
+ Text {
+ text: index
+ }
+ }
+ }
+ Component {
+ id: viewComponent
+ PathView {
+ id: view
+ objectName: "view"
+ width: 240
+ height: 320
+ model: 5
+ delegate: adelegate
+ highlight: Rectangle {
+ width: 60
+ height: 20
+ color: "yellow"
+ }
+ path: Path {
+ startY: 120
+ startX: 160
+ PathQuad {
+ y: 120
+ x: 80
+ controlY: 330
+ controlX: 100
+ }
+ PathLine {
+ y: 160
+ x: 20
+ }
+ PathCubic {
+ y: 120
+ x: 160
+ control1Y: 0
+ control1X: 100
+ control2Y: 0
+ control2X: 200
+ }
+ }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qquickpathview/tst_qquickpathview.cpp b/tests/auto/declarative/qquickpathview/tst_qquickpathview.cpp
index ee7f993ebd..b0efc5838d 100644
--- a/tests/auto/declarative/qquickpathview/tst_qquickpathview.cpp
+++ b/tests/auto/declarative/qquickpathview/tst_qquickpathview.cpp
@@ -45,6 +45,7 @@
#include <QtDeclarative/qdeclarativecomponent.h>
#include <QtDeclarative/qdeclarativecontext.h>
#include <QtDeclarative/qdeclarativeexpression.h>
+#include <QtDeclarative/qdeclarativeincubator.h>
#include <QtDeclarative/private/qquickpathview_p.h>
#include <QtDeclarative/private/qdeclarativepath_p.h>
#include <QtDeclarative/private/qquicktext_p.h>
@@ -118,6 +119,7 @@ private slots:
void missingPercent();
void creationContext();
void currentOffsetOnInsertion();
+ void asynchronous();
private:
QQuickView *createView();
@@ -833,7 +835,7 @@ void tst_QQuickPathView::pathMoved()
QPointF offset;//Center of item is at point, but pos is from corner
offset.setX(firstItem->width()/2);
offset.setY(firstItem->height()/2);
- QCOMPARE(firstItem->pos() + offset, start);
+ QTRY_COMPARE(firstItem->pos() + offset, start);
pathview->setOffset(1.0);
for (int i=0; i<model.count(); i++) {
@@ -1497,6 +1499,62 @@ void tst_QQuickPathView::currentOffsetOnInsertion()
delete canvas;
}
+void tst_QQuickPathView::asynchronous()
+{
+ QQuickView *canvas = createView();
+ canvas->show();
+ QDeclarativeIncubationController controller;
+ canvas->engine()->setIncubationController(&controller);
+
+ canvas->setSource(TESTDATA("asyncloader.qml"));
+
+ QQuickItem *rootObject = qobject_cast<QQuickItem*>(canvas->rootObject());
+ QVERIFY(rootObject);
+
+ QQuickPathView *pathview = 0;
+ while (!pathview) {
+ bool b = false;
+ controller.incubateWhile(&b);
+ pathview = rootObject->findChild<QQuickPathView*>("view");
+ }
+
+ // items will be created one at a time
+ for (int i = 0; i < 5; ++i) {
+ QVERIFY(findItem<QQuickItem>(pathview, "wrapper", i) == 0);
+ QQuickItem *item = 0;
+ while (!item) {
+ bool b = false;
+ controller.incubateWhile(&b);
+ item = findItem<QQuickItem>(pathview, "wrapper", i);
+ }
+ }
+
+ {
+ bool b = true;
+ controller.incubateWhile(&b);
+ }
+
+ // verify positioning
+ QQuickRectangle *firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0);
+ QVERIFY(firstItem);
+ QDeclarativePath *path = qobject_cast<QDeclarativePath*>(pathview->path());
+ QVERIFY(path);
+ QPointF start = path->pointAt(0.0);
+ QPointF offset;//Center of item is at point, but pos is from corner
+ offset.setX(firstItem->width()/2);
+ offset.setY(firstItem->height()/2);
+ QTRY_COMPARE(firstItem->pos() + offset, start);
+ pathview->setOffset(1.0);
+
+ for (int i=0; i<5; i++) {
+ QQuickItem *curItem = findItem<QQuickItem>(pathview, "wrapper", i);
+ QPointF itemPos(path->pointAt(0.2 + i*0.2));
+ QCOMPARE(curItem->pos() + offset, QPointF(qRound(itemPos.x()), qRound(itemPos.y())));
+ }
+
+ delete canvas;
+}
+
QQuickView *tst_QQuickPathView::createView()
{
QQuickView *canvas = new QQuickView(0);
diff --git a/tests/auto/declarative/qquickrepeater/data/asyncloader.qml b/tests/auto/declarative/qquickrepeater/data/asyncloader.qml
new file mode 100644
index 0000000000..82094e2666
--- /dev/null
+++ b/tests/auto/declarative/qquickrepeater/data/asyncloader.qml
@@ -0,0 +1,32 @@
+import QtQuick 2.0
+
+Item {
+ width: 360
+ height: 480
+
+ Loader {
+ asynchronous: true
+ sourceComponent: viewComponent
+ }
+
+ Component {
+ id: viewComponent
+ Column {
+ objectName: "container"
+ Repeater {
+ id: repeater
+ objectName: "repeater"
+
+ model: 10
+
+ delegate: Rectangle {
+ objectName: "delegate" + index
+ color: "red"
+ width: 360
+ height: 50
+ Text { text: index }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/auto/declarative/qquickrepeater/tst_qquickrepeater.cpp b/tests/auto/declarative/qquickrepeater/tst_qquickrepeater.cpp
index 355dd0d0dc..fc76480122 100644
--- a/tests/auto/declarative/qquickrepeater/tst_qquickrepeater.cpp
+++ b/tests/auto/declarative/qquickrepeater/tst_qquickrepeater.cpp
@@ -46,10 +46,12 @@
#include <QtDeclarative/qquickview.h>
#include <QtDeclarative/qdeclarativecontext.h>
#include <QtDeclarative/qdeclarativeexpression.h>
+#include <QtDeclarative/qdeclarativeincubator.h>
#include <private/qquickrepeater_p.h>
#include <private/qquicktext_p.h>
#include "../shared/util.h"
+#include "../../../shared/util.h"
inline QUrl TEST_FILE(const QString &filename)
{
@@ -73,6 +75,7 @@ private slots:
void resetModel();
void modelChanged();
void properties();
+ void asynchronous();
private:
QQuickView *createView();
@@ -636,6 +639,62 @@ void tst_QQuickRepeater::properties()
delete rootObject;
}
+void tst_QQuickRepeater::asynchronous()
+{
+ QQuickView *canvas = createView();
+ canvas->show();
+ QDeclarativeIncubationController controller;
+ canvas->engine()->setIncubationController(&controller);
+
+ canvas->setSource(TEST_FILE("asyncloader.qml"));
+
+ QQuickItem *rootObject = qobject_cast<QQuickItem*>(canvas->rootObject());
+ QVERIFY(rootObject);
+
+ QQuickItem *container = findItem<QQuickItem>(rootObject, "container");
+ QVERIFY(!container);
+ while (!container) {
+ bool b = false;
+ controller.incubateWhile(&b);
+ container = findItem<QQuickItem>(rootObject, "container");
+ }
+
+ QQuickRepeater *repeater = 0;
+ while (!repeater) {
+ bool b = false;
+ controller.incubateWhile(&b);
+ repeater = findItem<QQuickRepeater>(rootObject, "repeater");
+ }
+
+ // items will be created one at a time
+ for (int i = 0; i < 10; ++i) {
+ QString name("delegate");
+ name += QString::number(i);
+ QVERIFY(findItem<QQuickItem>(container, name) == 0);
+ QQuickItem *item = 0;
+ while (!item) {
+ bool b = false;
+ controller.incubateWhile(&b);
+ item = findItem<QQuickItem>(container, name);
+ }
+ }
+
+ {
+ bool b = true;
+ controller.incubateWhile(&b);
+ }
+
+ // verify positioning
+ for (int i = 0; i < 10; ++i) {
+ QString name("delegate");
+ name += QString::number(i);
+ QQuickItem *item = findItem<QQuickItem>(container, name);
+ QTRY_COMPARE(item->y(), i * 50.0);
+ }
+
+ delete canvas;
+}
+
QQuickView *tst_QQuickRepeater::createView()
{
QQuickView *canvas = new QQuickView(0);