aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/qml/qqmlcomponent.cpp1
-rw-r--r--src/qml/types/qqmldelegatemodel.cpp25
-rw-r--r--src/qml/types/qqmldelegatemodel_p.h2
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp14
-rw-r--r--src/quick/items/context2d/qquickcontext2d_p.h3
-rw-r--r--src/quick/items/context2d/qquickcontext2dtexture.cpp50
-rw-r--r--src/quick/items/context2d/qquickcontext2dtexture_p.h10
-rw-r--r--src/quick/items/qquickwindow.cpp9
-rw-r--r--tests/auto/quick/qquickcanvasitem/data/CanvasTestCase.qml4
-rw-r--r--tests/auto/quick/qquicklistview/data/layoutChangeSort.qml58
-rw-r--r--tests/auto/quick/qquicklistview/data/qtbug39492.qml40
-rw-r--r--tests/auto/quick/qquicklistview/qquicklistview.pro7
-rw-r--r--tests/auto/quick/qquicklistview/randomsortmodel.cpp107
-rw-r--r--tests/auto/quick/qquicklistview/randomsortmodel.h64
-rw-r--r--tests/auto/quick/qquicklistview/tst_qquicklistview.cpp126
-rw-r--r--tools/qmlplugindump/main.cpp12
16 files changed, 487 insertions, 45 deletions
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index 616f54d174..e087785901 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -1542,7 +1542,6 @@ void QmlIncubatorObject::statusChanged(QQmlIncubator::Status s)
callData->args[0] = QV4::Primitive::fromUInt32(s);
f->call(callData);
if (scope.hasException()) {
- ctx->catchException();
QQmlError error = QV4::ExecutionEngine::catchExceptionAsQmlError(ctx);
QQmlEnginePrivate::warning(QQmlEnginePrivate::get(d()->v8->engine()), error);
}
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp
index e2f1cffb16..91ddcf57e5 100644
--- a/src/qml/types/qqmldelegatemodel.cpp
+++ b/src/qml/types/qqmldelegatemodel.cpp
@@ -1526,6 +1526,18 @@ void QQmlDelegateModel::_q_dataChanged(const QModelIndex &begin, const QModelInd
_q_itemsChanged(begin.row(), end.row() - begin.row() + 1, roles);
}
+bool QQmlDelegateModel::isDescendantOf(const QPersistentModelIndex& desc, const QList< QPersistentModelIndex >& parents) const
+{
+ for (int i = 0, c = parents.count(); i < c; ++i) {
+ for (QPersistentModelIndex parent = desc; parent.isValid(); parent = parent.parent()) {
+ if (parent == parents[i])
+ return true;
+ }
+ }
+
+ return false;
+}
+
void QQmlDelegateModel::_q_layoutAboutToBeChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint)
{
Q_D(QQmlDelegateModel);
@@ -1534,8 +1546,9 @@ void QQmlDelegateModel::_q_layoutAboutToBeChanged(const QList<QPersistentModelIn
if (hint == QAbstractItemModel::VerticalSortHint) {
d->m_storedPersistentIndexes.clear();
- if (!parents.contains(d->m_adaptorModel.rootIndex))
+ if (!parents.isEmpty() && d->m_adaptorModel.rootIndex.isValid() && !isDescendantOf(d->m_adaptorModel.rootIndex, parents)) {
return;
+ }
for (int i = 0; i < d->m_count; ++i) {
const QModelIndex index = d->m_adaptorModel.aim()->index(i, 0, d->m_adaptorModel.rootIndex);
@@ -1555,20 +1568,16 @@ void QQmlDelegateModel::_q_layoutChanged(const QList<QPersistentModelIndex> &par
return;
if (hint == QAbstractItemModel::VerticalSortHint) {
- if (!parents.contains(d->m_adaptorModel.rootIndex))
+ if (!parents.isEmpty() && d->m_adaptorModel.rootIndex.isValid() && !isDescendantOf(d->m_adaptorModel.rootIndex, parents)) {
return;
+ }
for (int i = 0, c = d->m_storedPersistentIndexes.count(); i < c; ++i) {
const QPersistentModelIndex &index = d->m_storedPersistentIndexes.at(i);
if (i == index.row())
continue;
- QVector<Compositor::Insert> inserts;
- QVector<Compositor::Remove> removes;
- d->m_compositor.listItemsMoved(&d->m_adaptorModel, i, index.row(), 1, &removes, &inserts);
- if (!removes.isEmpty() || !inserts.isEmpty()) {
- d->itemsMoved(removes, inserts);
- }
+ _q_itemsMoved(i, index.row(), 1);
}
d->m_storedPersistentIndexes.clear();
diff --git a/src/qml/types/qqmldelegatemodel_p.h b/src/qml/types/qqmldelegatemodel_p.h
index 0b67179163..53cc94bbdf 100644
--- a/src/qml/types/qqmldelegatemodel_p.h
+++ b/src/qml/types/qqmldelegatemodel_p.h
@@ -143,6 +143,8 @@ private Q_SLOTS:
void _q_layoutChanged(const QList<QPersistentModelIndex>&, QAbstractItemModel::LayoutChangeHint);
private:
+ bool isDescendantOf(const QPersistentModelIndex &desc, const QList<QPersistentModelIndex> &parents) const;
+
Q_DISABLE_COPY(QQmlDelegateModel)
};
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index 4b70934320..57c7bd4a00 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -4031,6 +4031,8 @@ public:
void run() Q_DECL_OVERRIDE { delete texture; }
};
+QMutex QQuickContext2D::mutex;
+
QQuickContext2D::QQuickContext2D(QObject *parent)
: QQuickCanvasContext(parent)
, m_buffer(new QQuickContext2DCommandBuffer)
@@ -4044,6 +4046,8 @@ QQuickContext2D::QQuickContext2D(QObject *parent)
QQuickContext2D::~QQuickContext2D()
{
+ mutex.lock();
+ m_texture->setItem(0);
delete m_buffer;
if (m_renderTarget == QQuickCanvasItem::FramebufferObject) {
@@ -4064,7 +4068,7 @@ QQuickContext2D::~QQuickContext2D()
c->texture = m_texture;
m_canvas->window()->scheduleRenderJob(c, QQuickWindow::AfterSynchronizingStage);
} else {
- delete m_texture;
+ m_texture->deleteLater();
}
}
} else {
@@ -4073,6 +4077,7 @@ QQuickContext2D::~QQuickContext2D()
// currently be doing.
m_texture->deleteLater();
}
+ mutex.unlock();
}
QV4::ReturnedValue QQuickContext2D::v4value() const
@@ -4143,6 +4148,7 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args
m_glContext->setShareContext(cc);
if (renderThread != QThread::currentThread())
m_glContext->moveToThread(renderThread);
+ m_texture->initializeOpenGL(m_glContext, m_surface.data());
}
connect(m_texture, SIGNAL(textureChanged()), SIGNAL(textureChanged()));
@@ -4331,10 +4337,4 @@ void QQuickContext2D::setV8Engine(QV8Engine *engine)
}
}
-QQuickContext2DCommandBuffer* QQuickContext2D::nextBuffer()
-{
- QMutexLocker lock(&m_mutex);
- return m_bufferQueue.isEmpty() ? 0 : m_bufferQueue.dequeue();
-}
-
QT_END_NAMESPACE
diff --git a/src/quick/items/context2d/qquickcontext2d_p.h b/src/quick/items/context2d/qquickcontext2d_p.h
index bd1a83ce08..c679bc33cb 100644
--- a/src/quick/items/context2d/qquickcontext2d_p.h
+++ b/src/quick/items/context2d/qquickcontext2d_p.h
@@ -185,7 +185,6 @@ public:
QQuickCanvasItem* canvas() const { return m_canvas; }
QQuickContext2DCommandBuffer* buffer() const { return m_buffer; }
- QQuickContext2DCommandBuffer* nextBuffer();
bool bufferValid() const { return m_buffer != 0; }
void popState();
@@ -255,7 +254,7 @@ public:
QImage m_grabbedImage;
bool m_grabbed:1;
- QMutex m_mutex;
+ static QMutex mutex;
};
diff --git a/src/quick/items/context2d/qquickcontext2dtexture.cpp b/src/quick/items/context2d/qquickcontext2dtexture.cpp
index 7e88e18c65..17d4feae6b 100644
--- a/src/quick/items/context2d/qquickcontext2dtexture.cpp
+++ b/src/quick/items/context2d/qquickcontext2dtexture.cpp
@@ -90,6 +90,8 @@ struct GLAcquireContext {
QQuickContext2DTexture::QQuickContext2DTexture()
: m_context(0)
+ , m_gl(0)
+ , m_surface(0)
, m_item(0)
, m_canvasWindowChanged(false)
, m_dirtyTexture(false)
@@ -146,8 +148,12 @@ void QQuickContext2DTexture::setAntialiasing(bool antialiasing)
void QQuickContext2DTexture::setItem(QQuickCanvasItem* item)
{
m_item = item;
- m_context = (QQuickContext2D*)item->rawContext(); // FIXME
- m_state = m_context->state;
+ if (m_item) {
+ m_context = (QQuickContext2D*) item->rawContext(); // FIXME
+ m_state = m_context->state;
+ } else {
+ m_context = 0;
+ }
}
bool QQuickContext2DTexture::setCanvasWindow(const QRect& r)
@@ -239,12 +245,15 @@ bool QQuickContext2DTexture::canvasDestroyed()
void QQuickContext2DTexture::paint(QQuickContext2DCommandBuffer *ccb)
{
+ QQuickContext2D::mutex.lock();
if (canvasDestroyed()) {
delete ccb;
+ QQuickContext2D::mutex.unlock();
return;
}
+ QQuickContext2D::mutex.unlock();
- GLAcquireContext currentContext(m_context->glContext(), m_context->surface());
+ GLAcquireContext currentContext(m_gl, m_surface);
if (!m_tiledCanvas) {
paintWithoutTiles(ccb);
@@ -442,7 +451,7 @@ QSGTexture *QQuickContext2DFBOTexture::textureForNextFrame(QSGTexture *lastTextu
}
if (m_dirtyTexture) {
- if (!m_context->glContext()) {
+ if (!m_gl) {
// on a rendering thread, use the fbo directly...
texture->setTextureId(m_fbo->texture());
} else {
@@ -500,18 +509,18 @@ bool QQuickContext2DFBOTexture::doMultisampling() const
void QQuickContext2DFBOTexture::grabImage(const QRectF& rf)
{
Q_ASSERT(rf.isValid());
- if (!m_fbo) {
- m_context->setGrabbedImage(QImage());
- return;
- }
-
- QImage grabbed;
- {
- GLAcquireContext ctx(m_context->glContext(), m_context->surface());
- grabbed = m_fbo->toImage().scaled(m_fboSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation).mirrored().copy(rf.toRect());
+ QQuickContext2D::mutex.lock();
+ if (m_context) {
+ if (!m_fbo) {
+ m_context->setGrabbedImage(QImage());
+ } else {
+ QImage grabbed;
+ GLAcquireContext ctx(m_gl, m_surface);
+ grabbed = m_fbo->toImage().scaled(m_fboSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation).mirrored().copy(rf.toRect());
+ m_context->setGrabbedImage(grabbed);
+ }
}
-
- m_context->setGrabbedImage(grabbed);
+ QQuickContext2D::mutex.unlock();
}
void QQuickContext2DFBOTexture::compositeTile(QQuickContext2DTile* tile)
@@ -601,7 +610,7 @@ void QQuickContext2DFBOTexture::endPainting()
if (m_multisampledFbo)
QOpenGLFramebufferObject::blitFramebuffer(m_fbo, m_multisampledFbo);
- if (m_context->glContext()) {
+ if (m_gl) {
/* When rendering happens on the render thread, the fbo's texture is
* used directly for display. If we are on the GUI thread or a
* dedicated Canvas render thread, we need to decouple the FBO from
@@ -657,9 +666,12 @@ QQuickContext2DTile* QQuickContext2DImageTexture::createTile() const
void QQuickContext2DImageTexture::grabImage(const QRectF& rf)
{
Q_ASSERT(rf.isValid());
- Q_ASSERT(m_context);
- QImage grabbed = m_displayImage.copy(rf.toRect());
- m_context->setGrabbedImage(grabbed);
+ QQuickContext2D::mutex.lock();
+ if (m_context) {
+ QImage grabbed = m_displayImage.copy(rf.toRect());
+ m_context->setGrabbedImage(grabbed);
+ }
+ QQuickContext2D::mutex.unlock();
}
QSGTexture *QQuickContext2DImageTexture::textureForNextFrame(QSGTexture *last)
diff --git a/src/quick/items/context2d/qquickcontext2dtexture_p.h b/src/quick/items/context2d/qquickcontext2dtexture_p.h
index 7c48453857..169eef8b95 100644
--- a/src/quick/items/context2d/qquickcontext2dtexture_p.h
+++ b/src/quick/items/context2d/qquickcontext2dtexture_p.h
@@ -113,6 +113,11 @@ public:
virtual QSGTexture *textureForNextFrame(QSGTexture *lastFrame) = 0;
bool event(QEvent *e);
+ void initializeOpenGL(QOpenGLContext *gl, QOffscreenSurface *s) {
+ m_gl = gl;
+ m_surface = s;
+ }
+
Q_SIGNALS:
void textureChanged();
@@ -137,7 +142,10 @@ protected:
QRect createTiles(const QRect& window);
QList<QQuickContext2DTile*> m_tiles;
- QQuickContext2D* m_context;
+ QQuickContext2D *m_context;
+
+ QOpenGLContext *m_gl;
+ QSurface *m_surface;
QQuickContext2D::State m_state;
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 04539800a5..fc61ef7d98 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -3226,6 +3226,8 @@ QQmlIncubationController *QQuickWindow::incubationController() const
\warning Make very sure that a signal handler for beforeSynchronizing leaves the GL
context in the same state as it was when the signal handler was entered. Failing to
do so can result in the scene not rendering properly.
+
+ \sa resetOpenGLState()
*/
/*!
@@ -3247,6 +3249,7 @@ QQmlIncubationController *QQuickWindow::incubationController() const
do so can result in the scene not rendering properly.
\since 5.3
+ \sa resetOpenGLState()
*/
/*!
@@ -3267,6 +3270,8 @@ QQmlIncubationController *QQuickWindow::incubationController() const
\warning Make very sure that a signal handler for beforeRendering leaves the GL
context in the same state as it was when the signal handler was entered. Failing to
do so can result in the scene not rendering properly.
+
+ \sa resetOpenGLState()
*/
/*!
@@ -3286,6 +3291,8 @@ QQmlIncubationController *QQuickWindow::incubationController() const
\warning Make very sure that a signal handler for afterRendering() leaves the GL
context in the same state as it was when the signal handler was entered. Failing to
do so can result in the scene not rendering properly.
+
+ \sa resetOpenGLState()
*/
/*!
@@ -3338,7 +3345,7 @@ QQmlIncubationController *QQuickWindow::incubationController() const
context in the same state as it was when the signal handler was entered. Failing to
do so can result in the scene not rendering properly.
- \sa sceneGraphInvalidated()
+ \sa sceneGraphInvalidated(), resetOpenGLState()
\since 5.3
*/
diff --git a/tests/auto/quick/qquickcanvasitem/data/CanvasTestCase.qml b/tests/auto/quick/qquickcanvasitem/data/CanvasTestCase.qml
index 70682bed0b..c8c2f4960f 100644
--- a/tests/auto/quick/qquickcanvasitem/data/CanvasTestCase.qml
+++ b/tests/auto/quick/qquickcanvasitem/data/CanvasTestCase.qml
@@ -19,8 +19,8 @@ TestCase {
// { tag:"image cooperative", properties:{width:100, height:100, renderTarget:Canvas.Image, renderStrategy:Canvas.Cooperative}},
{ tag:"image immediate", properties:{width:100, height:100, renderTarget:Canvas.Image, renderStrategy:Canvas.Immediate}},
// { tag:"fbo cooperative", properties:{width:100, height:100, renderTarget:Canvas.FramebufferObject, renderStrategy:Canvas.Cooperative}},
-// { tag:"fbo immediate", properties:{width:100, height:100, renderTarget:Canvas.FramebufferObject, renderStrategy:Canvas.Immediate}},
-// { tag:"fbo threaded", properties:{width:100, height:100, renderTarget:Canvas.FramebufferObject, renderStrategy:Canvas.Threaded}}
+ { tag:"fbo immediate", properties:{width:100, height:100, renderTarget:Canvas.FramebufferObject, renderStrategy:Canvas.Immediate}},
+ { tag:"fbo threaded", properties:{width:100, height:100, renderTarget:Canvas.FramebufferObject, renderStrategy:Canvas.Threaded}}
];
return [];
}
diff --git a/tests/auto/quick/qquicklistview/data/layoutChangeSort.qml b/tests/auto/quick/qquicklistview/data/layoutChangeSort.qml
new file mode 100644
index 0000000000..e54f164e45
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/data/layoutChangeSort.qml
@@ -0,0 +1,58 @@
+import QtQuick 2.0
+import QtQml.Models 2.1
+
+Rectangle {
+ id: root
+ width: 240
+ height: 320
+ color: "#ffffff"
+
+
+ Component {
+ id: myDelegate
+ Rectangle {
+ id: wrapper
+ objectName: "wrapper"
+ height: 20
+ width: 240
+ Text {
+ objectName: "delegateText"
+ text: display
+ }
+ color: ListView.isCurrentItem ? "lightsteelblue" : "white"
+ }
+ }
+
+ DelegateModel {
+ id: delegateModel
+ objectName: "delegateModel"
+ model: testModel
+ delegate: myDelegate
+ }
+
+ ListView {
+ id: list
+ objectName: "listView"
+ model: delegateModel;
+ focus: true
+ anchors.fill: parent
+
+
+ section {
+ property: "SortRole";
+ delegate: Rectangle {
+ width: parent.width;
+ height: 20;
+ color: "steelblue";
+
+ Text {
+ anchors {
+ fill: parent;
+ margins: 5;
+ }
+ text: section;
+ }
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview/data/qtbug39492.qml b/tests/auto/quick/qquicklistview/data/qtbug39492.qml
new file mode 100644
index 0000000000..4df3a080d7
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/data/qtbug39492.qml
@@ -0,0 +1,40 @@
+import QtQuick 2.0
+import QtQml.Models 2.1
+
+Rectangle {
+ id: root
+ width: 240
+ height: 320
+ color: "#ffffff"
+
+
+ Component {
+ id: myDelegate
+ Rectangle {
+ id: wrapper
+ objectName: "wrapper"
+ height: 20
+ width: 240
+ Text {
+ objectName: "delegateText"
+ text: display
+ }
+ color: ListView.isCurrentItem ? "lightsteelblue" : "white"
+ }
+ }
+
+ DelegateModel {
+ id: delegateModel
+ objectName: "delegateModel"
+ model: testModel
+ delegate: myDelegate
+ }
+
+ ListView {
+ id: list
+ objectName: "listView"
+ model: delegateModel;
+ focus: true
+ anchors.fill: parent
+ }
+}
diff --git a/tests/auto/quick/qquicklistview/qquicklistview.pro b/tests/auto/quick/qquicklistview/qquicklistview.pro
index 2ae04d32fe..c9b634b9e8 100644
--- a/tests/auto/quick/qquicklistview/qquicklistview.pro
+++ b/tests/auto/quick/qquicklistview/qquicklistview.pro
@@ -4,10 +4,13 @@ TARGET = tst_qquicklistview
macx:CONFIG -= app_bundle
HEADERS += incrementalmodel.h \
- proxytestinnermodel.h
+ proxytestinnermodel.h \
+ randomsortmodel.h
SOURCES += tst_qquicklistview.cpp \
incrementalmodel.cpp \
- proxytestinnermodel.cpp
+ proxytestinnermodel.cpp \
+ randomsortmodel.cpp
+
include (../../shared/util.pri)
include (../shared/util.pri)
diff --git a/tests/auto/quick/qquicklistview/randomsortmodel.cpp b/tests/auto/quick/qquicklistview/randomsortmodel.cpp
new file mode 100644
index 0000000000..e9082e39c9
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/randomsortmodel.cpp
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "randomsortmodel.h"
+
+RandomSortModel::RandomSortModel(QObject* parent):
+ QAbstractListModel(parent)
+{
+ for (int i = 0; i < 10; ++i) {
+ mData.append(qMakePair(QString::fromLatin1("Item %1").arg(i), i * 10));
+ }
+}
+
+QHash<int, QByteArray> RandomSortModel::roleNames() const
+{
+ QHash<int,QByteArray> roles = QAbstractItemModel::roleNames();
+ roles[Qt::UserRole] = "SortRole";
+ return roles;
+}
+
+
+int RandomSortModel::rowCount(const QModelIndex& parent) const
+{
+ if (!parent.isValid())
+ return mData.count();
+
+ return 0;
+}
+
+QVariant RandomSortModel::data(const QModelIndex& index, int role) const
+{
+ if (!index.isValid()) {
+ return QVariant();
+ }
+
+ if (index.row() >= mData.count()) {
+ return QVariant();
+ }
+
+ if (role == Qt::DisplayRole) {
+ return QString::fromLatin1("%1 (weight %2)").arg(mData[index.row()].first).arg(mData[index.row()].second);
+ } else if (role == Qt::UserRole) {
+ return mData[index.row()].second;
+ }
+
+ return QVariant();
+}
+
+void RandomSortModel::randomize()
+{
+ const int row = qrand() % mData.count();
+ int random;
+ bool exists = false;
+ // Make sure we won't end up with two items with the same weight, as that
+ // would make unit-testing much harder
+ do {
+ exists = false;
+ random = qrand() % (mData.count() * 10);
+ QList<QPair<QString, int> >::ConstIterator iter, end;
+ for (iter = mData.constBegin(), end = mData.constEnd(); iter != end; ++iter) {
+ if ((*iter).second == random) {
+ exists = true;
+ break;
+ }
+ }
+ } while (exists);
+ mData[row].second = random;
+ Q_EMIT dataChanged(index(row, 0), index(row, 0));
+}
diff --git a/tests/auto/quick/qquicklistview/randomsortmodel.h b/tests/auto/quick/qquicklistview/randomsortmodel.h
new file mode 100644
index 0000000000..8d28698d9b
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/randomsortmodel.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef RANDOMSORTMODEL_H
+#define RANDOMSORTMODEL_H
+
+#include <QAbstractListModel>
+
+class RandomSortModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+public:
+ explicit RandomSortModel(QObject* parent = 0);
+ QHash<int, QByteArray> roleNames() const;
+
+ QVariant data(const QModelIndex& index, int role) const;
+ int rowCount(const QModelIndex& parent = QModelIndex()) const;
+
+ void randomize();
+
+ private:
+ QList<QPair<QString, int> > mData;
+};
+
+#endif // RANDOMSORTMODEL_H
diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
index c8ab62cbbc..0e477965f0 100644
--- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
+++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
@@ -41,6 +41,8 @@
#include <QtTest/QtTest>
#include <QtCore/QStringListModel>
+#include <QtCore/QSortFilterProxyModel>
+#include <QtGui/QStandardItemModel>
#include <QtQuick/qquickview.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcontext.h>
@@ -50,11 +52,13 @@
#include <QtQuick/private/qquicktext_p.h>
#include <QtQml/private/qqmlobjectmodel_p.h>
#include <QtQml/private/qqmllistmodel_p.h>
+#include <QtQml/private/qqmldelegatemodel_p.h>
#include "../../shared/util.h"
#include "../shared/viewtestutil.h"
#include "../shared/visualtestutil.h"
#include "incrementalmodel.h"
#include "proxytestinnermodel.h"
+#include "randomsortmodel.h"
#include <math.h>
Q_DECLARE_METATYPE(Qt::LayoutDirection)
@@ -62,6 +66,7 @@ Q_DECLARE_METATYPE(QQuickItemView::VerticalLayoutDirection)
Q_DECLARE_METATYPE(QQuickItemView::PositionMode)
Q_DECLARE_METATYPE(QQuickListView::Orientation)
Q_DECLARE_METATYPE(Qt::Key)
+Q_DECLARE_METATYPE(QPersistentModelIndex)
using namespace QQuickViewTestUtil;
using namespace QQuickVisualTestUtil;
@@ -234,6 +239,11 @@ private slots:
void QTBUG_38209();
void programmaticFlickAtBounds();
+ void layoutChange();
+
+ void QTBUG_39492_data();
+ void QTBUG_39492();
+
private:
template <class T> void items(const QUrl &source);
template <class T> void changed(const QUrl &source);
@@ -7418,8 +7428,120 @@ void tst_QQuickListView::programmaticFlickAtBounds()
QVERIFY(!spy.wait(100));
}
-QTEST_MAIN(tst_QQuickListView)
+void tst_QQuickListView::layoutChange()
+{
+ RandomSortModel *model = new RandomSortModel;
+ QSortFilterProxyModel *sortModel = new QSortFilterProxyModel;
+ sortModel->setSourceModel(model);
+ sortModel->setSortRole(Qt::UserRole);
+ sortModel->setDynamicSortFilter(true);
+ sortModel->sort(0);
-#include "tst_qquicklistview.moc"
+ QScopedPointer<QQuickView> window(createView());
+ window->rootContext()->setContextProperty("testModel", QVariant::fromValue(sortModel));
+ window->setSource(testFileUrl("layoutChangeSort.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QQuickListView *listview = window->rootObject()->findChild<QQuickListView *>("listView");
+ QVERIFY(listview);
+
+ for (int iter = 0; iter < 100; iter++) {
+ for (int i = 0; i < sortModel->rowCount(); ++i) {
+ QQuickItem *delegateItem = listview->itemAt(10, 10 + 2 * i * 20 + 20); // item + group
+ QVERIFY(delegateItem);
+ QQuickItem *delegateText = delegateItem->findChild<QQuickItem *>("delegateText");
+ QVERIFY(delegateText);
+
+ QCOMPARE(delegateText->property("text").toString(),
+ sortModel->index(i, 0, QModelIndex()).data().toString());
+ }
+
+ model->randomize();
+ listview->forceLayout();
+ QTest::qWait(5); // give view a chance to update
+ }
+}
+
+void tst_QQuickListView::QTBUG_39492_data()
+{
+ QStandardItemModel *sourceModel = new QStandardItemModel(this);
+ for (int i = 0; i < 5; ++i) {
+ QStandardItem *item = new QStandardItem(QString::number(i));
+ for (int j = 0; j < 5; ++j) {
+ QStandardItem *subItem = new QStandardItem(QString("%1-%2").arg(i).arg(j));
+ item->appendRow(subItem);
+ }
+ sourceModel->appendRow(item);
+ }
+
+ QSortFilterProxyModel *sortModel = new QSortFilterProxyModel(this);
+ sortModel->setSourceModel(sourceModel);
+
+ QTest::addColumn<QSortFilterProxyModel*>("model");
+ QTest::addColumn<QPersistentModelIndex>("rootIndex");
+
+ QTest::newRow("invalid rootIndex")
+ << sortModel
+ << QPersistentModelIndex();
+ QTest::newRow("rootIndex 1")
+ << sortModel
+ << QPersistentModelIndex(sortModel->index(1, 0));
+ QTest::newRow("rootIndex 3")
+ << sortModel
+ << QPersistentModelIndex(sortModel->index(3, 0));
+
+ const QModelIndex rootIndex2 = sortModel->index(2, 0);
+ QTest::newRow("rootIndex 2-1")
+ << sortModel
+ << QPersistentModelIndex(sortModel->index(1, 0, rootIndex2));
+}
+
+void tst_QQuickListView::QTBUG_39492()
+{
+ QFETCH(QSortFilterProxyModel*, model);
+ QFETCH(QPersistentModelIndex, rootIndex);
+
+ QQuickView *window = getView();
+ window->rootContext()->setContextProperty("testModel", QVariant::fromValue(model));
+ window->setSource(testFileUrl("qtbug39492.qml"));
+
+ QQuickListView *listview = window->rootObject()->findChild<QQuickListView *>("listView");
+ QVERIFY(listview);
+
+ QQmlDelegateModel *delegateModel = window->rootObject()->findChild<QQmlDelegateModel *>("delegateModel");
+ QVERIFY(delegateModel);
+
+ delegateModel->setRootIndex(QVariant::fromValue(QModelIndex(rootIndex)));
+ model->sort(0, Qt::AscendingOrder);
+ listview->forceLayout();
+
+ for (int i = 0; i < model->rowCount(rootIndex); ++i) {
+ QQuickItem *delegateItem = listview->itemAt(10, 10 + i * 20);
+ QVERIFY(delegateItem);
+ QQuickItem *delegateText = delegateItem->findChild<QQuickItem *>("delegateText");
+ QVERIFY(delegateText);
+ QCOMPARE(delegateText->property("text").toString(),
+ model->index(i, 0, rootIndex).data().toString());
+ }
+
+ model->sort(0, Qt::DescendingOrder);
+ listview->forceLayout();
+
+ for (int i = 0; i < model->rowCount(rootIndex); ++i) {
+ QQuickItem *delegateItem = listview->itemAt(10, 10 + i * 20);
+ QVERIFY(delegateItem);
+ QQuickItem *delegateText = delegateItem->findChild<QQuickItem *>("delegateText");
+ QVERIFY(delegateText);
+ QCOMPARE(delegateText->property("text").toString(),
+ model->index(i, 0, rootIndex).data().toString());
+ }
+
+ releaseView(window);
+}
+
+QTEST_MAIN(tst_QQuickListView)
+
+#include "tst_qquicklistview.moc"
diff --git a/tools/qmlplugindump/main.cpp b/tools/qmlplugindump/main.cpp
index bc55c40434..4934d20f75 100644
--- a/tools/qmlplugindump/main.cpp
+++ b/tools/qmlplugindump/main.cpp
@@ -69,6 +69,10 @@
#ifdef Q_OS_UNIX
#include <signal.h>
#endif
+#ifdef Q_OS_WIN
+#include <crtdbg.h>
+#include <qt_windows.h>
+#endif
QString pluginImportPath;
bool verbose = false;
@@ -306,6 +310,7 @@ QSet<const QMetaObject *> collectReachableMetaObjects(QQmlEngine *engine,
std::cerr << "Got " << qPrintable( tyName )
<< " (" << qPrintable( QString::fromUtf8(ty->typeName()) ) << ")" << std::endl;
collectReachableMetaObjects(object, &metas);
+ object->deleteLater();
} else {
std::cerr << "Could not create" << qPrintable(tyName) << std::endl;
}
@@ -731,6 +736,13 @@ void printDebugMessage(QtMsgType, const QMessageLogContext &, const QString &msg
int main(int argc, char *argv[])
{
+#ifdef Q_OS_WIN
+ // we do not want windows popping up if the module loaded triggers an assert
+ SetErrorMode(SEM_NOGPFAULTERRORBOX);
+ _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
+ _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG);
+ _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
+#endif
// The default message handler might not print to console on some systems. Enforce this.
qInstallMessageHandler(printDebugMessage);
#ifdef Q_OS_UNIX