/**************************************************************************** | |
** | |
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). | |
** All rights reserved. | |
** Contact: Nokia Corporation (qt-info@nokia.com) | |
** | |
** This file is part of the QtDeclarative module of the Qt Toolkit. | |
** | |
** $QT_BEGIN_LICENSE:LGPL$ | |
** GNU Lesser General Public License Usage | |
** This file may be used under the terms of the GNU Lesser General Public | |
** License version 2.1 as published by the Free Software Foundation and | |
** appearing in the file LICENSE.LGPL included in the packaging of this | |
** file. Please review the following information to ensure the GNU Lesser | |
** General Public License version 2.1 requirements will be met: | |
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. | |
** | |
** In addition, as a special exception, Nokia gives you certain additional | |
** rights. These rights are described in the Nokia Qt LGPL Exception | |
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. | |
** | |
** GNU General Public License Usage | |
** Alternatively, this file may be used under the terms of the GNU General | |
** Public License version 3.0 as published by the Free Software Foundation | |
** and appearing in the file LICENSE.GPL included in the packaging of this | |
** file. Please review the following information to ensure the GNU General | |
** Public License version 3.0 requirements will be met: | |
** http://www.gnu.org/copyleft/gpl.html. | |
** | |
** Other Usage | |
** Alternatively, this file may be used in accordance with the terms and | |
** conditions contained in a signed written agreement between you and Nokia. | |
** | |
** | |
** | |
** | |
** | |
** $QT_END_LICENSE$ | |
** | |
****************************************************************************/ | |
#include "private/qdeclarativevme_p.h" | |
#include "private/qdeclarativecompiler_p.h" | |
#include "private/qdeclarativeboundsignal_p.h" | |
#include "private/qdeclarativestringconverters_p.h" | |
#include "private/qmetaobjectbuilder_p.h" | |
#include "private/qdeclarativedata_p.h" | |
#include "qdeclarative.h" | |
#include "private/qdeclarativecustomparser_p.h" | |
#include "qdeclarativeengine.h" | |
#include "qdeclarativecontext.h" | |
#include "qdeclarativecomponent.h" | |
#include "private/qdeclarativebinding_p.h" | |
#include "private/qdeclarativeengine_p.h" | |
#include "private/qdeclarativecomponent_p.h" | |
#include "private/qdeclarativevmemetaobject_p.h" | |
#include "private/qdeclarativebinding_p_p.h" | |
#include "private/qdeclarativecontext_p.h" | |
#include "private/qdeclarativecompiledbindings_p.h" | |
#include "private/qdeclarativeglobal_p.h" | |
#include "qdeclarativescriptstring.h" | |
#include <QStack> | |
#include <QWidget> | |
#include <QColor> | |
#include <QPointF> | |
#include <QSizeF> | |
#include <QRectF> | |
#include <QtCore/qdebug.h> | |
#include <QtCore/qvarlengtharray.h> | |
#include <QtCore/qcoreapplication.h> | |
#include <QtCore/qdatetime.h> | |
QT_BEGIN_NAMESPACE | |
QDeclarativeVME::QDeclarativeVME() | |
{ | |
} | |
#define VME_EXCEPTION(desc) \ | |
{ \ | |
QDeclarativeError error; \ | |
error.setDescription(desc.trimmed()); \ | |
error.setLine(instr.line); \ | |
error.setUrl(comp->url); \ | |
vmeErrors << error; \ | |
break; \ | |
} | |
struct ListInstance | |
{ | |
ListInstance() | |
: type(0) {} | |
ListInstance(int t) | |
: type(t) {} | |
int type; | |
QDeclarativeListProperty<void> qListProperty; | |
}; | |
QObject *QDeclarativeVME::run(QDeclarativeContextData *ctxt, QDeclarativeCompiledData *comp, | |
int start, int count, const QBitField &bindingSkipList) | |
{ | |
QDeclarativeVMEStack<QObject *> stack; | |
if (start == -1) start = 0; | |
if (count == -1) count = comp->bytecode.count(); | |
return run(stack, ctxt, comp, start, count, bindingSkipList); | |
} | |
void QDeclarativeVME::runDeferred(QObject *object) | |
{ | |
QDeclarativeData *data = QDeclarativeData::get(object); | |
if (!data || !data->context || !data->deferredComponent) | |
return; | |
QDeclarativeContextData *ctxt = data->context; | |
QDeclarativeCompiledData *comp = data->deferredComponent; | |
int start = data->deferredIdx + 1; | |
int count = data->deferredComponent->bytecode.at(data->deferredIdx).defer.deferCount; | |
QDeclarativeVMEStack<QObject *> stack; | |
stack.push(object); | |
run(stack, ctxt, comp, start, count, QBitField()); | |
} | |
inline bool fastHasBinding(QObject *o, int index) | |
{ | |
QDeclarativeData *ddata = static_cast<QDeclarativeData *>(QObjectPrivate::get(o)->declarativeData); | |
return ddata && (ddata->bindingBitsSize > index) && | |
(ddata->bindingBits[index / 32] & (1 << (index % 32))); | |
} | |
static void removeBindingOnProperty(QObject *o, int index) | |
{ | |
QDeclarativeAbstractBinding *binding = QDeclarativePropertyPrivate::setBinding(o, index, -1, 0); | |
if (binding) binding->destroy(); | |
} | |
#define CLEAN_PROPERTY(o, index) if (fastHasBinding(o, index)) removeBindingOnProperty(o, index) | |
QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, | |
QDeclarativeContextData *ctxt, | |
QDeclarativeCompiledData *comp, | |
int start, int count, | |
const QBitField &bindingSkipList) | |
{ | |
Q_ASSERT(comp); | |
Q_ASSERT(ctxt); | |
const QList<QDeclarativeCompiledData::TypeReference> &types = comp->types; | |
const QList<QString> &primitives = comp->primitives; | |
const QList<QByteArray> &datas = comp->datas; | |
const QList<QDeclarativeCompiledData::CustomTypeData> &customTypeData = comp->customTypeData; | |
const QList<int> &intData = comp->intData; | |
const QList<float> &floatData = comp->floatData; | |
const QList<QDeclarativePropertyCache *> &propertyCaches = comp->propertyCaches; | |
const QList<QDeclarativeParser::Object::ScriptBlock> &scripts = comp->scripts; | |
const QList<QUrl> &urls = comp->urls; | |
QDeclarativeEnginePrivate::SimpleList<QDeclarativeAbstractBinding> bindValues; | |
QDeclarativeEnginePrivate::SimpleList<QDeclarativeParserStatus> parserStatus; | |
QDeclarativeVMEStack<ListInstance> qliststack; | |
vmeErrors.clear(); | |
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(ctxt->engine); | |
int status = -1; //for dbus | |
QDeclarativePropertyPrivate::WriteFlags flags = QDeclarativePropertyPrivate::BypassInterceptor | | |
QDeclarativePropertyPrivate::RemoveBindingOnAliasWrite; | |
for (int ii = start; !isError() && ii < (start + count); ++ii) { | |
const QDeclarativeInstruction &instr = comp->bytecode.at(ii); | |
switch(instr.type) { | |
case QDeclarativeInstruction::Init: | |
{ | |
if (instr.init.bindingsSize) | |
bindValues = QDeclarativeEnginePrivate::SimpleList<QDeclarativeAbstractBinding>(instr.init.bindingsSize); | |
if (instr.init.parserStatusSize) | |
parserStatus = QDeclarativeEnginePrivate::SimpleList<QDeclarativeParserStatus>(instr.init.parserStatusSize); | |
if (instr.init.contextCache != -1) | |
ctxt->setIdPropertyData(comp->contextCaches.at(instr.init.contextCache)); | |
if (instr.init.compiledBinding != -1) | |
ctxt->optimizedBindings = new QDeclarativeCompiledBindings(datas.at(instr.init.compiledBinding).constData(), ctxt); | |
} | |
break; | |
case QDeclarativeInstruction::CreateObject: | |
{ | |
QBitField bindings; | |
if (instr.create.bindingBits != -1) { | |
const QByteArray &bits = datas.at(instr.create.bindingBits); | |
bindings = QBitField((const quint32*)bits.constData(), | |
bits.size() * 8); | |
} | |
if (stack.isEmpty()) | |
bindings = bindings.united(bindingSkipList); | |
QObject *o = | |
types.at(instr.create.type).createInstance(ctxt, bindings, &vmeErrors); | |
if (!o) { | |
VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Unable to create object of type %1").arg(QString::fromLatin1(types.at(instr.create.type).className))); | |
} | |
QDeclarativeData *ddata = QDeclarativeData::get(o); | |
Q_ASSERT(ddata); | |
if (stack.isEmpty()) { | |
if (ddata->context) { | |
Q_ASSERT(ddata->context != ctxt); | |
Q_ASSERT(ddata->outerContext); | |
Q_ASSERT(ddata->outerContext != ctxt); | |
QDeclarativeContextData *c = ddata->context; | |
while (c->linkedContext) c = c->linkedContext; | |
c->linkedContext = ctxt; | |
} else { | |
ctxt->addObject(o); | |
} | |
ddata->ownContext = true; | |
} else if (!ddata->context) { | |
ctxt->addObject(o); | |
} | |
ddata->setImplicitDestructible(); | |
ddata->outerContext = ctxt; | |
ddata->lineNumber = instr.line; | |
ddata->columnNumber = instr.create.column; | |
if (instr.create.data != -1) { | |
QDeclarativeCustomParser *customParser = | |
types.at(instr.create.type).type->customParser(); | |
customParser->setCustomData(o, datas.at(instr.create.data)); | |
} | |
if (!stack.isEmpty()) { | |
QObject *parent = stack.top(); | |
if (o->isWidgetType()) { | |
QWidget *widget = static_cast<QWidget*>(o); | |
if (parent->isWidgetType()) { | |
QWidget *parentWidget = static_cast<QWidget*>(parent); | |
widget->setParent(parentWidget); | |
} else { | |
// TODO: parent might be a layout | |
} | |
} else { | |
QDeclarative_setParent_noEvent(o, parent); | |
} | |
} | |
stack.push(o); | |
} | |
break; | |
case QDeclarativeInstruction::CreateSimpleObject: | |
{ | |
QObject *o = (QObject *)operator new(instr.createSimple.typeSize + | |
sizeof(QDeclarativeData)); | |
::memset(o, 0, instr.createSimple.typeSize + sizeof(QDeclarativeData)); | |
instr.createSimple.create(o); | |
QDeclarativeData *ddata = (QDeclarativeData *)(((const char *)o) + instr.createSimple.typeSize); | |
const QDeclarativeCompiledData::TypeReference &ref = types.at(instr.createSimple.type); | |
if (!ddata->propertyCache && ref.typePropertyCache) { | |
ddata->propertyCache = ref.typePropertyCache; | |
ddata->propertyCache->addref(); | |
} | |
ddata->lineNumber = instr.line; | |
ddata->columnNumber = instr.createSimple.column; | |
QObjectPrivate::get(o)->declarativeData = ddata; | |
ddata->context = ddata->outerContext = ctxt; | |
ddata->nextContextObject = ctxt->contextObjects; | |
if (ddata->nextContextObject) | |
ddata->nextContextObject->prevContextObject = &ddata->nextContextObject; | |
ddata->prevContextObject = &ctxt->contextObjects; | |
ctxt->contextObjects = ddata; | |
QObject *parent = stack.top(); | |
QDeclarative_setParent_noEvent(o, parent); | |
stack.push(o); | |
} | |
break; | |
case QDeclarativeInstruction::SetId: | |
{ | |
QObject *target = stack.top(); | |
ctxt->setIdProperty(instr.setId.index, target); | |
} | |
break; | |
case QDeclarativeInstruction::SetDefault: | |
{ | |
ctxt->contextObject = stack.top(); | |
} | |
break; | |
case QDeclarativeInstruction::CreateComponent: | |
{ | |
QDeclarativeComponent *qcomp = | |
new QDeclarativeComponent(ctxt->engine, comp, ii + 1, instr.createComponent.count, | |
stack.isEmpty() ? 0 : stack.top()); | |
QDeclarativeData *ddata = QDeclarativeData::get(qcomp, true); | |
Q_ASSERT(ddata); | |
ctxt->addObject(qcomp); | |
if (stack.isEmpty()) | |
ddata->ownContext = true; | |
ddata->setImplicitDestructible(); | |
ddata->outerContext = ctxt; | |
ddata->lineNumber = instr.line; | |
ddata->columnNumber = instr.create.column; | |
QDeclarativeComponentPrivate::get(qcomp)->creationContext = ctxt; | |
stack.push(qcomp); | |
ii += instr.createComponent.count; | |
} | |
break; | |
case QDeclarativeInstruction::StoreMetaObject: | |
{ | |
QObject *target = stack.top(); | |
QMetaObject mo; | |
const QByteArray &metadata = datas.at(instr.storeMeta.data); | |
QMetaObjectBuilder::fromRelocatableData(&mo, 0, metadata); | |
const QDeclarativeVMEMetaData *data = | |
(const QDeclarativeVMEMetaData *)datas.at(instr.storeMeta.aliasData).constData(); | |
(void)new QDeclarativeVMEMetaObject(target, &mo, data, comp); | |
if (instr.storeMeta.propertyCache != -1) { | |
QDeclarativeData *ddata = QDeclarativeData::get(target, true); | |
if (ddata->propertyCache) ddata->propertyCache->release(); | |
ddata->propertyCache = propertyCaches.at(instr.storeMeta.propertyCache); | |
ddata->propertyCache->addref(); | |
} | |
} | |
break; | |
case QDeclarativeInstruction::StoreVariant: | |
{ | |
QObject *target = stack.top(); | |
CLEAN_PROPERTY(target, instr.storeString.propertyIndex); | |
// XXX - can be more efficient | |
QVariant v = QDeclarativeStringConverters::variantFromString(primitives.at(instr.storeString.value)); | |
void *a[] = { &v, 0, &status, &flags }; | |
QMetaObject::metacall(target, QMetaObject::WriteProperty, | |
instr.storeString.propertyIndex, a); | |
} | |
break; | |
case QDeclarativeInstruction::StoreVariantInteger: | |
{ | |
QObject *target = stack.top(); | |
CLEAN_PROPERTY(target, instr.storeString.propertyIndex); | |
QVariant v(instr.storeInteger.value); | |
void *a[] = { &v, 0, &status, &flags }; | |
QMetaObject::metacall(target, QMetaObject::WriteProperty, | |
instr.storeString.propertyIndex, a); | |
} | |
break; | |
case QDeclarativeInstruction::StoreVariantDouble: | |
{ | |
QObject *target = stack.top(); | |
CLEAN_PROPERTY(target, instr.storeString.propertyIndex); | |
QVariant v(instr.storeDouble.value); | |
void *a[] = { &v, 0, &status, &flags }; | |
QMetaObject::metacall(target, QMetaObject::WriteProperty, | |
instr.storeString.propertyIndex, a); | |
} | |
break; | |
case QDeclarativeInstruction::StoreVariantBool: | |
{ | |
QObject *target = stack.top(); | |
CLEAN_PROPERTY(target, instr.storeString.propertyIndex); | |
QVariant v(instr.storeBool.value); | |
void *a[] = { &v, 0, &status, &flags }; | |
QMetaObject::metacall(target, QMetaObject::WriteProperty, | |
instr.storeString.propertyIndex, a); | |
} | |
break; | |
case QDeclarativeInstruction::StoreString: | |
{ | |
QObject *target = stack.top(); | |
CLEAN_PROPERTY(target, instr.storeString.propertyIndex); | |
void *a[] = { (void *)&primitives.at(instr.storeString.value), 0, &status, &flags }; | |
QMetaObject::metacall(target, QMetaObject::WriteProperty, | |
instr.storeString.propertyIndex, a); | |
} | |
break; | |
case QDeclarativeInstruction::StoreUrl: | |
{ | |
QObject *target = stack.top(); | |
CLEAN_PROPERTY(target, instr.storeUrl.propertyIndex); | |
void *a[] = { (void *)&urls.at(instr.storeUrl.value), 0, &status, &flags }; | |
QMetaObject::metacall(target, QMetaObject::WriteProperty, | |
instr.storeUrl.propertyIndex, a); | |
} | |
break; | |
case QDeclarativeInstruction::StoreFloat: | |
{ | |
QObject *target = stack.top(); | |
CLEAN_PROPERTY(target, instr.storeFloat.propertyIndex); | |
float f = instr.storeFloat.value; | |
void *a[] = { &f, 0, &status, &flags }; | |
QMetaObject::metacall(target, QMetaObject::WriteProperty, | |
instr.storeFloat.propertyIndex, a); | |
} | |
break; | |
case QDeclarativeInstruction::StoreDouble: | |
{ | |
QObject *target = stack.top(); | |
CLEAN_PROPERTY(target, instr.storeDouble.propertyIndex); | |
double d = instr.storeDouble.value; | |
void *a[] = { &d, 0, &status, &flags }; | |
QMetaObject::metacall(target, QMetaObject::WriteProperty, | |
instr.storeDouble.propertyIndex, a); | |
} | |
break; | |
case QDeclarativeInstruction::StoreBool: | |
{ | |
QObject *target = stack.top(); | |
CLEAN_PROPERTY(target, instr.storeBool.propertyIndex); | |
void *a[] = { (void *)&instr.storeBool.value, 0, &status, &flags }; | |
QMetaObject::metacall(target, QMetaObject::WriteProperty, | |
instr.storeBool.propertyIndex, a); | |
} | |
break; | |
case QDeclarativeInstruction::StoreInteger: | |
{ | |
QObject *target = stack.top(); | |
CLEAN_PROPERTY(target, instr.storeInteger.propertyIndex); | |
void *a[] = { (void *)&instr.storeInteger.value, 0, &status, &flags }; | |
QMetaObject::metacall(target, QMetaObject::WriteProperty, | |
instr.storeInteger.propertyIndex, a); | |
} | |
break; | |
case QDeclarativeInstruction::StoreColor: | |
{ | |
QObject *target = stack.top(); | |
CLEAN_PROPERTY(target, instr.storeColor.propertyIndex); | |
QColor c = QColor::fromRgba(instr.storeColor.value); | |
void *a[] = { &c, 0, &status, &flags }; | |
QMetaObject::metacall(target, QMetaObject::WriteProperty, | |
instr.storeColor.propertyIndex, a); | |
} | |
break; | |
case QDeclarativeInstruction::StoreDate: | |
{ | |
QObject *target = stack.top(); | |
CLEAN_PROPERTY(target, instr.storeDate.propertyIndex); | |
QDate d = QDate::fromJulianDay(instr.storeDate.value); | |
void *a[] = { &d, 0, &status, &flags }; | |
QMetaObject::metacall(target, QMetaObject::WriteProperty, | |
instr.storeDate.propertyIndex, a); | |
} | |
break; | |
case QDeclarativeInstruction::StoreTime: | |
{ | |
QObject *target = stack.top(); | |
CLEAN_PROPERTY(target, instr.storeTime.propertyIndex); | |
QTime t; | |
t.setHMS(intData.at(instr.storeTime.valueIndex), | |
intData.at(instr.storeTime.valueIndex+1), | |
intData.at(instr.storeTime.valueIndex+2), | |
intData.at(instr.storeTime.valueIndex+3)); | |
void *a[] = { &t, 0, &status, &flags }; | |
QMetaObject::metacall(target, QMetaObject::WriteProperty, | |
instr.storeTime.propertyIndex, a); | |
} | |
break; | |
case QDeclarativeInstruction::StoreDateTime: | |
{ | |
QObject *target = stack.top(); | |
CLEAN_PROPERTY(target, instr.storeDateTime.propertyIndex); | |
QTime t; | |
t.setHMS(intData.at(instr.storeDateTime.valueIndex+1), | |
intData.at(instr.storeDateTime.valueIndex+2), | |
intData.at(instr.storeDateTime.valueIndex+3), | |
intData.at(instr.storeDateTime.valueIndex+4)); | |
QDateTime dt(QDate::fromJulianDay(intData.at(instr.storeDateTime.valueIndex)), t); | |
void *a[] = { &dt, 0, &status, &flags }; | |
QMetaObject::metacall(target, QMetaObject::WriteProperty, | |
instr.storeDateTime.propertyIndex, a); | |
} | |
break; | |
case QDeclarativeInstruction::StorePoint: | |
{ | |
QObject *target = stack.top(); | |
CLEAN_PROPERTY(target, instr.storeRealPair.propertyIndex); | |
QPoint p = QPointF(floatData.at(instr.storeRealPair.valueIndex), | |
floatData.at(instr.storeRealPair.valueIndex+1)).toPoint(); | |
void *a[] = { &p, 0, &status, &flags }; | |
QMetaObject::metacall(target, QMetaObject::WriteProperty, | |
instr.storeRealPair.propertyIndex, a); | |
} | |
break; | |
case QDeclarativeInstruction::StorePointF: | |
{ | |
QObject *target = stack.top(); | |
CLEAN_PROPERTY(target, instr.storeRealPair.propertyIndex); | |
QPointF p(floatData.at(instr.storeRealPair.valueIndex), | |
floatData.at(instr.storeRealPair.valueIndex+1)); | |
void *a[] = { &p, 0, &status, &flags }; | |
QMetaObject::metacall(target, QMetaObject::WriteProperty, | |
instr.storeRealPair.propertyIndex, a); | |
} | |
break; | |
case QDeclarativeInstruction::StoreSize: | |
{ | |
QObject *target = stack.top(); | |
CLEAN_PROPERTY(target, instr.storeRealPair.propertyIndex); | |
QSize p = QSizeF(floatData.at(instr.storeRealPair.valueIndex), | |
floatData.at(instr.storeRealPair.valueIndex+1)).toSize(); | |
void *a[] = { &p, 0, &status, &flags }; | |
QMetaObject::metacall(target, QMetaObject::WriteProperty, | |
instr.storeRealPair.propertyIndex, a); | |
} | |
break; | |
case QDeclarativeInstruction::StoreSizeF: | |
{ | |
QObject *target = stack.top(); | |
CLEAN_PROPERTY(target, instr.storeRealPair.propertyIndex); | |
QSizeF s(floatData.at(instr.storeRealPair.valueIndex), | |
floatData.at(instr.storeRealPair.valueIndex+1)); | |
void *a[] = { &s, 0, &status, &flags }; | |
QMetaObject::metacall(target, QMetaObject::WriteProperty, | |
instr.storeRealPair.propertyIndex, a); | |
} | |
break; | |
case QDeclarativeInstruction::StoreRect: | |
{ | |
QObject *target = stack.top(); | |
CLEAN_PROPERTY(target, instr.storeRect.propertyIndex); | |
QRect r = QRectF(floatData.at(instr.storeRect.valueIndex), | |
floatData.at(instr.storeRect.valueIndex+1), | |
floatData.at(instr.storeRect.valueIndex+2), | |
floatData.at(instr.storeRect.valueIndex+3)).toRect(); | |
void *a[] = { &r, 0, &status, &flags }; | |
QMetaObject::metacall(target, QMetaObject::WriteProperty, | |
instr.storeRect.propertyIndex, a); | |
} | |
break; | |
case QDeclarativeInstruction::StoreRectF: | |
{ | |
QObject *target = stack.top(); | |
CLEAN_PROPERTY(target, instr.storeRect.propertyIndex); | |
QRectF r(floatData.at(instr.storeRect.valueIndex), | |
floatData.at(instr.storeRect.valueIndex+1), | |
floatData.at(instr.storeRect.valueIndex+2), | |
floatData.at(instr.storeRect.valueIndex+3)); | |
void *a[] = { &r, 0, &status, &flags }; | |
QMetaObject::metacall(target, QMetaObject::WriteProperty, | |
instr.storeRect.propertyIndex, a); | |
} | |
break; | |
case QDeclarativeInstruction::StoreVector3D: | |
{ | |
QObject *target = stack.top(); | |
CLEAN_PROPERTY(target, instr.storeVector3D.propertyIndex); | |
QVector3D p(floatData.at(instr.storeVector3D.valueIndex), | |
floatData.at(instr.storeVector3D.valueIndex+1), | |
floatData.at(instr.storeVector3D.valueIndex+2)); | |
void *a[] = { &p, 0, &status, &flags }; | |
QMetaObject::metacall(target, QMetaObject::WriteProperty, | |
instr.storeVector3D.propertyIndex, a); | |
} | |
break; | |
case QDeclarativeInstruction::StoreObject: | |
{ | |
QObject *assignObj = stack.pop(); | |
QObject *target = stack.top(); | |
CLEAN_PROPERTY(target, instr.storeObject.propertyIndex); | |
void *a[] = { (void *)&assignObj, 0, &status, &flags }; | |
QMetaObject::metacall(target, QMetaObject::WriteProperty, | |
instr.storeObject.propertyIndex, a); | |
} | |
break; | |
case QDeclarativeInstruction::AssignCustomType: | |
{ | |
QObject *target = stack.top(); | |
CLEAN_PROPERTY(target, instr.assignCustomType.propertyIndex); | |
QDeclarativeCompiledData::CustomTypeData data = customTypeData.at(instr.assignCustomType.valueIndex); | |
const QString &primitive = primitives.at(data.index); | |
QDeclarativeMetaType::StringConverter converter = | |
QDeclarativeMetaType::customStringConverter(data.type); | |
QVariant v = (*converter)(primitive); | |
QMetaProperty prop = | |
target->metaObject()->property(instr.assignCustomType.propertyIndex); | |
if (v.isNull() || ((int)prop.type() != data.type && prop.userType() != data.type)) | |
VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot assign value %1 to property %2").arg(primitive).arg(QString::fromUtf8(prop.name()))); | |
void *a[] = { (void *)v.data(), 0, &status, &flags }; | |
QMetaObject::metacall(target, QMetaObject::WriteProperty, | |
instr.assignCustomType.propertyIndex, a); | |
} | |
break; | |
case QDeclarativeInstruction::AssignSignalObject: | |
{ | |
// XXX optimize | |
QObject *assign = stack.pop(); | |
QObject *target = stack.top(); | |
int sigIdx = instr.assignSignalObject.signal; | |
const QByteArray &pr = datas.at(sigIdx); | |
QDeclarativeProperty prop(target, QString::fromUtf8(pr)); | |
if (prop.type() & QDeclarativeProperty::SignalProperty) { | |
QMetaMethod method = QDeclarativeMetaType::defaultMethod(assign); | |
if (method.signature() == 0) | |
VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot assign object type %1 with no default method").arg(QString::fromLatin1(assign->metaObject()->className()))); | |
if (!QMetaObject::checkConnectArgs(prop.method().signature(), method.signature())) | |
VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot connect mismatched signal/slot %1 %vs. %2").arg(QString::fromLatin1(method.signature())).arg(QString::fromLatin1(prop.method().signature()))); | |
QDeclarativePropertyPrivate::connect(target, prop.index(), assign, method.methodIndex()); | |
} else { | |
VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot assign an object to signal property %1").arg(QString::fromUtf8(pr))); | |
} | |
} | |
break; | |
case QDeclarativeInstruction::StoreSignal: | |
{ | |
QObject *target = stack.top(); | |
QObject *context = stack.at(stack.count() - 1 - instr.storeSignal.context); | |
QMetaMethod signal = target->metaObject()->method(instr.storeSignal.signalIndex); | |
QDeclarativeBoundSignal *bs = new QDeclarativeBoundSignal(target, signal, target); | |
QDeclarativeExpression *expr = | |
new QDeclarativeExpression(ctxt, context, primitives.at(instr.storeSignal.value)); | |
expr->setSourceLocation(comp->name, instr.line); | |
static_cast<QDeclarativeExpressionPrivate *>(QObjectPrivate::get(expr))->name = datas.at(instr.storeSignal.name); | |
bs->setExpression(expr); | |
} | |
break; | |
case QDeclarativeInstruction::StoreImportedScript: | |
{ | |
ctxt->addImportedScript(scripts.at(instr.storeScript.value)); | |
} | |
break; | |
case QDeclarativeInstruction::StoreScriptString: | |
{ | |
QObject *target = stack.top(); | |
QObject *scope = stack.at(stack.count() - 1 - instr.storeScriptString.scope); | |
QDeclarativeScriptString ss; | |
ss.setContext(ctxt->asQDeclarativeContext()); | |
ss.setScopeObject(scope); | |
ss.setScript(primitives.at(instr.storeScriptString.value)); | |
void *a[] = { &ss, 0, &status, &flags }; | |
QMetaObject::metacall(target, QMetaObject::WriteProperty, | |
instr.storeScriptString.propertyIndex, a); | |
} | |
break; | |
case QDeclarativeInstruction::BeginObject: | |
{ | |
QObject *target = stack.top(); | |
QDeclarativeParserStatus *status = reinterpret_cast<QDeclarativeParserStatus *>(reinterpret_cast<char *>(target) + instr.begin.castValue); | |
parserStatus.append(status); | |
status->d = &parserStatus.values[parserStatus.count - 1]; | |
status->classBegin(); | |
} | |
break; | |
case QDeclarativeInstruction::StoreBinding: | |
case QDeclarativeInstruction::StoreBindingOnAlias: | |
{ | |
QObject *target = | |
stack.at(stack.count() - 1 - instr.assignBinding.owner); | |
QObject *context = | |
stack.at(stack.count() - 1 - instr.assignBinding.context); | |
QDeclarativeProperty mp = | |
QDeclarativePropertyPrivate::restore(datas.at(instr.assignBinding.property), target, ctxt); | |
int coreIndex = mp.index(); | |
if ((stack.count() - instr.assignBinding.owner) == 1 && bindingSkipList.testBit(coreIndex)) | |
break; | |
QDeclarativeBinding *bind = new QDeclarativeBinding((void *)datas.at(instr.assignBinding.value).constData(), comp, context, ctxt, comp->name, instr.line, 0); | |
bindValues.append(bind); | |
bind->m_mePtr = &bindValues.values[bindValues.count - 1]; | |
bind->setTarget(mp); | |
if (instr.type == QDeclarativeInstruction::StoreBindingOnAlias) { | |
QDeclarativeAbstractBinding *old = QDeclarativePropertyPrivate::setBindingNoEnable(target, coreIndex, QDeclarativePropertyPrivate::valueTypeCoreIndex(mp), bind); | |
if (old) { old->destroy(); } | |
} else { | |
bind->addToObject(target, QDeclarativePropertyPrivate::bindingIndex(mp)); | |
} | |
} | |
break; | |
case QDeclarativeInstruction::StoreCompiledBinding: | |
{ | |
QObject *target = | |
stack.at(stack.count() - 1 - instr.assignBinding.owner); | |
QObject *scope = | |
stack.at(stack.count() - 1 - instr.assignBinding.context); | |
int property = instr.assignBinding.property; | |
if (stack.count() == 1 && bindingSkipList.testBit(property & 0xFFFF)) | |
break; | |
QDeclarativeAbstractBinding *binding = | |
ctxt->optimizedBindings->configBinding(instr.assignBinding.value, target, scope, property); | |
bindValues.append(binding); | |
binding->m_mePtr = &bindValues.values[bindValues.count - 1]; | |
binding->addToObject(target, property); | |
} | |
break; | |
case QDeclarativeInstruction::StoreValueSource: | |
{ | |
QObject *obj = stack.pop(); | |
QDeclarativePropertyValueSource *vs = reinterpret_cast<QDeclarativePropertyValueSource *>(reinterpret_cast<char *>(obj) + instr.assignValueSource.castValue); | |
QObject *target = stack.at(stack.count() - 1 - instr.assignValueSource.owner); | |
QDeclarativeProperty prop = | |
QDeclarativePropertyPrivate::restore(datas.at(instr.assignValueSource.property), target, ctxt); | |
obj->setParent(target); | |
vs->setTarget(prop); | |
} | |
break; | |
case QDeclarativeInstruction::StoreValueInterceptor: | |
{ | |
QObject *obj = stack.pop(); | |
QDeclarativePropertyValueInterceptor *vi = reinterpret_cast<QDeclarativePropertyValueInterceptor *>(reinterpret_cast<char *>(obj) + instr.assignValueInterceptor.castValue); | |
QObject *target = stack.at(stack.count() - 1 - instr.assignValueInterceptor.owner); | |
QDeclarativeProperty prop = | |
QDeclarativePropertyPrivate::restore(datas.at(instr.assignValueInterceptor.property), target, ctxt); | |
obj->setParent(target); | |
vi->setTarget(prop); | |
QDeclarativeVMEMetaObject *mo = static_cast<QDeclarativeVMEMetaObject *>((QMetaObject*)target->metaObject()); | |
mo->registerInterceptor(prop.index(), QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), vi); | |
} | |
break; | |
case QDeclarativeInstruction::StoreObjectQList: | |
{ | |
QObject *assign = stack.pop(); | |
const ListInstance &list = qliststack.top(); | |
list.qListProperty.append((QDeclarativeListProperty<void>*)&list.qListProperty, assign); | |
} | |
break; | |
case QDeclarativeInstruction::AssignObjectList: | |
{ | |
// This is only used for assigning interfaces | |
QObject *assign = stack.pop(); | |
const ListInstance &list = qliststack.top(); | |
int type = list.type; | |
void *ptr = 0; | |
const char *iid = QDeclarativeMetaType::interfaceIId(type); | |
if (iid) | |
ptr = assign->qt_metacast(iid); | |
if (!ptr) | |
VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot assign object to list")); | |
list.qListProperty.append((QDeclarativeListProperty<void>*)&list.qListProperty, ptr); | |
} | |
break; | |
case QDeclarativeInstruction::StoreVariantObject: | |
{ | |
QObject *assign = stack.pop(); | |
QObject *target = stack.top(); | |
CLEAN_PROPERTY(target, instr.storeObject.propertyIndex); | |
QVariant v = QVariant::fromValue(assign); | |
void *a[] = { &v, 0, &status, &flags }; | |
QMetaObject::metacall(target, QMetaObject::WriteProperty, | |
instr.storeObject.propertyIndex, a); | |
} | |
break; | |
case QDeclarativeInstruction::StoreInterface: | |
{ | |
QObject *assign = stack.pop(); | |
QObject *target = stack.top(); | |
CLEAN_PROPERTY(target, instr.storeObject.propertyIndex); | |
int coreIdx = instr.storeObject.propertyIndex; | |
QMetaProperty prop = target->metaObject()->property(coreIdx); | |
int t = prop.userType(); | |
const char *iid = QDeclarativeMetaType::interfaceIId(t); | |
bool ok = false; | |
if (iid) { | |
void *ptr = assign->qt_metacast(iid); | |
if (ptr) { | |
void *a[] = { &ptr, 0, &status, &flags }; | |
QMetaObject::metacall(target, | |
QMetaObject::WriteProperty, | |
coreIdx, a); | |
ok = true; | |
} | |
} | |
if (!ok) | |
VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot assign object to interface property")); | |
} | |
break; | |
case QDeclarativeInstruction::FetchAttached: | |
{ | |
QObject *target = stack.top(); | |
QObject *qmlObject = qmlAttachedPropertiesObjectById(instr.fetchAttached.id, target); | |
if (!qmlObject) | |
VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Unable to create attached object")); | |
stack.push(qmlObject); | |
} | |
break; | |
case QDeclarativeInstruction::FetchQList: | |
{ | |
QObject *target = stack.top(); | |
qliststack.push(ListInstance(instr.fetchQmlList.type)); | |
void *a[1]; | |
a[0] = (void *)&(qliststack.top().qListProperty); | |
QMetaObject::metacall(target, QMetaObject::ReadProperty, | |
instr.fetchQmlList.property, a); | |
} | |
break; | |
case QDeclarativeInstruction::FetchObject: | |
{ | |
QObject *target = stack.top(); | |
QObject *obj = 0; | |
// NOTE: This assumes a cast to QObject does not alter the | |
// object pointer | |
void *a[1]; | |
a[0] = &obj; | |
QMetaObject::metacall(target, QMetaObject::ReadProperty, | |
instr.fetch.property, a); | |
if (!obj) | |
VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot set properties on %1 as it is null").arg(QString::fromUtf8(target->metaObject()->property(instr.fetch.property).name()))); | |
stack.push(obj); | |
} | |
break; | |
case QDeclarativeInstruction::PopQList: | |
{ | |
qliststack.pop(); | |
} | |
break; | |
case QDeclarativeInstruction::Defer: | |
{ | |
if (instr.defer.deferCount) { | |
QObject *target = stack.top(); | |
QDeclarativeData *data = | |
QDeclarativeData::get(target, true); | |
comp->addref(); | |
data->deferredComponent = comp; | |
data->deferredIdx = ii; | |
ii += instr.defer.deferCount; | |
} | |
} | |
break; | |
case QDeclarativeInstruction::PopFetchedObject: | |
{ | |
stack.pop(); | |
} | |
break; | |
case QDeclarativeInstruction::FetchValueType: | |
{ | |
QObject *target = stack.top(); | |
if (instr.fetchValue.bindingSkipList != 0) { | |
// Possibly need to clear bindings | |
QDeclarativeData *targetData = QDeclarativeData::get(target); | |
if (targetData) { | |
QDeclarativeAbstractBinding *binding = | |
QDeclarativePropertyPrivate::binding(target, instr.fetchValue.property, -1); | |
if (binding && binding->bindingType() != QDeclarativeAbstractBinding::ValueTypeProxy) { | |
QDeclarativePropertyPrivate::setBinding(target, instr.fetchValue.property, -1, 0); | |
binding->destroy(); | |
} else if (binding) { | |
QDeclarativeValueTypeProxyBinding *proxy = | |
static_cast<QDeclarativeValueTypeProxyBinding *>(binding); | |
proxy->removeBindings(instr.fetchValue.bindingSkipList); | |
} | |
} | |
} | |
QDeclarativeValueType *valueHandler = ep->valueTypes[instr.fetchValue.type]; | |
valueHandler->read(target, instr.fetchValue.property); | |
stack.push(valueHandler); | |
} | |
break; | |
case QDeclarativeInstruction::PopValueType: | |
{ | |
QDeclarativeValueType *valueHandler = | |
static_cast<QDeclarativeValueType *>(stack.pop()); | |
QObject *target = stack.top(); | |
valueHandler->write(target, instr.fetchValue.property, | |
QDeclarativePropertyPrivate::BypassInterceptor); | |
} | |
break; | |
default: | |
qFatal("QDeclarativeCompiledData: Internal error - unknown instruction %d", instr.type); | |
break; | |
} | |
} | |
if (isError()) { | |
if (!stack.isEmpty()) { | |
delete stack.at(0); // ### What about failures in deferred creation? | |
} else { | |
ctxt->destroy(); | |
} | |
QDeclarativeEnginePrivate::clear(bindValues); | |
QDeclarativeEnginePrivate::clear(parserStatus); | |
return 0; | |
} | |
if (bindValues.count) | |
ep->bindValues << bindValues; | |
else if (bindValues.values) | |
bindValues.clear(); | |
if (parserStatus.count) | |
ep->parserStatus << parserStatus; | |
else if (parserStatus.values) | |
parserStatus.clear(); | |
Q_ASSERT(stack.count() == 1); | |
return stack.top(); | |
} | |
bool QDeclarativeVME::isError() const | |
{ | |
return !vmeErrors.isEmpty(); | |
} | |
QList<QDeclarativeError> QDeclarativeVME::errors() const | |
{ | |
return vmeErrors; | |
} | |
QObject * | |
QDeclarativeCompiledData::TypeReference::createInstance(QDeclarativeContextData *ctxt, | |
const QBitField &bindings, | |
QList<QDeclarativeError> *errors) const | |
{ | |
if (type) { | |
QObject *rv = 0; | |
void *memory = 0; | |
type->create(&rv, &memory, sizeof(QDeclarativeData)); | |
QDeclarativeData *ddata = new (memory) QDeclarativeData; | |
ddata->ownMemory = false; | |
QObjectPrivate::get(rv)->declarativeData = ddata; | |
if (typePropertyCache && !ddata->propertyCache) { | |
ddata->propertyCache = typePropertyCache; | |
ddata->propertyCache->addref(); | |
} | |
return rv; | |
} else { | |
Q_ASSERT(component); | |
return QDeclarativeComponentPrivate::begin(ctxt, 0, component, -1, -1, 0, errors, bindings); | |
} | |
} | |
QT_END_NAMESPACE |