diff options
author | Michael Brasser <michael.brasser@nokia.com> | 2009-04-22 04:47:24 (GMT) |
---|---|---|
committer | Michael Brasser <michael.brasser@nokia.com> | 2009-04-22 04:47:24 (GMT) |
commit | 2366667fc97eb6a56203b2dd7dac776ff4164abd (patch) | |
tree | b2acb6cc6bfe475d7e619e4788973b61fff775e0 /src/declarative/qml/qmlcompiler.cpp | |
parent | 2c762f3b8b284a7c6dc0c499b7052013bad5b707 (diff) | |
download | Qt-2366667fc97eb6a56203b2dd7dac776ff4164abd.zip Qt-2366667fc97eb6a56203b2dd7dac776ff4164abd.tar.gz Qt-2366667fc97eb6a56203b2dd7dac776ff4164abd.tar.bz2 |
Initial import of kinetic-dui branch from the old kinetic
Diffstat (limited to 'src/declarative/qml/qmlcompiler.cpp')
-rw-r--r-- | src/declarative/qml/qmlcompiler.cpp | 1662 |
1 files changed, 1662 insertions, 0 deletions
diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp new file mode 100644 index 0000000..9af0a06 --- /dev/null +++ b/src/declarative/qml/qmlcompiler.cpp @@ -0,0 +1,1662 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qmlcompiler_p.h" +#include <qfxperf.h> +#include "qmlparser_p.h" +#include "private/qmlxmlparser_p.h" +#include <qmlpropertyvaluesource.h> +#include <qmlcomponent.h> +#include "private/qmetaobjectbuilder_p.h" +#include <qmlbasicscript.h> +#include <QColor> +#include <QDebug> +#include <QPointF> +#include <QSizeF> +#include <QRectF> +#include <private/qmlcompiledcomponent_p.h> +#include <private/qmlstringconverters_p.h> +#include <private/qmlengine_p.h> +#include <qmlengine.h> +#include <qmlcontext.h> +#include <qmlmetatype.h> +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE +/* + New properties and signals can be added to any QObject type from QML. + <QObject> + <properties><Property name="myProperty" /></properties> + <signals><Signal name="mySignal" /></signals> + </QObject + The special names used as magical properties (in the above case "properties" + and "signals") are defined here. +*/ +#define PROPERTIES_NAME "properties" +#define SIGNALS_NAME "signals" + +using namespace QmlParser; + +int QmlCompiledData::indexForString(const QString &data) +{ + int idx = primitives.indexOf(data); + if(idx == -1) { + idx = primitives.count(); + primitives << data; + } + return idx; +} + +int QmlCompiledData::indexForByteArray(const QByteArray &data) +{ + int idx = datas.indexOf(data); + if(idx == -1) { + idx = datas.count(); + datas << data; + } + return idx; +} + +int QmlCompiledData::indexForFloat(float *data, int count) +{ + Q_ASSERT(count > 0); + + for(int ii = 0; ii < floatData.count() - count; ++ii) { + bool found = true; + for(int jj = 0; jj < count; ++jj) { + if(floatData.at(ii + jj) != data[jj]) { + found = false; + break; + } + } + + if(found) + return ii; + } + + int idx = floatData.count(); + for(int ii = 0; ii < count; ++ii) + floatData << data[ii]; + + return idx; +} + +int QmlCompiledData::indexForInt(int *data, int count) +{ + Q_ASSERT(count > 0); + + for(int ii = 0; ii < floatData.count() - count; ++ii) { + bool found = true; + for(int jj = 0; jj < count; ++jj) { + if(intData.at(ii + jj) != data[jj]) { + found = false; + break; + } + } + + if(found) + return ii; + } + + int idx = intData.count(); + for(int ii = 0; ii < count; ++ii) + intData << data[ii]; + + return idx; +} + +QmlCompiler::QmlCompiler() +: exceptionLine(-1), output(0) +{ +} + +bool QmlCompiler::isError() const +{ + return exceptionLine != -1; +} + +qint64 QmlCompiler::errorLine() const +{ + return exceptionLine; +} + +QString QmlCompiler::errorDescription() const +{ + return exceptionDescription; +} + +bool QmlCompiler::isValidId(const QString &val) +{ + if(val.isEmpty()) + return false; + + QChar u(QLatin1Char('_')); + for(int ii = 0; ii < val.count(); ++ii) + if(val.at(ii) != u && + ((ii == 0 && !val.at(ii).isLetter()) || + (ii != 0 && !val.at(ii).isLetterOrNumber())) ) + return false; + + return true; +} + +/*! + Returns true if \a str is a valid binding string, false otherwise. + + Valid binding strings are those enclosed in braces ({}). +*/ +bool QmlCompiler::isBinding(const QString &str) +{ + return str.startsWith(QLatin1Char('{')) && str.endsWith(QLatin1Char('}')); +} + +/*! + Returns true if property name \a name refers to an attached property, false + otherwise. + + Attached property names are those that start with a capital letter. +*/ +bool QmlCompiler::isAttachedProperty(const QByteArray &name) +{ + return !name.isEmpty() && name.at(0) >= 'A' && name.at(0) <= 'Z'; +} + +QmlCompiler::StoreInstructionResult +QmlCompiler::generateStoreInstruction(QmlCompiledData &cdata, + QmlInstruction &instr, + const QMetaProperty &prop, + int coreIdx, int primitive, + const QString *string) +{ + if(!prop.isWritable()) + return ReadOnly; + if(prop.isEnumType()) { + int value; + if (prop.isFlagType()) { + value = prop.enumerator().keysToValue(string->toLatin1().constData()); + } else + value = prop.enumerator().keyToValue(string->toLatin1().constData()); + if(value == -1) + return InvalidData; + instr.type = QmlInstruction::StoreInteger; + instr.storeInteger.propertyIndex = coreIdx; + instr.storeInteger.value = value; + return Ok; + } + int type = prop.type(); + switch(type) { + case -1: + instr.type = QmlInstruction::StoreVariant; + instr.storeString.propertyIndex = coreIdx; + if(primitive == -1) + primitive = cdata.indexForString(*string); + instr.storeString.value = primitive; + break; + break; + case QVariant::String: + { + instr.type = QmlInstruction::StoreString; + instr.storeString.propertyIndex = coreIdx; + if(string->startsWith(QLatin1Char('\'')) && string->endsWith(QLatin1Char('\''))) { + QString unquotedString = string->mid(1, string->length() - 2); + primitive = cdata.indexForString(unquotedString); + } else { + if(primitive == -1) + primitive = cdata.indexForString(*string); + } + instr.storeString.value = primitive; + } + break; + case QVariant::UInt: + { + instr.type = QmlInstruction::StoreInteger; + instr.storeInteger.propertyIndex = coreIdx; + bool ok; + int value = string->toUInt(&ok); + if (!ok) + return InvalidData; + instr.storeInteger.value = value; + } + break; + case QVariant::Int: + { + instr.type = QmlInstruction::StoreInteger; + instr.storeInteger.propertyIndex = coreIdx; + bool ok; + int value = string->toInt(&ok); + if (!ok) + return InvalidData; + instr.storeInteger.value = value; + } + break; + case 135: + case QVariant::Double: + { + instr.type = QmlInstruction::StoreReal; + instr.storeReal.propertyIndex = coreIdx; + bool ok; + float value = string->toFloat(&ok); + if (!ok) + return InvalidData; + instr.storeReal.value = value; + } + break; + case QVariant::Color: + { + QColor c = QmlStringConverters::colorFromString(*string); + if (!c.isValid()) + return InvalidData; + instr.type = QmlInstruction::StoreColor; + instr.storeColor.propertyIndex = coreIdx; + instr.storeColor.value = c.rgba(); + } + break; + case QVariant::Date: + { + QDate d = QDate::fromString(*string, Qt::ISODate); + if (!d.isValid()) + return InvalidData; + instr.type = QmlInstruction::StoreDate; + instr.storeDate.propertyIndex = coreIdx; + instr.storeDate.value = d.toJulianDay(); + } + break; + case QVariant::Time: + { + QTime time = QTime::fromString(*string, Qt::ISODate); + if (!time.isValid()) + return InvalidData; + int data[] = { time.hour(), time.minute(), time.second(), time.msec() }; + int index = cdata.indexForInt(data, 4); + instr.type = QmlInstruction::StoreTime; + instr.storeTime.propertyIndex = coreIdx; + instr.storeTime.valueIndex = index; + } + break; + case QVariant::DateTime: + { + QDateTime dateTime = QDateTime::fromString(*string, Qt::ISODate); + if (!dateTime.isValid()) + return InvalidData; + int data[] = { dateTime.date().toJulianDay(), + dateTime.time().hour(), + dateTime.time().minute(), + dateTime.time().second(), + dateTime.time().msec() }; + int index = cdata.indexForInt(data, 5); + instr.type = QmlInstruction::StoreDateTime; + instr.storeDateTime.propertyIndex = coreIdx; + instr.storeDateTime.valueIndex = index; + } + break; + case QVariant::Point: + case QVariant::PointF: + { + bool ok; + QPointF point = QmlStringConverters::pointFFromString(*string, &ok); + if (!ok) + return InvalidData; + float data[] = { point.x(), point.y() }; + int index = cdata.indexForFloat(data, 2); + if (type == QVariant::PointF) + instr.type = QmlInstruction::StorePointF; + else + instr.type = QmlInstruction::StorePoint; + instr.storeRealPair.propertyIndex = coreIdx; + instr.storeRealPair.valueIndex = index; + } + break; + case QVariant::Size: + case QVariant::SizeF: + { + bool ok; + QSizeF size = QmlStringConverters::sizeFFromString(*string, &ok); + if (!ok) + return InvalidData; + float data[] = { size.width(), size.height() }; + int index = cdata.indexForFloat(data, 2); + if (type == QVariant::SizeF) + instr.type = QmlInstruction::StoreSizeF; + else + instr.type = QmlInstruction::StoreSize; + instr.storeRealPair.propertyIndex = coreIdx; + instr.storeRealPair.valueIndex = index; + } + break; + case QVariant::Rect: + case QVariant::RectF: + { + bool ok; + QRectF rect = QmlStringConverters::rectFFromString(*string, &ok); + if (!ok) + return InvalidData; + float data[] = { rect.x(), rect.y(), + rect.width(), rect.height() }; + int index = cdata.indexForFloat(data, 4); + if (type == QVariant::RectF) + instr.type = QmlInstruction::StoreRectF; + else + instr.type = QmlInstruction::StoreRect; + instr.storeRect.propertyIndex = coreIdx; + instr.storeRect.valueIndex = index; + } + break; + case QVariant::Bool: + { + bool ok; + bool b = QmlStringConverters::boolFromString(*string, &ok); + if (!ok) + return InvalidData; + instr.type = QmlInstruction::StoreBool; + instr.storeBool.propertyIndex = coreIdx; + instr.storeBool.value = b; + } + break; + default: + { + int t = prop.type(); + if(t == QVariant::UserType) + t = prop.userType(); + QmlMetaType::StringConverter converter = + QmlMetaType::customStringConverter(t); + if (converter) { + int index = cdata.customTypeData.count(); + instr.type = QmlInstruction::AssignCustomType; + instr.assignCustomType.propertyIndex = coreIdx; + instr.assignCustomType.valueIndex = index; + + QmlCompiledData::CustomTypeData data; + if(primitive == -1) + primitive = cdata.indexForString(*string); + data.index = primitive; + data.type = t; + cdata.customTypeData << data; + break; + } + } + return UnknownType; + break; + } + return Ok; +} + +void QmlCompiler::reset(QmlCompiledComponent *cc, bool deleteMemory) +{ + cc->types.clear(); + cc->primitives.clear(); + cc->floatData.clear(); + cc->intData.clear(); + cc->customTypeData.clear(); + cc->datas.clear(); + if(deleteMemory) { + for(int ii = 0; ii < cc->mos.count(); ++ii) + qFree(cc->mos.at(ii)); + } + cc->mos.clear(); + cc->bytecode.clear(); +} + +#define COMPILE_EXCEPTION(desc) \ + { \ + exceptionLine = obj->line; \ + QDebug d(&exceptionDescription); \ + d << desc; \ + return false; \ + } + +#define COMPILE_CHECK(a) \ + { \ + if (!a) return false; \ + } + +bool QmlCompiler::compile(QmlEngine *engine, + QmlCompositeTypeManager::TypeData *unit, + QmlCompiledComponent *out) +{ +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxPerfTimer<QFxPerf::Compile> pc; +#endif + exceptionLine = -1; + + Q_ASSERT(out); + reset(out, true); + + output = out; + + // Compile types + for(int ii = 0; ii < unit->types.count(); ++ii) { + QmlCompositeTypeManager::TypeData::TypeReference &tref = unit->types[ii]; + QmlCompiledComponent::TypeReference ref; + if(tref.type) + ref.type = tref.type; + else if(tref.unit) { + ref.component = tref.unit->toComponent(engine); + ref.ref = tref.unit; + ref.ref->addref(); + } else if(tref.parser) + ref.parser = tref.parser; + ref.className = unit->data.types().at(ii).toLatin1(); + out->types << ref; + } + + Object *root = unit->data.tree(); + if(!root) { + exceptionDescription = QLatin1String("Can't compile because of earlier errors"); + output = 0; + return false; + } + + compileTree(root); + + if(!isError()) { + out->dumpPre(); + } else { + reset(out, true); + } + + output = 0; + return !isError(); +} + +void QmlCompiler::compileTree(Object *tree) +{ + QmlInstruction init; + init.type = QmlInstruction::Init; + init.line = 0; + init.init.dataSize = 0; + output->bytecode << init; + + if(!compileObject(tree, 0)) // Compile failed + return; + + QmlInstruction def; + init.line = 0; + def.type = QmlInstruction::SetDefault; + output->bytecode << def; + + optimizeExpressions(0, output->bytecode.count() - 1, 0); +} + +bool QmlCompiler::compileObject(Object *obj, int ctxt) +{ + if(obj->type != -1) { + obj->metatype = + QmlMetaType::metaObjectForType(output->types.at(obj->type).className); + } + + if(output->types.at(obj->type).className == "Component") { + COMPILE_CHECK(compileComponent(obj, ctxt)); + return true; + } + + ctxt = 0; + + // Only use magical "properties" and "signals" properties if the type + // doesn't have already have them + bool ignoreProperties = false; + bool ignoreSignals = false; + if(obj->metatype && obj->metatype->indexOfProperty(PROPERTIES_NAME) != -1) + ignoreProperties = true; + if(obj->metatype && obj->metatype->indexOfProperty(SIGNALS_NAME) != -1) + ignoreSignals = true; + + Property *propertiesProperty = ignoreProperties?0:obj->getProperty(PROPERTIES_NAME, false); + Property *signalsProperty = ignoreSignals?0:obj->getProperty(SIGNALS_NAME, false); + + if(propertiesProperty) { + obj->dynamicPropertiesProperty = propertiesProperty; + obj->properties.remove(PROPERTIES_NAME); + } + if(signalsProperty) { + obj->dynamicSignalsProperty = signalsProperty; + obj->properties.remove(SIGNALS_NAME); + } + + if(obj->type != -1 && output->types.at(obj->type).parser) { + QByteArray data = obj->custom; + int ref = output->indexForByteArray(data); + + QmlInstruction create; + create.type = QmlInstruction::CreateCustomObject; + create.line = obj->line; + create.createCustom.type = obj->type; + create.createCustom.data = ref; + output->bytecode << create; + } else { + // Create the object + QmlInstruction create; + create.type = QmlInstruction::CreateObject; + create.line = obj->line; + create.create.type = obj->type; + output->bytecode << create; + } + + COMPILE_CHECK(compileDynamicPropertiesAndSignals(obj)); + + if(obj->type != -1) { + if(output->types.at(obj->type).component) { + QmlInstruction begin; + begin.type = QmlInstruction::TryBeginObject; + begin.line = obj->line; + output->bytecode << begin; + } else { + int cast = QmlMetaType::qmlParserStatusCast(QmlMetaType::type(output->types.at(obj->type).className)); + if(cast != -1) { + QmlInstruction begin; + begin.type = QmlInstruction::BeginObject; + begin.begin.castValue = cast; + begin.line = obj->line; + output->bytecode << begin; + } + } + } + + foreach(Property *prop, obj->properties) { + if(!ignoreProperties && prop->name == PROPERTIES_NAME) { + } else if(!ignoreSignals && prop->name == SIGNALS_NAME) { + } else if(prop->name.length() >= 3 && prop->name.startsWith("on") && + ('A' <= prop->name.at(2) && 'Z' >= prop->name.at(2))) { + COMPILE_CHECK(compileSignal(prop, obj)); + } else { + COMPILE_CHECK(compileProperty(prop, obj, ctxt)); + } + } + + if(obj->defaultProperty) + COMPILE_CHECK(compileProperty(obj->defaultProperty, obj, ctxt)); + + if(obj->type != -1) { + if(output->types.at(obj->type).component) { + QmlInstruction complete; + complete.type = QmlInstruction::TryCompleteObject; + complete.line = obj->line; + output->bytecode << complete; + } else { + int cast = QmlMetaType::qmlParserStatusCast(QmlMetaType::type(output->types.at(obj->type).className)); + if(cast != -1) { + QmlInstruction complete; + complete.type = QmlInstruction::CompleteObject; + complete.complete.castValue = cast; + complete.line = obj->line; + output->bytecode << complete; + } + } + } + + return true; +} + +bool QmlCompiler::compileComponent(Object *obj, int ctxt) +{ + Property *idProp = 0; + if(obj->properties.count() > 1 || + (obj->properties.count() == 1 && obj->properties.begin().key() != "id")) + COMPILE_EXCEPTION("Invalid component specification"); + if(obj->defaultProperty && + (obj->defaultProperty->value || obj->defaultProperty->values.count() > 1 || + (obj->defaultProperty->values.count() == 1 && !obj->defaultProperty->values.first()->object))) + COMPILE_EXCEPTION("Invalid component body specification"); + if(obj->properties.count()) + idProp = *obj->properties.begin(); + if(idProp && (idProp->value || idProp->values.count() > 1)) + COMPILE_EXCEPTION("Invalid component id specification"); + + Object *root = 0; + if(obj->defaultProperty && obj->defaultProperty->values.count()) + root = obj->defaultProperty->values.first()->object; + + COMPILE_CHECK(compileComponentFromRoot(root, ctxt)); + + if(idProp && idProp->values.count()) { + QString val = idProp->values.at(0)->primitive; + if(!isValidId(val)) + COMPILE_EXCEPTION("Invalid id property value"); + + if(ids.contains(val)) + COMPILE_EXCEPTION("id is not unique"); + ids.insert(val); + + int pref = output->indexForString(val); + QmlInstruction id; + id.type = QmlInstruction::SetId; + id.line = idProp->line; + id.setId.value = pref; + id.setId.save = -1; + output->bytecode << id; + } + + return true; +} + +bool QmlCompiler::compileComponentFromRoot(Object *obj, int ctxt) +{ + output->bytecode.push_back(QmlInstruction()); + QmlInstruction &create = output->bytecode.last(); + create.type = QmlInstruction::CreateComponent; + create.line = obj->line; + int count = output->bytecode.count(); + + QmlInstruction init; + init.type = QmlInstruction::Init; + init.init.dataSize = 0; + init.line = obj->line; + output->bytecode << init; + + QSet<QString> oldIds = ids; + ids.clear(); + if(obj) + COMPILE_CHECK(compileObject(obj, ctxt)); + ids = oldIds; + + create.createComponent.count = output->bytecode.count() - count; + + int inc = optimizeExpressions(count, count - 1 + create.createComponent.count, count); + create.createComponent.count += inc; + return true; +} + + +bool QmlCompiler::compileFetchedObject(Object *obj, int ctxt) +{ + if(obj->defaultProperty) + COMPILE_CHECK(compileProperty(obj->defaultProperty, obj, ctxt)); + + foreach(Property *prop, obj->properties) { + if(prop->name.length() >= 3 && prop->name.startsWith("on") && + ('A' <= prop->name.at(2) && 'Z' >= prop->name.at(2))) { + COMPILE_CHECK(compileSignal(prop, obj)); + } else { + COMPILE_CHECK(compileProperty(prop, obj, ctxt)); + } + } + + return true; +} + +bool QmlCompiler::compileSignal(Property *prop, Object *obj) +{ + if(prop->values.isEmpty() && !prop->value) + return true; + + if(prop->value || prop->values.count() > 1) + COMPILE_EXCEPTION("Incorrectly specified signal"); + + if(prop->values.at(0)->object) { + int pr = output->indexForByteArray(prop->name); + + bool rv = compileObject(prop->values.at(0)->object, 0); + + if(rv) { + QmlInstruction assign; + assign.type = QmlInstruction::AssignSignalObject; + assign.line = prop->values.at(0)->line; + assign.assignSignalObject.signal = pr; + + output->bytecode << assign; + + prop->values.at(0)->type = Value::SignalObject; + } + + return rv; + + } else { + QString script = prop->values.at(0)->primitive.trimmed(); + if(script.isEmpty()) + return true; + + if(isBinding(script)) + COMPILE_EXCEPTION("Cannot assign binding to signal property"); + + int idx = output->indexForString(script); + int pr = output->indexForByteArray(prop->name); + + QmlInstruction assign; + assign.type = QmlInstruction::AssignSignal; + assign.line = prop->values.at(0)->line; + assign.assignSignal.signal = pr; + assign.assignSignal.value = idx; + + output->bytecode << assign; + + prop->values.at(0)->type = Value::SignalExpression; + } + + return true; +} + +bool QmlCompiler::compileProperty(Property *prop, Object *obj, int ctxt) +{ + if(prop->values.isEmpty() && !prop->value) + return true; + + // First we're going to need a reference to this property + if(obj->type != -1) { + + const QMetaObject *mo = obj->metaObject(); + if(mo) { + if(prop->isDefault) { + QMetaProperty p = QmlMetaType::defaultProperty(mo); + // XXX + // Currently we don't handle enums in the static analysis + // so we let them drop through to generateStoreInstruction() + if(p.name() && !p.isEnumType()) { + prop->index = mo->indexOfProperty(p.name()); + prop->name = p.name(); + + int t = p.type(); + if(t == QVariant::UserType) + t = p.userType(); + + prop->type = t; + } + } else { + prop->index = mo->indexOfProperty(prop->name.constData()); + QMetaProperty p = mo->property(prop->index); + // XXX + // Currently we don't handle enums in the static analysis + // so we let them drop through to generateStoreInstruction() + if(p.name() && !p.isEnumType()) { + int t = p.type(); + if(t == QVariant::UserType) + t = p.userType(); + + prop->type = t; + } + } + } + } else { + const QMetaObject *mo = obj->metaObject(); + if(mo) { + if(prop->isDefault) { + QMetaProperty p = QmlMetaType::defaultProperty(mo); + if(p.name()) { + prop->index = mo->indexOfProperty(p.name()); + prop->name = p.name(); + } + int t = p.type(); + if(t == QVariant::UserType) + t = p.userType(); + prop->type = t; + } else { + prop->index = mo->indexOfProperty(prop->name.constData()); + QMetaProperty p = mo->property(prop->index); + int t = p.type(); + if(t == QVariant::UserType) + t = p.userType(); + prop->type = t; + } + } + } + + if(prop->name == "id") { + + COMPILE_CHECK(compileIdProperty(prop, obj)); + + } else if(isAttachedProperty(prop->name)) { + + COMPILE_CHECK(compileAttachedProperty(prop, obj, ctxt)); + + } else if(prop->value) { + + COMPILE_CHECK(compileNestedProperty(prop, ctxt)); + + } else if(QmlMetaType::isQmlList(prop->type) || + QmlMetaType::isList(prop->type)) { + + COMPILE_CHECK(compileListProperty(prop, obj, ctxt)); + + } else { + + COMPILE_CHECK(compilePropertyAssignment(prop, obj, ctxt)); + + } + + return true; +} + +bool QmlCompiler::compileIdProperty(QmlParser::Property *prop, + QmlParser::Object *obj) +{ + if(prop->value) + COMPILE_EXCEPTION("The 'id' property cannot be fetched"); + if(prop->values.count() > 1) + COMPILE_EXCEPTION("The 'id' property cannot be multiset"); + + if(prop->values.count() == 1) { + if(prop->values.at(0)->object) + COMPILE_EXCEPTION("Cannot assign an object as an id"); + QString val = prop->values.at(0)->primitive; + if(!isValidId(val)) + COMPILE_EXCEPTION(val << "is not a valid id"); + if(ids.contains(val)) + COMPILE_EXCEPTION("id is not unique"); + ids.insert(val); + + int pref = output->indexForString(val); + + if(prop->type == QVariant::String) { + QmlInstruction assign; + assign.type = QmlInstruction::StoreString; + assign.storeString.propertyIndex = prop->index; + assign.storeString.value = pref; + assign.line = prop->values.at(0)->line; + output->bytecode << assign; + + prop->values.at(0)->type = Value::Id; + } else { + prop->values.at(0)->type = Value::Literal; + } + + QmlInstruction id; + id.type = QmlInstruction::SetId; + id.line = prop->values.at(0)->line; + id.setId.value = pref; + id.setId.save = -1; + id.line = prop->values.at(0)->line; + output->bytecode << id; + + obj->id = val.toLatin1(); + } + + return true; +} + +bool QmlCompiler::compileAttachedProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + int ctxt) +{ + if(!prop->value) + COMPILE_EXCEPTION("Incorrect usage of an attached property"); + + QmlInstruction fetch; + fetch.type = QmlInstruction::FetchAttached; + fetch.line = prop->line; + int ref = output->indexForByteArray(prop->name); + fetch.fetchAttached.idx = ref; + output->bytecode << fetch; + + COMPILE_CHECK(compileFetchedObject(prop->value, ctxt + 1)); + + QmlInstruction pop; + pop.type = QmlInstruction::PopFetchedObject; + pop.line = prop->line; + output->bytecode << pop; + + return true; +} + +bool QmlCompiler::compileNestedProperty(QmlParser::Property *prop, + int ctxt) +{ + if(prop->type != 0) + prop->value->metatype = QmlMetaType::metaObjectForType(prop->type); + + QmlInstruction fetch; + if(prop->index != -1 && + QmlMetaType::isObject(prop->value->metatype)) { + fetch.type = QmlInstruction::FetchObject; + fetch.fetch.property = prop->index; + fetch.fetch.isObject = true; + } else { + fetch.type = QmlInstruction::ResolveFetchObject; + fetch.fetch.property = output->indexForByteArray(prop->name); + } + fetch.line = prop->line; + output->bytecode << fetch; + + COMPILE_CHECK(compileFetchedObject(prop->value, ctxt + 1)); + + QmlInstruction pop; + pop.type = QmlInstruction::PopFetchedObject; + pop.line = prop->line; + output->bytecode << pop; + + return true; +} + +bool QmlCompiler::compileListProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + int ctxt) +{ + int t = prop->type; + if(QmlMetaType::isQmlList(t)) { + QmlInstruction fetch; + fetch.line = prop->line; + fetch.type = QmlInstruction::FetchQmlList; + fetch.fetchQmlList.property = prop->index; + fetch.fetchQmlList.type = QmlMetaType::qmlListType(t); + output->bytecode << fetch; + + for(int ii = 0; ii < prop->values.count(); ++ii) { + Value *v = prop->values.at(ii); + if(v->object) { + v->type = Value::CreatedObject; + COMPILE_CHECK(compileObject(v->object, ctxt)); + QmlInstruction assign; + assign.type = QmlInstruction::AssignObjectList; + assign.line = prop->line; + assign.assignObject.property = output->indexForByteArray(prop->name); + assign.assignObject.castValue = 0; + output->bytecode << assign; + } else { + COMPILE_EXCEPTION("Cannot assign primitives to lists"); + } + } + + QmlInstruction pop; + pop.type = QmlInstruction::PopQList; + pop.line = prop->line; + output->bytecode << pop; + } else { + Q_ASSERT(QmlMetaType::isList(t)); + + QmlInstruction fetch; + fetch.type = QmlInstruction::FetchQList; + fetch.line = prop->line; + fetch.fetch.property = prop->index; + output->bytecode << fetch; + + bool assignedBinding = false; + for(int ii = 0; ii < prop->values.count(); ++ii) { + Value *v = prop->values.at(ii); + if(v->object) { + v->type = Value::CreatedObject; + COMPILE_CHECK(compileObject(v->object, ctxt)); + QmlInstruction assign; + assign.type = QmlInstruction::AssignObjectList; + assign.line = v->line; + assign.assignObject.property = output->indexForByteArray(prop->name); + assign.assignObject.castValue = 0; + output->bytecode << assign; + } else if(isBinding(v->primitive)) { + if(assignedBinding) + COMPILE_EXCEPTION("Can only assign one binding to lists"); + + compileBinding(v->primitive, prop, ctxt, obj->metaObject(), v->line); + v->type = Value::PropertyBinding; + } else { + COMPILE_EXCEPTION("Cannot assign primitives to lists"); + } + } + + QmlInstruction pop; + pop.line = prop->line; + pop.type = QmlInstruction::PopQList; + output->bytecode << pop; + } + return true; +} + +bool QmlCompiler::compilePropertyAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + int ctxt) +{ + for(int ii = 0; ii < prop->values.count(); ++ii) { + Value *v = prop->values.at(ii); + if(v->object) { + + COMPILE_CHECK(compilePropertyObjectAssignment(prop, obj, v, ctxt)); + + } else { + + COMPILE_CHECK(compilePropertyLiteralAssignment(prop, obj, v, ctxt)); + + } + } + + return true; +} + +bool QmlCompiler::compilePropertyObjectAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + QmlParser::Value *v, + int ctxt) +{ + if(v->object->type != -1) + v->object->metatype = QmlMetaType::metaObjectForType(output->types.at(v->object->type).className); + + if(v->object->metaObject()) { + + const QMetaObject *propmo = + QmlMetaType::rawMetaObjectForType(prop->type); + + bool isPropertyValue = false; + bool isAssignable = false; + + if(propmo) { + // We want to raw metaObject here as the raw metaobject is the + // actual property type before we applied any extensions + const QMetaObject *c = v->object->metatype; + while(propmo && c) { + isPropertyValue = isPropertyValue || (c == &QmlPropertyValueSource::staticMetaObject); + isAssignable = isAssignable || (c == propmo); + c = c->superClass(); + } + } else { + const QMetaObject *c = v->object->metatype; + while(!isPropertyValue && c) { + isPropertyValue = c == &QmlPropertyValueSource::staticMetaObject; + c = c->superClass(); + } + } + + if(!propmo && !isPropertyValue) { + COMPILE_CHECK(compileObject(v->object, ctxt)); + + QmlInstruction assign; + assign.type = QmlInstruction::AssignObject; + assign.line = v->object->line; + assign.assignObject.castValue = 0; + if(prop->isDefault) + assign.assignObject.property = -1; + else + assign.assignObject.property = + output->indexForByteArray(prop->name); + output->bytecode << assign; + + v->type = Value::CreatedObject; + } else if(isAssignable) { + COMPILE_CHECK(compileObject(v->object, ctxt)); + + QmlInstruction assign; + assign.type = QmlInstruction::StoreObject; + assign.line = v->object->line; + assign.storeObject.propertyIndex = prop->index; + // XXX - this cast may not be 0 + assign.storeObject.cast = 0; + output->bytecode << assign; + + v->type = Value::CreatedObject; + } else if(propmo == &QmlComponent::staticMetaObject) { + + COMPILE_CHECK(compileComponentFromRoot(v->object, ctxt)); + + QmlInstruction assign; + assign.type = QmlInstruction::StoreObject; + assign.line = v->object->line; + assign.storeObject.propertyIndex = prop->index; + // XXX - this cast may not be 0 + assign.storeObject.cast = 0; + output->bytecode << assign; + + v->type = Value::Component; + } else if(isPropertyValue) { + COMPILE_CHECK(compileObject(v->object, ctxt)); + + if (prop->index != -1) { + QmlInstruction assign; + assign.type = QmlInstruction::StoreValueSource; + assign.line = v->object->line; + assign.assignValueSource.property = prop->index; + output->bytecode << assign; + } else { + QmlInstruction assign; + assign.type = QmlInstruction::AssignValueSource; + assign.line = v->object->line; + assign.assignValueSource.property = output->indexForByteArray(prop->name);; + output->bytecode << assign; + } + + v->type = Value::ValueSource; + } else { + COMPILE_EXCEPTION("Unassignable object"); + } + + } else { + COMPILE_CHECK(compileObject(v->object, ctxt)); + + QmlInstruction assign; + assign.type = QmlInstruction::AssignObject; + assign.line = v->object->line; + assign.assignObject.property = output->indexForByteArray(prop->name); + assign.assignObject.castValue = 0; + output->bytecode << assign; + + v->type = Value::CreatedObject; + } + + return true; +} + +bool QmlCompiler::compilePropertyLiteralAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + QmlParser::Value *v, + int ctxt) +{ + if(isBinding(v->primitive)) { + + compileBinding(v->primitive, prop, ctxt, obj->metaObject(), v->line); + + v->type = Value::PropertyBinding; + + } else { + + QmlInstruction assign; + assign.line = v->line; + + bool doassign = true; + if(prop->index != -1) { + StoreInstructionResult r = + generateStoreInstruction(*output, assign, obj->metaObject()->property(prop->index), prop->index, -1, &v->primitive); + + if(r == Ok) { + doassign = false; + } else if(r == InvalidData) { + //### we are restricted to a rather generic message here. If we can find a way to move + // the exception into generateStoreInstruction we could potentially have better messages. + // (the problem is that both compile and run exceptions can be generated, though) + COMPILE_EXCEPTION("Cannot assign value" << v->primitive << "to property" << obj->metaObject()->property(prop->index).name()); + doassign = false; + } else if(r == ReadOnly) { + COMPILE_EXCEPTION("Cannot assign value" << v->primitive << "to the read-only property" << obj->metaObject()->property(prop->index).name()); + } else { + doassign = true; + } + } + + if(doassign) { + assign.type = QmlInstruction::AssignConstant; + if(prop->isDefault) { + assign.assignConstant.property = -1; + } else { + assign.assignConstant.property = + output->indexForByteArray(prop->name); + } + assign.assignConstant.constant = + output->indexForString(v->primitive); + } + + output->bytecode << assign; + + v->type = Value::Literal; + } + return true; +} + +bool QmlCompiler::findDynamicProperties(QmlParser::Property *prop, + QmlParser::Object *obj) +{ + QList<Object::DynamicProperty> definedProperties; + + struct TypeNameToType { + const char *name; + Object::DynamicProperty::Type type; + } propTypeNameToTypes[] = { + { "", Object::DynamicProperty::Variant }, + { "int", Object::DynamicProperty::Int }, + { "bool", Object::DynamicProperty::Bool }, + { "double", Object::DynamicProperty::Real }, + { "real", Object::DynamicProperty::Real }, + { "string", Object::DynamicProperty::String }, + { "color", Object::DynamicProperty::Color }, + { "date", Object::DynamicProperty::Date }, + { "variant", Object::DynamicProperty::Variant } + }; + const int propTypeNameToTypesCount = sizeof(propTypeNameToTypes) / + sizeof(propTypeNameToTypes[0]); + + + if(prop->value) + COMPILE_EXCEPTION("Invalid property specification"); + + bool seenDefault = false; + for(int ii = 0; ii < prop->values.count(); ++ii) { + QmlParser::Value *val = prop->values.at(ii); + if(!val->object) + COMPILE_EXCEPTION("Invalid property specification"); + + QmlParser::Object *obj = val->object; + if(obj->type == -1 || output->types.at(obj->type).className != "Property") + COMPILE_EXCEPTION("Use Property tag to specify properties"); + + + enum Seen { None = 0, Name = 0x01, + Type = 0x02, Value = 0x04, + ValueChanged = 0x08, + Default = 0x10 } seen = None; + + Object::DynamicProperty propDef; + + for(QHash<QByteArray, QmlParser::Property *>::ConstIterator iter = + obj->properties.begin(); + iter != obj->properties.end(); + ++iter) { + + QmlParser::Property *property = *iter; + if(property->name == "name") { + if (seen & Name) + COMPILE_EXCEPTION("May only specify Property name once"); + seen = (Seen)(seen | Name); + + if(property->value || property->values.count() != 1 || + property->values.at(0)->object) + COMPILE_EXCEPTION("Invalid Property name"); + + propDef.name = property->values.at(0)->primitive.toLatin1(); + + } else if(property->name == "type") { + if (seen & Type) + COMPILE_EXCEPTION("May only specify Property type once"); + seen = (Seen)(seen | Type); + + if(property->value || property->values.count() != 1 || + property->values.at(0)->object) + COMPILE_EXCEPTION("Invalid Property type"); + + QString type = property->values.at(0)->primitive.toLower(); + bool found = false; + for(int ii = 0; !found && ii < propTypeNameToTypesCount; ++ii) { + if(type == QLatin1String(propTypeNameToTypes[ii].name)){ + found = true; + propDef.type = propTypeNameToTypes[ii].type; + } + + } + + if(!found) + COMPILE_EXCEPTION("Invalid Property type"); + + } else if(property->name == "value") { + if (seen & Value) + COMPILE_EXCEPTION("May only specify Property value once"); + seen = (Seen)(seen | Value); + + propDef.defaultValue = property; + } else if(property->name == "onValueChanged") { + if (seen & ValueChanged) + COMPILE_EXCEPTION("May only specify Property onValueChanged once"); + seen = (Seen)(seen | ValueChanged); + + if(property->value || property->values.count() != 1 || + property->values.at(0)->object) + COMPILE_EXCEPTION("Invalid Property onValueChanged"); + + propDef.onValueChanged = property->values.at(0)->primitive; + + } else if(property->name == "default") { + if(seen & Default) + COMPILE_EXCEPTION("May only specify Property default once"); + seen = (Seen)(seen | Default); + if(property->value || property->values.count() != 1 || + property->values.at(0)->object) + COMPILE_EXCEPTION("Invalid Property default"); + + bool defaultValue = + QmlStringConverters::boolFromString(property->values.at(0)->primitive); + propDef.isDefaultProperty = defaultValue; + if(defaultValue) { + if(seenDefault) + COMPILE_EXCEPTION("Only one property may be the default"); + seenDefault = true; + } + + } else { + COMPILE_EXCEPTION("Invalid Property property"); + } + + } + if(obj->defaultProperty) { + if(seen & Value) + COMPILE_EXCEPTION("May only specify Property value once"); + + seen = (Seen)(seen | Value); + propDef.defaultValue = obj->defaultProperty; + } + + if(!(seen & Name)) + COMPILE_EXCEPTION("Must specify Property name"); + + definedProperties << propDef; + } + + obj->dynamicProperties = definedProperties; + return true; +} + +bool QmlCompiler::findDynamicSignals(QmlParser::Property *sigs, + QmlParser::Object *obj) +{ + QList<Object::DynamicSignal> definedSignals; + + if(sigs->value) + COMPILE_EXCEPTION("Invalid signal specification"); + + for(int ii = 0; ii < sigs->values.count(); ++ii) { + QmlParser::Value *val = sigs->values.at(ii); + if(!val->object) + COMPILE_EXCEPTION("Invalid signal specification"); + + QmlParser::Object *obj = val->object; + if(obj->type == -1 || output->types.at(obj->type).className != "Signal") + COMPILE_EXCEPTION("Use Signal tag to specify signals"); + + enum Seen { None = 0, Name = 0x01 } seen = None; + Object::DynamicSignal sigDef; + + for(QHash<QByteArray, QmlParser::Property *>::ConstIterator iter = + obj->properties.begin(); + iter != obj->properties.end(); + ++iter) { + + QmlParser::Property *property = *iter; + if(property->name == "name") { + if (seen & Name) + COMPILE_EXCEPTION("May only specify Signal name once"); + seen = (Seen)(seen | Name); + + if(property->value || property->values.count() != 1 || + property->values.at(0)->object) + COMPILE_EXCEPTION("Invalid Signal name"); + + sigDef.name = property->values.at(0)->primitive.toLatin1(); + + } else { + COMPILE_EXCEPTION("Invalid Signal property"); + } + + } + + if(obj->defaultProperty) + COMPILE_EXCEPTION("Invalid Signal property"); + + if(!(seen & Name)) + COMPILE_EXCEPTION("Must specify Signal name"); + + definedSignals << sigDef; + } + + obj->dynamicSignals = definedSignals; + return true; +} + +bool QmlCompiler::compileDynamicPropertiesAndSignals(QmlParser::Object *obj) +{ + if(obj->dynamicPropertiesProperty) + findDynamicProperties(obj->dynamicPropertiesProperty, obj); + if(obj->dynamicSignalsProperty) + findDynamicSignals(obj->dynamicSignalsProperty, obj); + + if(obj->dynamicProperties.isEmpty() && obj->dynamicSignals.isEmpty()) + return true; + + QMetaObjectBuilder builder; + if(obj->metatype) + builder.setClassName(QByteArray(obj->metatype->className()) + "QML"); + + builder.setFlags(QMetaObjectBuilder::DynamicMetaObject); + for(int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { + const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); + + if(p.isDefaultProperty) + builder.addClassInfo("DefaultProperty", p.name); + + QByteArray type; + switch(p.type) { + case Object::DynamicProperty::Variant: + type = "QVariant"; + break; + case Object::DynamicProperty::Int: + type = "int"; + break; + case Object::DynamicProperty::Bool: + type = "bool"; + break; + case Object::DynamicProperty::Real: + type = "double"; + break; + case Object::DynamicProperty::String: + type = "QString"; + break; + case Object::DynamicProperty::Color: + type = "QColor"; + break; + case Object::DynamicProperty::Date: + type = "QDate"; + break; + } + + builder.addSignal("qml__" + QByteArray::number(ii) + "()"); + builder.addProperty(p.name, type, ii); + } + + for(int ii = 0; ii < obj->dynamicSignals.count(); ++ii) { + const Object::DynamicSignal &s = obj->dynamicSignals.at(ii); + builder.addSignal(s.name + "()"); + } + + if(obj->metatype) + builder.setSuperClass(obj->metatype); + + obj->extObject = builder.toMetaObject(); + + output->mos << obj->extObject; + QmlInstruction store; + store.type = QmlInstruction::StoreMetaObject; + store.storeMeta.data = output->mos.count() - 1; + store.line = obj->line; + output->bytecode << store; + + for(int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { + const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); + + if(p.defaultValue) { + p.defaultValue->name = p.name; + p.defaultValue->isDefault = false; + COMPILE_CHECK(compileProperty(p.defaultValue, obj, 0)); + } + + if(!p.onValueChanged.isEmpty()) { + QmlInstruction assign; + assign.type = QmlInstruction::AssignSignal; + assign.line = obj->line; + assign.assignSignal.signal = + output->indexForByteArray("onQml__" + QByteArray::number(ii)); + assign.assignSignal.value = + output->indexForString(p.onValueChanged); + output->bytecode << assign; + } + } + + return true; +} + +void QmlCompiler::compileBinding(const QString &str, QmlParser::Property *prop, + int ctxt, const QMetaObject *mo, qint64 line) +{ + Q_ASSERT(isBinding(str)); + + QString bind = str.mid(1, str.length() - 2).trimmed(); + QmlBasicScript bs; + bs.compile(bind.toLatin1()); + + int bref; + if(bs.isValid()) { + bref = output->indexForByteArray(QByteArray(bs.compileData(), bs.compileDataSize())); + } else { + bref = output->indexForString(bind); + } + + QmlInstruction assign; + assign.assignBinding.context = ctxt; + assign.line = line; + if(prop->index != -1) { + if(bs.isValid()) + assign.type = QmlInstruction::StoreCompiledBinding; + else + assign.type = QmlInstruction::StoreBinding; + + assign.assignBinding.property = prop->index; + assign.assignBinding.value = bref; + assign.assignBinding.category = QmlMetaProperty::Unknown; + if(mo) { + //XXX we should generate an exception if the property is read-only + QMetaProperty mp = mo->property(assign.assignBinding.property); + assign.assignBinding.category = QmlMetaProperty::propertyCategory(mp); + } + } else { + if(bs.isValid()) + assign.type = QmlInstruction::AssignCompiledBinding; + else + assign.type = QmlInstruction::AssignBinding; + assign.assignBinding.property = output->indexForByteArray(prop->name); + assign.assignBinding.value = bref; + assign.assignBinding.category = QmlMetaProperty::Unknown; + } + output->bytecode << assign; +} + +int QmlCompiler::optimizeExpressions(int start, int end, int patch) +{ + QHash<QString, int> ids; + int saveCount = 0; + int newInstrs = 0; + + for(int ii = start; ii <= end; ++ii) { + const QmlInstruction &instr = output->bytecode.at(ii); + + if(instr.type == QmlInstruction::CreateComponent) { + ii += instr.createComponent.count - 1; + continue; + } + + if(instr.type == QmlInstruction::SetId) { + QString id = output->primitives.at(instr.setId.value); + ids.insert(id, ii); + } + } + + for(int ii = start; ii <= end; ++ii) { + const QmlInstruction &instr = output->bytecode.at(ii); + + if(instr.type == QmlInstruction::CreateComponent) { + ii += instr.createComponent.count - 1; + continue; + } + + if(instr.type == QmlInstruction::StoreCompiledBinding) { + QmlBasicScript s(output->datas.at(instr.assignBinding.value).constData()); + + if(s.isSingleLoad()) { + QString slt = QLatin1String(s.singleLoadTarget()); + if(!slt.at(0).isUpper()) + continue; + + if(ids.contains(slt) && + instr.assignBinding.category == QmlMetaProperty::Object) { + int id = ids[slt]; + int saveId = -1; + + if(output->bytecode.at(id).setId.save != -1) { + saveId = output->bytecode.at(id).setId.save; + } else { + output->bytecode[id].setId.save = saveCount; + saveId = saveCount; + ++saveCount; + } + + int prop = instr.assignBinding.property; + + QmlInstruction &rwinstr = output->bytecode[ii]; + rwinstr.type = QmlInstruction::PushProperty; + rwinstr.pushProperty.property = prop; + + QmlInstruction instr; + instr.type = QmlInstruction::AssignStackObject; + instr.line = 0; + instr.assignStackObject.property = newInstrs; + instr.assignStackObject.object = saveId; + output->bytecode << instr; + ++newInstrs; + } + } + } + + } + + if(saveCount) + output->bytecode[patch].init.dataSize = saveCount; + + return newInstrs; +} + +QmlCompiledData::QmlCompiledData() +{ +} + +QmlCompiledData::QmlCompiledData(const QmlCompiledData &other) +{ + *this = other; +} + +QmlCompiledData::~QmlCompiledData() +{ + for(int ii = 0; ii < types.count(); ++ii) { + if(types.at(ii).ref) + types.at(ii).ref->release(); + } +} + +QmlCompiledData &QmlCompiledData::operator=(const QmlCompiledData &other) +{ + types = other.types; + primitives = other.primitives; + floatData = other.floatData; + intData = other.intData; + customTypeData = other.customTypeData; + datas = other.datas; + mos = other.mos; + bytecode = other.bytecode; + return *this; +} + +QObject *QmlCompiledData::TypeReference::createInstance() const +{ + if(type) { + return type->create(); + } else if(component) { + return component->create(QmlContext::activeContext()); + } else { + return 0; + } +} + + +QT_END_NAMESPACE |