Implement ListModel in V8
This commit is contained in:
parent
53085399f5
commit
1325c54974
|
@ -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(); }
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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());
|
||||
ModelNode *value = new ModelNode(m_model);
|
||||
QScriptValue v = it.value();
|
||||
QV8Engine *v8engine = m_model->engine();
|
||||
|
||||
if (v.isArray()) {
|
||||
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);
|
||||
|
||||
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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -19,4 +19,8 @@ Item {
|
|||
item.done = true
|
||||
}
|
||||
}
|
||||
|
||||
function runEval(js) {
|
||||
eval(js);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue