Implement ListModel in V8
authorAaron Kennedy <aaron.kennedy@nokia.com>
Tue, 7 Jun 2011 06:54:09 +0000 (16:54 +1000)
committerAaron Kennedy <aaron.kennedy@nokia.com>
Tue, 7 Jun 2011 07:00:11 +0000 (17:00 +1000)
14 files changed:
src/declarative/qml/qdeclarativeengine_p.h
src/declarative/qml/qdeclarativepropertycache.cpp
src/declarative/qml/v8/qv8engine.cpp
src/declarative/qml/v8/qv8engine_p.h
src/declarative/qml/v8/qv8qobjectwrapper.cpp
src/declarative/qml/v8/qv8variantwrapper.cpp
src/declarative/qml/v8/qv8worker.cpp
src/declarative/util/qdeclarativelistmodel.cpp
src/declarative/util/qdeclarativelistmodel_p.h
src/declarative/util/qdeclarativelistmodel_p_p.h
src/declarative/util/qdeclarativelistmodelworkeragent.cpp
src/declarative/util/qdeclarativelistmodelworkeragent_p.h
tests/auto/declarative/qdeclarativelistmodel/data/model.qml
tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp

index a12269f..4aa54be 100644 (file)
@@ -278,6 +278,7 @@ public:
     static void warning(QDeclarativeEnginePrivate *, const QDeclarativeError &);
     static void warning(QDeclarativeEnginePrivate *, const QList<QDeclarativeError> &);
 
+    static QV8Engine *getV8Engine(QDeclarativeEngine *e) { return &e->d_func()->v8engine; }
     static QScriptEngine *getScriptEngine(QDeclarativeEngine *e) { return &e->d_func()->scriptEngine; }
     static QDeclarativeEngine *getEngine(QScriptEngine *e) { return static_cast<QDeclarativeScriptEngine*>(e)->p->q_func(); }
     static QDeclarativeEnginePrivate *get(QDeclarativeEngine *e) { return e->d_func(); }
index e48a849..b2aad7b 100644 (file)
@@ -168,8 +168,8 @@ void QDeclarativePropertyCache::clear()
     indexCache.clear();
     methodIndexCache.clear();
     stringCache.clear();
-    constructor.Dispose();
-    constructor = v8::Persistent<v8::Function>();
+    constructor.Dispose(); 
+    constructor.Clear();
 }
 
 QDeclarativePropertyCache::Data QDeclarativePropertyCache::create(const QMetaObject *metaObject, 
@@ -252,7 +252,7 @@ void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaOb
     Q_UNUSED(revision);
 
     constructor.Dispose(); // Now invalid
-    constructor = v8::Persistent<v8::Function>();
+    constructor.Clear();
 
     allowedRevisionCache.append(0);
 
@@ -416,16 +416,18 @@ QDeclarativePropertyCache::Data *
 QDeclarativePropertyCache::property(QDeclarativeEngine *engine, QObject *obj, 
                                     v8::Handle<v8::String> name, Data &local)
 {
-    Q_ASSERT(engine);
-    QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
-
+    // XXX Optimize for worker script case where engine isn't available
     QDeclarativePropertyCache *cache = 0;
-    QDeclarativeData *ddata = QDeclarativeData::get(obj);
-    if (ddata && ddata->propertyCache && ddata->propertyCache->qmlEngine() == engine) // XXX aakenend
-        cache = ddata->propertyCache;
-    if (!cache) {
-        cache = ep->cache(obj);
-        if (cache && ddata && !ddata->propertyCache) { cache->addref(); ddata->propertyCache = cache; }
+    if (engine) {
+        QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+
+        QDeclarativeData *ddata = QDeclarativeData::get(obj);
+        if (ddata && ddata->propertyCache && ddata->propertyCache->qmlEngine() == engine) // XXX aakenend
+            cache = ddata->propertyCache;
+        if (!cache) {
+            cache = ep->cache(obj);
+            if (cache && ddata && !ddata->propertyCache) { cache->addref(); ddata->propertyCache = cache; }
+        }
     }
 
     QDeclarativePropertyCache::Data *rv = 0;
@@ -433,7 +435,8 @@ QDeclarativePropertyCache::property(QDeclarativeEngine *engine, QObject *obj,
     if (cache) {
         rv = cache->property(name);
     } else {
-        QString strname = ep->v8engine.toString(name);
+        QString strname = QV8Engine::toStringStatic(name);
+        // QString strname = ep->v8engine.toString(name);
         local = QDeclarativePropertyCache::create(obj->metaObject(), strname);
         if (local.isValid())
             rv = &local;
index ced07e1..87bb1fc 100644 (file)
@@ -67,7 +67,7 @@
 QT_BEGIN_NAMESPACE
 
 QV8Engine::QV8Engine()
-: m_xmlHttpRequestData(0), m_sqlDatabaseData(0)
+: m_xmlHttpRequestData(0), m_sqlDatabaseData(0), m_listModelData(0)
 {
 }
 
@@ -77,6 +77,8 @@ QV8Engine::~QV8Engine()
     m_sqlDatabaseData = 0;
     qt_rem_qmlxmlhttprequest(this, m_xmlHttpRequestData); 
     m_xmlHttpRequestData = 0;
+    delete m_listModelData;
+    m_listModelData = 0;
 
     m_getOwnPropertyNames.Dispose(); m_getOwnPropertyNames.Clear();
     
@@ -88,6 +90,7 @@ QV8Engine::~QV8Engine()
     m_contextWrapper.destroy();
     m_stringWrapper.destroy();
     m_context.Dispose();
+    m_context.Clear();
 }
 
 void QV8Engine::init(QDeclarativeEngine *engine)
@@ -146,6 +149,7 @@ QVariant QV8Engine::toVariant(v8::Handle<v8::Value> value, int typeHint)
             case QV8ObjectResource::XMLHttpRequestType:
             case QV8ObjectResource::DOMNodeType:
             case QV8ObjectResource::SQLDatabaseType:
+            case QV8ObjectResource::ListModelType:
                 return QVariant();
             case QV8ObjectResource::QObjectType:
                 return qVariantFromValue<QObject *>(m_qobjectWrapper.toQObject(r));
index d4b8730..5aec866 100644 (file)
@@ -90,7 +90,8 @@ class QV8ObjectResource : public v8::Object::ExternalResource
 public:
     QV8ObjectResource(QV8Engine *engine) : engine(engine) { Q_ASSERT(engine); }
     enum ResourceType { ContextType, QObjectType, TypeType, ListType, VariantType, 
-                        ValueTypeType, XMLHttpRequestType, DOMNodeType, SQLDatabaseType };
+                        ValueTypeType, XMLHttpRequestType, DOMNodeType, SQLDatabaseType,
+                        ListModelType };
     virtual ResourceType resourceType() const = 0;
 
     QV8Engine *engine;
@@ -170,6 +171,10 @@ public:
     QV8Engine();
     ~QV8Engine();
 
+    struct Deletable {
+        ~Deletable() {}
+    };
+
     void init(QDeclarativeEngine *);
 
     QDeclarativeEngine *engine() { return m_engine; }
@@ -184,6 +189,9 @@ public:
     void *xmlHttpRequestData() { return m_xmlHttpRequestData; }
     void *sqlDatabaseData() { return m_sqlDatabaseData; }
 
+    Deletable *listModelData() { return m_listModelData; }
+    void setListModelData(Deletable *d) { if (m_listModelData) delete m_listModelData; m_listModelData = d; }
+
     QDeclarativeContextData *callingContext();
 
     v8::Local<v8::Array> getOwnPropertyNames(v8::Handle<v8::Object>);
@@ -246,6 +254,7 @@ private:
 
     void *m_xmlHttpRequestData;
     void *m_sqlDatabaseData;
+    Deletable *m_listModelData;
 
     QSet<QString> m_illegalNames;
 
index 2647197..9ac482e 100644 (file)
@@ -70,6 +70,9 @@ Q_DECLARE_METATYPE(QDeclarativeV8Handle);
 #define QOBJECT_TOSTRING_INDEX -2
 #define QOBJECT_DESTROY_INDEX -3
 
+// XXX Need to check all calls to QDeclarativeEngine *engine() to confirm this class works
+// correctly in a worker thread
+
 class QV8QObjectResource : public QV8ObjectResource
 {
     V8_RESOURCE_TYPE(QObjectType);
@@ -153,11 +156,11 @@ void QV8QObjectWrapper::destroy()
     qDeleteAll(m_connections);
     m_connections.clear();
 
-    m_hiddenObject.Dispose();
-    m_destroySymbol.Dispose();
-    m_toStringSymbol.Dispose();
-    m_methodConstructor.Dispose();
-    m_constructor.Dispose();
+    m_hiddenObject.Dispose(); m_hiddenObject.Clear();
+    m_destroySymbol.Dispose(); m_destroySymbol.Clear();
+    m_toStringSymbol.Dispose(); m_toStringSymbol.Clear();
+    m_methodConstructor.Dispose(); m_methodConstructor.Clear();
+    m_constructor.Dispose(); m_constructor.Clear();
 }
 
 #define FAST_VALUE_GETTER(name, cpptype, defaultvalue, constructor) \
@@ -175,8 +178,8 @@ static v8::Handle<v8::Value> name ## ValueGetter(v8::Local<v8::String>, const v8
     int notify = (data & 0x7FFF0000) >> 16; \
     if (notify == 0x7FFF) notify = -1; \
  \
-    QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(resource->engine->engine()); \
-    if (notify /* 0 means constant */ && ep->captureProperties) { \
+    QDeclarativeEnginePrivate *ep = resource->engine->engine()?QDeclarativeEnginePrivate::get(resource->engine->engine()):0; \
+    if (ep && notify /* 0 means constant */ && ep->captureProperties) { \
         typedef QDeclarativeEnginePrivate::CapturedProperty CapturedProperty; \
         ep->capturedProperties << CapturedProperty(object, index, notify); \
     } \
@@ -331,7 +334,7 @@ v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject
     if (!result)
         return v8::Handle<v8::Value>();
 
-    QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine->engine());
+    QDeclarativeEnginePrivate *ep = engine->engine()?QDeclarativeEnginePrivate::get(engine->engine()):0;
 
     if (revisionMode == QV8QObjectWrapper::CheckRevision && result->revision != 0) {
         QDeclarativeData *ddata = QDeclarativeData::get(object);
@@ -351,7 +354,7 @@ v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject
         }
     }
 
-    if (ep->captureProperties && !result->isConstant()) {
+    if (ep && ep->captureProperties && !result->isConstant()) {
         if (result->coreIndex == 0)
             ep->capturedProperties << CapturedProperty(QDeclarativeData::get(object, true)->objectNameNotifier());
         else
@@ -661,6 +664,7 @@ static void WeakQObjectInstanceCallback(v8::Persistent<v8::Value> handle, void *
     QV8QObjectInstance *instance = (QV8QObjectInstance *)data;
     instance->v8object.Clear();
     handle.Dispose();
+    handle.Clear();
 }
 
 v8::Local<v8::Object> QDeclarativePropertyCache::newQObject(QObject *object, QV8Engine *engine)
@@ -808,7 +812,6 @@ v8::Handle<v8::Value> QV8QObjectWrapper::newQObject(QObject *object)
         return rv;
 
     } else {
-
         // If this object is tainted, we have to check to see if it is in our
         // tainted object list
         TaintedHash::Iterator iter =
@@ -896,6 +899,8 @@ QV8QObjectConnectionList::~QV8QObjectConnectionList()
         for (int ii = 0; ii < connections.count(); ++ii) {
             connections[ii].thisObject.Dispose();
             connections[ii].function.Dispose();
+            connections[ii].thisObject.Clear();
+            connections[ii].function.Clear();
         }
     }
     slotHash.clear();
@@ -1081,6 +1086,8 @@ v8::Handle<v8::Value> QV8QObjectWrapper::Disconnect(const v8::Arguments &args)
                     // Match!
                     connection.thisObject.Dispose();
                     connection.function.Dispose();
+                    connection.thisObject.Clear();
+                    connection.function.Clear();
                     connections.removeAt(ii);
                     return v8::Undefined();
                 }
@@ -1097,6 +1104,8 @@ v8::Handle<v8::Value> QV8QObjectWrapper::Disconnect(const v8::Arguments &args)
                 // Match!
                 connection.thisObject.Dispose();
                 connection.function.Dispose();
+                connection.thisObject.Clear();
+                connection.function.Clear();
                 connections.removeAt(ii);
                 return v8::Undefined();
             }
index 2d91a33..de3cb11 100644 (file)
@@ -95,10 +95,10 @@ void QV8VariantWrapper::init(QV8Engine *engine)
 
 void QV8VariantWrapper::destroy()
 {
-    m_destroy.Dispose();
-    m_preserve.Dispose();
-    m_scarceConstructor.Dispose();
-    m_constructor.Dispose();
+    m_destroy.Dispose(); m_destroy.Clear();
+    m_preserve.Dispose(); m_preserve.Clear();
+    m_scarceConstructor.Dispose(); m_scarceConstructor.Clear();
+    m_constructor.Dispose(); m_constructor.Clear();
 }
 
 v8::Local<v8::Object> QV8VariantWrapper::newVariant(const QVariant &value)
@@ -106,13 +106,12 @@ v8::Local<v8::Object> QV8VariantWrapper::newVariant(const QVariant &value)
     bool scarceResource = value.type() == QVariant::Pixmap ||
                           value.type() == QVariant::Image;
 
-    QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(m_engine->engine());
-
     // XXX aakenned - NewInstance() is slow for our case
     v8::Local<v8::Object> rv;
     QV8VariantResource *r = new QV8VariantResource(m_engine, value);
 
     if (scarceResource) {
+        QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(m_engine->engine());
         Q_ASSERT(ep->scarceResourcesRefCount);
         rv = m_scarceConstructor->NewInstance();
         ep->scarceResources.insert(r);
index 6b6ecd8..846fdb7 100644 (file)
@@ -41,6 +41,9 @@
 
 #include "qv8worker_p.h"
 
+#include <private/qdeclarativelistmodel_p.h>
+#include <private/qdeclarativelistmodelworkeragent_p.h>
+
 QT_BEGIN_NAMESPACE
 
 // We allow the following JavaScript types to be passed between the main and 
@@ -70,7 +73,8 @@ enum Type {
     WorkerUint32,
     WorkerNumber,
     WorkerDate,
-    WorkerRegexp
+    WorkerRegexp,
+    WorkerListModel
 };
 
 static inline quint32 valueheader(Type type, quint32 size = 0)
@@ -98,6 +102,11 @@ static inline void push(QByteArray &data, double value)
     data.append((const char *)&value, sizeof(double));
 }
 
+static inline void push(QByteArray &data, void *ptr)
+{
+    data.append((const char *)&ptr, sizeof(void *));
+}
+
 static inline void reserve(QByteArray &data, int extra)
 {
     data.reserve(data.size() + extra);
@@ -117,6 +126,13 @@ static inline double popDouble(const char *&data)
     return rv;
 }
 
+static inline void *popPtr(const char *&data)
+{
+    void *rv = *((void **)data);
+    data += sizeof(void *);
+    return rv;
+}
+
 // XXX double check exception safety
 
 #include <QDebug>
@@ -221,23 +237,21 @@ void QV8Worker::serialize(QByteArray &data, v8::Handle<v8::Value> v, QV8Engine *
                 serialize(data, val, engine);
             }
         }
