diff options
-rw-r--r-- | src/quick/items/qquickitemview.cpp | 44 | ||||
-rw-r--r-- | src/quick/items/qquickitemview_p_p.h | 4 | ||||
-rw-r--r-- | src/quick/items/qquicklistview.cpp | 33 | ||||
-rw-r--r-- | tests/auto/qmltest/qtbug46798/tst_qtbug46798.qml | 71 |
4 files changed, 118 insertions, 34 deletions
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index af47aa837b..7a55bd6e0a 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -71,19 +71,19 @@ FxViewItem::~FxViewItem() qreal FxViewItem::itemX() const { - return transitionableItem ? transitionableItem->itemX() : item->x(); + return transitionableItem ? transitionableItem->itemX() : (item ? item->x() : 0); } qreal FxViewItem::itemY() const { - return transitionableItem ? transitionableItem->itemY() : item->y(); + return transitionableItem ? transitionableItem->itemY() : (item ? item->y() : 0); } void FxViewItem::moveTo(const QPointF &pos, bool immediate) { if (transitionableItem) transitionableItem->moveTo(pos, immediate); - else + else if (item) item->setPosition(pos); } @@ -91,21 +91,26 @@ void FxViewItem::setVisible(bool visible) { if (!visible && transitionableItem && transitionableItem->transitionScheduledOrRunning()) return; - QQuickItemPrivate::get(item)->setCulled(!visible); + if (item) + QQuickItemPrivate::get(item)->setCulled(!visible); } void FxViewItem::trackGeometry(bool track) { if (track) { if (!trackGeom) { - QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); - itemPrivate->addItemChangeListener(QQuickItemViewPrivate::get(view), QQuickItemPrivate::Geometry); + if (item) { + QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); + itemPrivate->addItemChangeListener(QQuickItemViewPrivate::get(view), QQuickItemPrivate::Geometry); + } trackGeom = true; } } else { if (trackGeom) { - QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); - itemPrivate->removeItemChangeListener(QQuickItemViewPrivate::get(view), QQuickItemPrivate::Geometry); + if (item) { + QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); + itemPrivate->removeItemChangeListener(QQuickItemViewPrivate::get(view), QQuickItemPrivate::Geometry); + } trackGeom = false; } } @@ -2044,8 +2049,9 @@ bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult currentChanges.removedItems.clear(); if (currentChanges.currentChanged) { - if (currentChanges.currentRemoved && currentItem && currentItem->attached) { - currentItem->attached->setIsCurrentItem(false); + if (currentChanges.currentRemoved && currentItem) { + if (currentItem->item && currentItem->attached) + currentItem->attached->setIsCurrentItem(false); releaseItem(currentItem); currentItem = 0; } @@ -2097,10 +2103,10 @@ bool QQuickItemViewPrivate::applyRemovalChange(const QQmlChangeSet::Change &remo } else { // removed item visibleAffected = true; - if (!removal.isMove() && item->attached) + if (!removal.isMove() && item->item && item->attached) item->attached->emitRemove(); - if (item->attached && item->attached->delayRemove() && !removal.isMove()) { + if (item->item && item->attached && item->attached->delayRemove() && !removal.isMove()) { item->index = -1; QObject::connect(item->attached, SIGNAL(delayRemoveChanged()), q, SLOT(destroyRemoved()), Qt::QueuedConnection); ++it; @@ -2357,12 +2363,14 @@ bool QQuickItemViewPrivate::releaseItem(FxViewItem *item) item->trackGeometry(false); QQmlInstanceModel::ReleaseFlags flags = model->release(item->item); - if (flags == 0) { - // item was not destroyed, and we no longer reference it. - QQuickItemPrivate::get(item->item)->setCulled(true); - unrequestedItems.insert(item->item, model->indexOf(item->item, q)); - } else if (flags & QQmlInstanceModel::Destroyed) { - item->item->setParentItem(0); + if (item->item) { + if (flags == 0) { + // item was not destroyed, and we no longer reference it. + QQuickItemPrivate::get(item->item)->setCulled(true); + unrequestedItems.insert(item->item, model->indexOf(item->item, q)); + } else if (flags & QQmlInstanceModel::Destroyed) { + item->item->setParentItem(0); + } } delete item; return flags != QQmlInstanceModel::Referenced; diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h index 5ac88a7585..67ef413d31 100644 --- a/src/quick/items/qquickitemview_p_p.h +++ b/src/quick/items/qquickitemview_p_p.h @@ -53,6 +53,8 @@ public: qreal itemX() const; qreal itemY() const; + inline qreal itemWidth() const { return item ? item->width() : 0; } + inline qreal itemHeight() const { return item ? item->height() : 0; } void moveTo(const QPointF &pos, bool immediate); void setVisible(bool visible); @@ -75,7 +77,7 @@ public: virtual bool contains(qreal x, qreal y) const = 0; - QQuickItem *item; + QPointer<QQuickItem> item; QQuickItemView *view; QQuickItemViewTransitionableItem *transitionableItem; QQuickItemViewAttached *attached; diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp index eec36b59c8..c0287168f3 100644 --- a/src/quick/items/qquicklistview.cpp +++ b/src/quick/items/qquicklistview.cpp @@ -267,18 +267,18 @@ public: } qreal itemPosition() const { if (view->orientation() == QQuickListView::Vertical) - return (view->verticalLayoutDirection() == QQuickItemView::BottomToTop ? -item->height()-itemY() : itemY()); + return (view->verticalLayoutDirection() == QQuickItemView::BottomToTop ? -itemHeight()-itemY() : itemY()); else - return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -item->width()-itemX() : itemX()); + return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -itemWidth()-itemX() : itemX()); } qreal size() const { if (section()) - return (view->orientation() == QQuickListView::Vertical ? item->height()+section()->height() : item->width()+section()->width()); + return (view->orientation() == QQuickListView::Vertical ? itemHeight()+section()->height() : itemWidth()+section()->width()); else - return (view->orientation() == QQuickListView::Vertical ? item->height() : item->width()); + return (view->orientation() == QQuickListView::Vertical ? itemHeight() : itemWidth()); } qreal itemSize() const { - return (view->orientation() == QQuickListView::Vertical ? item->height() : item->width()); + return (view->orientation() == QQuickListView::Vertical ? itemHeight() : itemWidth()); } qreal sectionSize() const { if (section()) @@ -289,11 +289,11 @@ public: if (view->orientation() == QQuickListView::Vertical) { return (view->verticalLayoutDirection() == QQuickItemView::BottomToTop ? -itemY() - : itemY() + item->height()); + : itemY() + itemHeight()); } else { return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -itemX() - : itemX() + item->width()); + : itemX() + itemWidth()); } } void setPosition(qreal pos, bool immediate = false) { @@ -320,8 +320,8 @@ public: item->setWidth(size); } bool contains(qreal x, qreal y) const Q_DECL_OVERRIDE { - return (x >= itemX() && x < itemX() + item->width() && - y >= itemY() && y < itemY() + item->height()); + return (x >= itemX() && x < itemX() + itemWidth() && + y >= itemY() && y < itemY() + itemHeight()); } QQuickListView *view; @@ -332,7 +332,7 @@ private: if (view->verticalLayoutDirection() == QQuickItemView::BottomToTop) { if (section()) pos += section()->height(); - return QPointF(itemX(), -item->height() - pos); + return QPointF(itemX(), -itemHeight() - pos); } else { if (section()) pos += section()->height(); @@ -342,7 +342,7 @@ private: if (view->effectiveLayoutDirection() == Qt::RightToLeft) { if (section()) pos += section()->width(); - return QPointF(-item->width() - pos, itemY()); + return QPointF(-itemWidth() - pos, itemY()); } else { if (section()) pos += section()->width(); @@ -612,7 +612,7 @@ bool QQuickListViewPrivate::releaseItem(FxViewItem *item) QQuickListViewAttached *att = static_cast<QQuickListViewAttached*>(item->attached); bool released = QQuickItemViewPrivate::releaseItem(item); - if (released && att && att->m_sectionItem) { + if (released && item->item && att && att->m_sectionItem) { // We hold no more references to this item int i = 0; do { @@ -670,7 +670,8 @@ bool QQuickListViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal qCDebug(lcItemViewDelegateLifecycle) << "refill: append item" << modelIndex << "pos" << pos << "buffer" << doBuffer << "item" << item->item->objectName(); if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems() item->setPosition(pos, true); - QQuickItemPrivate::get(item->item)->setCulled(doBuffer); + if (item->item) + QQuickItemPrivate::get(item->item)->setCulled(doBuffer); pos += item->size() + spacing; visibleItems.append(item); ++modelIndex; @@ -688,7 +689,8 @@ bool QQuickListViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal visiblePos -= item->size() + spacing; if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems() item->setPosition(visiblePos, true); - QQuickItemPrivate::get(item->item)->setCulled(doBuffer); + if (item->item) + QQuickItemPrivate::get(item->item)->setCulled(doBuffer); visibleItems.prepend(item); changed = true; } @@ -2851,7 +2853,8 @@ void QQuickListView::viewportMoved(Qt::Orientations orient) qreal to = d->isContentFlowReversed() ? -d->position()+d->displayMarginEnd : d->position()+d->size()+d->displayMarginEnd; for (int i = 0; i < d->visibleItems.count(); ++i) { FxViewItem *item = static_cast<FxListItemSG*>(d->visibleItems.at(i)); - QQuickItemPrivate::get(item->item)->setCulled(item->endPosition() < from || item->position() > to); + if (item->item) + QQuickItemPrivate::get(item->item)->setCulled(item->endPosition() < from || item->position() > to); } if (d->currentItem) QQuickItemPrivate::get(d->currentItem->item)->setCulled(d->currentItem->endPosition() < from || d->currentItem->position() > to); diff --git a/tests/auto/qmltest/qtbug46798/tst_qtbug46798.qml b/tests/auto/qmltest/qtbug46798/tst_qtbug46798.qml new file mode 100644 index 0000000000..9de9a621f6 --- /dev/null +++ b/tests/auto/qmltest/qtbug46798/tst_qtbug46798.qml @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtQml.Models 2.3 +import QtTest 1.1 + +Item { + id: top + + ListView { + id: listViewWithObjectModel // QTBUG-46798 + anchors.fill: parent + model: ObjectModel { + id: objectModel + Rectangle { width: 160; height: 160; color: "red" } + Rectangle { width: 160; height: 160; color: "green" } + Rectangle { width: 160; height: 160; color: "blue" } + } + } + + TestCase { + name: "QTBUG-46798" + when: windowShown + + function test_bug46798() { + var item = objectModel.get(0) + if (item) { + objectModel.remove(0) + item.destroy() + } + } + } +} |