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(); }
indexCache.clear();
methodIndexCache.clear();
stringCache.clear();
- constructor.Dispose();
- constructor = v8::Persistent<v8::Function>();
+ constructor.Dispose();
+ constructor.Clear();
}
QDeclarativePropertyCache::Data QDeclarativePropertyCache::create(const QMetaObject *metaObject,
Q_UNUSED(revision);
constructor.Dispose(); // Now invalid
- constructor = v8::Persistent<v8::Function>();
+ constructor.Clear();
allowedRevisionCache.append(0);
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;
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;
QT_BEGIN_NAMESPACE
QV8Engine::QV8Engine()
-: m_xmlHttpRequestData(0), m_sqlDatabaseData(0)
+: m_xmlHttpRequestData(0), m_sqlDatabaseData(0), m_listModelData(0)
{
}
m_sqlDatabaseData = 0;
qt_rem_qmlxmlhttprequest(this, m_xmlHttpRequestData);
m_xmlHttpRequestData = 0;
+ delete m_listModelData;
+ m_listModelData = 0;
m_getOwnPropertyNames.Dispose(); m_getOwnPropertyNames.Clear();
m_contextWrapper.destroy();
m_stringWrapper.destroy();
m_context.Dispose();
+ m_context.Clear();
}
void QV8Engine::init(QDeclarativeEngine *engine)
case QV8ObjectResource::XMLHttpRequestType:
case QV8ObjectResource::DOMNodeType:
case QV8ObjectResource::SQLDatabaseType:
+ case QV8ObjectResource::ListModelType:
return QVariant();
case QV8ObjectResource::QObjectType:
return qVariantFromValue<QObject *>(m_qobjectWrapper.toQObject(r));
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;
QV8Engine();
~QV8Engine();
+ struct Deletable {
+ ~Deletable() {}
+ };
+
void init(QDeclarativeEngine *);
QDeclarativeEngine *engine() { return m_engine; }
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>);
void *m_xmlHttpRequestData;
void *m_sqlDatabaseData;
+ Deletable *m_listModelData;
QSet<QString> m_illegalNames;
#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);
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) \
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); \
} \
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);
}
}
- if (ep->captureProperties && !result->isConstant()) {
+ if (ep && ep->captureProperties && !result->isConstant()) {
if (result->coreIndex == 0)
ep->capturedProperties << CapturedProperty(QDeclarativeData::get(object, true)->objectNameNotifier());
else
QV8QObjectInstance *instance = (QV8QObjectInstance *)data;
instance->v8object.Clear();
handle.Dispose();
+ handle.Clear();
}
v8::Local<v8::Object> QDeclarativePropertyCache::newQObject(QObject *object, QV8Engine *engine)
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 =
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();
// Match!
connection.thisObject.Dispose();
connection.function.Dispose();
+ connection.thisObject.Clear();
+ connection.function.Clear();
connections.removeAt(ii);
return v8::Undefined();
}
// Match!
connection.thisObject.Dispose();
connection.function.Dispose();
+ connection.thisObject.Clear();
+ connection.function.Clear();
connections.removeAt(ii);
return v8::Undefined();
}
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)
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);
#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
WorkerUint32,
WorkerNumber,
WorkerDate,
- WorkerRegexp
+ WorkerRegexp,
+ WorkerListModel
};
static inline quint32 valueheader(Type type, quint32 size = 0)
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);
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>
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)
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();
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)
{
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;
\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;
}
}
bool ok = m_flat ? m_flat->insert(index, valuemap) : m_nested->insert(index, valuemap);
+
if (ok && !inWorkerThread()) {
emit itemsInserted(index, 1);
emit countChanged();
\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);
}
/*!
\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));
}
/*!
\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);
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;
}
}
if (index == count()) {
- append(valuemap);
+ append(handle);
} else {
if (m_flat)
m_flat->set(index, valuemap, roles);
*/
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)
{
}
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());
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) {
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());
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()) {
}
}
-
-
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)
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)
{
}
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);
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);
}
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));
}
}
}
}
-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))
{
}
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)
{
}
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
#include <private/qlistmodelinterface_p.h>
#include <QtScript/qscriptvalue.h>
+#include <private/qv8engine_p.h>
+
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
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();
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();
QT_MODULE(Declarative)
class QDeclarativeOpenMetaObject;
-class QScriptEngine;
class QDeclarativeListModelWorkerAgent;
struct ModelNode;
class FlatListScriptClass;
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;
};
+#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.
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:
~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:
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);
bool m_ownsRoot;
QDeclarativeListModel *m_listModel;
+ QV8Engine *engine() const;
private:
friend struct ModelNode;
mutable QStringList roleStrings;
{
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);
class ModelNodeMetaObject : public QDeclarativeOpenMetaObject
{
public:
- ModelNodeMetaObject(QScriptEngine *seng, ModelObject *object);
+ ModelNodeMetaObject(QV8Engine *eng, ModelObject *object);
bool m_enabled;
void propertyWritten(int index);
private:
- QScriptEngine *m_seng;
+ QV8Engine *m_engine;
ModelObject *m_obj;
};
-
/*
A ModelNode is created for each item in a NestedListModel.
*/
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();
}
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))
{
}
{
}
-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;
}
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);
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);
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);
#include <QMutex>
#include <QWaitCondition>
+#include <private/qv8engine_p.h>
+
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QDeclarativeListModelWorkerAgent(QDeclarativeListModel *);
~QDeclarativeListModelWorkerAgent();
- void setScriptEngine(QScriptEngine *eng);
- QScriptEngine *scriptEngine() const;
+ void setV8Engine(QV8Engine *eng);
+ QV8Engine *v8engine() const;
void addref();
void release();
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();
private:
friend class QDeclarativeWorkerScriptEnginePrivate;
- friend class FlatListScriptClass;
- QScriptEngine *m_engine;
+ friend class QDeclarativeListModelV8Data;
+ QV8Engine *m_engine;
struct Change {
enum { Inserted, Removed, Moved, Changed } type;
item.done = true
}
}
+
+ function runEval(js) {
+ eval(js);
+ }
}
void property_changes_worker_data();
void clear();
};
+
int tst_qdeclarativelistmodel::roleFromName(const QDeclarativeListModel *model, const QString &roleName)
{
QList<int> roles = model->roles();
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;
}
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;
}
qApp->processEvents();
}
-
-
void tst_qdeclarativelistmodel::dynamic_worker_sync_data()
{
dynamic_data();
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
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");
}
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
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)));
// 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);
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;
delete item;
}
-
void tst_qdeclarativelistmodel::error_data()
{
QTest::addColumn<QString>("qml");
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));
}
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"
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());
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);
<< "b" << 0 << true << "get(0).b.count == 0";
}
-
void tst_qdeclarativelistmodel::property_changes_worker()
{
// nested models are not supported when WorkerScript is involved
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);