aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/qml/qqmlvaluetype.cpp20
-rw-r--r--src/qml/types/qqmlitemmodels.qdoc115
-rw-r--r--src/qml/types/qqmlmodelindexvaluetype.cpp60
-rw-r--r--src/qml/types/qqmlmodelindexvaluetype_p.h215
-rw-r--r--src/qml/types/types.pri2
-rw-r--r--tests/auto/qml/qml.pro1
-rw-r--r--tests/auto/qml/qqmlitemmodels/data/itemselection.qml36
-rw-r--r--tests/auto/qml/qqmlitemmodels/data/itemselectionrange.qml32
-rw-r--r--tests/auto/qml/qqmlitemmodels/data/modelindex.qml19
-rw-r--r--tests/auto/qml/qqmlitemmodels/data/modelindexconversion.qml9
-rw-r--r--tests/auto/qml/qqmlitemmodels/data/modelindexlist.qml21
-rw-r--r--tests/auto/qml/qqmlitemmodels/data/persistentmodelindex.qml23
-rw-r--r--tests/auto/qml/qqmlitemmodels/qqmlitemmodels.pro23
-rw-r--r--tests/auto/qml/qqmlitemmodels/qtestmodel.h322
-rw-r--r--tests/auto/qml/qqmlitemmodels/testtypes.h148
-rw-r--r--tests/auto/qml/qqmlitemmodels/tst_qqmlitemmodels.cpp223
16 files changed, 1269 insertions, 0 deletions
diff --git a/src/qml/qml/qqmlvaluetype.cpp b/src/qml/qml/qqmlvaluetype.cpp
index be14eb44c2..1528ebda37 100644
--- a/src/qml/qml/qqmlvaluetype.cpp
+++ b/src/qml/qml/qqmlvaluetype.cpp
@@ -37,6 +37,7 @@
#include <private/qqmlglobal_p.h>
#include <QtCore/qdebug.h>
#include <private/qmetaobjectbuilder_p.h>
+#include <private/qqmlmodelindexvaluetype_p.h>
QT_BEGIN_NAMESPACE
@@ -61,6 +62,14 @@ QQmlValueTypeFactoryImpl::QQmlValueTypeFactoryImpl()
{
for (unsigned int ii = 0; ii < QVariant::UserType; ++ii)
valueTypes[ii] = 0;
+
+ // See types wrapped in qqmlmodelindexvaluetype_p.h
+ qRegisterMetaType<QModelIndexList>();
+ qRegisterMetaType<QPersistentModelIndex>();
+ qRegisterMetaType<QItemSelectionRange>();
+ qRegisterMetaType<QItemSelection>();
+ QMetaType::registerConverter<QModelIndex, QPersistentModelIndex>(&QQmlModelIndexValueType::toPersistentModelIndex);
+ QMetaType::registerConverter<QPersistentModelIndex, QModelIndex>(&QQmlPersistentModelIndexValueType::toModelIndex);
}
QQmlValueTypeFactoryImpl::~QQmlValueTypeFactoryImpl()
@@ -101,12 +110,23 @@ const QMetaObject *QQmlValueTypeFactoryImpl::metaObjectForMetaType(int t)
return &QQmlRectFValueType::staticMetaObject;
case QVariant::EasingCurve:
return &QQmlEasingValueType::staticMetaObject;
+ case QVariant::ModelIndex:
+ return &QQmlModelIndexValueType::staticMetaObject;
default:
if (const QMetaObject *mo = QQml_valueTypeProvider()->metaObjectForMetaType(t))
return mo;
break;
}
+ if (t == qMetaTypeId<QPersistentModelIndex>())
+ return &QQmlPersistentModelIndexValueType::staticMetaObject;
+ else if (t == qMetaTypeId<QModelIndexList>())
+ return &QQmlModelIndexListValueType::staticMetaObject;
+ else if (t == qMetaTypeId<QItemSelectionRange>())
+ return &QQmlItemSelectionRangeValueType::staticMetaObject;
+ else if (t == qMetaTypeId<QItemSelection>())
+ return &QQmlItemSelectionValueType::staticMetaObject;
+
QMetaType metaType(t);
if (metaType.flags() & QMetaType::IsGadget)
return metaType.metaObject();
diff --git a/src/qml/types/qqmlitemmodels.qdoc b/src/qml/types/qqmlitemmodels.qdoc
new file mode 100644
index 0000000000..25c9321115
--- /dev/null
+++ b/src/qml/types/qqmlitemmodels.qdoc
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: http://www.gnu.org/copyleft/fdl.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \chapter QModelIndex & Co. in QML
+
+ Since Qt 5.5, QModelIndex and QPersistentModelIndex are exposed in QML as
+ value-based types. Also exposed in a similar fashion are QModelIndexList,
+ QItemSelectionRange and QItemSelection. All objects from these types can
+ be passed back and forth between QML and C++ as \c var properties or plain
+ JavaScript variables.
+
+ We detail here which API all these classes get exposed in QML. Please refer
+ to the C++ documentation for more information.
+
+ \note Since all these types are exposed as gadgets, there are no property
+ change notification signals emitted. Therefore binding to their properties
+ may not give the expected results. This is especially true for QPersistentModelIndex.
+ It is perfectly possible to bind to properties holding any of those types.
+
+ \section1 \l QModelIndex and \l QPersistentModelIndex
+
+ \list
+ \li \b row : int
+ \li \b column : int
+ \li \b parent : QModelIndex
+ \li \b valid : bool
+ \li \b model : QAbstractItemModel
+ \li \b internalId : quint64
+ \endlist
+
+ All these properties are read-only, as their C++ counterpart.
+
+ \note The usual caveats apply to QModelIndex in QML. If the underlying model changes
+ or gets deleted, it may become dangerous to access its properties. Therefore, you
+ should not store any QModelIndex. You can, however, store QPersistentModelIndexes
+ in a safe way.
+
+ \section1 \l QItemSelectionRange
+
+ \list
+ \li \b top : int
+ \li \b left : int
+ \li \b bottom : int
+ \li \b right : int
+ \li \b width : int
+ \li \b height : int
+ \li \b topLeft : QPersistentModelIndex
+ \li \b bottomRight : QPersistentModelIndex
+ \li \b parent : QModelIndex
+ \li \b valid : bool
+ \li \b empty : bool
+ \li \b model : QAbstractItemModel
+ \endlist
+
+ All these properties are read-only, as their C++ counterpart. In addition,
+ we also expose the following functions:
+
+ \list
+ \li bool \b{contains}(QModelIndex index)
+ \li bool \b{contains}(int row, int column, QModelIndex parentIndex)
+ \li bool \b{intersects}(QItemSelectionRange other)
+ \li QItemSelectionRange \b{intersected}(QItemSelectionRange other)
+ \endlist
+
+ \section1 \l QModelIndexList and \l QItemSelection
+
+ Both \l QModelIndexList and \l QItemSelection expose the following properties
+ and functions as part of their \l QList API:
+
+ \list
+ \li \b length : int
+ \li object \b{at}(int i)
+ \li void \b{append}(object o)
+ \li void \b{prepend}(o)
+ \li void \b{insert}(int i, object o)
+ \li void \b{removeFirst}()
+ \li void \b{removeLast}()
+ \li void \b{removeAt}(int i)
+ \endlist
+
+ In addition, \l QItemSelection also exposes the following functions:
+
+ \list
+ \li void \b{select}(QModelIndex topLeft, QModelIndex bottomRight)
+ \li bool \b{contains}(QModelIndex index)
+ \li void \b{merge}(QItemSelection other, QItemSelectionModel::SelectionFlags command)
+ \endlist
+
+ \sa ItemSelectionModel
+*/
diff --git a/src/qml/types/qqmlmodelindexvaluetype.cpp b/src/qml/types/qqmlmodelindexvaluetype.cpp
new file mode 100644
index 0000000000..03ae05b4b5
--- /dev/null
+++ b/src/qml/types/qqmlmodelindexvaluetype.cpp
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlmodelindexvaluetype_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+*/
+QString QQmlModelIndexValueType::propertiesString(const QModelIndex &idx)
+{
+ if (!idx.isValid())
+ return QLatin1String("()");
+ return QString(QLatin1String("(%1,%2,0x%3,%4(0x%5))"))
+ .arg(idx.row()).arg(idx.column()).arg(idx.internalId(), 0, 16)
+ .arg(idx.model()->metaObject()->className()).arg(quintptr(idx.model()), 0, 16);
+}
+
+/*!
+ \internal
+*/
+QString QQmlItemSelectionRangeValueType::toString() const
+{
+ return QString(QLatin1String("QItemSelectionRange(%1,%2)"))
+ .arg(reinterpret_cast<const QQmlPersistentModelIndexValueType *>(&v.topLeft())->toString())
+ .arg(reinterpret_cast<const QQmlPersistentModelIndexValueType *>(&v.bottomRight())->toString());
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/types/qqmlmodelindexvaluetype_p.h b/src/qml/types/qqmlmodelindexvaluetype_p.h
new file mode 100644
index 0000000000..0e655ab3d7
--- /dev/null
+++ b/src/qml/types/qqmlmodelindexvaluetype_p.h
@@ -0,0 +1,215 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLMODELINDEXVALUETYPE_P_H
+#define QQMLMODELINDEXVALUETYPE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qabstractitemmodel.h>
+#include <QtCore/qitemselectionmodel.h>
+
+QT_BEGIN_NAMESPACE
+
+struct QQmlModelIndexValueType
+{
+ QModelIndex v;
+
+ Q_PROPERTY(int row READ row CONSTANT FINAL)
+ Q_PROPERTY(int column READ column CONSTANT FINAL)
+ Q_PROPERTY(QModelIndex parent READ parent FINAL)
+ Q_PROPERTY(bool valid READ isValid CONSTANT FINAL)
+ Q_PROPERTY(QAbstractItemModel *model READ model CONSTANT FINAL)
+ Q_PROPERTY(quint64 internalId READ internalId CONSTANT FINAL)
+ Q_GADGET
+
+public:
+ Q_INVOKABLE QString toString() const
+ { return QLatin1String("QModelIndex") + propertiesString(v); }
+
+ inline int row() const Q_DECL_NOTHROW { return v.row(); }
+ inline int column() const Q_DECL_NOTHROW { return v.column(); }
+ inline QModelIndex parent() const { return v.parent(); }
+ inline bool isValid() const Q_DECL_NOTHROW { return v.isValid(); }
+ inline QAbstractItemModel *model() const Q_DECL_NOTHROW
+ { return const_cast<QAbstractItemModel *>(v.model()); }
+ quint64 internalId() const { return v.internalId(); }
+
+ static QString propertiesString(const QModelIndex &idx);
+
+ static QPersistentModelIndex toPersistentModelIndex(const QModelIndex &index)
+ { return QPersistentModelIndex(index); }
+};
+
+struct QQmlPersistentModelIndexValueType
+{
+ QPersistentModelIndex v;
+
+ Q_PROPERTY(int row READ row FINAL)
+ Q_PROPERTY(int column READ column FINAL)
+ Q_PROPERTY(QModelIndex parent READ parent FINAL)
+ Q_PROPERTY(bool valid READ isValid FINAL)
+ Q_PROPERTY(QAbstractItemModel *model READ model FINAL)
+ Q_PROPERTY(quint64 internalId READ internalId FINAL)
+ Q_GADGET
+
+public:
+ Q_INVOKABLE QString toString() const
+ { return QLatin1String("QPersistentModelIndex") + QQmlModelIndexValueType::propertiesString(v); }
+
+ inline int row() const { return v.row(); }
+ inline int column() const { return v.column(); }
+ inline QModelIndex parent() const { return v.parent(); }
+ inline bool isValid() const { return v.isValid(); }
+ inline QAbstractItemModel *model() const { return const_cast<QAbstractItemModel *>(v.model()); }
+ inline quint64 internalId() const { return v.internalId(); }
+
+ static const QModelIndex &toModelIndex(const QPersistentModelIndex &index)
+ { return index; }
+};
+
+struct QQmlItemSelectionRangeValueType
+{
+ QItemSelectionRange v;
+
+ Q_PROPERTY(int top READ top FINAL)
+ Q_PROPERTY(int left READ left FINAL)
+ Q_PROPERTY(int bottom READ bottom FINAL)
+ Q_PROPERTY(int right READ right FINAL)
+ Q_PROPERTY(int width READ width FINAL)
+ Q_PROPERTY(int height READ height FINAL)
+ Q_PROPERTY(QPersistentModelIndex topLeft READ topLeft FINAL)
+ Q_PROPERTY(QPersistentModelIndex bottomRight READ bottomRight FINAL)
+ Q_PROPERTY(QModelIndex parent READ parent FINAL)
+ Q_PROPERTY(bool valid READ isValid FINAL)
+ Q_PROPERTY(bool empty READ isEmpty FINAL)
+ Q_PROPERTY(QAbstractItemModel *model READ model FINAL)
+ Q_GADGET
+
+public:
+ Q_INVOKABLE QString toString() const;
+ Q_INVOKABLE inline bool contains(const QModelIndex &index) const
+ { return v.contains(index); }
+ Q_INVOKABLE inline bool contains(int row, int column, const QModelIndex &parentIndex) const
+ { return v.contains(row, column, parentIndex); }
+ Q_INVOKABLE inline bool intersects(const QItemSelectionRange &other) const
+ { return v.intersects(other); }
+ Q_INVOKABLE QItemSelectionRange intersected(const QItemSelectionRange &other) const
+ { return v.intersected(other); }
+
+ inline int top() const { return v.top(); }
+ inline int left() const { return v.left(); }
+ inline int bottom() const { return v.bottom(); }
+ inline int right() const { return v.right(); }
+ inline int width() const { return v.width(); }
+ inline int height() const { return v.height(); }
+ inline QPersistentModelIndex &topLeft() const { return const_cast<QPersistentModelIndex &>(v.topLeft()); }
+ inline QPersistentModelIndex &bottomRight() const { return const_cast<QPersistentModelIndex &>(v.bottomRight()); }
+ inline QModelIndex parent() const { return v.parent(); }
+ inline QAbstractItemModel *model() const { return const_cast<QAbstractItemModel *>(v.model()); }
+ inline bool isValid() const { return v.isValid(); }
+ inline bool isEmpty() const { return v.isEmpty(); }
+};
+
+template<typename V, typename T>
+QString q_listToString(const QList<T> &list, const QLatin1String &typeName)
+{
+ QString result = typeName;
+ result.append(QLatin1Char('('));
+ for (typename QList<T>::size_type i = 0; i < list.count(); ++i) {
+ if (i)
+ result.append(QLatin1String(", "));
+ result.append(reinterpret_cast<const V *>(&list.at(i))->toString());
+ }
+ return result.append(QLatin1Char(')'));
+}
+
+// Invokable QList<T> API forwarding for value types
+#define QLISTVALUETYPE_QML_API(T) \
+ Q_PROPERTY(int length READ length FINAL) \
+ Q_INVOKABLE T at(int i) { return v.at(i); } \
+ Q_INVOKABLE void append(const T &o) { v.append(o); } \
+ Q_INVOKABLE void prepend(const T &o) { v.prepend(o); } \
+ Q_INVOKABLE void insert(int i, const T &o) { v.insert(i, o); } \
+ Q_INVOKABLE void removeFirst() { v.removeFirst(); } \
+ Q_INVOKABLE void removeLast() { v.removeLast(); } \
+ Q_INVOKABLE void removeAt(int i) { v.removeAt(i); } \
+ int length() const { return v.length(); }
+
+struct QQmlModelIndexListValueType
+{
+ QModelIndexList v;
+
+ Q_GADGET
+
+public:
+ Q_INVOKABLE QString toString()
+ { return q_listToString<QQmlModelIndexValueType>(v, QLatin1String("")); }
+
+ QLISTVALUETYPE_QML_API(QModelIndex)
+};
+
+struct QQmlItemSelectionValueType
+{
+ QItemSelection v;
+
+ Q_GADGET
+
+public:
+ Q_INVOKABLE QString toString()
+ { return q_listToString<QQmlItemSelectionRangeValueType>(v, QLatin1String("QItemSelection")); }
+ Q_INVOKABLE void select(const QModelIndex &topLeft, const QModelIndex &bottomRight)
+ { v.select(topLeft, bottomRight); }
+ Q_INVOKABLE bool contains(const QModelIndex &index) const
+ { return v.contains(index); }
+ Q_INVOKABLE void merge(const QItemSelection &other, int command)
+ { v.merge(other, QItemSelectionModel::SelectionFlags(command)); }
+
+ QLISTVALUETYPE_QML_API(QItemSelectionRange)
+};
+
+#undef QLISTVALUETYPE_INVOKABLE_API
+
+QT_END_NAMESPACE
+
+#endif // QQMLMODELINDEXVALUETYPE_P_H
+
diff --git a/src/qml/types/types.pri b/src/qml/types/types.pri
index 3e6153759d..d2e5020738 100644
--- a/src/qml/types/types.pri
+++ b/src/qml/types/types.pri
@@ -5,6 +5,7 @@ SOURCES += \
$$PWD/qqmllistmodel.cpp \
$$PWD/qqmllistmodelworkeragent.cpp \
$$PWD/qqmlmodelsmodule.cpp \
+ $$PWD/qqmlmodelindexvaluetype.cpp \
$$PWD/qqmlobjectmodel.cpp \
$$PWD/qqmltimer.cpp \
$$PWD/qquickpackage.cpp \
@@ -20,6 +21,7 @@ HEADERS += \
$$PWD/qqmllistmodel_p_p.h \
$$PWD/qqmllistmodelworkeragent_p.h \
$$PWD/qqmlmodelsmodule_p.h \
+ $$PWD/qqmlmodelindexvaluetype_p.h \
$$PWD/qqmlobjectmodel_p.h \
$$PWD/qqmltimer_p.h \
$$PWD/qquickpackage_p.h \
diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro
index 3449050fe8..a5c3211f0d 100644
--- a/tests/auto/qml/qml.pro
+++ b/tests/auto/qml/qml.pro
@@ -48,6 +48,7 @@ PRIVATETESTS += \
qqmllistcompositor \
qqmllistmodel \
qqmllistmodelworkerscript \
+ qqmlitemmodels \
qqmltypeloader \
qqmlparser \
qquickworkerscript \
diff --git a/tests/auto/qml/qqmlitemmodels/data/itemselection.qml b/tests/auto/qml/qqmlitemmodels/data/itemselection.qml
new file mode 100644
index 0000000000..57cb6436e9
--- /dev/null
+++ b/tests/auto/qml/qqmlitemmodels/data/itemselection.qml
@@ -0,0 +1,36 @@
+import Test 1.0
+
+ItemModelsTest {
+ property var itemSelection
+ property int count
+ property bool contains: false
+
+ function range(top, bottom, left, right, parent) {
+ if (parent === undefined)
+ parent = invalidModelIndex()
+ var topLeft = model.index(top, left, parent)
+ var bottomRight = model.index(bottom, right, parent)
+ return createItemSelectionRange(topLeft, bottomRight)
+ }
+
+ onModelChanged: {
+ itemSelection = createItemSelection()
+ itemSelection.prepend(range(0, 0, 0, 5))
+ itemSelection.append(range(0, 5, 0, 0))
+ for (var i = 0; i < 3; i++)
+ itemSelection.insert(i, range(i, i + 1, i + 2, i + 3))
+
+ var itemSelection2 = createItemSelection()
+ for (i = 3; i < 6; i++)
+ itemSelection2.select(model.index(i, i + 1), model.index(i + 2, i + 3))
+
+ itemSelection.merge(itemSelection2, 2 /*ItemSelectionModel.Select*/)
+
+ count = itemSelection.length
+ contains = itemSelection.contains(model.index(0, 0))
+
+ itemSelection.removeAt(3)
+ itemSelection.removeFirst()
+ itemSelection.removeLast()
+ }
+}
diff --git a/tests/auto/qml/qqmlitemmodels/data/itemselectionrange.qml b/tests/auto/qml/qqmlitemmodels/data/itemselectionrange.qml
new file mode 100644
index 0000000000..72f732abaf
--- /dev/null
+++ b/tests/auto/qml/qqmlitemmodels/data/itemselectionrange.qml
@@ -0,0 +1,32 @@
+import Test 1.0
+
+ItemModelsTest {
+ property var itemSelectionRange: createItemSelectionRange(invalidModelIndex(), invalidModelIndex())
+ property int top: itemSelectionRange.top
+ property int left: itemSelectionRange.left
+ property int bottom: itemSelectionRange.bottom
+ property int right: itemSelectionRange.right
+ property int width: itemSelectionRange.width
+ property int height: itemSelectionRange.height
+ property bool isValid: itemSelectionRange.valid
+ property bool isEmpty: itemSelectionRange.empty
+ property var isrModel: itemSelectionRange.model
+ property bool contains1: false
+ property bool contains2: false
+ property bool intersects: false
+ property var intersected
+
+ onModelChanged: {
+ if (model) {
+ var parentIndex = model.index(0, 0)
+ var index1 = model.index(3, 0, parentIndex)
+ var index2 = model.index(5, 6, parentIndex)
+ itemSelectionRange = createItemSelectionRange(index1, index2)
+
+ contains1 = itemSelectionRange.contains(index1)
+ contains2 = itemSelectionRange.contains(4, 3, parentIndex)
+ intersects = itemSelectionRange.intersects(createItemSelectionRange(parentIndex, parentIndex))
+ intersected = itemSelectionRange.intersected(createItemSelectionRange(parentIndex, parentIndex))
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmlitemmodels/data/modelindex.qml b/tests/auto/qml/qqmlitemmodels/data/modelindex.qml
new file mode 100644
index 0000000000..0d6e3624cb
--- /dev/null
+++ b/tests/auto/qml/qqmlitemmodels/data/modelindex.qml
@@ -0,0 +1,19 @@
+import Test 1.0
+
+ItemModelsTest {
+ property bool isValid: modelIndex.valid
+ property int row: modelIndex.row
+ property int column: modelIndex.column
+ property var parent: modelIndex.parent
+ property var model: modelIndex.model
+ property var internalId: modelIndex.internalId
+
+ onSignalWithModelIndex: {
+ isValid = index.valid
+ row = index.row
+ column = index.column
+ parent = index.parent
+ model = index.model
+ internalId = index.internalId
+ }
+}
diff --git a/tests/auto/qml/qqmlitemmodels/data/modelindexconversion.qml b/tests/auto/qml/qqmlitemmodels/data/modelindexconversion.qml
new file mode 100644
index 0000000000..91ee05eaa9
--- /dev/null
+++ b/tests/auto/qml/qqmlitemmodels/data/modelindexconversion.qml
@@ -0,0 +1,9 @@
+import Test 1.0
+
+ItemModelsTest {
+
+ onModelChanged: {
+ modelIndex = createPersistentModelIndex(model.index(0, 0))
+ persistentModelIndex = model.index(1, 1)
+ }
+}
diff --git a/tests/auto/qml/qqmlitemmodels/data/modelindexlist.qml b/tests/auto/qml/qqmlitemmodels/data/modelindexlist.qml
new file mode 100644
index 0000000000..44393392d3
--- /dev/null
+++ b/tests/auto/qml/qqmlitemmodels/data/modelindexlist.qml
@@ -0,0 +1,21 @@
+import Test 1.0
+
+ItemModelsTest {
+ property var modelIndexList
+ property int count
+
+ onModelChanged: {
+ modelIndexList = createModelIndexList()
+ modelIndexList.prepend(model.index(0, 0))
+ modelIndexList.append(model.index(1, 1))
+ for (var i = 0; i < 3; i++)
+ modelIndexList.insert(i, model.index(2 + i, 2 + i))
+
+ count = modelIndexList.length
+ modelIndex = modelIndexList.at(0)
+
+ modelIndexList.removeAt(3)
+ modelIndexList.removeFirst()
+ modelIndexList.removeLast()
+ }
+}
diff --git a/tests/auto/qml/qqmlitemmodels/data/persistentmodelindex.qml b/tests/auto/qml/qqmlitemmodels/data/persistentmodelindex.qml
new file mode 100644
index 0000000000..13037065a6
--- /dev/null
+++ b/tests/auto/qml/qqmlitemmodels/data/persistentmodelindex.qml
@@ -0,0 +1,23 @@
+import Test 1.0
+
+ItemModelsTest {
+ property bool isValid: persistentModelIndex.valid
+ property int row: persistentModelIndex.row
+ property int column: persistentModelIndex.column
+ property var parent: persistentModelIndex.parent
+ property var model: persistentModelIndex.model
+ property var internalId: persistentModelIndex.internalId
+
+ property var pmi
+
+ onSignalWithPersistentModelIndex: {
+ isValid = index.valid
+ row = index.row
+ column = index.column
+ parent = index.parent
+ model = index.model
+ internalId = index.internalId
+
+ pmi = createPersistentModelIndex(model.index(0, 0))
+ }
+}
diff --git a/tests/auto/qml/qqmlitemmodels/qqmlitemmodels.pro b/tests/auto/qml/qqmlitemmodels/qqmlitemmodels.pro
new file mode 100644
index 0000000000..f76c6d0d25
--- /dev/null
+++ b/tests/auto/qml/qqmlitemmodels/qqmlitemmodels.pro
@@ -0,0 +1,23 @@
+CONFIG += testcase
+TARGET = tst_qqmlitemmodels
+macx:CONFIG -= app_bundle
+
+HEADERS = qtestmodel.h testtypes.h
+SOURCES += tst_qqmlitemmodels.cpp
+
+include (../../shared/util.pri)
+
+TESTDATA = data/*
+
+CONFIG += parallel_test
+
+QT += core qml testlib
+DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
+
+DISTFILES += \
+ data/modelindex.qml \
+ data/persistentmodelindex.qml \
+ data/itemselectionrange.qml \
+ data/modelindexlist.qml \
+ data/itemselection.qml \
+ data/modelindexconversion.qml
diff --git a/tests/auto/qml/qqmlitemmodels/qtestmodel.h b/tests/auto/qml/qqmlitemmodels/qtestmodel.h
new file mode 100644
index 0000000000..bb0a169652
--- /dev/null
+++ b/tests/auto/qml/qqmlitemmodels/qtestmodel.h
@@ -0,0 +1,322 @@
+/****************************************************************************
+**
+** 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:LGPL21$
+** 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 The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q_TEST_MODEL_H
+#define Q_TEST_MODEL_H
+
+#include <QtCore/qabstractitemmodel.h>
+
+class TestModel: public QAbstractItemModel
+{
+ Q_OBJECT
+
+public:
+ TestModel(QObject *parent = 0): QAbstractItemModel(parent),
+ fetched(false), rows(10), cols(1), levels(INT_MAX), wrongIndex(false) { init(); }
+
+ TestModel(int _rows, int _cols, QObject *parent = 0): QAbstractItemModel(parent),
+ fetched(false), rows(_rows), cols(_cols), levels(INT_MAX), wrongIndex(false) { init(); }
+
+ void init() {
+ decorationsEnabled = false;
+ alternateChildlessRows = true;
+ tree = new Node(rows);
+ }
+
+ inline qint32 level(const QModelIndex &index) const {
+ Node *n = (Node *)index.internalPointer();
+ if (!n)
+ return -1;
+ int l = -1;
+ while (n != tree) {
+ n = n->parent;
+ ++l;
+ }
+ return l;
+ }
+
+ void resetModel()
+ {
+ beginResetModel();
+ fetched = false;
+ delete tree;
+ tree = new Node(rows);
+ endResetModel();
+ }
+
+ QString displayData(const QModelIndex &idx) const
+ {
+ return QString("[%1,%2,%3,%4]").arg(idx.row()).arg(idx.column()).arg(idx.internalId()).arg(hasChildren(idx));
+ }
+
+ bool canFetchMore(const QModelIndex &) const {
+ return !fetched;
+ }
+
+ void fetchMore(const QModelIndex &) {
+ fetched = true;
+ }
+
+ bool hasChildren(const QModelIndex &parent = QModelIndex()) const {
+ bool hasFetched = fetched;
+ fetched = true;
+ bool r = QAbstractItemModel::hasChildren(parent);
+ fetched = hasFetched;
+ return r;
+ }
+
+ int rowCount(const QModelIndex& parent = QModelIndex()) const {
+ if (!fetched)
+ qFatal("%s: rowCount should not be called before fetching", Q_FUNC_INFO);
+ if ((parent.column() > 0) || (level(parent) > levels)
+ || (alternateChildlessRows && parent.row() > 0 && (parent.row() & 1)))
+ return 0;
+ Node *n = (Node*)parent.internalPointer();
+ if (!n)
+ n = tree;
+ return n->children.count();
+ }
+
+ int columnCount(const QModelIndex& parent = QModelIndex()) const {
+ if ((parent.column() > 0) || (level(parent) > levels)
+ || (alternateChildlessRows && parent.row() > 0 && (parent.row() & 1)))
+ return 0;
+ return cols;
+ }
+
+ bool isEditable(const QModelIndex &index) const {
+ if (index.isValid())
+ return true;
+ return false;
+ }
+
+ Q_INVOKABLE QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const
+ {
+ if (row < 0 || column < 0 || (level(parent) > levels) || column >= cols)
+ return QModelIndex();
+ Node *pn = (Node*)parent.internalPointer();
+ if (!pn)
+ pn = tree;
+ if (row >= pn->children.count())
+ return QModelIndex();
+
+ Node *n = pn->children.at(row);
+ if (!n) {
+ n = new Node(rows, pn);
+ pn->children[row] = n;
+ }
+ return createIndex(row, column, n);
+ }
+
+ QModelIndex parent(const QModelIndex &index) const
+ {
+ Node *n = (Node *)index.internalPointer();
+ if (!n || n->parent == tree)
+ return QModelIndex();
+ Q_ASSERT(n->parent->parent);
+ int parentRow = n->parent->parent->children.indexOf(n->parent);
+ Q_ASSERT(parentRow != -1);
+ return createIndex(parentRow, 0, n->parent);
+ }
+
+ QVariant data(const QModelIndex &idx, int role) const
+ {
+ if (!idx.isValid())
+ return QVariant();
+
+ Node *pn = (Node *)idx.internalPointer();
+ if (!pn)
+ pn = tree;
+ if (pn != tree)
+ pn = pn->parent;
+ if (idx.row() < 0 || idx.column() < 0 || idx.column() >= cols
+ || idx.row() >= pn->children.count()) {
+ wrongIndex = true;
+ qWarning("Invalid modelIndex [%d,%d,%p]", idx.row(), idx.column(),
+ idx.internalPointer());
+ return QVariant();
+ }
+
+ if (role == Qt::DisplayRole) {
+ return displayData(idx);
+ }
+
+ return QVariant();
+ }
+
+ bool setData(const QModelIndex &index, const QVariant &value, int role)
+ {
+ Q_UNUSED(value);
+ QVector<int> changedRole(1, role);
+ emit dataChanged(index, index, changedRole);
+ return true;
+ }
+
+ void groupedSetData(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
+ {
+ emit dataChanged(topLeft, bottomRight, roles);
+ }
+
+ void changeLayout(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>())
+ {
+ emit layoutAboutToBeChanged(parents);
+ emit layoutChanged(parents);
+ }
+
+ bool removeRows(int row, int count, const QModelIndex &parent)
+ {
+ beginRemoveRows(parent, row, row + count - 1);
+ Node *n = (Node *)parent.internalPointer();
+ if (!n)
+ n = tree;
+ n->removeRows(row, count);
+ endRemoveRows();
+ return true;
+ }
+
+ void removeLastColumn()
+ {
+ beginRemoveColumns(QModelIndex(), cols - 1, cols - 1);
+ --cols;
+ endRemoveColumns();
+ }
+
+ void removeAllColumns()
+ {
+ beginRemoveColumns(QModelIndex(), 0, cols - 1);
+ cols = 0;
+ endRemoveColumns();
+ }
+
+ bool insertRows(int row, int count, const QModelIndex &parent)
+ {
+ beginInsertRows(parent, row, row + count - 1);
+ Node *n = (Node *)parent.internalPointer();
+ if (!n)
+ n = tree;
+ n->addRows(row, count);
+ endInsertRows();
+ return true;
+ }
+
+ bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild)
+ {
+ Q_ASSERT_X(sourceRow >= 0 && sourceRow < rowCount(sourceParent)
+ && count > 0 && sourceRow + count < rowCount(sourceParent)
+ && destinationChild >= 0 && destinationChild <= rowCount(destinationParent),
+ Q_FUNC_INFO, "Rows out of range.");
+ Q_ASSERT_X(!(sourceParent == destinationParent && destinationChild >= sourceRow && destinationChild < sourceRow + count),
+ Q_FUNC_INFO, "Moving rows onto themselves.");
+ if (!beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1, destinationParent, destinationChild))
+ return false;
+ Node *src = (Node *)sourceParent.internalPointer();
+ if (!src)
+ src = tree;
+ Node *dest = (Node *)destinationParent.internalPointer();
+ if (!dest)
+ dest = tree;
+ QVector<Node *> buffer = src->children.mid(sourceRow, count);
+ if (src != dest) {
+ src->removeRows(sourceRow, count, true /* keep alive */);
+ dest->addRows(destinationChild, count);
+ } else {
+ QVector<Node *> &c = dest->children;
+ if (sourceRow < destinationChild) {
+ memmove(&c[sourceRow], &c[sourceRow + count], sizeof(Node *) * (destinationChild - sourceRow - count));
+ destinationChild -= count;
+ } else {
+ memmove(&c[destinationChild + count], &c[destinationChild], sizeof(Node *) * (sourceRow - destinationChild));
+ }
+ }
+ for (int i = 0; i < count; i++) {
+ Node *n = buffer[i];
+ n->parent = dest;
+ dest->children[i + destinationChild] = n;
+ }
+
+ endMoveRows();
+ return true;
+ }
+
+ void setDecorationsEnabled(bool enable)
+ {
+ decorationsEnabled = enable;
+ }
+
+ mutable bool fetched;
+ bool decorationsEnabled;
+ bool alternateChildlessRows;
+ int rows, cols;
+ int levels;
+ mutable bool wrongIndex;
+
+ struct Node {
+ Node *parent;
+ QVector<Node *> children;
+
+ Node(int rows, Node *p = 0) : parent(p)
+ {
+ addRows(0, rows);
+ }
+
+ ~Node()
+ {
+ foreach (Node *n, children)
+ delete n;
+ }
+
+ void addRows(int row, int count)
+ {
+ if (count > 0) {
+ children.reserve(children.count() + count);
+ children.insert(row, count, (Node *)0);
+ }
+ }
+
+ void removeRows(int row, int count, bool keepAlive = false)
+ {
+ int newCount = qMax(children.count() - count, 0);
+ int effectiveCountDiff = children.count() - newCount;
+ if (effectiveCountDiff > 0) {
+ if (!keepAlive)
+ for (int i = 0; i < effectiveCountDiff; i++)
+ delete children[i + row];
+ children.remove(row, effectiveCountDiff);
+ }
+ }
+ };
+
+ Node *tree;
+};
+
+#endif // Q_TEST_MODEL_H
diff --git a/tests/auto/qml/qqmlitemmodels/testtypes.h b/tests/auto/qml/qqmlitemmodels/testtypes.h
new file mode 100644
index 0000000000..5345609cd3
--- /dev/null
+++ b/tests/auto/qml/qqmlitemmodels/testtypes.h
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** 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:LGPL21$
+** 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 The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTTYPES_H
+#define TESTTYPES_H
+
+#include <QtCore/qabstractitemmodel.h>
+#include <QtCore/qitemselectionmodel.h>
+#include "qdebug.h"
+
+class ItemModelsTest : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QAbstractItemModel *model READ model WRITE setModel NOTIFY modelChanged)
+ Q_PROPERTY(QModelIndex modelIndex READ modelIndex WRITE setModelIndex NOTIFY changed)
+ Q_PROPERTY(QPersistentModelIndex persistentModelIndex READ persistentModelIndex WRITE setPersistentModelIndex NOTIFY changed)
+
+public:
+ QModelIndex modelIndex() const
+ {
+ return m_modelIndex;
+ }
+
+ QPersistentModelIndex persistentModelIndex() const
+ {
+ return m_persistentModelIndex;
+ }
+
+ void emitChanged()
+ {
+ emit changed();
+ }
+
+ void emitSignalWithModelIndex(const QModelIndex &index)
+ {
+ emit signalWithModelIndex(index);
+ }
+
+ void emitSignalWithPersistentModelIndex(const QPersistentModelIndex &index)
+ {
+ emit signalWithPersistentModelIndex(index);
+ }
+
+ QAbstractItemModel * model() const
+ {
+ return m_model;
+ }
+
+ Q_INVOKABLE QModelIndex invalidModelIndex() const
+ {
+ return QModelIndex();
+ }
+
+ Q_INVOKABLE QModelIndexList createModelIndexList() const
+ {
+ return QModelIndexList();
+ }
+
+ Q_INVOKABLE QItemSelectionRange createItemSelectionRange(const QModelIndex &tl, const QModelIndex &br) const
+ {
+ return QItemSelectionRange(tl, br);
+ }
+
+ Q_INVOKABLE QItemSelection createItemSelection()
+ {
+ return QItemSelection();
+ }
+
+ Q_INVOKABLE QPersistentModelIndex createPersistentModelIndex(const QModelIndex &index)
+ {
+ return QPersistentModelIndex(index);
+ }
+
+public slots:
+ void setModelIndex(const QModelIndex &arg)
+ {
+ if (m_modelIndex == arg)
+ return;
+
+ m_modelIndex = arg;
+ emit changed();
+ }
+
+ void setPersistentModelIndex(const QPersistentModelIndex &arg)
+ {
+ if (m_persistentModelIndex == arg)
+ return;
+
+ m_persistentModelIndex = arg;
+ emit changed();
+ }
+
+ void setModel(QAbstractItemModel *arg)
+ {
+ if (m_model == arg)
+ return;
+
+ m_model = arg;
+ emit modelChanged(arg);
+ }
+
+signals:
+ void changed();
+
+ void signalWithModelIndex(QModelIndex index);
+ void signalWithPersistentModelIndex(QPersistentModelIndex index);
+
+ void modelChanged(QAbstractItemModel * arg);
+
+private:
+ QModelIndex m_modelIndex;
+ QPersistentModelIndex m_persistentModelIndex;
+ QAbstractItemModel *m_model;
+};
+
+#endif // TESTTYPES_H
+
diff --git a/tests/auto/qml/qqmlitemmodels/tst_qqmlitemmodels.cpp b/tests/auto/qml/qqmlitemmodels/tst_qqmlitemmodels.cpp
new file mode 100644
index 0000000000..d7e3931376
--- /dev/null
+++ b/tests/auto/qml/qqmlitemmodels/tst_qqmlitemmodels.cpp
@@ -0,0 +1,223 @@
+/****************************************************************************
+**
+** 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:LGPL21$
+** 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 The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qtest.h>
+#include <QQmlEngine>
+#include <QQmlComponent>
+#include <QDebug>
+#include <QStringListModel>
+#include "../../shared/util.h"
+#include "testtypes.h"
+#include "qtestmodel.h"
+
+#define INIT_TEST_OBJECT(fileName, object) \
+ QQmlComponent component_##object(&engine, testFileUrl(fileName)); \
+ QScopedPointer<ItemModelsTest>object(qobject_cast<ItemModelsTest *>(component_##object.create())); \
+
+
+class tst_qqmlitemmodels : public QQmlDataTest
+{
+ Q_OBJECT
+
+public:
+ tst_qqmlitemmodels() {}
+
+private slots:
+ void initTestCase();
+
+ void modelIndex();
+ void persistentModelIndex();
+ void modelIndexConversion();
+ void itemSelectionRange();
+ void itemSelection();
+ void modelIndexList();
+
+private:
+ QQmlEngine engine;
+};
+
+void tst_qqmlitemmodels::initTestCase()
+{
+ QQmlDataTest::initTestCase();
+ qmlRegisterType<ItemModelsTest>("Test", 1, 0, "ItemModelsTest");
+}
+
+void tst_qqmlitemmodels::modelIndex()
+{
+ INIT_TEST_OBJECT("modelindex.qml", object);
+ TestModel model(10, 10);
+
+ QModelIndex index = object->modelIndex();
+ for (int i = 0; i < 5; i++) {
+ QCOMPARE(object->property("isValid").toBool(), index.isValid());
+ QCOMPARE(object->property("row").toInt(), index.row());
+ QCOMPARE(object->property("column").toInt(), index.column());
+ QCOMPARE(object->property("parent").toModelIndex(), index.parent());
+ QCOMPARE(object->property("model").value<QAbstractItemModel *>(), index.model());
+ QCOMPARE(object->property("internalId").toULongLong(), index.internalId());
+
+ if (i < 3) {
+ index = model.index(2 + i, 4 - i, index);
+ object->setModelIndex(index);
+ } else if (i < 4) {
+ index = model.index(2 + i, 4 - i);
+ object->emitSignalWithModelIndex(index);
+ }
+ }
+}
+
+void tst_qqmlitemmodels::persistentModelIndex()
+{
+ INIT_TEST_OBJECT("persistentmodelindex.qml", object);
+ TestModel model(10, 10);
+
+ QPersistentModelIndex index = object->persistentModelIndex();
+ for (int i = 0; i < 5; i++) {
+ QCOMPARE(object->property("isValid").toBool(), index.isValid());
+ QCOMPARE(object->property("row").toInt(), index.row());
+ QCOMPARE(object->property("column").toInt(), index.column());
+ QCOMPARE(object->property("parent").toModelIndex(), index.parent());
+ QCOMPARE(object->property("model").value<QAbstractItemModel *>(), index.model());
+ QCOMPARE(object->property("internalId").toULongLong(), index.internalId());
+
+ if (i < 2) {
+ index = model.index(2 + i, 4 - i, index);
+ object->setPersistentModelIndex(index);
+ } else if (i < 3) {
+ model.removeRow(2);
+ QVERIFY(!index.isValid()); // QPersistentModelIndex should update
+ object->emitChanged(); // Help QML get the new values as QPMI doesn't emit anything
+ } else if (i < 4) {
+ index = model.index(2 + i, 4 - i);
+ object->emitSignalWithPersistentModelIndex(index);
+ }
+ }
+
+ const QVariant &pmiVariant = object->property("pmi");
+ QCOMPARE(pmiVariant.type(), QVariant::UserType);
+ QCOMPARE(pmiVariant.userType(), qMetaTypeId<QPersistentModelIndex>());
+ QCOMPARE(pmiVariant.value<QPersistentModelIndex>(), QPersistentModelIndex(model.index(0, 0)));
+}
+
+void tst_qqmlitemmodels::itemSelectionRange()
+{
+ INIT_TEST_OBJECT("itemselectionrange.qml", object);
+ TestModel model(10, 10);
+
+ for (int i = 0; i < 2; i++) {
+ const QVariant &isrVariant = object->property("itemSelectionRange");
+ QCOMPARE(isrVariant.type(), QVariant::UserType);
+ QCOMPARE(isrVariant.userType(), qMetaTypeId<QItemSelectionRange>());
+ const QItemSelectionRange &isr = isrVariant.value<QItemSelectionRange>();
+ if (i > 0) {
+ QModelIndex parentIndex = model.index(0, 0);
+ QCOMPARE(QModelIndex(isr.topLeft()), model.index(3, 0, parentIndex));
+ QCOMPARE(QModelIndex(isr.bottomRight()), model.index(5, 6, parentIndex));
+ } else {
+ QCOMPARE(QModelIndex(isr.topLeft()), QModelIndex());
+ QCOMPARE(QModelIndex(isr.bottomRight()), QModelIndex());
+ }
+
+ QCOMPARE(object->property("top").toInt(), isr.top());
+ QCOMPARE(object->property("left").toInt(), isr.left());
+ QCOMPARE(object->property("bottom").toInt(), isr.bottom());
+ QCOMPARE(object->property("right").toInt(), isr.right());
+ QCOMPARE(object->property("width").toInt(), isr.width());
+ QCOMPARE(object->property("height").toInt(), isr.height());
+ QCOMPARE(object->property("isValid").toBool(), isr.isValid());
+ QCOMPARE(object->property("isEmpty").toBool(), isr.isEmpty());
+ QCOMPARE(object->property("isrModel").value<QAbstractItemModel *>(), isr.model());
+
+ // Set model for the 2nd iteration and test again
+ object->setModel(&model);
+ }
+
+ // Check API function calls
+ QVERIFY(object->property("contains1").toBool());
+ QVERIFY(object->property("contains2").toBool());
+ QVERIFY(!object->property("intersects").toBool());
+ const QVariant &isrVariant = object->property("intersected");
+ QCOMPARE(isrVariant.type(), QVariant::UserType);
+ QCOMPARE(isrVariant.userType(), qMetaTypeId<QItemSelectionRange>());
+}
+
+void tst_qqmlitemmodels::modelIndexConversion()
+{
+ INIT_TEST_OBJECT("modelindexconversion.qml", object);
+ TestModel model(10, 10);
+ object->setModel(&model);
+
+ QCOMPARE(object->modelIndex(), model.index(0, 0));
+ QCOMPARE(object->persistentModelIndex(), QPersistentModelIndex(model.index(1, 1)));
+}
+
+void tst_qqmlitemmodels::itemSelection()
+{
+ INIT_TEST_OBJECT("itemselection.qml", object);
+ TestModel model(10, 10);
+
+ object->setModel(&model);
+ QCOMPARE(object->property("count").toInt(), 8);
+ QCOMPARE(object->property("contains").toBool(), true);
+
+ QVariant milVariant = object->property("itemSelection");
+ QCOMPARE(milVariant.type(), QVariant::UserType);
+ QCOMPARE(milVariant.userType(), qMetaTypeId<QItemSelection>());
+
+ const QItemSelection &mil = milVariant.value<QItemSelection>();
+ QCOMPARE(mil.count(), 5);
+}
+
+void tst_qqmlitemmodels::modelIndexList()
+{
+ INIT_TEST_OBJECT("modelindexlist.qml", object);
+ TestModel model(10, 10);
+
+ object->setModel(&model);
+ QCOMPARE(object->property("count").toInt(), 5);
+
+ QVariant milVariant = object->property("modelIndexList");
+ QCOMPARE(milVariant.type(), QVariant::UserType);
+ QCOMPARE(milVariant.userType(), qMetaTypeId<QModelIndexList>());
+
+ const QModelIndexList &mil = milVariant.value<QModelIndexList>();
+ QCOMPARE(mil.count(), 2);
+ QCOMPARE(mil.at(0), model.index(3, 3));
+ QCOMPARE(mil.at(1), model.index(4, 4));
+}
+
+#undef INIT_TEST_OBJECT
+
+QTEST_MAIN(tst_qqmlitemmodels)
+
+#include "tst_qqmlitemmodels.moc"