Remove QModelIndexList value type, use Array instead

We implement this by adding QModelIndexList to the
set of sequence types.

Change-Id: If7e0e88ab0c2916c2b65a926f8241549520d7391
Reviewed-by: Stephen Kelly <steveire@gmail.com>
This commit is contained in:
Gabriel de Dietrich 2015-03-03 18:36:51 +01:00
parent 226419514e
commit ae1c3eba3e
7 changed files with 126 additions and 46 deletions

View File

@ -41,6 +41,9 @@
#include <private/qv4scopedvalue_p.h>
#include "qv4runtime_p.h"
#include "qv4objectiterator_p.h"
#include <private/qqmlvaluetypewrapper_p.h>
#include <private/qqmlmodelindexvaluetype_p.h>
#include <QtCore/qabstractitemmodel.h>
#include <algorithm>
@ -71,7 +74,8 @@ static void generateWarning(QV4::ExecutionEngine *v4, const QString& description
F(bool, Bool, QList<bool>, false) \
F(QString, String, QList<QString>, QString()) \
F(QString, QString, QStringList, QString()) \
F(QUrl, Url, QList<QUrl>, QUrl())
F(QUrl, Url, QList<QUrl>, QUrl()) \
F(QModelIndex, QModelIndex, QModelIndexList, QModelIndex())
static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *engine, const QString &element)
{
@ -88,6 +92,12 @@ static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *engine, co
return engine->newString(element.toString())->asReturnedValue();
}
static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *engine, const QModelIndex &element)
{
const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(QMetaType::QModelIndex);
return QV4::QQmlValueTypeWrapper::create(engine, QVariant(element), vtmo, QMetaType::QModelIndex);
}
static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *, qreal element)
{
return QV4::Encode(element);
@ -113,6 +123,11 @@ static QString convertElementToString(const QUrl &element)
return element.toString();
}
static QString convertElementToString(const QModelIndex &element)
{
return reinterpret_cast<const QQmlModelIndexValueType *>(&element)->toString();
}
static QString convertElementToString(qreal element)
{
QString qstr;
@ -145,6 +160,14 @@ template <> QUrl convertValueToElement(const Value &value)
return QUrl(value.toQString());
}
template <> QModelIndex convertValueToElement(const Value &value)
{
const QQmlValueTypeWrapper *v = value_cast<QQmlValueTypeWrapper>(value);
if (v)
return v->toVariant().toModelIndex();
return QModelIndex();
}
template <> qreal convertValueToElement(const Value &value)
{
return value.toNumber();
@ -541,6 +564,9 @@ DEFINE_OBJECT_VTABLE(QQmlIntList);
typedef QQmlSequence<QList<QUrl> > QQmlUrlList;
template<>
DEFINE_OBJECT_VTABLE(QQmlUrlList);
typedef QQmlSequence<QModelIndexList> QQmlQModelIndexList;
template<>
DEFINE_OBJECT_VTABLE(QQmlQModelIndexList);
typedef QQmlSequence<QList<bool> > QQmlBoolList;
template<>
DEFINE_OBJECT_VTABLE(QQmlBoolList);

View File

@ -64,7 +64,6 @@ QQmlValueTypeFactoryImpl::QQmlValueTypeFactoryImpl()
valueTypes[ii] = 0;
// See types wrapped in qqmlmodelindexvaluetype_p.h
qRegisterMetaType<QModelIndexList>();
qRegisterMetaType<QItemSelectionRange>();
qRegisterMetaType<QItemSelection>();
}
@ -112,18 +111,16 @@ const QMetaObject *QQmlValueTypeFactoryImpl::metaObjectForMetaType(int t)
case QVariant::PersistentModelIndex:
return &QQmlPersistentModelIndexValueType::staticMetaObject;
default:
if (t == qMetaTypeId<QItemSelectionRange>())
return &QQmlItemSelectionRangeValueType::staticMetaObject;
if (t == qMetaTypeId<QItemSelection>())
return &QQmlItemSelectionValueType::staticMetaObject;
if (const QMetaObject *mo = QQml_valueTypeProvider()->metaObjectForMetaType(t))
return mo;
break;
}
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();

View File

@ -60,6 +60,17 @@
should not store any QModelIndex. You can, however, store QPersistentModelIndexes
in a safe way.
\section1 QModelIndexList
\l QModelIndexList is exposed in QML as a JavaScript array. Conversions are
automatically made from and to C++. In fact, any JavaScript array can be
converted back to QModelIndexList, with non-QModelIndex objects replaced by
invalid QModelIndexes.
\note QModelIndex to QPersistentModelIndex conversion happens when accessing
the array elements because any QModelIndexList property retains reference
semantics when exposed this way.
\section1 \l QItemSelectionRange
\list
@ -87,10 +98,10 @@
\li QItemSelectionRange \b{intersected}(QItemSelectionRange other)
\endlist
\section1 \l QModelIndexList and \l QItemSelection
\section1 QItemSelection
Both \l QModelIndexList and \l QItemSelection expose the following properties
and functions as part of their \l QList API:
\l QItemSelection exposes the following properties and functions as part of
its \l QList API:
\list
\li \b length : int

View File