+    } else if (engine->isQObject(v)) {
+        // XXX Can we generalize this?
+        QDeclarativeListModel *lm = qobject_cast<QDeclarativeListModel *>(engine->toQObject(v));
+        if (lm && lm->agent()) {
+            QDeclarativeListModelWorkerAgent *agent = lm->agent();
+            agent->addref();
+            push(data, valueheader(WorkerListModel));
+            push(data, (void *)agent);
+            return;
+        } 
+        // No other QObject's are allowed to be sent
+        push(data, valueheader(WorkerUndefined));
     } else {
         push(data, valueheader(WorkerUndefined));
     }
-
-    // XXX Need to serialize QDeclarativeListModel
-    /*
-        QDeclarativeListModel *lm = qobject_cast<QDeclarativeListModel *>(value.toQObject());
-        if (lm) {
-            QDeclarativeListModelWorkerAgent *agent = lm->agent();
-            if (agent) {
-                QDeclarativeListModelWorkerAgent::VariantRef v(agent);
-                return QVariant::fromValue(v);
-            } else {
-                return QVariant();
-            }
-        }
-    */
 }
 
 v8::Handle<v8::Value> QV8Worker::deserialize(const char *&data, QV8Engine *engine)
@@ -300,6 +314,20 @@ v8::Handle<v8::Value> QV8Worker::deserialize(const char *&data, QV8Engine *engin
         data += ALIGN(length * sizeof(uint16_t));
         return v8::RegExp::New(source, (v8::RegExp::Flags)flags);
     }
+    case WorkerListModel:
+    {
+        void *ptr = popPtr(data);
+        QDeclarativeListModelWorkerAgent *agent = (QDeclarativeListModelWorkerAgent *)ptr;
+        v8::Handle<v8::Value> rv = engine->newQObject(agent);
+        if (rv->IsObject()) {
+            QDeclarativeListModelWorkerAgent::VariantRef ref(agent);
+            QVariant var = qVariantFromValue(ref);
+            rv->ToObject()->SetHiddenValue(v8::String::New("qml::ref"), engine->fromVariant(var));
+        }
+        agent->release();
+        agent->setV8Engine(engine);
+        return rv;
+    }
     }
     Q_ASSERT(!"Unreachable");
     return v8::Undefined();
