Remove QItemSelection value-type, use Array instead
authorGabriel de Dietrich <gabriel.dedietrich@theqtcompany.com>
Fri, 6 Mar 2015 18:27:22 +0000 (19:27 +0100)
committerGabriel de Dietrich <gabriel.dedietrich@theqtcompany.com>
Sun, 22 Mar 2015 16:20:29 +0000 (16:20 +0000)
We implement this by adding QItemSelection to the
set of sequence types.

Change-Id: Ia3db376c806d8f062639e22c7f4bf392f114c266
Reviewed-by: Stephen Kelly <steveire@gmail.com>
src/qml/jsruntime/qv4sequenceobject.cpp
src/qml/qml/qqmlvaluetype.cpp
src/qml/types/qqmlitemmodels.qdoc
src/qml/types/qqmlmodelindexvaluetype_p.h
tests/auto/qml/qqmlitemmodels/data/itemselection.qml
tests/auto/qml/qqmlitemmodels/testtypes.h
tests/auto/qml/qqmlitemmodels/tst_qqmlitemmodels.cpp

index f7adf6e..f1f546b 100644 (file)
@@ -75,7 +75,8 @@ static void generateWarning(QV4::ExecutionEngine *v4, const QString& description
     F(QString, String, QList<QString>, QString()) \
     F(QString, QString, QStringList, QString()) \
     F(QUrl, Url, QList<QUrl>, QUrl()) \
-    F(QModelIndex, QModelIndex, QModelIndexList, QModelIndex())
+    F(QModelIndex, QModelIndex, QModelIndexList, QModelIndex()) \
+    F(QItemSelectionRange, QItemSelectionRange, QItemSelection, QItemSelectionRange())
 
 static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *engine, const QString &element)
 {
@@ -98,6 +99,13 @@ static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *engine, co
     return QV4::QQmlValueTypeWrapper::create(engine, QVariant(element), vtmo, QMetaType::QModelIndex);
 }
 
+static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *engine, const QItemSelectionRange &element)
+{
+    int metaTypeId = qMetaTypeId<QItemSelectionRange>();
+    const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(metaTypeId);
+    return QV4::QQmlValueTypeWrapper::create(engine, QVariant::fromValue(element), vtmo, metaTypeId);
+}
+
 static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *, qreal element)
 {
     return QV4::Encode(element);
@@ -128,6 +136,11 @@ static QString convertElementToString(const QModelIndex &element)
     return reinterpret_cast<const QQmlModelIndexValueType *>(&element)->toString();
 }
 
+static QString convertElementToString(const QItemSelectionRange &element)
+{
+    return reinterpret_cast<const QQmlItemSelectionRangeValueType *>(&element)->toString();
+}
+
 static QString convertElementToString(qreal element)
 {
     QString qstr;
@@ -168,6 +181,14 @@ template <> QModelIndex convertValueToElement(const Value &value)
     return QModelIndex();
 }
 
+template <> QItemSelectionRange convertValueToElement(const Value &value)
+{
+    const QQmlValueTypeWrapper *v = value_cast<QQmlValueTypeWrapper>(value);
+    if (v)
+        return v->toVariant().value<QItemSelectionRange>();
+    return QItemSelectionRange();
+}
+
 template <> qreal convertValueToElement(const Value &value)
 {
     return value.toNumber();
@@ -567,6 +588,9 @@ DEFINE_OBJECT_VTABLE(QQmlUrlList);
 typedef QQmlSequence<QModelIndexList> QQmlQModelIndexList;
 template<>
 DEFINE_OBJECT_VTABLE(QQmlQModelIndexList);
+typedef QQmlSequence<QItemSelection> QQmlQItemSelectionRangeList;
+template<>
+DEFINE_OBJECT_VTABLE(QQmlQItemSelectionRangeList);
 typedef QQmlSequence<QList<bool> > QQmlBoolList;
 template<>
 DEFINE_OBJECT_VTABLE(QQmlBoolList);
index 6711ad2..490ac66 100644 (file)
@@ -65,7 +65,6 @@ QQmlValueTypeFactoryImpl::QQmlValueTypeFactoryImpl()
 
     // See types wrapped in qqmlmodelindexvaluetype_p.h
     qRegisterMetaType<QItemSelectionRange>();
-    qRegisterMetaType<QItemSelection>();
 }
 
 QQmlValueTypeFactoryImpl::~QQmlValueTypeFactoryImpl()