@ -175,19 +175,6 @@ QString q_listToString(const QList<T> &list, const QLatin1String &typeName)
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;

View File

@ -1,21 +1,30 @@
import Test 1.0
ItemModelsTest {
property var modelIndexList
property int count
property var modelIndexListCopy
property var modelIndexListRead
property var modelIndexListBinding: modelIndexList
property bool varPropIsArray
property bool varIsArray
property bool propIsArray
onModelChanged: {
modelIndexList = createModelIndexList()
modelIndexList.prepend(model.index(0, 0))
modelIndexList.append(model.index(1, 1))
var jsModelIndexList = []
for (var i = 0; i < 3; i++)
modelIndexList.insert(i, model.index(2 + i, 2 + i))
jsModelIndexList.push(model.index(2 + i, 2 + i))
jsModelIndexList.push("Hi Bronsky!")
modelIndex = jsModelIndexList[0]
count = modelIndexList.length
modelIndex = modelIndexList.at(0)
propIsArray = modelIndexList instanceof Array
modelIndexList = jsModelIndexList
modelIndexListRead = modelIndexList
modelIndexList.removeAt(3)
modelIndexList.removeFirst()
modelIndexList.removeLast()
modelIndexListCopy = someModelIndexList()
varPropIsArray = modelIndexListCopy instanceof Array
jsModelIndexList = someModelIndexList()
varIsArray = jsModelIndexList instanceof Array
}
}

View File

@ -45,8 +45,15 @@ class ItemModelsTest : public QObject
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)
Q_PROPERTY(QModelIndexList modelIndexList READ modelIndexList WRITE setModelIndexList NOTIFY changed)
public:
ItemModelsTest(QObject *parent = 0)
: QObject(parent)
, m_model(0)
{
}
QModelIndex modelIndex() const
{
return m_modelIndex;
@ -57,6 +64,26 @@ public:
return m_persistentModelIndex;
}
QModelIndexList modelIndexList()
{
static bool firstTime = true;
if (firstTime && m_model && m_modelIndexList.isEmpty()) {
firstTime = false;
for (int i = 0; i < m_model->rowCount(); i++)
m_modelIndexList << m_model->index(i, 0);
}
return m_modelIndexList;
}
Q_INVOKABLE QModelIndexList someModelIndexList() const
{
QModelIndexList list;
if (m_model)
for (int i = 0; i < m_model->rowCount(); i++)
list << m_model->index(i, 0);
return list;
}
void emitChanged()
{
emit changed();
@ -82,11 +109,6 @@ public:
return QModelIndex();
}
Q_INVOKABLE QModelIndexList createModelIndexList() const
{
return QModelIndexList();
}
Q_INVOKABLE QItemSelectionRange createItemSelectionRange(const QModelIndex &tl, const QModelIndex &br) const
{
return QItemSelectionRange(tl, br);
@ -130,6 +152,15 @@ public slots:
emit modelChanged(arg);
}
void setModelIndexList(QModelIndexList arg)
{
if (m_modelIndexList == arg)
return;
m_modelIndexList = arg;
emit changed();
}
signals:
void changed();
@ -142,6 +173,7 @@ private:
QModelIndex m_modelIndex;
QPersistentModelIndex m_persistentModelIndex;
QAbstractItemModel *m_model;
QModelIndexList m_modelIndexList;
};
#endif // TESTTYPES_H

View File

@ -198,17 +198,35 @@ void tst_qqmlitemmodels::modelIndexList()
{
INIT_TEST_OBJECT("modelindexlist.qml", object);
TestModel model(10, 10);
model.fetchMore(QModelIndex());
object->setModel(&model);
QCOMPARE(object->property("count").toInt(), 5);
QVERIFY(object->property("propIsArray").toBool());
QVERIFY(object->property("varPropIsArray").toBool());
QVERIFY(object->property("varIsArray").toBool());
QVariant milVariant = object->property("modelIndexList");
QCOMPARE(milVariant.userType(), qMetaTypeId<QModelIndexList>());
QCOMPARE(object->property("count").toInt(), 10);
const QModelIndexList &mil = object->modelIndexList();
QCOMPARE(mil.count(), 4);
for (int i = 0; i < 3; i++)
QCOMPARE(mil.at(i), model.index(2 + i, 2 + i));
QCOMPARE(mil.at(3), QModelIndex()); // The string inserted at the end should result in an invalid index
QCOMPARE(mil.at(0), object->modelIndex());
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));
QVariant cppMILVariant = object->property("modelIndexListCopy");
QCOMPARE(cppMILVariant.userType(), qMetaTypeId<QModelIndexList>());
QModelIndexList someMIL = object->someModelIndexList();
QCOMPARE(cppMILVariant.value<QModelIndexList>(), someMIL);
const char *propNames[] = { "modelIndexListRead", "modelIndexListBinding", 0 };
for (const char **name = propNames; *name; name++) {
QVariant milVariant = object->property(*name);
QCOMPARE(milVariant.userType(), qMetaTypeId<QModelIndexList>());
const QModelIndexList &milProp = milVariant.value<QModelIndexList>();
QCOMPARE(milProp.count(), mil.count());
QCOMPARE(milProp, mil);
}
}
#undef INIT_TEST_OBJECT