index 4f66dba..1f26140 100644 (file)
@@ -58,6 +58,122 @@ Q_DECLARE_METATYPE(QListModelInterface *)
 
 QT_BEGIN_NAMESPACE
 
+QV8ListModelResource::QV8ListModelResource(FlatListModel *model, FlatNodeData *data, QV8Engine *engine)
+: QV8ObjectResource(engine), model(model), nodeData(data)
+{
+    if (nodeData) nodeData->addData(this);
+}
+
+QV8ListModelResource::~QV8ListModelResource()
+{
+    if (nodeData) nodeData->removeData(this);
+}
+
+class QDeclarativeListModelV8Data : public QV8Engine::Deletable
+{
+public:
+    QDeclarativeListModelV8Data();
+    ~QDeclarativeListModelV8Data();
+
+    v8::Persistent<v8::Function> constructor;
+
+    static v8::Local<v8::Object> create(QV8Engine *);
+
+    static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property, 
+                                        const v8::AccessorInfo &info);
+    static v8::Handle<v8::Value> Setter(v8::Local<v8::String> property, 
+                                        v8::Local<v8::Value> value,
+                                        const v8::AccessorInfo &info);
+};
+
+v8::Local<v8::Object> QDeclarativeListModelV8Data::create(QV8Engine *engine)
+{
+    if (!engine->listModelData()) {
+        QDeclarativeListModelV8Data *d = new QDeclarativeListModelV8Data;
+        engine->setListModelData(d);
+    }
+
+    QDeclarativeListModelV8Data *d = (QDeclarativeListModelV8Data *)engine->listModelData();
+    return d->constructor->NewInstance();
+}
+
+QDeclarativeListModelV8Data::QDeclarativeListModelV8Data()
+{
+    v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+    ft->InstanceTemplate()->SetNamedPropertyHandler(Getter, Setter);
+    ft->InstanceTemplate()->SetHasExternalResource(true);
+    constructor = v8::Persistent<v8::Function>::New(ft->GetFunction());
+}
+
+QDeclarativeListModelV8Data::~QDeclarativeListModelV8Data()
+{
+    constructor.Dispose(); constructor.Clear();
+}
+
+v8::Handle<v8::Value> QDeclarativeListModelV8Data::Getter(v8::Local<v8::String> property, 
+                                                          const v8::AccessorInfo &info)
+{
+    QV8ListModelResource *r =  v8_resource_cast<QV8ListModelResource>(info.This());
+    if (!r)
+        return v8::Undefined();
+
+    if (!r->nodeData) // Item at this index has been deleted
+        return v8::Undefined();
+
+
+    int index = r->nodeData->index;
+    QString propName = r->engine->toString(property);
+
+    int role = r->model->m_strings.value(propName, -1);
+
+    if (role >= 0 && index >=0 ) {
+        const QHash<int, QVariant> &row = r->model->m_values[index];
+        return r->engine->fromVariant(row[role]);
+    }
+
+    return v8::Undefined();
+}
+
+v8::Handle<v8::Value> QDeclarativeListModelV8Data::Setter(v8::Local<v8::String> property, 
+                                                          v8::Local<v8::Value> value,
+                                                          const v8::AccessorInfo &info)
+{
+    QV8ListModelResource *r =  v8_resource_cast<QV8ListModelResource>(info.This());
+    if (!r)
+        return v8::Undefined();
+
+    if (!r->nodeData) // item at this index has been deleted
+        return value;
+
+
+    if (!value->IsRegExp() && !value->IsDate() && value->IsObject() && !r->engine->isVariant(value)) {
+        qmlInfo(r->model->m_listModel) << "Cannot add list-type data when modifying or after modification from a worker script";
+        return value;
+    }
+
+    int index = r->nodeData->index;
+    QString propName = r->engine->toString(property);
+
+    int role = r->model->m_strings.value(propName, -1);
+    if (role >= 0 && index >= 0) {
+        QHash<int, QVariant> &row = r->model->m_values[index];
+        row[role] = r->engine->toVariant(value, -1);
+
+        QList<int> roles;
+        roles << role;
+        if (r->model->m_parentAgent) {
+            // This is the list in the worker thread, so tell the agent to
+            // emit itemsChanged() later
+            r->model->m_parentAgent->changedData(index, 1, roles);
+        } else {
+            // This is the list in the main thread, so emit itemsChanged()
+            emit r->model->m_listModel->itemsChanged(index, 1, roles);
+        }
+    }
+
+    return value;
+}
+
 template<typename T>
 void qdeclarativelistmodel_move(int from, int to, int n, T *items)
 {
@@ -367,13 +483,14 @@ QDeclarativeListModel *ModelNode::model(const NestedListModel *model)
 ModelObject *ModelNode::object(const NestedListModel *model)
 {
     if (!objectCache) {
-        objectCache = new ModelObject(this, 
-                const_cast<NestedListModel*>(model), 
-                QDeclarativeEnginePrivate::getScriptEngine(qmlEngine(model->m_listModel)));
+        QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(qmlEngine(model->m_listModel));
+        objectCache = new ModelObject(this, const_cast<NestedListModel*>(model), &ep->v8engine);
+
         QHash<QString, ModelNode *>::iterator it;
         for (it = properties.begin(); it != properties.end(); ++it) {
             objectCache->setValue(it.key().toUtf8(), model->valueForNode(*it));
         }
+
         objectCache->setNodeUpdatesEnabled(true);
     }
     return objectCache;
@@ -419,9 +536,11 @@ void QDeclarativeListModel::remove(int index)
 
     \sa set() append()
 */
-void QDeclarativeListModel::insert(int index, const QScriptValue& valuemap)
+void QDeclarativeListModel::insert(int index, const QDeclarativeV8Handle &handle)
 {
-    if (!valuemap.isObject() || valuemap.isArray()) {
+    v8::Handle<v8::Value> valuemap = handle.toHandle();
+
+    if (!valuemap->IsObject() || valuemap->IsArray()) {
         qmlInfo(this) << tr("insert: value is not an object");
         return;
     }
@@ -432,6 +551,7 @@ void QDeclarativeListModel::insert(int index, const QScriptValue& valuemap)
     }
 
     bool ok = m_flat ?  m_flat->insert(index, valuemap) : m_nested->insert(index, valuemap);
+
     if (ok && !inWorkerThread()) {
         emit itemsInserted(index, 1);
         emit countChanged();
@@ -494,14 +614,16 @@ void QDeclarativeListModel::move(int from, int to, int n)
 
     \sa set() remove()
 */
-void QDeclarativeListModel::append(const QScriptValue& valuemap)
+void QDeclarativeListModel::append(const QDeclarativeV8Handle &handle)
 {
-    if (!valuemap.isObject() || valuemap.isArray()) {
+    v8::Handle<v8::Value> valuemap = handle.toHandle();
+
+    if (!valuemap->IsObject() || valuemap->IsArray()) {
         qmlInfo(this) << tr("append: value is not an object");
         return;
     }
 
-    insert(count(), valuemap);
+    insert(count(), handle);
 }
 
 /*!
@@ -535,10 +657,10 @@ void QDeclarativeListModel::append(const QScriptValue& valuemap)
 
     \sa append()
 */
-QScriptValue QDeclarativeListModel::get(int index) const
+QDeclarativeV8Handle QDeclarativeListModel::get(int index) const
 {
     // the internal flat/nested class checks for bad index
-    return m_flat ? m_flat->get(index) : m_nested->get(index);
+    return QDeclarativeV8Handle::fromHandle(m_flat ? m_flat->get(index) : m_nested->get(index));
 }
 
 /*!
@@ -557,7 +679,7 @@ QScriptValue QDeclarativeListModel::get(int index) const
 
     \sa append()
 */
-void QDeclarativeListModel::set(int index, const QScriptValue& valuemap)
+void QDeclarativeListModel::set(int index, const QDeclarativeV8Handle &valuemap)
 {
     QList<int> roles;
     set(index, valuemap, &roles);
@@ -565,9 +687,11 @@ void QDeclarativeListModel::set(int index, const QScriptValue& valuemap)
         emit itemsChanged(index, 1, roles);
 }
 
-void QDeclarativeListModel::set(int index, const QScriptValue& valuemap, QList<int> *roles)
+void QDeclarativeListModel::set(int index, const QDeclarativeV8Handle &handle, QList<int> *roles)
 {
-    if (!valuemap.isObject() || valuemap.isArray()) {
+    v8::Handle<v8::Value> valuemap = handle.toHandle();
+
+    if (!valuemap->IsObject() || valuemap->IsArray()) {
         qmlInfo(this) << tr("set: value is not an object");
         return;
     }
@@ -577,7 +701,7 @@ void QDeclarativeListModel::set(int index, const QScriptValue& valuemap, QList<i
     }
 
     if (index == count()) {
-        append(valuemap);
+        append(handle);
     } else {
         if (m_flat)
             m_flat->set(index, valuemap, roles);
@@ -912,7 +1036,7 @@ bool QDeclarativeListModelParser::definesEmptyList(const QString &s)
 */
 
 FlatListModel::FlatListModel(QDeclarativeListModel *base)
-    : m_scriptEngine(0), m_listModel(base), m_scriptClass(0), m_parentAgent(0)
+: m_engine(0), m_listModel(base), m_scriptClass(0), m_parentAgent(0)
 {
 }
 
@@ -960,7 +1084,7 @@ void FlatListModel::remove(int index)
     removedNode(index);
 }
 
-bool FlatListModel::insert(int index, const QScriptValue &value)
+bool FlatListModel::insert(int index, v8::Handle<v8::Value> value)
 {
     Q_ASSERT(index >= 0 && index <= m_values.count());
 
@@ -974,19 +1098,27 @@ bool FlatListModel::insert(int index, const QScriptValue &value)
     return true;
 }
 
-QScriptValue FlatListModel::get(int index) const
+QV8Engine *FlatListModel::engine() const
 {
-    QScriptEngine *scriptEngine = m_scriptEngine ? m_scriptEngine : QDeclarativeEnginePrivate::getScriptEngine(qmlEngine(m_listModel));
+    return m_engine?m_engine:QDeclarativeEnginePrivate::getV8Engine(qmlEngine(m_listModel));
+}
 
-    if (!scriptEngine) 
-        return 0;
+QV8Engine *NestedListModel::engine() const
+{
+    return QDeclarativeEnginePrivate::getV8Engine(qmlEngine(m_listModel));
+}
+
+v8::Handle<v8::Value> FlatListModel::get(int index) const
+{
+    QV8Engine *v8engine = engine();
+
+    if (!v8engine) 
+        return v8::Undefined();
 
     if (index < 0 || index >= m_values.count())
-        return scriptEngine->undefinedValue();
+        return v8::Undefined();
 
     FlatListModel *that = const_cast<FlatListModel*>(this);
-    if (!m_scriptClass)
-        that->m_scriptClass = new FlatListScriptClass(that, scriptEngine);
 
     FlatNodeData *data = m_nodeData.value(index);
     if (!data) {
@@ -994,10 +1126,13 @@ QScriptValue FlatListModel::get(int index) const
         that->m_nodeData.replace(index, data);
     }
 
-    return QScriptDeclarativeClass::newObject(scriptEngine, m_scriptClass, new FlatNodeObjectData(data));
+    v8::Local<v8::Object> rv = QDeclarativeListModelV8Data::create(v8engine);
+    QV8ListModelResource *r = new QV8ListModelResource(that, data, v8engine);
+    rv->SetExternalResource(r);
+    return rv;
 }
 
-void FlatListModel::set(int index, const QScriptValue &value, QList<int> *roles)
+void FlatListModel::set(int index, v8::Handle<v8::Value> value, QList<int> *roles)
 {
     Q_ASSERT(index >= 0 && index < m_values.count());
 
@@ -1032,19 +1167,25 @@ void FlatListModel::move(int from, int to, int n)
     moveNodes(from, to, n);
 }
 
-bool FlatListModel::addValue(const QScriptValue &value, QHash<int, QVariant> *row, QList<int> *roles)
+bool FlatListModel::addValue(v8::Handle<v8::Value> value, QHash<int, QVariant> *row, QList<int> *roles)
 {
-    QScriptValueIterator it(value);
-    while (it.hasNext()) {
-        it.next();
-        QScriptValue value = it.value();
-        if (!value.isVariant() && !value.isRegExp() && !value.isDate() && value.isObject()) {
+    if (!value->IsObject())
+        return false;
+
+    v8::Local<v8::Array> properties = engine()->getOwnPropertyNames(value->ToObject());
+    uint32_t length = properties->Length();
+    for (uint32_t ii = 0; ii < length; ++ii) {
+        // XXX TryCatch?
+        v8::Handle<v8::Value> property = properties->Get(ii);
+        v8::Handle<v8::Value> jsv = value->ToObject()->Get(property);
+
+        if (!jsv->IsRegExp() && !jsv->IsDate() && jsv->IsObject() && !engine()->isVariant(jsv)) {
             qmlInfo(m_listModel) << "Cannot add list-type data when modifying or after modification from a worker script";
             return false;
         }
 
-        QString name = it.name();
-        QVariant v = it.value().toVariant();
+        QString name = engine()->toString(property);
+        QVariant v = engine()->toVariant(jsv, -1);
 
         QHash<QString, int>::Iterator iter = m_strings.find(name);
         if (iter == m_strings.end()) {
@@ -1100,27 +1241,26 @@ void FlatListModel::moveNodes(int from, int to, int n)
     }
 }
 
-
-
 FlatNodeData::~FlatNodeData()
 {
-    for (QSet<FlatNodeObjectData *>::Iterator iter = objects.begin(); iter != objects.end(); ++iter) {
-        FlatNodeObjectData *data = *iter;
+    for (QSet<QV8ListModelResource *>::Iterator iter = objects.begin(); iter != objects.end(); ++iter) {
+        QV8ListModelResource *data = *iter;
         data->nodeData = 0;
     }
 }
 
-void FlatNodeData::addData(FlatNodeObjectData *data) 
+void FlatNodeData::addData(QV8ListModelResource *data) 
 {
     objects.insert(data);
 }
 
-void FlatNodeData::removeData(FlatNodeObjectData *data)
+void FlatNodeData::removeData(QV8ListModelResource *data)
 {
     objects.remove(data);
 }
 
 
+#if 0
 FlatListScriptClass::FlatListScriptClass(FlatListModel *model, QScriptEngine *seng)
     : QScriptDeclarativeClass(seng),
       m_model(model)
@@ -1193,11 +1333,10 @@ bool FlatListScriptClass::compare(Object *obj1, Object *obj2)
 
     return data1->nodeData->index == data2->nodeData->index;
 }
-
-
+#endif
 
 NestedListModel::NestedListModel(QDeclarativeListModel *base)
-    : _root(0), m_ownsRoot(false), m_listModel(base), _rolesOk(false)
+: _root(0), m_ownsRoot(false), m_listModel(base), _rolesOk(false)
 {
 }
 
@@ -1315,7 +1454,7 @@ void NestedListModel::remove(int index)
         delete node;
 }
 
-bool NestedListModel::insert(int index, const QScriptValue& valuemap)
+bool NestedListModel::insert(int index, v8::Handle<v8::Value> valuemap)
 {
     if (!_root) {
         _root = new ModelNode(this);
@@ -1336,44 +1475,47 @@ void NestedListModel::move(int from, int to, int n)
     qdeclarativelistmodel_move<QVariantList>(from, to, n, &_root->values);
 }
 
-QScriptValue NestedListModel::get(int index) const
+v8::Handle<v8::Value> NestedListModel::get(int index) const
 {   
     QDeclarativeEngine *eng = qmlEngine(m_listModel);
     if (!eng) 
-        return 0;
+        return v8::Undefined();;
 
-    if (index < 0 || index >= count()) {
-        QScriptEngine *seng = QDeclarativeEnginePrivate::getScriptEngine(eng);
-        if (seng)
-            return seng->undefinedValue();
-        return 0;
-    }
+    if (index < 0 || index >= count()) 
+        return v8::Undefined();
 
     ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index));
     if (!node)
-        return 0;
-    
-#if 0
-    return QDeclarativeEnginePrivate::qmlScriptObject(node->object(this), eng);
-#endif
+        return v8::Undefined();;
+
+    return QDeclarativeEnginePrivate::get(eng)->v8engine.newQObject(node->object(this));
 }
 
-void NestedListModel::set(int index, const QScriptValue& valuemap, QList<int> *roles)
+void NestedListModel::set(int index, v8::Handle<v8::Value> valuemap, QList<int> *roles)
 {
     Q_ASSERT(index >=0 && index < count());
 
+    if (!valuemap->IsObject())
+        return;
+
     ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index));
     bool emitItemsChanged = node->setObjectValue(valuemap);
     if (!emitItemsChanged)
         return;
 
-    QScriptValueIterator it(valuemap);
-    while (it.hasNext()) {
-        it.next();
-        int r = roleStrings.indexOf(it.name());
+    QV8Engine *v8engine = engine();
+
+    v8::Local<v8::Array> properties = v8engine->getOwnPropertyNames(valuemap->ToObject());
+    uint32_t length = properties->Length();
+    for (uint32_t ii = 0; ii < length; ++ii) {
+        // XXX TryCatch?
+        v8::Handle<v8::Value> property = properties->Get(ii);
+        QString name = v8engine->toString(property);
+
+        int r = roleStrings.indexOf(name);
         if (r < 0) {
             r = roleStrings.count();
-            roleStrings << it.name();
+            roleStrings << name;
         }
         roles->append(r);
     }
@@ -1458,55 +1600,75 @@ void ModelNode::clear()
     properties.clear();
 }
 
-bool ModelNode::setObjectValue(const QScriptValue& valuemap, bool writeToCache)
+bool ModelNode::setObjectValue(v8::Handle<v8::Value> valuemap, bool writeToCache)
 {
+    if (!valuemap->IsObject())
+        return false;
+
     bool emitItemsChanged = false;
 
-    QScriptValueIterator it(valuemap);
-    while (it.hasNext()) {
-        it.next();
-        ModelNode *prev = properties.value(it.name());
+    QV8Engine *v8engine = m_model->engine();
+
+    v8::Local<v8::Array> propertyNames = v8engine->getOwnPropertyNames(valuemap->ToObject());
+    uint32_t length = propertyNames->Length();
+
+    for (uint32_t ii = 0; ii < length; ++ii) {
+        // XXX TryCatch?
+        v8::Handle<v8::Value> property = propertyNames->Get(ii);
+        v8::Handle<v8::Value> v = valuemap->ToObject()->Get(property);
+
+        QString name = v8engine->toString(property);
+        ModelNode *prev = properties.value(name);
         ModelNode *value = new ModelNode(m_model);
-        QScriptValue v = it.value();
 
-        if (v.isArray()) {
+        if (v->IsArray()) {
             value->isArray = true;
             value->setListValue(v);
             if (writeToCache && objectCache)
-                objectCache->setValue(it.name().toUtf8(), QVariant::fromValue(value->model(m_model)));
+                objectCache->setValue(name.toUtf8(), QVariant::fromValue(value->model(m_model)));
             emitItemsChanged = true;    // for now, too inefficient to check whether list and sublists have changed
         } else {
-            value->values << v.toVariant();
+            value->values << v8engine->toVariant(v, -1);
             if (writeToCache && objectCache)
-                objectCache->setValue(it.name().toUtf8(), value->values.last());
+                objectCache->setValue(name.toUtf8(), value->values.last());
             if (!emitItemsChanged && prev && prev->values.count() == 1
                     && prev->values[0] != value->values.last()) {
                 emitItemsChanged = true;
             }
         }
-        if (properties.contains(it.name()))
-            delete properties[it.name()];
-        properties.insert(it.name(), value);
+        if (properties.contains(name))
+            delete properties[name];
+        properties.insert(name, value);
     }
     return emitItemsChanged;
 }
 
-void ModelNode::setListValue(const QScriptValue& valuelist) {
+void ModelNode::setListValue(v8::Handle<v8::Value> valuelist) 
+{
+    Q_ASSERT(valuelist->IsArray());
     values.clear();
-    int size = valuelist.property(QLatin1String("length")).toInt32();
-    for (int i=0; i<size; i++) {
+
+    QV8Engine *engine = m_model->engine();
+
+    v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(valuelist);
+    uint32_t length = array->Length();
+    for (uint32_t ii = 0; ii < length; ++ii) {
         ModelNode *value = new ModelNode(m_model);
-        QScriptValue v = valuelist.property(i);
-        if (v.isArray()) {
+
+        // XXX TryCatch?
+        v8::Handle<v8::Value> v = array->Get(ii);
+
+        if (v->IsArray()) {
             value->isArray = true;
             value->setListValue(v);
-        } else if (v.isObject()) {
-            value->listIndex = i;
+        } else if (v->IsObject()) {
+            value->listIndex = ii;
             value->setObjectValue(v);
         } else {
-            value->listIndex = i;
-            value->values << v.toVariant();
+            value->listIndex = ii;
+            value->values << engine->toVariant(v, -1);
         }
+
         values.append(QVariant::fromValue(value));
     }
 }
@@ -1583,10 +1745,8 @@ void ModelNode::dump(ModelNode *node, int ind)
     }
 }
 
-ModelObject::ModelObject(ModelNode *node, NestedListModel *model, QScriptEngine *seng)
-    : m_model(model),
-      m_node(node),
-      m_meta(new ModelNodeMetaObject(seng, this))
+ModelObject::ModelObject(ModelNode *node, NestedListModel *model, QV8Engine *eng)
+: m_model(model), m_node(node), m_meta(new ModelNodeMetaObject(eng, this))
 {
 }
 
@@ -1601,12 +1761,8 @@ void ModelObject::setNodeUpdatesEnabled(bool enable)
     m_meta->m_enabled = enable;
 }
 
-
-ModelNodeMetaObject::ModelNodeMetaObject(QScriptEngine *seng, ModelObject *object)
-    : QDeclarativeOpenMetaObject(object),
-      m_enabled(false),
-      m_seng(seng),
-      m_obj(object)
+ModelNodeMetaObject::ModelNodeMetaObject(QV8Engine *eng, ModelObject *object)
+: QDeclarativeOpenMetaObject(object), m_enabled(false), m_engine(eng), m_obj(object)
 {
 }
 
@@ -1618,12 +1774,13 @@ void ModelNodeMetaObject::propertyWritten(int index)
     QString propName = QString::fromUtf8(name(index));
     QVariant value = operator[](index);
 
-    QScriptValue sv = m_seng->newObject();
-    sv.setProperty(propName, m_seng->newVariant(value));
-    bool changed = m_obj->m_node->setObjectValue(sv, false);
+    v8::HandleScope handle_scope;
+    v8::Context::Scope scope(m_engine->context());
+    v8::Local<v8::Object> object = v8::Object::New();
+    object->Set(m_engine->toString(propName), m_engine->variantWrapper()->newVariant(value));
+    bool changed = m_obj->m_node->setObjectValue(object, false);
     if (changed)
         m_obj->m_node->changedProperty(propName);
 }
 
-
 QT_END_NAMESPACE
index 93a3183..5962f37 100644 (file)
@@ -53,6 +53,8 @@
 #include <private/qlistmodelinterface_p.h>
 #include <QtScript/qscriptvalue.h>
 
+#include <private/qv8engine_p.h>
+
 QT_BEGIN_HEADER
 
 QT_BEGIN_NAMESPACE
@@ -80,10 +82,10 @@ public:
 
     Q_INVOKABLE void clear();
     Q_INVOKABLE void remove(int index);
-    Q_INVOKABLE void append(const QScriptValue&);
-    Q_INVOKABLE void insert(int index, const QScriptValue&);
-    Q_INVOKABLE QScriptValue get(int index) const;
-    Q_INVOKABLE void set(int index, const QScriptValue&);
+    Q_INVOKABLE void append(const QDeclarativeV8Handle &);
+    Q_INVOKABLE void insert(int index, const QDeclarativeV8Handle &);
+    Q_INVOKABLE QDeclarativeV8Handle get(int index) const;
+    Q_INVOKABLE void set(int index, const QDeclarativeV8Handle &);
     Q_INVOKABLE void setProperty(int index, const QString& property, const QVariant& value);
     Q_INVOKABLE void move(int from, int to, int count);
     Q_INVOKABLE void sync();
@@ -97,13 +99,13 @@ private:
     friend class QDeclarativeListModelParser;
     friend class QDeclarativeListModelWorkerAgent;
     friend class FlatListModel;
-    friend class FlatListScriptClass;
+    friend class QDeclarativeListModelV8Data;
     friend struct ModelNode;
 
     // Constructs a flat list model for a worker agent
     QDeclarativeListModel(const QDeclarativeListModel *orig, QDeclarativeListModelWorkerAgent *parent);
 
-    void set(int index, const QScriptValue&, QList<int> *roles);
+    void set(int index, const QDeclarativeV8Handle &, QList<int> *roles);
     void setProperty(int index, const QString& property, const QVariant& value, QList<int> *roles);
 
     bool flatten();
index 84a6e90..b7fbd0e 100644 (file)
@@ -67,7 +67,6 @@ QT_BEGIN_NAMESPACE
 QT_MODULE(Declarative)
 
 class QDeclarativeOpenMetaObject;
-class QScriptEngine;
 class QDeclarativeListModelWorkerAgent;
 struct ModelNode;
 class FlatListScriptClass;
@@ -87,24 +86,25 @@ public:
     int count() const;
     void clear();
     void remove(int index);
-    bool insert(int index, const QScriptValue&);
-    QScriptValue get(int index) const;
-    void set(int index, const QScriptValue&, QList<int> *roles);
+    bool insert(int index, v8::Handle<v8::Value>);
+    v8::Handle<v8::Value> get(int index) const;
+    void set(int index, v8::Handle<v8::Value>, QList<int> *roles);
     void setProperty(int index, const QString& property, const QVariant& value, QList<int> *roles);
     void move(int from, int to, int count);
 
 private:    
     friend class QDeclarativeListModelWorkerAgent;
     friend class QDeclarativeListModel;
-    friend class FlatListScriptClass;
+    friend class QDeclarativeListModelV8Data;
     friend class FlatNodeData;
 
-    bool addValue(const QScriptValue &value, QHash<int, QVariant> *row, QList<int> *roles);
+    bool addValue(v8::Handle<v8::Value> value, QHash<int, QVariant> *row, QList<int> *roles);
     void insertedNode(int index);
     void removedNode(int index);
     void moveNodes(int from, int to, int n);
 
-    QScriptEngine *m_scriptEngine;
+    QV8Engine *engine() const;
+    QV8Engine *m_engine;
     QHash<int, QString> m_roles;
     QHash<QString, int> m_strings;
     QList<QHash<int, QVariant> > m_values;
@@ -116,6 +116,7 @@ private:
 };
 
 
+#if 0
 /*
     Created when get() is called on a FlatListModel. This allows changes to the
     object returned by get() to be tracked, and passed onto the model.
@@ -133,12 +134,13 @@ public:
 private:
     FlatListModel *m_model;
 };
+#endif
 
 /*
     FlatNodeData and FlatNodeObjectData allow objects returned by get() to still
     point to the correct list index if move(), insert() or remove() are called.
 */
-struct FlatNodeObjectData;
+class QV8ListModelResource;
 class FlatNodeData
 {
 public:
@@ -147,31 +149,26 @@ public:
 
     ~FlatNodeData();
 
-    void addData(FlatNodeObjectData *data);
-    void removeData(FlatNodeObjectData *data);
+    void addData(QV8ListModelResource *data);
+    void removeData(QV8ListModelResource *data);
 
     int index;
 
 private:
-    QSet<FlatNodeObjectData*> objects;
+    QSet<QV8ListModelResource*> objects;
 };
 
-struct FlatNodeObjectData : public QScriptDeclarativeClass::Object
+class QV8ListModelResource : public QV8ObjectResource
 {
-    FlatNodeObjectData(FlatNodeData *data) : nodeData(data) {
-        nodeData->addData(this);
-    }
-
-    ~FlatNodeObjectData() {
-        if (nodeData)
-            nodeData->removeData(this);
-    }
+    V8_RESOURCE_TYPE(ListModelType);
+public:
+    QV8ListModelResource(FlatListModel *model, FlatNodeData *data, QV8Engine *engine);
+    ~QV8ListModelResource();
 
+    FlatListModel *model;
     FlatNodeData *nodeData;
 };
 
-
-
 class NestedListModel
 {
 public:
@@ -187,9 +184,9 @@ public:
     int count() const;
     void clear();
     void remove(int index);
-    bool insert(int index, const QScriptValue&);
-    QScriptValue get(int index) const;
-    void set(int index, const QScriptValue&, QList<int> *roles);
+    bool insert(int index, v8::Handle<v8::Value>);
+    v8::Handle<v8::Value> get(int index) const;
+    void set(int index, v8::Handle<v8::Value>, QList<int> *roles);
     void setProperty(int index, const QString& property, const QVariant& value, QList<int> *roles);
     void move(int from, int to, int count);
 
@@ -200,6 +197,7 @@ public:
     bool m_ownsRoot;
     QDeclarativeListModel *m_listModel;
 
+    QV8Engine *engine() const;
 private:
     friend struct ModelNode;
     mutable QStringList roleStrings;
@@ -212,7 +210,7 @@ class ModelObject : public QObject
 {
     Q_OBJECT
 public:
-    ModelObject(ModelNode *node, NestedListModel *model, QScriptEngine *seng);
+    ModelObject(ModelNode *node, NestedListModel *model, QV8Engine *eng);
     void setValue(const QByteArray &name, const QVariant &val);
     void setNodeUpdatesEnabled(bool enable);
 
@@ -226,7 +224,7 @@ private:
 class ModelNodeMetaObject : public QDeclarativeOpenMetaObject
 {
 public:
-    ModelNodeMetaObject(QScriptEngine *seng, ModelObject *object);
+    ModelNodeMetaObject(QV8Engine *eng, ModelObject *object);
 
     bool m_enabled;
 
@@ -234,11 +232,10 @@ protected:
     void propertyWritten(int index);
 
 private:
-    QScriptEngine *m_seng;
+    QV8Engine *m_engine;
     ModelObject *m_obj;
 };
 
-
 /*
     A ModelNode is created for each item in a NestedListModel.
 */
@@ -255,8 +252,8 @@ struct ModelNode
     QDeclarativeListModel *model(const NestedListModel *model);
     ModelObject *object(const NestedListModel *model);
 
-    bool setObjectValue(const QScriptValue& valuemap, bool writeToCache = true);
-    void setListValue(const QScriptValue& valuelist);
+    bool setObjectValue(v8::Handle<v8::Value> valuemap, bool writeToCache = true);
+    void setListValue(v8::Handle<v8::Value> valuelist);
     bool setProperty(const QString& prop, const QVariant& val);
     void changedProperty(const QString &name) const;
     void updateListIndexes();
index efc83a5..c6855d3 100644 (file)
@@ -83,10 +83,7 @@ void QDeclarativeListModelWorkerAgent::Data::changedChange(int index, int count,
 }
 
 QDeclarativeListModelWorkerAgent::QDeclarativeListModelWorkerAgent(QDeclarativeListModel *model)
-    : m_engine(0), 
-      m_ref(1), 
-      m_orig(model), 
-      m_copy(new QDeclarativeListModel(model, this))
+: m_engine(0), m_ref(1), m_orig(model), m_copy(new QDeclarativeListModel(model, this))
 {
 }
 
@@ -94,14 +91,14 @@ QDeclarativeListModelWorkerAgent::~QDeclarativeListModelWorkerAgent()
 {
 }
 
-void QDeclarativeListModelWorkerAgent::setScriptEngine(QScriptEngine *eng)
+void QDeclarativeListModelWorkerAgent::setV8Engine(QV8Engine *eng)
 {
     m_engine = eng;
     if (m_copy->m_flat)
-        m_copy->m_flat->m_scriptEngine = eng;
+        m_copy->m_flat->m_engine = eng;
 }
 
-QScriptEngine *QDeclarativeListModelWorkerAgent::scriptEngine() const
+QV8Engine *QDeclarativeListModelWorkerAgent::v8engine() const
 {
     return m_engine;
 }
@@ -140,7 +137,7 @@ void QDeclarativeListModelWorkerAgent::remove(int index)
         data.removeChange(index, 1);
 }
 
-void QDeclarativeListModelWorkerAgent::append(const QScriptValue &value)
+void QDeclarativeListModelWorkerAgent::append(const QDeclarativeV8Handle &value)
 {
     int count = m_copy->count();
     m_copy->append(value);
@@ -149,7 +146,7 @@ void QDeclarativeListModelWorkerAgent::append(const QScriptValue &value)
         data.insertChange(m_copy->count() - 1, 1);
 }
 
-void QDeclarativeListModelWorkerAgent::insert(int index, const QScriptValue &value)
+void QDeclarativeListModelWorkerAgent::insert(int index, const QDeclarativeV8Handle &value)
 {
     int count = m_copy->count();
     m_copy->insert(index, value);
@@ -158,12 +155,12 @@ void QDeclarativeListModelWorkerAgent::insert(int index, const QScriptValue &val
         data.insertChange(index, 1);
 }
 
-QScriptValue QDeclarativeListModelWorkerAgent::get(int index) const
+QDeclarativeV8Handle QDeclarativeListModelWorkerAgent::get(int index) const
 {
     return m_copy->get(index);
 }
 
-void QDeclarativeListModelWorkerAgent::set(int index, const QScriptValue &value)
+void QDeclarativeListModelWorkerAgent::set(int index, const QDeclarativeV8Handle &value)
 {
     QList<int> roles;
     m_copy->set(index, value, &roles);
index fa8c773..d8aae68 100644 (file)
@@ -60,6 +60,8 @@
 #include <QMutex>
 #include <QWaitCondition>
 
+#include <private/qv8engine_p.h>
+
 QT_BEGIN_HEADER
 
 QT_BEGIN_NAMESPACE
@@ -78,8 +80,8 @@ public:
     QDeclarativeListModelWorkerAgent(QDeclarativeListModel *);
     ~QDeclarativeListModelWorkerAgent();
 
-    void setScriptEngine(QScriptEngine *eng);
-    QScriptEngine *scriptEngine() const;
+    void setV8Engine(QV8Engine *eng);
+    QV8Engine *v8engine() const;
 
     void addref();
     void release();
@@ -88,10 +90,10 @@ public:
 
     Q_INVOKABLE void clear();
     Q_INVOKABLE void remove(int index);
-    Q_INVOKABLE void append(const QScriptValue &);
-    Q_INVOKABLE void insert(int index, const QScriptValue&);
-    Q_INVOKABLE QScriptValue get(int index) const;
-    Q_INVOKABLE void set(int index, const QScriptValue &);
+    Q_INVOKABLE void append(const QDeclarativeV8Handle &);
+    Q_INVOKABLE void insert(int index, const QDeclarativeV8Handle &);
+    Q_INVOKABLE QDeclarativeV8Handle get(int index) const;
+    Q_INVOKABLE void set(int index, const QDeclarativeV8Handle &);
     Q_INVOKABLE void setProperty(int index, const QString& property, const QVariant& value);
     Q_INVOKABLE void move(int from, int to, int count);
     Q_INVOKABLE void sync();
@@ -116,8 +118,8 @@ protected:
 
 private:
     friend class QDeclarativeWorkerScriptEnginePrivate;
-    friend class FlatListScriptClass;
-    QScriptEngine *m_engine;
+    friend class QDeclarativeListModelV8Data;
+    QV8Engine *m_engine;
 
     struct Change {
         enum { Inserted, Removed, Moved, Changed } type;
index bfd547e..a1a599c 100644 (file)
@@ -19,4 +19,8 @@ Item {
             item.done = true
         }
     }
+
+    function runEval(js) {
+        eval(js);
+    }
 }
index d923a7a..0cd9df2 100644 (file)
@@ -108,6 +108,7 @@ private slots:
     void property_changes_worker_data();
     void clear();
 };
+
 int tst_qdeclarativelistmodel::roleFromName(const QDeclarativeListModel *model, const QString &roleName)
 {
     QList<int> roles = model->roles();
@@ -152,19 +153,74 @@ void tst_qdeclarativelistmodel::waitForWorker(QDeclarativeItem *item)
     QVERIFY(timer.isActive());
 }
 
+void tst_qdeclarativelistmodel::static_types_data()
+{
+    QTest::addColumn<QString>("qml");
+    QTest::addColumn<QVariant>("value");
+
+    QTest::newRow("string")
+        << "ListElement { foo: \"bar\" }"
+        << QVariant(QString("bar"));
+
+    QTest::newRow("real")
+        << "ListElement { foo: 10.5 }"
+        << QVariant(10.5);
+
+    QTest::newRow("real0")
+        << "ListElement { foo: 0 }"
+        << QVariant(double(0));
+
+    QTest::newRow("bool")
+        << "ListElement { foo: false }"
+        << QVariant(false);
+
+    QTest::newRow("bool")
+        << "ListElement { foo: true }"
+        << QVariant(true);
+
+    QTest::newRow("enum")
+        << "ListElement { foo: Text.AlignHCenter }"
+        << QVariant(double(QDeclarativeText::AlignHCenter));
+}
+
+void tst_qdeclarativelistmodel::static_types()
+{
+    QFETCH(QString, qml);
+    QFETCH(QVariant, value);
+
+    qml = "import QtQuick 1.0\nItem { property variant test: model.get(0).foo; ListModel { id: model; " + qml + " } }";
+
+    QDeclarativeEngine engine;
+    QDeclarativeComponent component(&engine);
+    component.setData(qml.toUtf8(),
+                      QUrl::fromLocalFile(QString("dummy.qml")));
+
+    QVERIFY(!component.isError());
+
+    QObject *obj = component.create();
+    QVERIFY(obj != 0);
+
+    QVariant actual = obj->property("test");
+
+    QCOMPARE(actual, value);
+    QCOMPARE(actual.toString(), value.toString());
+
+    delete obj;
+}
+
 void tst_qdeclarativelistmodel::static_i18n()
 {
     QString expect = QString::fromUtf8("na\303\257ve");
 
-    QString componentStr = "import QtQuick 1.0\nListModel { ListElement { prop1: \""+expect+"\"; prop2: QT_TR_NOOP(\""+expect+"\") } }";
+    QString componentStr = "import QtQuick 1.0\nItem { property string prop1: model.get(0).prop1; property string prop2: model.get(0).prop2; ListModel { id: model; ListElement { prop1: \""+expect+"\"; prop2: QT_TR_NOOP(\""+expect+"\") } } }";
     QDeclarativeEngine engine;
     QDeclarativeComponent component(&engine);
     component.setData(componentStr.toUtf8(), QUrl::fromLocalFile(""));
-    QDeclarativeListModel *obj = qobject_cast<QDeclarativeListModel*>(component.create());
+    QObject *obj = component.create();
     QVERIFY(obj != 0);
-    QString prop1 = obj->get(0).property(QLatin1String("prop1")).toString();
+    QString prop1 = obj->property("prop1").toString();
     QCOMPARE(prop1,expect);
-    QString prop2 = obj->get(0).property(QLatin1String("prop2")).toString();
+    QString prop2 = obj->property("prop2").toString();
     QCOMPARE(prop2,expect); // (no, not translated, QT_TR_NOOP is a no-op)
     delete obj;
 }
@@ -180,25 +236,29 @@ void tst_qdeclarativelistmodel::static_nestedElements()
 
     QString componentStr = 
         "import QtQuick 1.0\n"
-        "ListModel {\n"
-        "   ListElement {\n"
-        "       attributes: [\n";
+        "Item {\n"
+        "    property variant count: model.get(0).attributes.count\n"
+        "    ListModel {\n"
+        "        id: model\n"
+        "        ListElement {\n"
+        "            attributes: [\n";
     componentStr += elementsStr.toUtf8().constData();
     componentStr += 
-        "       ]\n"
-        "   }\n"
+        "            ]\n"
+        "        }\n"
+        "    }\n"
         "}";
 
     QDeclarativeEngine engine;
     QDeclarativeComponent component(&engine);
     component.setData(componentStr.toUtf8(), QUrl::fromLocalFile(""));
 
-    QDeclarativeListModel *obj = qobject_cast<QDeclarativeListModel*>(component.create());
+    QObject *obj = component.create();
     QVERIFY(obj != 0);
 
-    QScriptValue prop = obj->get(0).property(QLatin1String("attributes")).property(QLatin1String("count"));
-    QVERIFY(prop.isNumber());
-    QCOMPARE(prop.toInt32(), qint32(elementCount));
+    QVariant count = obj->property("count");
+    QCOMPARE(count.type(), QVariant::Int);
+    QCOMPARE(count.toInt(), elementCount);
 
     delete obj;
 }
@@ -384,8 +444,6 @@ void tst_qdeclarativelistmodel::dynamic_worker()
     qApp->processEvents();
 }
 
-
-
 void tst_qdeclarativelistmodel::dynamic_worker_sync_data()
 {
     dynamic_data();
@@ -438,6 +496,17 @@ void tst_qdeclarativelistmodel::dynamic_worker_sync()
     qApp->processEvents();
 }
 
+#define RUNEVAL(object, string) \
+    QVERIFY(QMetaObject::invokeMethod(object, "runEval", Q_ARG(QVariant, QString(string))));
+
+inline QVariant runexpr(QDeclarativeEngine *engine, const QString &str)
+{
+    QDeclarativeExpression expr(engine->rootContext(), 0, str);
+    return expr.evaluate();
+}
+
+#define RUNEXPR(string) runexpr(&engine, QString(string))
+
 void tst_qdeclarativelistmodel::convertNestedToFlat_fail()
 {
     // If a model has nested data, it cannot be used at all from a worker script
@@ -450,11 +519,9 @@ void tst_qdeclarativelistmodel::convertNestedToFlat_fail()
     QDeclarativeItem *item = createWorkerTest(&eng, &component, &model);
     QVERIFY(item != 0);
 
-    QScriptEngine s_eng;
-    QScriptValue plainData = s_eng.newObject();
-    plainData.setProperty("foo", QScriptValue(123));
-    model.append(plainData);
-    model.append(nestedListValue(&s_eng));
+    RUNEVAL(item, "model.append({foo: 123})");
+    RUNEVAL(item, "model.append({foo: [{}, {}]})");
+
     QCOMPARE(model.count(), 2);
 
     QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML ListModel: List contains list-type data and cannot be used from a worker script");
@@ -482,6 +549,7 @@ void tst_qdeclarativelistmodel::convertNestedToFlat_fail_data()
 }
 
 void tst_qdeclarativelistmodel::convertNestedToFlat_ok()
+
 {
     // If a model only has plain data, it can be modified from a worker script. However,
     // once the model is used from a worker script, it no longer accepts nested data
@@ -494,10 +562,8 @@ void tst_qdeclarativelistmodel::convertNestedToFlat_ok()
     QDeclarativeItem *item = createWorkerTest(&eng, &component, &model);
     QVERIFY(item != 0);
 
-    QScriptEngine s_eng;
-    QScriptValue plainData = s_eng.newObject();
-    plainData.setProperty("foo", QScriptValue(123));
-    model.append(plainData);
+    RUNEVAL(item, "model.append({foo: 123})");
+
     QCOMPARE(model.count(), 1);
 
     QVERIFY(QMetaObject::invokeMethod(item, "evalExpressionViaWorker", Q_ARG(QVariant, script)));
@@ -505,20 +571,21 @@ void tst_qdeclarativelistmodel::convertNestedToFlat_ok()
 
     // can still add plain data
     int count = model.count();
-    model.append(plainData);
+
+    RUNEVAL(item, "model.append({foo: 123})");
+
     QCOMPARE(model.count(), count+1);
 
-    QScriptValue nested = nestedListValue(&s_eng);
     const char *warning = "<Unknown File>: QML ListModel: Cannot add list-type data when modifying or after modification from a worker script";
 
     QTest::ignoreMessage(QtWarningMsg, warning);
-    model.append(nested);
+    RUNEVAL(item, "model.append({foo: [{}, {}]})");
 
     QTest::ignoreMessage(QtWarningMsg, warning);
-    model.insert(0, nested);
+    RUNEVAL(item, "model.insert(0, {foo: [{}, {}]})");
 
     QTest::ignoreMessage(QtWarningMsg, warning);
-    model.set(0, nested);
+    RUNEVAL(item, "model.set(0, {foo: [{}, {}]})");
 
     QCOMPARE(model.count(), count+1);
 
@@ -531,67 +598,6 @@ void tst_qdeclarativelistmodel::convertNestedToFlat_ok_data()
     convertNestedToFlat_fail_data();
 }
 
-void tst_qdeclarativelistmodel::static_types_data()
-{
-    QTest::addColumn<QString>("qml");
-    QTest::addColumn<QVariant>("value");
-
-    QTest::newRow("string")
-        << "ListElement { foo: \"bar\" }"
-        << QVariant(QString("bar"));
-
-    QTest::newRow("real")
-        << "ListElement { foo: 10.5 }"
-        << QVariant(10.5);
-
-    QTest::newRow("real0")
-        << "ListElement { foo: 0 }"
-        << QVariant(double(0));
-
-    QTest::newRow("bool")
-        << "ListElement { foo: false }"
-        << QVariant(false);
-
-    QTest::newRow("bool")
-        << "ListElement { foo: true }"
-        << QVariant(true);
-
-    QTest::newRow("enum")
-        << "ListElement { foo: Text.AlignHCenter }"
-        << QVariant(double(QDeclarativeText::AlignHCenter));
-}
-
-void tst_qdeclarativelistmodel::static_types()
-{
-    QFETCH(QString, qml);
-    QFETCH(QVariant, value);
-
-    qml = "import QtQuick 1.0\nListModel { " + qml + " }";
-
-    QDeclarativeEngine engine;
-    QDeclarativeComponent component(&engine);
-    component.setData(qml.toUtf8(),
-                      QUrl::fromLocalFile(QString("dummy.qml")));
-
-    if (value.toString().startsWith("QTBUG-"))
-        QEXPECT_FAIL("",value.toString().toLatin1(),Abort);
-
-    QVERIFY(!component.isError());
-
-    QDeclarativeListModel *obj = qobject_cast<QDeclarativeListModel*>(component.create());
-    QVERIFY(obj != 0);
-
-    QScriptValue actual = obj->get(0).property(QLatin1String("foo"));
-
-    QCOMPARE(actual.isString(), value.type() == QVariant::String);
-    QCOMPARE(actual.isBoolean(), value.type() == QVariant::Bool);
-    QCOMPARE(actual.isNumber(), value.type() == QVariant::Double);
-
-    QCOMPARE(actual.toString(), value.toString());
-
-    delete obj;
-}
-
 void tst_qdeclarativelistmodel::enumerate()
 {
     QDeclarativeEngine eng;
@@ -608,7 +614,6 @@ void tst_qdeclarativelistmodel::enumerate()
     delete item;
 }
 
-
 void tst_qdeclarativelistmodel::error_data()
 {
     QTest::addColumn<QString>("qml");
@@ -701,21 +706,16 @@ void tst_qdeclarativelistmodel::set()
     QDeclarativeEngine engine;
     QDeclarativeListModel model;
     QDeclarativeEngine::setContextForObject(&model,engine.rootContext());
-    engine.rootContext()->setContextObject(&model);
-    QScriptEngine *seng = QDeclarativeEnginePrivate::getScriptEngine(&engine);
+    engine.rootContext()->setContextProperty("model", &model);
 
-    QScriptValue sv = seng->newObject();
-    sv.setProperty("test", QScriptValue(false));
-    model.append(sv);
+    RUNEXPR("model.append({test:false})");
+    RUNEXPR("model.set(0, {test:true})");
 
-    sv.setProperty("test", QScriptValue(true));
-    model.set(0, sv);
-    QCOMPARE(model.get(0).property("test").toBool(), true); // triggers creation of model cache
+    QCOMPARE(RUNEXPR("model.get(0).test").toBool(), true); // triggers creation of model cache
     QCOMPARE(model.data(0, model.roles()[0]), qVariantFromValue(true)); 
 
-    sv.setProperty("test", QScriptValue(false));
-    model.set(0, sv);
-    QCOMPARE(model.get(0).property("test").toBool(), false); // tests model cache is updated
+    RUNEXPR("model.set(0, {test:false})");
+    QCOMPARE(RUNEXPR("model.get(0).test").toBool(), false); // tests model cache is updated
     QCOMPARE(model.data(0, model.roles()[0]), qVariantFromValue(false)); 
 }
 
@@ -729,8 +729,8 @@ void tst_qdeclarativelistmodel::get()
     QFETCH(QString, roleName);
     QFETCH(QVariant, roleValue);
 
-    QDeclarativeEngine eng;
-    QDeclarativeComponent component(&eng);
+    QDeclarativeEngine engine;
+    QDeclarativeComponent component(&engine);
     component.setData(
         "import QtQuick 1.0\n"
         "ListModel { \n"
@@ -743,7 +743,7 @@ void tst_qdeclarativelistmodel::get()
     QVERIFY(role >= 0);
 
     QSignalSpy spy(model, SIGNAL(itemsChanged(int, int, QList<int>)));
-    QDeclarativeExpression expr(eng.rootContext(), model, expression);
+    QDeclarativeExpression expr(engine.rootContext(), model, expression);
     expr.evaluate();
     QVERIFY(!expr.hasError());
 
@@ -792,17 +792,12 @@ void tst_qdeclarativelistmodel::get_worker()
     QDeclarativeComponent component(&eng, QUrl::fromLocalFile(SRCDIR "/data/model.qml"));
     QDeclarativeItem *item = createWorkerTest(&eng, &component, &model);
     QVERIFY(item != 0);
-    QScriptEngine *seng = QDeclarativeEnginePrivate::getScriptEngine(&eng);
 
     // Add some values like get() test
-    QScriptValue sv = seng->newObject();
-    sv.setProperty(QLatin1String("roleA"), seng->newVariant(QVariant::fromValue(100)));
-    model.append(sv);
-    sv = seng->newObject();
-    sv.setProperty(QLatin1String("roleA"), seng->newVariant(QVariant::fromValue(200)));
-    sv.setProperty(QLatin1String("roleB"), seng->newVariant(QVariant::fromValue(400)));
-    model.append(sv);
-    model.append(sv);
+    RUNEVAL(item, "model.append({roleA: 100})");
+    RUNEVAL(item, "model.append({roleA: 200, roleB: 400})");
+    RUNEVAL(item, "model.append({roleA: 200, roleB: 400})");
+
     int role = roleFromName(&model, roleName);
     QVERIFY(role >= 0);
 
@@ -1055,7 +1050,6 @@ void tst_qdeclarativelistmodel::property_changes_data()
             << "b" << 0 << true << "get(0).b.count == 0";
 }
 
-
 void tst_qdeclarativelistmodel::property_changes_worker()
 {
     // nested models are not supported when WorkerScript is involved
@@ -1108,33 +1102,26 @@ void tst_qdeclarativelistmodel::clear()
     QDeclarativeEngine engine;
     QDeclarativeListModel model;
     QDeclarativeEngine::setContextForObject(&model, engine.rootContext());
-    engine.rootContext()->setContextObject(&model);
-
-    QScriptEngine *seng = QDeclarativeEnginePrivate::getScriptEngine(&engine);
-    QScriptValue sv = seng->newObject();
-    QVariant result;
+    engine.rootContext()->setContextProperty("model", &model);
 
     model.clear();
     QCOMPARE(model.count(), 0);
 
-    sv.setProperty("propertyA", "value a");
-    sv.setProperty("propertyB", "value b");
-    model.append(sv);
+    RUNEXPR("model.append({propertyA: \"value a\", propertyB: \"value b\"})");
     QCOMPARE(model.count(), 1);
 
     model.clear();
     QCOMPARE(model.count(), 0);
 
-    model.append(sv);
-    model.append(sv);
+    RUNEXPR("model.append({propertyA: \"value a\", propertyB: \"value b\"})");
+    RUNEXPR("model.append({propertyA: \"value a\", propertyB: \"value b\"})");
     QCOMPARE(model.count(), 2);
 
     model.clear();
     QCOMPARE(model.count(), 0);
 
     // clearing does not remove the roles
-    sv.setProperty("propertyC", "value c");
-    model.append(sv);
+    RUNEXPR("model.append({propertyA: \"value a\", propertyB: \"value b\", propertyC: \"value c\"})");
     QList<int> roles = model.roles();
     model.clear();
     QCOMPARE(model.count(), 0);