@@ -113,8 +112,6 @@ const QMetaObject *QQmlValueTypeFactoryImpl::metaObjectForMetaType(int t)
     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;
index 70059b0..4e64aaa 100644 (file)
 
     \section1 QItemSelection
 
-    \l QItemSelection exposes the following properties and functions as part of
-    its \l QList API:
+    Similarly to QModelIndexList, \l QItemSelection is exposed in QML as a JavaScript
+    array of QItemSelectionRanges. Conversions are automatically made from and to C++.
+    In fact, any JavaScript array can be converted back to QItemSelection, with
+    non-QItemSelectionRange objects replaced by empty QItemSelectionRanges.
 
-    \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
 */
index e36f7a0..371335c 100644 (file)
@@ -150,50 +150,6 @@ public:
     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 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
index 57cb643..c2da716 100644 (file)
@@ -1,9 +1,10 @@
 import Test 1.0
 
 ItemModelsTest {
-    property var itemSelection
     property int count
     property bool contains: false
+    property var itemSelectionBinding: itemSelection
+    property var itemSelectionRead
 
     function range(top, bottom, left, right, parent) {
         if (parent === undefined)
@@ -14,23 +15,15 @@ ItemModelsTest {
     }
 
     onModelChanged: {
-        itemSelection = createItemSelection()
-        itemSelection.prepend(range(0, 0, 0, 5))
-        itemSelection.append(range(0, 5, 0, 0))
+        itemSelection = []
+        itemSelection.push(range(0, 0, 0, 5))
+        itemSelection.push(range(0, 5, 0, 0))
         for (var i = 0; i < 3; i++)
-            itemSelection.insert(i, range(i, i + 1, i + 2, i + 3))
+            itemSelection.splice(i, 0, 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*/)
+        itemSelectionRead = itemSelection
 
         count = itemSelection.length
-        contains = itemSelection.contains(model.index(0, 0))
-
-        itemSelection.removeAt(3)
-        itemSelection.removeFirst()
-        itemSelection.removeLast()
+        contains = itemSelection.some(function (range, idx) { return range.contains(model.index(0, 0)) })
     }
 }
index d61064f..69da24e 100644 (file)
@@ -46,6 +46,7 @@ class ItemModelsTest : public QObject
     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)
+    Q_PROPERTY(QItemSelection itemSelection READ itemSelection WRITE setItemSelection NOTIFY changed)
 
 public:
     ItemModelsTest(QObject *parent = 0)
@@ -84,6 +85,11 @@ public:
         return list;
     }
 
+    QItemSelection itemSelection() const
+    {
+        return m_itemSelection;
+    }
+
     void emitChanged()
     {
         emit changed();
@@ -161,6 +167,15 @@ public slots:
         emit changed();
     }
 
+    void setItemSelection(QItemSelection arg)
+    {
+        if (m_itemSelection == arg)
+            return;
+
+        m_itemSelection = arg;
+        emit changed();
+    }
+
 signals:
     void changed();
 
@@ -174,6 +189,7 @@ private:
     QPersistentModelIndex m_persistentModelIndex;
     QAbstractItemModel *m_model;
     QModelIndexList m_modelIndexList;
+    QItemSelection m_itemSelection;
 };
 
 #endif // TESTTYPES_H
index cd00593..637b9e4 100644 (file)
@@ -184,14 +184,18 @@ void tst_qqmlitemmodels::itemSelection()
     TestModel model(10, 10);
 
     object->setModel(&model);
-    QCOMPARE(object->property("count").toInt(), 8);
+    QCOMPARE(object->property("count").toInt(), 5);
     QCOMPARE(object->property("contains").toBool(), true);
 
-    QVariant milVariant = object->property("itemSelection");
-    QCOMPARE(milVariant.userType(), qMetaTypeId<QItemSelection>());
+    const char *propNames[] = { "itemSelectionRead", "itemSelectionBinding", 0 };
+    for (const char **name = propNames; *name; name++) {
+        QVariant isVariant = object->property(*name);
+        QCOMPARE(isVariant.userType(), qMetaTypeId<QItemSelection>());
 
-    const QItemSelection &mil = milVariant.value<QItemSelection>();
-    QCOMPARE(mil.count(), 5);
+        const QItemSelection &sel = isVariant.value<QItemSelection>();
+        QCOMPARE(sel.count(), object->itemSelection().count());
+        QCOMPARE(sel, object->itemSelection());
+    }
 }
 
 void tst_qqmlitemmodels::modelIndexList()