diff options
author | Michael Brasser <michael.brasser@nokia.com> | 2009-05-05 05:36:14 (GMT) |
---|---|---|
committer | Michael Brasser <michael.brasser@nokia.com> | 2009-05-05 05:36:14 (GMT) |
commit | 97d8f444993f194a584815d085d66923a4ffbc41 (patch) | |
tree | c451c126cef7dbd1ed865d68ce749cd4151345af /src | |
parent | 132830854a1b547666c1c65c7db1c6c089399637 (diff) | |
parent | 0725ca189ad30ec54a2a7a054404a50f20e2bfed (diff) | |
download | Qt-97d8f444993f194a584815d085d66923a4ffbc41.zip Qt-97d8f444993f194a584815d085d66923a4ffbc41.tar.gz Qt-97d8f444993f194a584815d085d66923a4ffbc41.tar.bz2 |
Merge branch 'kinetic-declarativeui' of git@scm.dev.nokia.troll.no:qt/kinetic into kinetic-declarativeui
Diffstat (limited to 'src')
26 files changed, 507 insertions, 1072 deletions
diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index 9067039..5198264 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -8,7 +8,6 @@ SOURCES += qml/qmlparser.cpp \ qml/qmlcontext.cpp \ qml/qmlcustomparser.cpp \ qml/qmlpropertyvaluesource.cpp \ - qml/qmlxmlparser.cpp \ qml/qmlproxymetaobject.cpp \ qml/qmlvme.cpp \ qml/qmlcompiler.cpp \ @@ -22,7 +21,8 @@ SOURCES += qml/qmlparser.cpp \ qml/qmlclassfactory.cpp \ qml/qmlparserstatus.cpp \ qml/qmlcompositetypemanager.cpp \ - qml/qmlinfo.cpp + qml/qmlinfo.cpp \ + qml/qmlerror.cpp HEADERS += qml/qmlparser_p.h \ qml/qmlinstruction_p.h \ @@ -36,7 +36,6 @@ HEADERS += qml/qmlparser_p.h \ qml/qmlcustomparser_p_p.h \ qml/qmlpropertyvaluesource.h \ qml/qmlboundsignal_p.h \ - qml/qmlxmlparser_p.h \ qml/qmlparserstatus.h \ qml/qmlproxymetaobject_p.h \ qml/qmlcompiledcomponent_p.h \ @@ -58,7 +57,8 @@ HEADERS += qml/qmlparser_p.h \ qml/qmlcontext_p.h \ qml/qmlcompositetypemanager_p.h \ qml/qmllist.h \ - qml/qmldeclarativedata_p.h + qml/qmldeclarativedata_p.h \ + qml/qmlerror.h # for qtscript debugger QT += scripttools diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index c9bdfec..b8f3921 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -64,17 +64,6 @@ #include "qmlscriptparser_p.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; @@ -147,7 +136,7 @@ int QmlCompiledData::indexForInt(int *data, int count) } QmlCompiler::QmlCompiler() -: exceptionLine(-1), output(0) +: exceptionLine(-1), exceptionColumn(-1), output(0) { } @@ -156,14 +145,19 @@ bool QmlCompiler::isError() const return exceptionLine != -1; } -qint64 QmlCompiler::errorLine() const +QList<QmlError> QmlCompiler::errors() const { - return exceptionLine; -} + QList<QmlError> rv; + + if(isError()) { + QmlError error; + error.setDescription(exceptionDescription); + error.setLine(exceptionLine); + error.setColumn(exceptionColumn); + rv << error; + } -QString QmlCompiler::errorDescription() const -{ - return exceptionDescription; + return rv; } bool QmlCompiler::isValidId(const QString &val) @@ -437,9 +431,19 @@ void QmlCompiler::reset(QmlCompiledComponent *cc, bool deleteMemory) cc->bytecode.clear(); } +#define COMPILE_EXCEPTION2(token, desc) \ + { \ + exceptionLine = token->line; \ + exceptionColumn = token->column; \ + QDebug d(&exceptionDescription); \ + d << desc; \ + return false; \ + } + #define COMPILE_EXCEPTION(desc) \ { \ exceptionLine = obj->line; \ + exceptionColumn = obj->column; \ QDebug d(&exceptionDescription); \ d << desc; \ return false; \ @@ -532,47 +536,14 @@ bool QmlCompiler::compileObject(Object *obj, int ctxt) 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); - } - int createInstrIdx = output->bytecode.count(); - 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.data = -1; - create.create.type = obj->type; - output->bytecode << create; - } + // Create the object + QmlInstruction create; + create.type = QmlInstruction::CreateObject; + create.line = obj->line; + create.create.data = -1; + create.create.type = obj->type; + output->bytecode << create; COMPILE_CHECK(compileDynamicPropertiesAndSignals(obj)); @@ -599,9 +570,7 @@ bool QmlCompiler::compileObject(Object *obj, int ctxt) QList<QmlCustomParserProperty> customProps; 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") && + if (prop->name.length() >= 3 && prop->name.startsWith("on") && ('A' <= prop->name.at(2) && 'Z' >= prop->name.at(2))) { if (!isCustomParser) { COMPILE_CHECK(compileSignal(prop, obj)); @@ -1215,10 +1184,10 @@ bool QmlCompiler::compilePropertyLiteralAssignment(QmlParser::Property *prop, //### 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()); + COMPILE_EXCEPTION2(v, "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()); + COMPILE_EXCEPTION2(v, "Cannot assign value" << v->primitive << "to the read-only property" << obj->metaObject()->property(prop->index).name()); } else { doassign = true; } @@ -1243,209 +1212,9 @@ bool QmlCompiler::compilePropertyLiteralAssignment(QmlParser::Property *prop, 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); - + // ### FIXME - Check that there is only one default property etc. if (obj->dynamicProperties.isEmpty() && obj->dynamicSignals.isEmpty()) return true; diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index 9a0ce1c..4acdcfa 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -45,6 +45,7 @@ #include <QtCore/qbytearray.h> #include <QtCore/qset.h> #include <qml.h> +#include <qmlerror.h> #include <private/qmlinstruction_p.h> #include <private/qmlcompositetypemanager_p.h> class QStringList; @@ -115,8 +116,7 @@ public: bool compile(QmlEngine *, QmlCompositeTypeData *, QmlCompiledComponent *); bool isError() const; - qint64 errorLine() const; - QString errorDescription() const; + QList<QmlError> errors() const; static bool isValidId(const QString &); static bool isBinding(const QString &); @@ -163,11 +163,6 @@ private: QmlParser::Value *value, int ctxt); - bool findDynamicProperties(QmlParser::Property *prop, - QmlParser::Object *obj); - bool findDynamicSignals(QmlParser::Property *sigs, - QmlParser::Object *obj); - bool compileDynamicPropertiesAndSignals(QmlParser::Object *obj); void compileBinding(const QString &, QmlParser::Property *prop, int ctxt, const QMetaObject *, qint64); @@ -176,6 +171,7 @@ private: QSet<QString> ids; qint64 exceptionLine; + qint64 exceptionColumn; QString exceptionDescription; QmlCompiledData *output; }; diff --git a/src/declarative/qml/qmlcomponent.cpp b/src/declarative/qml/qmlcomponent.cpp index c316f03..b1beb9c 100644 --- a/src/declarative/qml/qmlcomponent.cpp +++ b/src/declarative/qml/qmlcomponent.cpp @@ -60,17 +60,6 @@ QT_BEGIN_NAMESPACE class QByteArray; -bool QmlComponentPrivate::isXml(const QByteArray &ba) -{ - for (int i = 0; i < ba.size(); ++i) { - char c = ba.at(i); - if (c == ' ' || c == '\n' || c == '\r' || c == '\t') - continue; - return (c == '<'); - } - return true; -} - /*! \class QmlComponent \brief The QmlComponent class encapsulates a QML component description. @@ -137,9 +126,7 @@ void QmlComponentPrivate::fromTypeData(QmlCompositeTypeData *data) if (!c) { Q_ASSERT(data->status == QmlCompositeTypeData::Error); - errorDescription = data->errorDescription; - qWarning().nospace() << "QmlComponent: " - << data->errorDescription.toLatin1().constData(); + errors = data->errors; } else { @@ -192,10 +179,10 @@ QmlComponent::Status QmlComponent::status() const if (d->typeData) return Loading; + else if (!d->errors.isEmpty()) + return Error; else if (d->engine && d->cc) return Ready; - else if (!d->errorDescription.isEmpty()) - return Error; else return Null; } @@ -353,13 +340,17 @@ void QmlComponent::loadUrl(const QUrl &url) emit statusChanged(status()); } -QString QmlComponent::errorDescription() const +/*! + Return the list of errors that occured during the last compile or create + operation. An empty list is returned if isError() is not set. +*/ +QList<QmlError> QmlComponent::errors() const { Q_D(const QmlComponent); if (isError()) - return d->errorDescription; + return d->errors; else - return QString(); + return QList<QmlError>(); } /*! @@ -448,7 +439,7 @@ QObject *QmlComponent::beginCreate(QmlContext *context) } if (!isReady()) { - qWarning("QmlComponent: Cannot create un-ready component"); + qWarning("QmlComponent: Component is not ready"); return 0; } @@ -466,15 +457,9 @@ QObject *QmlComponent::beginCreate(QmlContext *context) QmlVME vme; QObject *rv = vme.run(ctxt, d->cc, d->start, d->count); - if (vme.isError()) { - qWarning().nospace() -#ifdef QML_VERBOSEERRORS_ENABLED - << "QmlComponent: " -#endif - << vme.errorDescription().toLatin1().constData() << " @" - << d->url.toString().toLatin1().constData() << ":" << vme.errorLine(); - } + if (vme.isError()) + d->errors = vme.errors(); ctxt->deactivate(); diff --git a/src/declarative/qml/qmlcomponent.h b/src/declarative/qml/qmlcomponent.h index 0493c1f..90f7467 100644 --- a/src/declarative/qml/qmlcomponent.h +++ b/src/declarative/qml/qmlcomponent.h @@ -46,7 +46,7 @@ #include <QtCore/qstring.h> #include <QtDeclarative/qfxglobal.h> #include <QtDeclarative/qml.h> - +#include <QtDeclarative/qmlerror.h> QT_BEGIN_HEADER @@ -77,7 +77,8 @@ public: bool isReady() const; bool isError() const; bool isLoading() const; - QString errorDescription() const; + + QList<QmlError> errors() const; QUrl url() const; diff --git a/src/declarative/qml/qmlcomponent_p.h b/src/declarative/qml/qmlcomponent_p.h index bb5f7bb..6a5345e 100644 --- a/src/declarative/qml/qmlcomponent_p.h +++ b/src/declarative/qml/qmlcomponent_p.h @@ -47,6 +47,7 @@ #include <QList> #include "private/qobject_p.h" #include "private/qmlcompositetypemanager_p.h" +#include <qmlerror.h> #include "qmlcomponent.h" class QmlComponent; class QmlEngine; @@ -68,7 +69,7 @@ public: void fromTypeData(QmlCompositeTypeData *data); - QString errorDescription; + QList<QmlError> errors; QUrl url; int start; @@ -81,7 +82,6 @@ public: QmlEngine *engine; void clear(); - static bool isXml(const QByteArray &); }; #endif // QMLCOMPONENT_P_H diff --git a/src/declarative/qml/qmlcompositetypemanager.cpp b/src/declarative/qml/qmlcompositetypemanager.cpp index 7f2cc58..fbe40bf 100644 --- a/src/declarative/qml/qmlcompositetypemanager.cpp +++ b/src/declarative/qml/qmlcompositetypemanager.cpp @@ -105,10 +105,9 @@ QmlCompositeTypeData::toCompiledComponent(QmlEngine *engine) QmlCompiler compiler; if (!compiler.compile(engine, this, compiledComponent)) { status = Error; - errorDescription = compiler.errorDescription() + - QLatin1String("@") + - url + QLatin1String(":") + - QString::number(compiler.errorLine()); + errors = compiler.errors(); + for(int ii = 0; ii < errors.count(); ++ii) + errors[ii].setUrl(url); compiledComponent->release(); compiledComponent = 0; } @@ -188,7 +187,10 @@ void QmlCompositeTypeManager::replyFinished() reply->url().toString(); unit->status = QmlCompositeTypeData::Error; - unit->errorDescription = errorDescription; + // ### FIXME + QmlError error; + error.setDescription(errorDescription); + unit->errors << error; doComplete(unit); } else { @@ -215,7 +217,10 @@ void QmlCompositeTypeManager::loadSource(QmlCompositeTypeData *unit) // ### - Fill in error errorDescription = QLatin1String("File error for URL ") + url.toString(); unit->status = QmlCompositeTypeData::Error; - unit->errorDescription = errorDescription; + // ### FIXME + QmlError error; + error.setDescription(errorDescription); + unit->errors << error; doComplete(unit); } @@ -234,7 +239,7 @@ void QmlCompositeTypeManager::setData(QmlCompositeTypeData *unit, if (!unit->data.parse(data, url)) { unit->status = QmlCompositeTypeData::Error; - unit->errorDescription = unit->data.errorDescription(); + unit->errors << unit->data.errors(); doComplete(unit); } else { @@ -273,7 +278,7 @@ void QmlCompositeTypeManager::checkComplete(QmlCompositeTypeData *unit) if (u->status == QmlCompositeTypeData::Error) { unit->status = QmlCompositeTypeData::Error; - unit->errorDescription = u->errorDescription; + unit->errors = u->errors; doComplete(unit); return; } else if (u->status == QmlCompositeTypeData::Waiting) { @@ -334,7 +339,7 @@ void QmlCompositeTypeManager::compile(QmlCompositeTypeData *unit) case QmlCompositeTypeData::Invalid: case QmlCompositeTypeData::Error: unit->status = QmlCompositeTypeData::Error; - unit->errorDescription = urlUnit->errorDescription; + unit->errors = urlUnit->errors; doComplete(unit); return; diff --git a/src/declarative/qml/qmlcompositetypemanager_p.h b/src/declarative/qml/qmlcompositetypemanager_p.h index bc86fcf..e4028d5 100644 --- a/src/declarative/qml/qmlcompositetypemanager_p.h +++ b/src/declarative/qml/qmlcompositetypemanager_p.h @@ -45,6 +45,7 @@ #include <qglobal.h> #include <private/qmlscriptparser_p.h> #include <private/qmlrefcount_p.h> +#include <qmlerror.h> QT_BEGIN_NAMESPACE @@ -65,7 +66,8 @@ struct QmlCompositeTypeData : public QmlRefCount Waiting }; Status status; - QString errorDescription; + + QList<QmlError> errors; QString url; QList<QmlCompositeTypeData *> dependants; diff --git a/src/declarative/qml/qmlcustomparser_p.h b/src/declarative/qml/qmlcustomparser_p.h index 0e6a619..e4e6089 100644 --- a/src/declarative/qml/qmlcustomparser_p.h +++ b/src/declarative/qml/qmlcustomparser_p.h @@ -98,26 +98,9 @@ class Q_DECLARATIVE_EXPORT QmlCustomParser public: virtual ~QmlCustomParser() {} - virtual QByteArray compile(QXmlStreamReader&, bool *ok)=0; virtual QByteArray compile(const QList<QmlCustomParserProperty> &, bool *ok); - virtual QVariant create(const QByteArray &)=0; virtual void setCustomData(QObject *, const QByteArray &); - - struct Register { - Register(const char *name, QmlCustomParser *parser) { - qmlRegisterCustomParser(name, parser); - } - }; - template<typename T> - struct Define { - static Register instance; - }; }; -#define QML_DEFINE_CUSTOM_PARSER(name, parserClass) \ - template<> QmlCustomParser::Register QmlCustomParser::Define<parserClass>::instance(# name, new parserClass); -#define QML_DEFINE_CUSTOM_PARSER_NS(namespacestring, name, parserClass) \ - template<> QmlCustomParser::Register QmlCustomParser::Define<parserClass>::instance(namespacestring "/" # name, new parserClass); - #define QML_DEFINE_CUSTOM_TYPE(TYPE, NAME, CUSTOMTYPE) \ template<> QmlPrivate::InstanceType QmlPrivate::Define<TYPE *>::instance(qmlRegisterCustomType<TYPE>(#NAME, #TYPE, new CUSTOMTYPE)); diff --git a/src/declarative/qml/qmldom.cpp b/src/declarative/qml/qmldom.cpp index 5380740..08755b1 100644 --- a/src/declarative/qml/qmldom.cpp +++ b/src/declarative/qml/qmldom.cpp @@ -70,6 +70,7 @@ QmlDomDocumentPrivate::~QmlDomDocumentPrivate() /*! \class QmlDomDocument + \internal \brief The QmlDomDocument class represents the root of a QML document A QML document is a self-contained snippet of QML, usually contained in a @@ -152,7 +153,7 @@ bool QmlDomDocument::load(QmlEngine *engine, const QByteArray &data) { Q_UNUSED(engine); - d->error = QString(); + d->errors.clear(); QmlCompiledComponent component; QmlCompiler compiler; @@ -160,11 +161,13 @@ bool QmlDomDocument::load(QmlEngine *engine, const QByteArray &data) QmlCompositeTypeData *td = ((QmlEnginePrivate *)QmlEnginePrivate::get(engine))->typeManager.getImmediate(data, QUrl());; if(td->status == QmlCompositeTypeData::Error) { - d->error = td->errorDescription; + d->errors = td->errors; td->release(); return false; } else if(td->status == QmlCompositeTypeData::Waiting) { - d->error = QLatin1String("QmlDomDocument supports local types only"); + QmlError error; + error.setDescription(QLatin1String("QmlDomDocument supports local types only")); + d->errors << error; td->release(); return false; } @@ -172,7 +175,7 @@ bool QmlDomDocument::load(QmlEngine *engine, const QByteArray &data) compiler.compile(engine, td, &component); if (compiler.isError()) { - d->error = compiler.errorDescription(); + d->errors = compiler.errors(); td->release(); return false; } @@ -188,14 +191,14 @@ bool QmlDomDocument::load(QmlEngine *engine, const QByteArray &data) /*! - Returns the last load error. The load error will be reset after a + Returns the last load errors. The load errors will be reset after a successful call to load(). \sa load() */ -QString QmlDomDocument::loadError() const +QList<QmlError> QmlDomDocument::errors() const { - return d->error; + return d->errors; } /*! @@ -249,6 +252,7 @@ QmlDomPropertyPrivate::~QmlDomPropertyPrivate() /*! \class QmlDomProperty + \internal \brief The QmlDomProperty class represents one property assignment in the QML DOM tree @@ -450,6 +454,7 @@ QmlDomObjectPrivate::properties(QmlParser::Property *property) const /*! \class QmlDomObject + \internal \brief The QmlDomObject class represents an object instantiation. Each object instantiated in a QML file has a corresponding QmlDomObject @@ -734,6 +739,7 @@ QmlDomBasicValuePrivate::~QmlDomBasicValuePrivate() /*! \class QmlDomValueLiteral + \internal \brief The QmlDomValueLiteral class represents a literal value. A literal value is a simple value, written inline with the QML. In the @@ -806,6 +812,7 @@ void QmlDomValueLiteral::setLiteral(const QString &value) /*! \class QmlDomValueBinding + \internal \brief The QmlDomValueBinding class represents a property binding. A property binding is an ECMAScript expression assigned to a property. In @@ -875,6 +882,7 @@ void QmlDomValueBinding::setBinding(const QString &expression) /*! \class QmlDomValueValueSource + \internal \brief The QmlDomValueValueSource class represents a value source assignment value. In QML, value sources are special value generating types that may be @@ -983,6 +991,7 @@ QmlDomValuePrivate::~QmlDomValuePrivate() /*! \class QmlDomValue + \internal \brief The QmlDomValue class represents a generic Qml value. QmlDomValue's can be assigned to QML \l {QmlDomProperty}{properties}. In @@ -1234,6 +1243,7 @@ QmlDomList QmlDomValue::toList() const /*! \class QmlDomList + \internal \brief The QmlDomList class represents a list of values assigned to a QML property. Lists of values can be assigned to properties. For example, the following @@ -1323,6 +1333,7 @@ void QmlDomList::setValues(const QList<QmlDomValue> &values) /*! \class QmlDomComponent + \internal \brief The QmlDomComponent class represents sub-component within a QML document. Sub-components are QmlComponents defined within a QML document. The diff --git a/src/declarative/qml/qmldom.h b/src/declarative/qml/qmldom.h index 47a89d9..74ed27c 100644 --- a/src/declarative/qml/qmldom.h +++ b/src/declarative/qml/qmldom.h @@ -44,6 +44,7 @@ #include <QtCore/qlist.h> #include <QtCore/qshareddata.h> +#include <QtDeclarative/qmlerror.h> QT_BEGIN_HEADER @@ -71,6 +72,7 @@ public: int version() const; + QList<QmlError> errors() const; QString loadError() const; bool load(QmlEngine *, const QByteArray &); QByteArray save() const; diff --git a/src/declarative/qml/qmldom_p.h b/src/declarative/qml/qmldom_p.h index 8ea56bf..4c3ca44 100644 --- a/src/declarative/qml/qmldom_p.h +++ b/src/declarative/qml/qmldom_p.h @@ -57,7 +57,7 @@ public: QmlDomDocumentPrivate(const QmlDomDocumentPrivate &); ~QmlDomDocumentPrivate(); - QString error; + QList<QmlError> errors; QmlParser::Object *root; }; diff --git a/src/declarative/qml/qmlerror.cpp b/src/declarative/qml/qmlerror.cpp new file mode 100644 index 0000000..2ed3500 --- /dev/null +++ b/src/declarative/qml/qmlerror.cpp @@ -0,0 +1,227 @@ +/**************************************************************************** +** +** 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 "qmlerror.h" +#include <QtCore/qdebug.h> +#include <QtCore/qfile.h> +#include <QtCore/qstringlist.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QmlError + \brief The QmlError class encapsulates a QML error +*/ +class QmlErrorPrivate +{ +public: + QmlErrorPrivate(); + + QUrl url; + QString description; + int line; + int column; +}; + +QmlErrorPrivate::QmlErrorPrivate() +: line(-1), column(-1) +{ +} + +/*! + Create an empty error object. +*/ +QmlError::QmlError() +: d(new QmlErrorPrivate) +{ +} + +/*! + Create a copy of \a other. +*/ +QmlError::QmlError(const QmlError &other) +: d(new QmlErrorPrivate) +{ + *this = other; +} + +/*! + Assign \a other to this error object. +*/ +QmlError &QmlError::operator=(const QmlError &other) +{ + d->url = other.d->url; + d->description = other.d->description; + d->line = other.d->line; + d->column = other.d->column; + return *this; +} + +/*! + \internal +*/ +QmlError::~QmlError() +{ + delete d; d = 0; +} + +/*! + Return the url for the file that caused this error. +*/ +QUrl QmlError::url() const +{ + return d->url; +} + +/*! + Set the \a url for the file that caused this error. +*/ +void QmlError::setUrl(const QUrl &url) +{ + d->url = url; +} + +/*! + Return the error description. +*/ +QString QmlError::description() const +{ + return d->description; +} + +/*! + Set the error \a description. +*/ +void QmlError::setDescription(const QString &description) +{ + d->description = description; +} + +/*! + Return the error line number. +*/ +int QmlError::line() const +{ + return d->line; +} + +/*! + Set the error \a line number. +*/ +void QmlError::setLine(int line) +{ + d->line = line; +} + +/*! + Return the error column number. +*/ +int QmlError::column() const +{ + return d->column; +} + +/*! + Set the error \a column number. +*/ +void QmlError::setColumn(int column) +{ + d->column = column; +} + +/*! + \relates QmlError + \fn QDebug operator<<(QDebug debug, const QmlError &error) + + Output a human readable version of \a error to \a debug. +*/ + +QDebug operator<<(QDebug debug, const QmlError &error) +{ + QUrl url = error.url(); + + QString output; + + output = url.toString() + QLatin1String(":") + + QString::number(error.line()); + + if(error.column() != -1) + output += QLatin1String(":") + QString::number(error.column()); + + output += QLatin1String(": ") + error.description(); + + debug << qPrintable(output) << "\n"; + + if (error.line() > 0 && error.column() > 0 && + url.scheme() == QLatin1String("file")) { + QString file = url.toLocalFile(); + QFile f(file); + if (f.open(QIODevice::ReadOnly)) { + QByteArray data = f.readAll(); + QTextStream stream(data, QIODevice::ReadOnly); + const QString code = stream.readAll(); + const QStringList lines = code.split(QLatin1Char('\n')); + + if (lines.count() >= error.line()) { + const QString &line = lines.at(error.line() - 1); + debug << qPrintable(line) << "\n"; + + int column = qMax(0, error.column() - 1); + column = qMin(column, line.length()); + + QByteArray ind; + ind.reserve(column); + for (int i = 0; i < column; ++i) { + const QChar ch = line.at(i); + if (ch.isSpace()) + ind.append(ch.unicode()); + else + ind.append(' '); + } + ind.append('^'); + debug << ind.constData(); + } + } + } + return debug; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlxmlparser_p.h b/src/declarative/qml/qmlerror.h index 9b45e28..57d2f8f 100644 --- a/src/declarative/qml/qmlxmlparser_p.h +++ b/src/declarative/qml/qmlerror.h @@ -39,12 +39,11 @@ ** ****************************************************************************/ -#ifndef QMLXMLPARSER_P_H -#define QMLXMLPARSER_P_H +#ifndef QMLERROR_H +#define QMLERROR_H -#include <QList> -#include <QUrl> -#include <qml.h> +#include <QtCore/qurl.h> +#include <QtCore/qstring.h> QT_BEGIN_HEADER @@ -52,38 +51,32 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) -namespace QmlParser { - class Object; -} - -class QByteArray; -class QmlXmlParser +class QDebug; +class QmlErrorPrivate; +class Q_DECLARATIVE_EXPORT QmlError { public: - QmlXmlParser(); - ~QmlXmlParser(); - - bool parse(const QByteArray &data, const QUrl &url=QUrl()); - QString errorDescription() const; - - QMap<QString,QString> nameSpacePaths() const; - QStringList types() const; - - QmlParser::Object *tree() const; - QmlParser::Object *takeTree(); - - void clear(); - + QmlError(); + QmlError(const QmlError &); + QmlError &operator=(const QmlError &); + ~QmlError(); + + QUrl url() const; + void setUrl(const QUrl &); + QString description() const; + void setDescription(const QString &); + int line() const; + void setLine(int); + int column() const; + void setColumn(int); private: - QMap<QString,QString> _nameSpacePaths; - QmlParser::Object *root; - QStringList _typeNames; - QString _error; + QmlErrorPrivate *d; }; +QDebug Q_DECLARATIVE_EXPORT operator<<(QDebug debug, const QmlError &error); + QT_END_NAMESPACE QT_END_HEADER -#endif // QMLXMLPARSER_P_H - +#endif // QMLERROR_H diff --git a/src/declarative/qml/qmlinstruction.cpp b/src/declarative/qml/qmlinstruction.cpp index 82924c8..52677c2 100644 --- a/src/declarative/qml/qmlinstruction.cpp +++ b/src/declarative/qml/qmlinstruction.cpp @@ -58,9 +58,6 @@ void QmlCompiledComponent::dump(QmlInstruction *instr, int idx) case QmlInstruction::CreateObject: qWarning() << idx << "\t" << line << "\t" << "CREATE\t\t\t" << instr->create.type << "\t\t\t" << types.at(instr->create.type).className; break; - case QmlInstruction::CreateCustomObject: - qWarning() << idx << "\t" << line << "\t" << "CREATE_CUSTOM\t\t" << instr->createCustom.type << "\t" << instr->createCustom.data << "\t\t" << types.at(instr->create.type).className; - break; case QmlInstruction::SetId: qWarning() << idx << "\t" << line << "\t" << "SETID\t\t\t" << instr->setId.value << "\t" << instr->setId.save << "\t\t" << primitives.at(instr->setId.value); break; diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h index 922fc61..462f9e4 100644 --- a/src/declarative/qml/qmlinstruction_p.h +++ b/src/declarative/qml/qmlinstruction_p.h @@ -63,7 +63,6 @@ public: // top of the stack. Init, /* init */ CreateObject, /* create */ - CreateCustomObject, /* createCustom */ SetId, /* setId */ SetDefault, CreateComponent, /* createComponent */ @@ -180,10 +179,6 @@ public: int data; } storeMeta; struct { - int type; - int data; - } createCustom; - struct { int value; int save; } setId; diff --git a/src/declarative/qml/qmlparser.cpp b/src/declarative/qml/qmlparser.cpp index ecb6f0b..d862315 100644 --- a/src/declarative/qml/qmlparser.cpp +++ b/src/declarative/qml/qmlparser.cpp @@ -63,8 +63,7 @@ QT_BEGIN_NAMESPACE using namespace QmlParser; QmlParser::Object::Object() -: type(-1), metatype(0), extObject(0), defaultProperty(0), line(-1), - dynamicPropertiesProperty(0), dynamicSignalsProperty(0) +: type(-1), metatype(0), extObject(0), defaultProperty(0), line(-1), column(-1) { } @@ -73,8 +72,6 @@ QmlParser::Object::~Object() if (defaultProperty) defaultProperty->release(); foreach(Property *prop, properties) prop->release(); - if (dynamicPropertiesProperty) dynamicPropertiesProperty->release(); - if (dynamicSignalsProperty) dynamicSignalsProperty->release(); } const QMetaObject *Object::metaObject() const @@ -127,12 +124,12 @@ QmlParser::Object::DynamicSignal::DynamicSignal(const DynamicSignal &o) } QmlParser::Property::Property() -: type(0), index(-1), value(0), isDefault(true), line(-1) +: type(0), index(-1), value(0), isDefault(true), line(-1), column(-1) { } QmlParser::Property::Property(const QByteArray &n) -: type(0), index(-1), value(0), name(n), isDefault(false), line(-1) +: type(0), index(-1), value(0), name(n), isDefault(false), line(-1), column(-1) { } @@ -161,7 +158,7 @@ void QmlParser::Property::addValue(Value *v) } QmlParser::Value::Value() -: type(Unknown), object(0), line(-1) +: type(Unknown), object(0), line(-1), column(-1) { } diff --git a/src/declarative/qml/qmlparser_p.h b/src/declarative/qml/qmlparser_p.h index e29cdbf..aeacee8 100644 --- a/src/declarative/qml/qmlparser_p.h +++ b/src/declarative/qml/qmlparser_p.h @@ -103,6 +103,7 @@ namespace QmlParser QHash<QByteArray, Property *> properties; qint64 line; + qint64 column; struct DynamicProperty { DynamicProperty(); @@ -123,10 +124,6 @@ namespace QmlParser QByteArray name; }; - // The "properties" property - Property *dynamicPropertiesProperty; - // The "signals" property - Property *dynamicSignalsProperty; // The list of dynamic properties described in the "properties" property QList<DynamicProperty> dynamicProperties; // The list of dynamic signals described in the "signals" property @@ -167,6 +164,7 @@ namespace QmlParser Object *object; qint64 line; + qint64 column; }; class Property : public QmlRefCount @@ -197,6 +195,7 @@ namespace QmlParser bool isDefault; qint64 line; + qint64 column; }; } diff --git a/src/declarative/qml/qmlscriptparser.cpp b/src/declarative/qml/qmlscriptparser.cpp index 8039b5c..81315c3 100644 --- a/src/declarative/qml/qmlscriptparser.cpp +++ b/src/declarative/qml/qmlscriptparser.cpp @@ -1,6 +1,5 @@ #include "qmlscriptparser_p.h" -#include "qmlxmlparser_p.h" #include "qmlparser_p.h" #include "parser/javascriptengine_p.h" @@ -65,10 +64,12 @@ protected: Object *defineObjectBinding(int line, AST::UiQualifiedId *propertyName, const QString &objectType, + AST::SourceLocation typeLocation, AST::UiObjectInitializer *initializer = 0); Object *defineObjectBinding_helper(int line, AST::UiQualifiedId *propertyName, const QString &objectType, + AST::SourceLocation typeLocation, AST::UiObjectInitializer *initializer = 0); QString getPrimitive(const QByteArray &propertyName, AST::ExpressionNode *expr); void defineProperty(const QString &propertyName, int line, const QString &primitive); @@ -194,11 +195,17 @@ QString ProcessAST::asString(AST::UiQualifiedId *node) const Object *ProcessAST::defineObjectBinding_helper(int line, AST::UiQualifiedId *propertyName, const QString &objectType, + AST::SourceLocation typeLocation, AST::UiObjectInitializer *initializer) { bool isType = !objectType.isEmpty() && objectType.at(0).isUpper() && !objectType.contains(QLatin1Char('.')); + if (!isType) { - qWarning() << "bad name for a class"; // ### FIXME + QmlError error; + error.setDescription("Expected type name"); + error.setLine(typeLocation.startLine); + error.setColumn(typeLocation.startColumn); + _parser->_errors << error; return false; } @@ -235,7 +242,7 @@ Object *ProcessAST::defineObjectBinding_helper(int line, if (!_parser->scriptFile().isEmpty()) { _stateStack.pushObject(obj); - Object *scriptObject= defineObjectBinding(line, 0, QLatin1String("Script")); + Object *scriptObject= defineObjectBinding(line, 0, QLatin1String("Script"), AST::SourceLocation()); _stateStack.pushObject(scriptObject); defineProperty(QLatin1String("src"), line, _parser->scriptFile()); _stateStack.pop(); // scriptObject @@ -264,11 +271,12 @@ Object *ProcessAST::defineObjectBinding_helper(int line, Object *ProcessAST::defineObjectBinding(int line, AST::UiQualifiedId *qualifiedId, const QString &objectType, + AST::SourceLocation typeLocation, AST::UiObjectInitializer *initializer) { if (objectType == QLatin1String("Connection")) { - Object *obj = defineObjectBinding_helper(line, 0, QLatin1String("Connection")); + Object *obj = defineObjectBinding_helper(line, 0, objectType, typeLocation); _stateStack.pushObject(obj); @@ -297,7 +305,7 @@ Object *ProcessAST::defineObjectBinding(int line, return obj; } - return defineObjectBinding_helper(line, qualifiedId, objectType, initializer); + return defineObjectBinding_helper(line, qualifiedId, objectType, typeLocation, initializer); } void ProcessAST::defineProperty(const QString &propertyName, int line, const QString &primitive) @@ -372,7 +380,11 @@ bool ProcessAST::visit(AST::UiPublicMember *node) } if(!typeFound) { - qWarning() << "Unknown property type" << memberType; // ### FIXME + QmlError error; + error.setDescription("Expected property type"); + error.setLine(node->typeToken.startLine); + error.setColumn(node->typeToken.startColumn); + _parser->_errors << error; return false; } @@ -402,6 +414,7 @@ bool ProcessAST::visit(AST::UiObjectDefinition *node) defineObjectBinding(node->identifierToken.startLine, 0, node->name->asString(), + node->identifierToken, node->initializer); return false; @@ -414,6 +427,7 @@ bool ProcessAST::visit(AST::UiObjectBinding *node) defineObjectBinding(node->identifierToken.startLine, node->qualifiedId, node->name->asString(), + node->identifierToken, node->initializer); return false; @@ -476,7 +490,8 @@ bool ProcessAST::visit(AST::UiScriptBinding *node) Value *v = new Value; v->primitive = primitive; - v->line = node->colonToken.startLine; + v->line = node->statement->firstSourceLocation().startLine; + v->column = node->statement->firstSourceLocation().startColumn; prop->addValue(v); while (propertyCount--) @@ -507,7 +522,11 @@ bool ProcessAST::visit(AST::UiSourceElement *node) { QmlParser::Object *obj = currentObject(); if (! (obj && obj->typeName == "Script")) { - // ### warning + QmlError error; + error.setDescription("JavaScript declaration outside Script element"); + error.setLine(node->firstSourceLocation().startLine); + error.setColumn(node->firstSourceLocation().startColumn); + _parser->_errors << error; return false; } @@ -535,7 +554,7 @@ bool ProcessAST::visit(AST::UiSourceElement *node) QmlScriptParser::QmlScriptParser() - : root(0), _errorLine(-1) +: root(0) { } @@ -546,21 +565,6 @@ QmlScriptParser::~QmlScriptParser() bool QmlScriptParser::parse(const QByteArray &data, const QUrl &url) { - if (QmlComponentPrivate::isXml(data)) { - // parse using the XML parser. - QmlXmlParser xmlParser; - if (xmlParser.parse(data, url)) { - _nameSpacePaths = xmlParser.nameSpacePaths(); - root = xmlParser.takeTree(); - _typeNames = xmlParser.types(); - return true; - } - - _error = xmlParser.errorDescription(); - _errorLine = 0; // ### FIXME - return false; - } - const QString fileName = url.toString(); QTextStream stream(data, QIODevice::ReadOnly); @@ -576,61 +580,34 @@ bool QmlScriptParser::parse(const QByteArray &data, const QUrl &url) lexer.setCode(code, /*line = */ 1); driver.setLexer(&lexer); - if (! parser.parse(&driver)) { - _error = parser.errorMessage(); - _errorLine = parser.errorLineNumber(); - - const QStringList lines = code.split(QLatin1Char('\n')); + if (! parser.parse(&driver) || !_errors.isEmpty()) { + // Extract errors from the parser foreach (const JavaScriptParser::DiagnosticMessage &m, parser.diagnosticMessages()) { if (m.isWarning()) continue; - qWarning().nospace() << qPrintable(fileName) << ":" - << m.line << ":" - << m.column << ": " - << "error: " - << qPrintable(m.message); - - const QString textLine = lines.at(m.line - 1); - - qWarning() << qPrintable(textLine); + QmlError error; + error.setUrl(url); + error.setDescription(m.message); + error.setLine(m.line); + error.setColumn(m.column); + _errors << error; - int column = qMax(0, m.column - 1); - column = qMin(column, textLine.length()); // paranoia check - - QByteArray ind; - ind.reserve(column); - - for (int i = 0; i < column; ++i) { - const QChar ch = textLine.at(i); - if (ch.isSpace()) - ind.append(ch.unicode()); - else - ind.append(' '); - } - ind.append('^'); - qWarning() << ind.constData(); } - - return false; } - ProcessAST process(this); - process(code, parser.ast()); - - return true; -} + if (_errors.isEmpty()) { + ProcessAST process(this); + process(code, parser.ast()); -QString QmlScriptParser::errorDescription() const -{ - return _error; -} + // Set the url for process errors + for(int ii = 0; ii < _errors.count(); ++ii) + _errors[ii].setUrl(url); + } -int QmlScriptParser::errorLine() const -{ - return _errorLine; + return _errors.isEmpty(); } QMap<QString,QString> QmlScriptParser::nameSpacePaths() const @@ -648,6 +625,11 @@ Object *QmlScriptParser::tree() const return root; } +QList<QmlError> QmlScriptParser::errors() const +{ + return _errors; +} + void QmlScriptParser::clear() { if (root) { @@ -656,9 +638,8 @@ void QmlScriptParser::clear() } _nameSpacePaths.clear(); _typeNames.clear(); - _error.clear(); + _errors.clear(); _scriptFile.clear(); - _errorLine = 0; } int QmlScriptParser::findOrCreateTypeId(const QString &name) diff --git a/src/declarative/qml/qmlscriptparser_p.h b/src/declarative/qml/qmlscriptparser_p.h index 0d89268..4155bba 100644 --- a/src/declarative/qml/qmlscriptparser_p.h +++ b/src/declarative/qml/qmlscriptparser_p.h @@ -3,6 +3,7 @@ #include <QtCore/QList> #include <QtCore/QUrl> +#include <QtDeclarative/qmlerror.h> #include <qml.h> QT_BEGIN_HEADER @@ -23,8 +24,6 @@ public: ~QmlScriptParser(); bool parse(const QByteArray &data, const QUrl &url = QUrl()); - QString errorDescription() const; - int errorLine() const; QMap<QString,QString> nameSpacePaths() const; QStringList types() const; @@ -33,6 +32,8 @@ public: void clear(); + QList<QmlError> errors() const; + // ### private: int findOrCreateTypeId(const QString &name); void setTree(QmlParser::Object *tree); @@ -42,12 +43,12 @@ public: void addNamespacePath(const QString &path); -private: +// ### private: + QList<QmlError> _errors; + QMap<QString,QString> _nameSpacePaths; QmlParser::Object *root; QStringList _typeNames; - QString _error; - int _errorLine; QString _scriptFile; }; diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index e6235e4..ad3d1d5 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -176,9 +176,14 @@ QmlVME::QmlVME() #define VME_EXCEPTION(desc) \ { \ - exceptionLine = instr.line; \ - QDebug d(&exceptionDescription); \ - d << desc; \ + QString str; \ + QDebug d(&str); \ + d << desc; \ + QmlError error; \ + error.setDescription(str); \ + error.setLine(instr.line); \ + error.setUrl(comp->url); \ + vmeErrors << error; \ break; \ } @@ -224,6 +229,8 @@ QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledComponent *comp, int start, in QStack<QmlMetaProperty> pushedProperties; QObject **savedObjects = 0; + vmeErrors.clear(); + if (start == -1) start = 0; if (count == -1) count = comp->bytecode.count(); @@ -270,27 +277,6 @@ QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledComponent *comp, int start, in } break; - case QmlInstruction::CreateCustomObject: - { -#ifdef Q_ENABLE_PERFORMANCE_LOG - QFxCompilerTimer<QFxCompiler::InstrCreateCustomObject> cc; -#endif - QVariant v = - types.at(instr.createCustom.type).parser->create(datas.at(instr.createCustom.data)); - // XXX - QObject *o = QmlMetaType::toQObject(v); - if (!o) - VME_EXCEPTION("Unable to create" << types.at(instr.create.type).className); - QmlEngine::setContextForObject(o, QmlContext::activeContext()); - - if (!stack.isEmpty()) { - QObject *parent = stack.top(); - o->setParent(parent); - } - stack.push(o); - } - break; - case QmlInstruction::SetId: { #ifdef Q_ENABLE_PERFORMANCE_LOG @@ -1072,17 +1058,12 @@ QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledComponent *comp, int start, in bool QmlVME::isError() const { - return exceptionLine != -1; -} - -qint64 QmlVME::errorLine() const -{ - return exceptionLine; + return !vmeErrors.isEmpty(); } -QString QmlVME::errorDescription() const +QList<QmlError> QmlVME::errors() const { - return exceptionDescription; + return vmeErrors; } void QmlVME::runStoreInstruction(QStack<QObject *> &stack, diff --git a/src/declarative/qml/qmlvme_p.h b/src/declarative/qml/qmlvme_p.h index 2a3be06..86cd040 100644 --- a/src/declarative/qml/qmlvme_p.h +++ b/src/declarative/qml/qmlvme_p.h @@ -44,6 +44,7 @@ #include <QString> #include <QStack> +#include <qmlerror.h> class QObject; QT_BEGIN_NAMESPACE @@ -60,13 +61,13 @@ public: QObject *run(QmlContext *, QmlCompiledComponent *, int start = -1, int end = -1); bool isError() const; - qint64 errorLine() const; - QString errorDescription() const; + QList<QmlError> errors() const; private: void runStoreInstruction(QStack<QObject *> &stack, QmlInstruction &, QmlCompiledData *); + QList<QmlError> vmeErrors; qint64 exceptionLine; QString exceptionDescription; }; diff --git a/src/declarative/qml/qmlxmlparser.cpp b/src/declarative/qml/qmlxmlparser.cpp deleted file mode 100644 index 35d2c0e..0000000 --- a/src/declarative/qml/qmlxmlparser.cpp +++ /dev/null @@ -1,391 +0,0 @@ -/**************************************************************************** -** -** 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 "qmlxmlparser_p.h" -#include "qmlcustomparser_p.h" -#include <qfxperf.h> -#include <QXmlStreamReader> -#include <QStack> -#include "qmlparser_p.h" -#include <private/qmlparser_p.h> -#include <QtCore/qdebug.h> - -QT_BEGIN_NAMESPACE -using namespace QmlParser; - -struct QmlXmlParserState { - QmlXmlParserState() : object(0), property(0) {} - QmlXmlParserState(Object *o) : object(o), property(0) {} - QmlXmlParserState(Object *o, Property *p) : object(o), property(p) {} - - Object *object; - Property *property; -}; - -struct QmlXmlParserStateStack : public QStack<QmlXmlParserState> -{ - void pushObject(Object *obj) - { - push(QmlXmlParserState(obj)); - } - - void pushProperty(const QString &name, int lineNumber) - { - const QmlXmlParserState &state = top(); - if (state.property) { - QmlXmlParserState s(state.property->getValue(), - state.property->getValue()->getProperty(name.toLatin1())); - s.property->line = lineNumber; - push(s); - } else { - QmlXmlParserState s(state.object, - state.object->getProperty(name.toLatin1())); - s.property->line = lineNumber; - push(s); - } - } -}; - -QmlXmlParser::~QmlXmlParser() -{ - if (root) - root->release(); -} - -QmlXmlParser::QmlXmlParser() -: root(0) -{ -} - -static QString flatXml(QXmlStreamReader& reader) -{ - QString result; - int depth=0; - QStringRef ns = reader.namespaceUri(); - while (depth>=0) { - switch (reader.tokenType()) { - case QXmlStreamReader::StartElement: - result += QLatin1Char('<'); - result += reader.name(); - if (reader.namespaceUri() != ns || depth==0) { - result += QLatin1String(" xmlns=\""); - result += reader.namespaceUri(); - result += QLatin1Char('"'); - } - foreach(QXmlStreamAttribute attr, reader.attributes()) { - result += QLatin1Char(' '); - result += attr.name(); - result += QLatin1String("=\""); - result += attr.value(); // XXX escape - result += QLatin1Char('"'); - } - result += QLatin1Char('>'); - ++depth; - break; - case QXmlStreamReader::EndElement: - result += QLatin1String("</"); - result += reader.name(); - result += QLatin1Char('>'); - --depth; - break; - case QXmlStreamReader::Characters: - result += reader.text(); - break; - default: - reader.raiseError(QLatin1String("Only StartElement, EndElement, and Characters permitted")); - break; - } - if (depth>=0) - reader.readNext(); - } - return result; -} - -bool QmlXmlParser::parse(const QByteArray &data, const QUrl &url) -{ -#ifdef Q_ENABLE_PERFORMANCE_LOG - QFxPerfTimer<QFxPerf::XmlParsing> pt; -#endif - - QString fileDisplayName; - if (url.isEmpty()) { - fileDisplayName = QLatin1String("<unspecified file>"); - } else if (url.scheme() == QLatin1String("file")) { - fileDisplayName = url.toLocalFile(); - } else { - fileDisplayName = url.toString(); - } - if (data.isEmpty()) { - _error = QLatin1String("No Qml was specified for parsing @") + fileDisplayName; - return false; - } - - QmlXmlParserStateStack states; - - QXmlStreamReader reader; - reader.addData(data); - - while(!reader.atEnd()) { - switch(reader.readNext()) { - case QXmlStreamReader::Invalid: - case QXmlStreamReader::NoToken: - case QXmlStreamReader::StartDocument: - case QXmlStreamReader::EndDocument: - break; - - case QXmlStreamReader::StartElement: - { - QString name = reader.name().toString(); - QString nameSpace = reader.namespaceUri().toString(); - int line = reader.lineNumber(); - bool isType = name.at(0).isUpper() && !name.contains(QLatin1Char('.')); - QString qualifiedname; - if (!nameSpace.isEmpty()) { - qualifiedname = nameSpace; - qualifiedname += QLatin1Char('/'); - } - qualifiedname += name; - QByteArray qualifiednameL1 = qualifiedname.toLatin1(); - QXmlStreamAttributes attrs = reader.attributes(); - - if (isType) { - // Class - int typeId = _typeNames.indexOf(qualifiedname); - if (typeId == -1) { - typeId = _typeNames.count(); - _typeNames.append(qualifiedname); - } - - Object *obj = new Object; - obj->type = typeId; - obj->typeName = qualifiednameL1; - obj->line = line; - - QmlCustomParser *customparser = QmlMetaType::customParser(qualifiednameL1); - if (customparser) { - bool ok; - obj->custom = customparser->compile(reader, &ok); - if (reader.tokenType() != QXmlStreamReader::EndElement) { - reader.raiseError(QLatin1String("Parser for ") + qualifiedname + QLatin1String(" did not end on end element")); - ok = false; - } - if (!ok) { - delete obj; - break; - } - } - - - if (!root) { - root = obj; - states.pushObject(obj); - } else { - const QmlXmlParserState &state = states.top(); - Value *v = new Value; - v->object = obj; - v->line = line; - if (state.property) - state.property->addValue(v); - else - state.object->getDefaultProperty()->addValue(v); - states.pushObject(obj); - } - } else { - // Property - if (!root) { - reader.raiseError(QLatin1String("Can't have a property with no object")); - break; - } - QStringList str = name.split(QLatin1Char('.')); - for (int ii = 0; ii < str.count(); ++ii) { - QString s = str.at(ii); - states.pushProperty(s, line); - } - if (!nameSpace.isEmpty()) { - // Pass non-QML as flat text property value - const QmlXmlParserState &state = states.top(); - Value *v = new Value; - v->primitive = flatXml(reader); - v->line = line; - state.property->addValue(v); - } - } - - // (even custom parsed content gets properties set) - foreach(QXmlStreamAttribute attr, attrs) { - QStringList str = attr.name().toString().split(QLatin1Char('.')); - - for (int ii = 0; ii < str.count(); ++ii) { - QString s = str.at(ii); - states.pushProperty(s, line); - } - - const QmlXmlParserState &state = states.top(); - Value *v = new Value; - v->primitive = attr.value().toString(); - v->line = reader.lineNumber(); - state.property->addValue(v); - - for (int ii = str.count() - 1; ii >= 0; --ii) - states.pop(); - } - } - - // Custom parsers and namespaced properties move - // the reader to the end element, so we handle that - // BEFORE continuing. - // - if (reader.tokenType()!=QXmlStreamReader::EndElement) - break; - // ELSE fallthrough to EndElement... - case QXmlStreamReader::EndElement: - { - QString name = reader.name().toString(); - Q_ASSERT(!name.isEmpty()); - if (name.at(0).isUpper() && !name.contains(QLatin1Char('.'))) { - // Class - states.pop(); - } else { - // Property - QStringList str = name.split(QLatin1Char('.')); - for (int ii = 0; ii < str.count(); ++ii) - states.pop(); - } - } - break; - case QXmlStreamReader::Characters: - if (!reader.isWhitespace()) { - const QmlXmlParserState &state = states.top(); - Value *v = new Value; - v->primitive = reader.text().toString(); - v->line = reader.lineNumber(); - if (state.property) - state.property->addValue(v); - else - state.object->getDefaultProperty()->addValue(v); - } - break; - - case QXmlStreamReader::Comment: - case QXmlStreamReader::DTD: - case QXmlStreamReader::EntityReference: - break; - case QXmlStreamReader::ProcessingInstruction: - if (reader.processingInstructionTarget() == QLatin1String("qtfx")) { - QString str = reader.processingInstructionData().toString(); - QString token, data; - int idx = str.indexOf(QLatin1Char(':')); - if (-1 != idx) { - token = str.left(idx); - data = str.mid(idx + 1); - } else { - token = str; - } - token = token.trimmed(); - data = data.trimmed(); - - // <?qtfx namespacepath: namespace=path> - - if (token == QLatin1String("namespacepath")) { - int eq=data.indexOf(QLatin1Char('=')); - if (eq>=0) { - _nameSpacePaths.insertMulti(data.left(eq),data.mid(eq+1)); - } - } else { - str = str.trimmed(); - qWarning().nospace() << "Unknown processing instruction " << str.toLatin1().constData() << " @" << fileDisplayName.toLatin1().constData() << ":" << reader.lineNumber(); - } - } - break; - } - } - - if (reader.hasError()) { - if (root) { - root->release(); - root = 0; - } - _error = reader.errorString() + QLatin1String(" @") + fileDisplayName + - QLatin1String(":") + QString::number(reader.lineNumber()); - } - - return root != 0; -} - -QMap<QString,QString> QmlXmlParser::nameSpacePaths() const -{ - return _nameSpacePaths; -} - -QStringList QmlXmlParser::types() const -{ - return _typeNames; -} - -QmlParser::Object *QmlXmlParser::tree() const -{ - return root; -} - -QmlParser::Object *QmlXmlParser::takeTree() -{ - QmlParser::Object *r = root; - root = 0; - return r; -} - -QString QmlXmlParser::errorDescription() const -{ - return _error; -} - -void QmlXmlParser::clear() -{ - if (root) { - root->release(); - root = 0; - } - _nameSpacePaths.clear(); - _typeNames.clear(); - _error.clear(); -} - -QT_END_NAMESPACE diff --git a/src/declarative/util/qfxview.cpp b/src/declarative/util/qfxview.cpp index cac73a0..f71b87e 100644 --- a/src/declarative/util/qfxview.cpp +++ b/src/declarative/util/qfxview.cpp @@ -233,8 +233,6 @@ QmlContext* QFxView::rootContext() */ void QFxView::execute() { - rootContext()->activate(); - if (d->qml.isEmpty()) { d->component = new QmlComponent(&d->engine, d->source, this); } else { @@ -249,6 +247,45 @@ void QFxView::execute() } /*! + \internal +*/ +void QFxView::printErrorLine(const QmlError &error) +{ + QUrl url = error.url(); + if (error.line() > 0 && error.column() > 0 && + url.scheme() == QLatin1String("file")) { + QString file = url.toLocalFile(); + QFile f(file); + if (f.open(QIODevice::ReadOnly)) { + QByteArray data = f.readAll(); + QTextStream stream(data, QIODevice::ReadOnly); + const QString code = stream.readAll(); + const QStringList lines = code.split(QLatin1Char('\n')); + + if (lines.count() >= error.line()) { + const QString &line = lines.at(error.line() - 1); + qWarning() << qPrintable(line); + + int column = qMax(0, error.column() - 1); + column = qMin(column, line.length()); + + QByteArray ind; + ind.reserve(column); + for (int i = 0; i < column; ++i) { + const QChar ch = line.at(i); + if (ch.isSpace()) + ind.append(ch.unicode()); + else + ind.append(' '); + } + ind.append('^'); + qWarning() << ind.constData(); + } + } + } +} + +/*! \internal */ void QFxView::continueExecute() @@ -260,8 +297,26 @@ void QFxView::continueExecute() return; } + if(d->component->isError()) { + QList<QmlError> errors = d->component->errors(); + foreach (const QmlError &error, errors) { + qWarning() << error; + } + + return; + } + QObject *obj = d->component->create(); - rootContext()->deactivate(); + + if(d->component->isError()) { + QList<QmlError> errors = d->component->errors(); + foreach (const QmlError &error, errors) { + qWarning() << error; + } + + return; + } + if (obj) { if (QFxItem *item = qobject_cast<QFxItem *>(obj)) { item->QSimpleCanvasItem::setParent(QSimpleCanvas::root()); @@ -330,7 +385,25 @@ QFxItem* QFxView::addItem(const QString &qml, QFxItem* parent) return 0; QmlComponent component(&d->engine, qml.toUtf8(), QUrl()); + if(d->component->isError()) { + QList<QmlError> errors = d->component->errors(); + foreach (const QmlError &error, errors) { + qWarning() << error; + } + + return 0; + } + QObject *obj = component.create(); + if(d->component->isError()) { + QList<QmlError> errors = d->component->errors(); + foreach (const QmlError &error, errors) { + qWarning() << error; + } + + return 0; + } + if (obj){ QFxItem *item = static_cast<QFxItem *>(obj); if (!parent) diff --git a/src/declarative/util/qfxview.h b/src/declarative/util/qfxview.h index d2cacf4..f575f27 100644 --- a/src/declarative/util/qfxview.h +++ b/src/declarative/util/qfxview.h @@ -57,7 +57,7 @@ QT_MODULE(Declarative) class QFxItem; class QmlEngine; class QmlContext; -class Canvas; +class QmlError; class QFxViewPrivate; class Q_DECLARATIVE_EXPORT QFxView : public QSimpleCanvas @@ -84,6 +84,7 @@ public: void dumpRoot(); + static void printErrorLine(const QmlError &); Q_SIGNALS: void sceneResized(QSize size); diff --git a/src/declarative/util/qmllistmodel.cpp b/src/declarative/util/qmllistmodel.cpp index 4837180..6ad0cb9 100644 --- a/src/declarative/util/qmllistmodel.cpp +++ b/src/declarative/util/qmllistmodel.cpp @@ -190,8 +190,6 @@ ModelObject::ModelObject(ModelNode *node) { } -QML_DECLARE_TYPE(ListModel); -QML_DEFINE_TYPE(ListModel,ListModel); ListModel::ListModel(QObject *parent) : QListModelInterface(parent), _rolesOk(false), _root(0) { @@ -304,14 +302,10 @@ int ListModel::count() const class ListModelParser : public QmlCustomParser { public: - virtual QByteArray compile(QXmlStreamReader& reader, bool *); QByteArray compile(const QList<QmlCustomParserProperty> &, bool *ok); - virtual QVariant create(const QByteArray &); - bool compileProperty(const QmlCustomParserProperty &prop, QList<ListInstruction> &instr, QByteArray &data); void setCustomData(QObject *, const QByteArray &); }; -QML_DEFINE_CUSTOM_PARSER(ListModel, ListModelParser); bool ListModelParser::compileProperty(const QmlCustomParserProperty &prop, QList<ListInstruction> &instr, QByteArray &data) { @@ -462,13 +456,10 @@ void ListModelParser::setCustomData(QObject *obj, const QByteArray &d) } } -class ListModel2 : public ListModel -{ -Q_OBJECT -}; -QML_DECLARE_TYPE(ListModel2); -QML_DEFINE_CUSTOM_TYPE(ListModel2, ListModel2, ListModelParser); +QML_DECLARE_TYPE(ListModel); +QML_DEFINE_CUSTOM_TYPE(ListModel, ListModel, ListModelParser); +// ### FIXME class ListElement : public QObject { Q_OBJECT @@ -512,170 +503,5 @@ ModelNode::~ModelNode() if (modelCache) { delete modelCache; modelCache = 0; } } -QByteArray ListModelParser::compile(QXmlStreamReader& reader, bool *ok) -{ - *ok = true; - - QByteArray data; - QList<ListInstruction> instr; - int depth=0; - - while(!reader.atEnd() && depth >= 0) { - switch(reader.readNext()) { - case QXmlStreamReader::StartElement: - { - QStringRef name = reader.name(); - bool isType = name.at(0).isUpper(); - - if (isType) { - ListInstruction li; - li.type = ListInstruction::Push; - li.dataIdx = -1; - instr << li; - - for (int i = 0; i < reader.attributes().count(); ++i) { - const QXmlStreamAttribute &attr = reader.attributes().at(i); - QStringRef attrName = attr.name(); - QStringRef attrValue = attr.value(); - - ListInstruction li; - int ref = data.count(); - data.append(attrName.toString().toLatin1()); - data.append('\0'); - li.type = ListInstruction::Set; - li.dataIdx = ref; - instr << li; - - ref = data.count(); - data.append(attrValue.toString().toLatin1()); - data.append('\0'); - li.type = ListInstruction::Value; - li.dataIdx = ref; - instr << li; - - li.type = ListInstruction::Pop; - li.dataIdx = -1; - instr << li; - } - } else { - ListInstruction li; - int ref = data.count(); - data.append(name.toString().toLatin1()); - data.append('\0'); - li.type = ListInstruction::Set; - li.dataIdx = ref; - instr << li; - } - } - ++depth; - break; - case QXmlStreamReader::EndElement: - { - ListInstruction li; - li.type = ListInstruction::Pop; - li.dataIdx = -1; - instr << li; - --depth; - } - break; - case QXmlStreamReader::Characters: - if (!reader.isWhitespace()) { - int ref = data.count(); - QByteArray d = reader.text().toString().toLatin1(); - d.append('\0'); - data.append(d); - - ListInstruction li; - li.type = ListInstruction::Value; - li.dataIdx = ref; - instr << li; - } - break; - - case QXmlStreamReader::Invalid: - case QXmlStreamReader::NoToken: - case QXmlStreamReader::StartDocument: - case QXmlStreamReader::EndDocument: - case QXmlStreamReader::Comment: - case QXmlStreamReader::DTD: - case QXmlStreamReader::EntityReference: - case QXmlStreamReader::ProcessingInstruction: - break; - } - } - - if (reader.hasError()) - *ok = true; - - if (!*ok) - return QByteArray(); - - int size = sizeof(ListModelData) + - instr.count() * sizeof(ListInstruction) + - data.count(); - - QByteArray rv; - rv.resize(size); - - ListModelData *lmd = (ListModelData *)rv.data(); - lmd->dataOffset = sizeof(ListModelData) + - instr.count() * sizeof(ListInstruction); - lmd->instrCount = instr.count(); - for (int ii = 0; ii < instr.count(); ++ii) - lmd->instructions()[ii] = instr.at(ii); - ::memcpy(rv.data() + lmd->dataOffset, data.constData(), data.count()); - - return rv; -} - -QVariant ListModelParser::create(const QByteArray &d) -{ - ListModel *rv = new ListModel; - ModelNode *root = new ModelNode; - rv->_root = root; - QStack<ModelNode *> nodes; - nodes << root; - - const ListModelData *lmd = (const ListModelData *)d.constData(); - const char *data = ((const char *)lmd) + lmd->dataOffset; - - for (int ii = 0; ii < lmd->instrCount; ++ii) { - const ListInstruction &instr = lmd->instructions()[ii]; - - switch(instr.type) { - case ListInstruction::Push: - { - ModelNode *n = nodes.top(); - ModelNode *n2 = new ModelNode; - n->values << qVariantFromValue(n2); - nodes.push(n2); - } - break; - - case ListInstruction::Pop: - nodes.pop(); - break; - - case ListInstruction::Value: - { - ModelNode *n = nodes.top(); - n->values.append(QByteArray(data + instr.dataIdx)); - } - break; - - case ListInstruction::Set: - { - ModelNode *n = nodes.top(); - ModelNode *n2 = new ModelNode; - n->properties.insert(QLatin1String(data + instr.dataIdx), n2); - nodes.push(n2); - } - break; - } - } - - return QVariant::fromValue(rv); -} - QT_END_NAMESPACE #include "qmllistmodel.moc" |