diff options
author | Alan Alpert <alan.alpert@nokia.com> | 2009-07-16 07:20:19 (GMT) |
---|---|---|
committer | Alan Alpert <alan.alpert@nokia.com> | 2009-07-16 07:20:19 (GMT) |
commit | 46fa97f020a310de3ad6f92860dffdb402955b14 (patch) | |
tree | 0e9c899bc82168533108170b536844768ddc0425 /src | |
parent | 319eba26b183c5d67f1950255bf3758b8fd64011 (diff) | |
parent | 14275363e5ae678ca92a6da4778035ca2ad1594c (diff) | |
download | Qt-46fa97f020a310de3ad6f92860dffdb402955b14.zip Qt-46fa97f020a310de3ad6f92860dffdb402955b14.tar.gz Qt-46fa97f020a310de3ad6f92860dffdb402955b14.tar.bz2 |
Merge branch 'kinetic-declarativeui' of git@scm.dev.nokia.troll.no:qt/kinetic into kinetic-declarativeui
Diffstat (limited to 'src')
35 files changed, 572 insertions, 647 deletions
diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index a06e974..a4c4ba2 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -161,7 +161,8 @@ enum PropertyFlags { ResolveUser = 0x00200000, Notify = 0x00400000, Dynamic = 0x00800000, - Constant = 0x00000400 + Constant = 0x00000400, + Final = 0x00000800 }; enum MethodFlags { @@ -2507,6 +2508,20 @@ bool QMetaProperty::isConstant() const } /*! + Returns true if the property is final; otherwise returns false. + + A property is final if the \c{Q_PROPERTY()}'s \c FINAL attribute + is set. +*/ +bool QMetaProperty::isFinal() const +{ + if (!mobj) + return false; + int flags = mobj->d.data[handle + 2]; + return flags & Final; +} + +/*! \obsolete Returns true if the property is editable for the given \a object; diff --git a/src/corelib/kernel/qmetaobject.h b/src/corelib/kernel/qmetaobject.h index adc31d1..9f36106 100644 --- a/src/corelib/kernel/qmetaobject.h +++ b/src/corelib/kernel/qmetaobject.h @@ -191,6 +191,7 @@ public: bool isUser(const QObject *obj = 0) const; bool isDynamic() const; bool isConstant() const; + bool isFinal() const; bool isFlagType() const; bool isEnumType() const; diff --git a/src/declarative/extra/qmlbehaviour.cpp b/src/declarative/extra/qmlbehaviour.cpp index 4165d56..c7ab1da 100644 --- a/src/declarative/extra/qmlbehaviour.cpp +++ b/src/declarative/extra/qmlbehaviour.cpp @@ -75,15 +75,12 @@ private: class QmlBehaviourPrivate : public QObjectPrivate { public: - QmlBehaviourPrivate() - : context(0), valueData(0), operations(this) {} + QmlBehaviourPrivate() : operations(this) {} QmlMetaProperty property; QVariant currentValue; QVariant fromValue; QVariant toValue; - QmlContext *context; - QmlBehaviourData *valueData; class AnimationList : public QmlConcreteList<QmlAbstractAnimation *> { public: @@ -128,7 +125,6 @@ QmlBehaviour::QmlBehaviour(QObject *parent) : QmlPropertyValueSource(*(new QmlBehaviourPrivate), parent) { Q_D(QmlBehaviour); - d->valueData = new QmlBehaviourData(this); d->group = new QParallelAnimationGroup(this); } @@ -200,10 +196,6 @@ void QmlBehaviour::propertyValueChanged() //### does this clean up everything needed? d->group->stop(); - d->valueData->e = newValue; - d->valueData->s = d->currentValue; - emit d->valueData->valuesChanged(); - QmlStateOperation::ActionList actions; Action action; action.property = d->property; @@ -238,22 +230,6 @@ void QmlBehaviour::setTarget(const QmlMetaProperty &property) } } -void QmlBehaviour::classBegin() -{ - Q_D(QmlBehaviour); - if (!d->context) { - d->context = new QmlContext(qmlContext(this), this); - d->context->addDefaultObject(d->valueData); - } - d->context->activate(); -} - -void QmlBehaviour::classComplete() -{ - Q_D(QmlBehaviour); - d->context->deactivate(); -} - QT_END_NAMESPACE #include "qmlbehaviour.moc" diff --git a/src/declarative/extra/qmlbehaviour.h b/src/declarative/extra/qmlbehaviour.h index 1b5f524..99fc779 100644 --- a/src/declarative/extra/qmlbehaviour.h +++ b/src/declarative/extra/qmlbehaviour.h @@ -54,12 +54,10 @@ QT_MODULE(Declarative) class QmlAbstractAnimation; class QmlBehaviourPrivate; -class Q_DECLARATIVE_EXPORT QmlBehaviour : public QmlPropertyValueSource, - public QmlParserStatus +class Q_DECLARATIVE_EXPORT QmlBehaviour : public QmlPropertyValueSource { Q_OBJECT Q_DECLARE_PRIVATE(QmlBehaviour) - Q_INTERFACES(QmlParserStatus) Q_PROPERTY(QVariant from READ fromValue WRITE setFromValue) Q_PROPERTY(QVariant to READ toValue WRITE setToValue) @@ -80,10 +78,6 @@ public: static bool _ignore; -protected: - virtual void classBegin(); - virtual void classComplete(); - private Q_SLOTS: void propertyValueChanged(); }; diff --git a/src/declarative/extra/qmlfolderlistmodel.cpp b/src/declarative/extra/qmlfolderlistmodel.cpp index acee5e1..4a71109 100644 --- a/src/declarative/extra/qmlfolderlistmodel.cpp +++ b/src/declarative/extra/qmlfolderlistmodel.cpp @@ -161,7 +161,9 @@ void QmlFolderListModel::classComplete() bool QmlFolderListModel::isFolder(int index) const { Q_D(const QmlFolderListModel); - return d->model.isDir(d->model.index(index, 0, d->folderIndex)); + if (index != -1) + return d->model.isDir(d->model.index(index, 0, d->folderIndex)); + return false; } void QmlFolderListModel::refresh() diff --git a/src/declarative/fx/qfxitem.h b/src/declarative/fx/qfxitem.h index 5fb4eff..a674df9 100644 --- a/src/declarative/fx/qfxitem.h +++ b/src/declarative/fx/qfxitem.h @@ -98,31 +98,31 @@ class Q_DECLARATIVE_EXPORT QFxItem : public QSimpleCanvasItem, public QmlParserS Q_OBJECT Q_INTERFACES(QmlParserStatus) - Q_PROPERTY(QFxItem * parent READ itemParent WRITE setItemParent NOTIFY parentChanged DESIGNABLE false) + Q_PROPERTY(QFxItem * parent READ itemParent WRITE setItemParent NOTIFY parentChanged DESIGNABLE false FINAL) Q_PROPERTY(QFxItem * moveToParent READ itemParent WRITE moveToParent NOTIFY parentChanged DESIGNABLE false) Q_PROPERTY(QString id READ id WRITE setId) Q_PROPERTY(QmlList<QFxItem *>* children READ children DESIGNABLE false) Q_PROPERTY(QmlList<QObject *>* resources READ resources DESIGNABLE false) - Q_PROPERTY(QFxAnchors * anchors READ anchors DESIGNABLE false CONSTANT) + Q_PROPERTY(QFxAnchors * anchors READ anchors DESIGNABLE false CONSTANT FINAL) Q_PROPERTY(QmlList<QObject *> *data READ data DESIGNABLE false) - Q_PROPERTY(QFxContents * contents READ contents DESIGNABLE false CONSTANT) + Q_PROPERTY(QFxContents * contents READ contents DESIGNABLE false CONSTANT FINAL) Q_PROPERTY(QmlList<QmlState *>* states READ states DESIGNABLE false) Q_PROPERTY(QmlList<QmlTransition *>* transitions READ transitions DESIGNABLE false) Q_PROPERTY(QString state READ state WRITE setState NOTIFY stateChanged) Q_PROPERTY(QUrl qml READ qml WRITE setQml NOTIFY qmlChanged) Q_PROPERTY(QFxItem *qmlItem READ qmlItem NOTIFY qmlChanged) - Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged) - Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged) - Q_PROPERTY(qreal z READ z WRITE setZ) - Q_PROPERTY(qreal width READ width WRITE setWidth NOTIFY widthChanged) - Q_PROPERTY(qreal height READ height WRITE setHeight NOTIFY heightChanged) - Q_PROPERTY(QFxAnchorLine left READ left CONSTANT) - Q_PROPERTY(QFxAnchorLine right READ right CONSTANT) - Q_PROPERTY(QFxAnchorLine horizontalCenter READ horizontalCenter CONSTANT) - Q_PROPERTY(QFxAnchorLine top READ top CONSTANT) - Q_PROPERTY(QFxAnchorLine bottom READ bottom CONSTANT) - Q_PROPERTY(QFxAnchorLine verticalCenter READ verticalCenter CONSTANT) - Q_PROPERTY(QFxAnchorLine baseline READ baseline CONSTANT) + Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged FINAL) + Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged FINAL) + Q_PROPERTY(qreal z READ z WRITE setZ FINAL) + Q_PROPERTY(qreal width READ width WRITE setWidth NOTIFY widthChanged FINAL) + Q_PROPERTY(qreal height READ height WRITE setHeight NOTIFY heightChanged FINAL) + Q_PROPERTY(QFxAnchorLine left READ left CONSTANT FINAL) + Q_PROPERTY(QFxAnchorLine right READ right CONSTANT FINAL) + Q_PROPERTY(QFxAnchorLine horizontalCenter READ horizontalCenter CONSTANT FINAL) + Q_PROPERTY(QFxAnchorLine top READ top CONSTANT FINAL) + Q_PROPERTY(QFxAnchorLine bottom READ bottom CONSTANT FINAL) + Q_PROPERTY(QFxAnchorLine verticalCenter READ verticalCenter CONSTANT FINAL) + Q_PROPERTY(QFxAnchorLine baseline READ baseline CONSTANT FINAL) Q_PROPERTY(qreal baselineOffset READ baselineOffset WRITE setBaselineOffset NOTIFY baselineOffsetChanged) Q_PROPERTY(bool flipVertically READ flipVertically WRITE setFlipVertically) Q_PROPERTY(bool flipHorizontally READ flipHorizontally WRITE setFlipHorizontally) @@ -131,11 +131,11 @@ class Q_DECLARATIVE_EXPORT QFxItem : public QSimpleCanvasItem, public QmlParserS Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity NOTIFY opacityChanged) Q_PROPERTY(QSimpleCanvasFilter *filter READ filter WRITE setFilter) Q_PROPERTY(bool clip READ clip WRITE setClip) - Q_PROPERTY(bool focusable READ isFocusable WRITE setFocusable) - Q_PROPERTY(bool focus READ hasFocus WRITE setFocus NOTIFY focusChanged) - Q_PROPERTY(bool activeFocus READ hasActiveFocus NOTIFY activeFocusChanged) + Q_PROPERTY(bool focusable READ isFocusable WRITE setFocusable FINAL) + Q_PROPERTY(bool focus READ hasFocus WRITE setFocus NOTIFY focusChanged FINAL) + Q_PROPERTY(bool activeFocus READ hasActiveFocus NOTIFY activeFocusChanged FINAL) Q_PROPERTY(QList<QFxTransform *>* transform READ transform) - Q_PROPERTY(bool visible READ visible WRITE setVisible NOTIFY visibleChanged) + Q_PROPERTY(bool visible READ visible WRITE setVisible NOTIFY visibleChanged FINAL) Q_CLASSINFO("DefaultProperty", "data") typedef QHash<QString, QFxItem *> QmlChildren; diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index 7f1c3f7..0b91ed3 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -26,6 +26,7 @@ SOURCES += qml/qmlparser.cpp \ qml/qmlerror.cpp \ qml/qmlscriptparser.cpp \ qml/qmlenginedebug.cpp \ + qml/qmlrewrite.cpp \ qml/qmlbasicscript.cpp HEADERS += qml/qmlparser_p.h \ @@ -67,6 +68,7 @@ HEADERS += qml/qmlparser_p.h \ qml/qmlscriptparser_p.h \ qml/qmlbasicscript_p.h \ qml/qmlenginedebug_p.h \ + qml/qmlrewrite_p.h \ qml/qpodvector_p.h # for qtscript debugger diff --git a/src/declarative/qml/qmlbasicscript.cpp b/src/declarative/qml/qmlbasicscript.cpp index 478491f..40ffffe 100644 --- a/src/declarative/qml/qmlbasicscript.cpp +++ b/src/declarative/qml/qmlbasicscript.cpp @@ -64,12 +64,7 @@ struct ScriptInstruction { FetchD0Constant, // constant FetchD1Constant, // constant - - Add, // NA - Subtract, // NA - Multiply, // NA Equals, // NA - And, // NA Int, // integer Bool, // boolean @@ -181,6 +176,9 @@ static QVariant toObjectOrVariant(const QVariant &v) static QVariant fetch_value(QObject *o, int idx, int type) { + if (!o) + return QVariant(); + switch(type) { case QVariant::String: { @@ -291,7 +289,7 @@ struct QmlBasicScriptCompiler QmlParser::Object *context; QmlParser::Object *component; - QHash<QString, QPair<QmlParser::Object *, int> > ids; + QHash<QString, QmlParser::Object *> ids; bool compile(QmlJS::AST::Node *); @@ -445,15 +443,6 @@ void QmlBasicScript::dump() qWarning().nospace() << "FETCH\t\t" << instr.fetch.idx << "\t\t" << QByteArray(data + instr.fetch.idx); break; - case ScriptInstruction::Add: - qWarning().nospace() << "ADD"; - break; - case ScriptInstruction::Subtract: - qWarning().nospace() << "SUBTRACT"; - break; - case ScriptInstruction::Multiply: - qWarning().nospace() << "MULTIPLY"; - break; case ScriptInstruction::Equals: qWarning().nospace() << "EQUALS"; break; @@ -588,10 +577,10 @@ bool QmlBasicScriptCompiler::parseName(AST::Node *node, if (ids.contains(name)) { instr.type = ScriptInstruction::LoadIdObject; - instr.fetch.idx = ids.value(name).second; + instr.fetch.idx = ids.value(name)->idIndex; if (type) - *type = ids.value(name).first; + *type = ids.value(name); } else { int d0Idx = context->metaObject()->indexOfProperty(name.toUtf8().constData()); @@ -679,11 +668,7 @@ bool QmlBasicScriptCompiler::tryBinaryExpression(AST::Node *node) AST::BinaryExpression *expr = static_cast<AST::BinaryExpression *>(node); - if (expr->op == QSOperator::Add || - expr->op == QSOperator::Sub || - expr->op == QSOperator::Equal || - expr->op == QSOperator::And || - expr->op == QSOperator::Mul) + if (expr->op == QSOperator::Equal) return true; } return false; @@ -700,21 +685,9 @@ bool QmlBasicScriptCompiler::compileBinaryExpression(AST::Node *node) ScriptInstruction instr; switch (expr->op) { - case QSOperator::Add: - instr.type = ScriptInstruction::Add; - break; - case QSOperator::Sub: - instr.type = ScriptInstruction::Subtract; - break; case QSOperator::Equal: instr.type = ScriptInstruction::Equals; break; - case QSOperator::And: - instr.type = ScriptInstruction::And; - break; - case QSOperator::Mul: - instr.type = ScriptInstruction::Multiply; - break; default: return false; } @@ -823,7 +796,7 @@ QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *c QObject *obj = contextPrivate->defaultObjects.at(0); stack.push(fetch_value(obj, instr.constant.idx, instr.constant.type)); - if (instr.constant.notify != 0) + if (obj && instr.constant.notify != 0) enginePrivate->capturedProperties << QmlEnginePrivate::CapturedProperty(obj, instr.constant.idx, instr.constant.notify); state = Reset; @@ -835,7 +808,7 @@ QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *c QObject *obj = contextPrivate->defaultObjects.at(1); stack.push(fetch_value(obj, instr.constant.idx, instr.constant.type)); - if (instr.constant.notify != 0) + if (obj && instr.constant.notify != 0) enginePrivate->capturedProperties << QmlEnginePrivate::CapturedProperty(obj, instr.constant.idx, instr.constant.notify); state = Reset; @@ -848,7 +821,7 @@ QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *c QObject *obj = qvariant_cast<QObject *>(o); stack.push(fetch_value(obj, instr.constant.idx, instr.constant.type)); - if (instr.constant.notify != 0) + if (obj && instr.constant.notify != 0) enginePrivate->capturedProperties << QmlEnginePrivate::CapturedProperty(obj, instr.constant.idx, instr.constant.notify); state = Reset; @@ -913,30 +886,6 @@ QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *c case ScriptInstruction::Bool: stack.push(QVariant(instr.boolean.value)); break; - case ScriptInstruction::Add: - { - QVariant rhs = stack.pop(); - QVariant lhs = stack.pop(); - - stack.push(rhs.toDouble() + lhs.toDouble()); - } - break; - case ScriptInstruction::Subtract: - { - QVariant rhs = stack.pop(); - QVariant lhs = stack.pop(); - - stack.push(lhs.toDouble() - rhs.toDouble()); - } - break; - case ScriptInstruction::Multiply: - { - QVariant rhs = stack.pop(); - QVariant lhs = stack.pop(); - - stack.push(rhs.toDouble() * lhs.toDouble()); - } - break; case ScriptInstruction::Equals: { QVariant rhs = stack.pop(); @@ -945,14 +894,6 @@ QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *c stack.push(rhs == lhs); } break; - case ScriptInstruction::And: - { - QVariant rhs = stack.pop(); - QVariant lhs = stack.pop(); - - stack.push(rhs.toBool() && lhs.toBool()); - } - break; default: break; } diff --git a/src/declarative/qml/qmlbasicscript_p.h b/src/declarative/qml/qmlbasicscript_p.h index 0c69397..77d59eb 100644 --- a/src/declarative/qml/qmlbasicscript_p.h +++ b/src/declarative/qml/qmlbasicscript_p.h @@ -85,7 +85,7 @@ public: QmlParser::Object *context; QmlParser::Property *property; QmlParser::Variant expression; - QHash<QString, QPair<QmlParser::Object *, int> > ids; + QHash<QString, QmlParser::Object *> ids; }; bool compile(const Expression &); diff --git a/src/declarative/qml/qmlcompileddata.cpp b/src/declarative/qml/qmlcompileddata.cpp index 0834794..0563891 100644 --- a/src/declarative/qml/qmlcompileddata.cpp +++ b/src/declarative/qml/qmlcompileddata.cpp @@ -50,8 +50,6 @@ QT_BEGIN_NAMESPACE -DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP); - int QmlCompiledData::pack(const char *data, size_t size) { const char *p = packData.constData(); @@ -193,9 +191,6 @@ const QMetaObject *QmlCompiledData::TypeReference::metaObject() const void QmlCompiledData::dumpInstructions() { - if (!compilerDump()) - return; - if (!name.isEmpty()) qWarning() << name; qWarning() << "Index\tLine\tOperation\t\tData1\tData2\t\tComments"; diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index ed9df03..b0bc6e8 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -68,23 +68,43 @@ QT_BEGIN_NAMESPACE +DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP); + using namespace QmlParser; +/*! + Instantiate a new QmlCompiler. +*/ QmlCompiler::QmlCompiler() : output(0) { } +/*! + Returns true if the last call to compile() caused errors. + + \sa errors() +*/ bool QmlCompiler::isError() const { return !exceptions.isEmpty(); } +/*! + Return the list of errors from the last call to compile(), or an empty list + if there were no errors. +*/ QList<QmlError> QmlCompiler::errors() const { return exceptions; } +/*! + Returns true if \a val is a legal object id, false otherwise. + + Legal ids must start with a letter or underscore, and contain only + letters, numbers and underscores. +*/ bool QmlCompiler::isValidId(const QString &val) { if (val.isEmpty()) @@ -122,27 +142,26 @@ bool QmlCompiler::isSignalPropertyName(const QByteArray &name) 'A' <= name.at(2) && 'Z' >= name.at(2); } -#define COMPILE_EXCEPTION2(token, desc) \ - { \ - QString exceptionDescription; \ - QmlError error; \ - error.setUrl(output->url); \ - error.setLine(token->location.start.line); \ - error.setColumn(token->location.start.column); \ - QDebug d(&exceptionDescription); \ - d << desc; \ - error.setDescription(exceptionDescription.trimmed()); \ - exceptions << error; \ - return false; \ - } +/*! + Inserts an error into the QmlCompiler error list, and returns false + (failure). -#define COMPILE_EXCEPTION(desc) \ + \a token is used to source the error line and column, and \a desc is the + error itself. \a desc can be an expression that can be piped into QDebug. + + For example: + + \code + COMPILE_EXCEPTION(property, "Error for property" << property->name); + \endcode +*/ +#define COMPILE_EXCEPTION(token, desc) \ { \ QString exceptionDescription; \ QmlError error; \ error.setUrl(output->url); \ - error.setLine(obj->location.start.line); \ - error.setColumn(obj->location.start.column); \ + error.setLine((token)->location.start.line); \ + error.setColumn((token)->location.start.column); \ QDebug d(&exceptionDescription); \ d << desc; \ error.setDescription(exceptionDescription.trimmed()); \ @@ -150,19 +169,28 @@ bool QmlCompiler::isSignalPropertyName(const QByteArray &name) return false; \ } +/*! + Returns false if \a is false, otherwise does nothing. +*/ #define COMPILE_CHECK(a) \ { \ if (!a) return false; \ } -// Compile a simple assignment of v to prop into instr +/*! + Returns true if literal \a v can be assigned to property \a prop, otherwise + false. + + This test corresponds to action taken by genLiteralAssignment(). Any change + made here, must have a corresponding action in genLiteralAssigment(). +*/ bool QmlCompiler::testLiteralAssignment(const QMetaProperty &prop, QmlParser::Value *v) { QString string = v->value.asScript(); if (!prop.isWritable()) - COMPILE_EXCEPTION2(v, "Invalid property assignment: read-only property"); + COMPILE_EXCEPTION(v, "Invalid property assignment: read-only property"); if (prop.isEnumType()) { int value; @@ -171,7 +199,7 @@ bool QmlCompiler::testLiteralAssignment(const QMetaProperty &prop, } else value = prop.enumerator().keyToValue(string.toLatin1().constData()); if (value == -1) - COMPILE_EXCEPTION2(v, "Invalid property assignment: unknown enumeration"); + COMPILE_EXCEPTION(v, "Invalid property assignment: unknown enumeration"); return true; } int type = prop.userType(); @@ -179,61 +207,61 @@ bool QmlCompiler::testLiteralAssignment(const QMetaProperty &prop, case -1: break; case QVariant::String: - if (!v->value.isString()) COMPILE_EXCEPTION2(v, "Invalid property assignment: string expected"); + if (!v->value.isString()) COMPILE_EXCEPTION(v, "Invalid property assignment: string expected"); break; case QVariant::Url: - if (!v->value.isString()) COMPILE_EXCEPTION2(v, "Invalid property assignment: url expected"); + if (!v->value.isString()) COMPILE_EXCEPTION(v, "Invalid property assignment: url expected"); break; case QVariant::UInt: { bool ok; string.toUInt(&ok); - if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: unsigned int expected"); + if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION(v, "Invalid property assignment: unsigned int expected"); } break; case QVariant::Int: { bool ok; string.toInt(&ok); - if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: int expected"); + if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION(v, "Invalid property assignment: int expected"); } break; case QMetaType::Float: { bool ok; string.toFloat(&ok); - if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: float expected"); + if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION(v, "Invalid property assignment: float expected"); } break; case QVariant::Double: { bool ok; string.toDouble(&ok); - if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: double expected"); + if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION(v, "Invalid property assignment: double expected"); } break; case QVariant::Color: { QColor c = QmlStringConverters::colorFromString(string); - if (!c.isValid()) COMPILE_EXCEPTION2(v, "Invalid property assignment: color expected"); + if (!c.isValid()) COMPILE_EXCEPTION(v, "Invalid property assignment: color expected"); } break; case QVariant::Date: { QDate d = QDate::fromString(string, Qt::ISODate); - if (!d.isValid()) COMPILE_EXCEPTION2(v, "Invalid property assignment: date expected"); + if (!d.isValid()) COMPILE_EXCEPTION(v, "Invalid property assignment: date expected"); } break; case QVariant::Time: { QTime time = QTime::fromString(string, Qt::ISODate); - if (!time.isValid()) COMPILE_EXCEPTION2(v, "Invalid property assignment: time expected"); + if (!time.isValid()) COMPILE_EXCEPTION(v, "Invalid property assignment: time expected"); } break; case QVariant::DateTime: { QDateTime dateTime = QDateTime::fromString(string, Qt::ISODate); - if (!dateTime.isValid()) COMPILE_EXCEPTION2(v, "Invalid property assignment: datetime expected"); + if (!dateTime.isValid()) COMPILE_EXCEPTION(v, "Invalid property assignment: datetime expected"); } break; case QVariant::Point: @@ -241,7 +269,7 @@ bool QmlCompiler::testLiteralAssignment(const QMetaProperty &prop, { bool ok; QPointF point = QmlStringConverters::pointFFromString(string, &ok); - if (!ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: point expected"); + if (!ok) COMPILE_EXCEPTION(v, "Invalid property assignment: point expected"); } break; case QVariant::Size: @@ -249,7 +277,7 @@ bool QmlCompiler::testLiteralAssignment(const QMetaProperty &prop, { bool ok; QSizeF size = QmlStringConverters::sizeFFromString(string, &ok); - if (!ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: size expected"); + if (!ok) COMPILE_EXCEPTION(v, "Invalid property assignment: size expected"); } break; case QVariant::Rect: @@ -257,12 +285,12 @@ bool QmlCompiler::testLiteralAssignment(const QMetaProperty &prop, { bool ok; QRectF rect = QmlStringConverters::rectFFromString(string, &ok); - if (!ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: rect expected"); + if (!ok) COMPILE_EXCEPTION(v, "Invalid property assignment: rect expected"); } break; case QVariant::Bool: { - if (!v->value.isBoolean()) COMPILE_EXCEPTION2(v, "Invalid property assignment: boolean expected"); + if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, "Invalid property assignment: boolean expected"); } break; default: @@ -273,13 +301,19 @@ bool QmlCompiler::testLiteralAssignment(const QMetaProperty &prop, QmlMetaType::StringConverter converter = QmlMetaType::customStringConverter(t); if (!converter) - COMPILE_EXCEPTION2(v, "Invalid property assignment: unknown type" << prop.type()); + COMPILE_EXCEPTION(v, "Invalid property assignment: unknown type" << prop.type()); } break; } return true; } +/*! + Generate a store instruction for assigning literal \a v to property \a prop. + + Any literal assignment that is approved in testLiteralAssignment() must have + a corresponding action in this method. +*/ void QmlCompiler::genLiteralAssignment(const QMetaProperty &prop, QmlParser::Value *v) { @@ -469,17 +503,31 @@ void QmlCompiler::genLiteralAssignment(const QMetaProperty &prop, output->bytecode << instr; } -void QmlCompiler::reset(QmlCompiledData *cc) +/*! + Resets data by clearing the lists that the QmlCompiler modifies. +*/ +void QmlCompiler::reset(QmlCompiledData *data) { - cc->types.clear(); - cc->primitives.clear(); - cc->floatData.clear(); - cc->intData.clear(); - cc->customTypeData.clear(); - cc->datas.clear(); - cc->bytecode.clear(); + data->types.clear(); + data->primitives.clear(); + data->floatData.clear(); + data->intData.clear(); + data->customTypeData.clear(); + data->datas.clear(); + data->bytecode.clear(); } +/*! + Compile \a unit, and store the output in \a out. \a engine is the QmlEngine + with which the QmlCompiledData will be associated. + + Returns true on success, false on failure. On failure, the compile errors + are available from errors(). + + If the environment variant QML_COMPILER_DUMP is set + (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr + on a successful compiler. +*/ bool QmlCompiler::compile(QmlEngine *engine, QmlCompositeTypeData *unit, QmlCompiledData *out) @@ -526,11 +574,14 @@ bool QmlCompiler::compile(QmlEngine *engine, compileTree(root); if (!isError()) { - out->dumpInstructions(); + if (compilerDump()) + out->dumpInstructions(); } else { reset(out); } + compileState = ComponentCompileState(); + savedCompileStates.clear(); output = 0; return !isError(); @@ -622,7 +673,7 @@ bool QmlCompiler::buildObject(Object *obj, const BindingContext &ctxt) bool canDefer = false; if (isCustomParser) { - if (testProperty(prop, obj)) { + if (doesPropertyExist(prop, obj)) { int ids = compileState.ids.count(); COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); canDefer = ids == compileState.ids.count(); @@ -651,7 +702,7 @@ bool QmlCompiler::buildObject(Object *obj, const BindingContext &ctxt) bool canDefer = false; if (isCustomParser) { - if (testProperty(prop, obj)) { + if (doesPropertyExist(prop, obj)) { int ids = compileState.ids.count(); COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); canDefer = ids == compileState.ids.count(); @@ -676,7 +727,7 @@ bool QmlCompiler::buildObject(Object *obj, const BindingContext &ctxt) QmlCustomParser *cp = output->types.at(obj->type).type->customParser(); obj->custom = cp->compile(customProps, &ok); if(!ok) - COMPILE_EXCEPTION("Failure compiling custom type"); + COMPILE_EXCEPTION(obj, "Failure compiling custom type"); } return true; @@ -876,36 +927,36 @@ bool QmlCompiler::buildComponent(QmlParser::Object *obj, Property *idProp = 0; if (obj->properties.count() > 1 || (obj->properties.count() == 1 && obj->properties.begin().key() != "id")) - COMPILE_EXCEPTION("Invalid component specification"); + COMPILE_EXCEPTION(obj, "Invalid component specification"); if (obj->properties.count()) idProp = *obj->properties.begin(); if (idProp && (idProp->value || idProp->values.count() > 1 || !isValidId(idProp->values.first()->primitive()))) - COMPILE_EXCEPTION("Invalid component id specification"); + COMPILE_EXCEPTION(obj, "Invalid component id specification"); if (idProp) { QString idVal = idProp->values.first()->primitive().toUtf8(); if (compileState.ids.contains(idVal)) - COMPILE_EXCEPTION("id is not unique"); + COMPILE_EXCEPTION(obj, "id is not unique"); addId(idVal, obj); - obj->id = idVal.toUtf8(); + obj->id = idVal; } // Check the Component tree is well formed 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"); + COMPILE_EXCEPTION(obj, "Invalid component body specification"); Object *root = 0; if (obj->defaultProperty && obj->defaultProperty->values.count()) root = obj->defaultProperty->values.first()->object; if (!root) - COMPILE_EXCEPTION("Cannot create empty component specification"); + COMPILE_EXCEPTION(obj, "Cannot create empty component specification"); // Build the component tree COMPILE_CHECK(buildComponentFromRoot(root, ctxt)); @@ -989,7 +1040,7 @@ bool QmlCompiler::buildSignal(QmlParser::Property *prop, QmlParser::Object *obj, Q_ASSERT(obj->metaObject()); if (prop->isEmpty()) - COMPILE_EXCEPTION2(prop, "Empty property assignment"); + COMPILE_EXCEPTION(prop, "Empty property assignment"); QByteArray name = prop->name; Q_ASSERT(name.startsWith("on")); @@ -1008,7 +1059,7 @@ bool QmlCompiler::buildSignal(QmlParser::Property *prop, QmlParser::Object *obj, } else { if (prop->value || prop->values.count() > 1) - COMPILE_EXCEPTION("Incorrectly specified signal"); + COMPILE_EXCEPTION(prop, "Incorrectly specified signal"); prop->index = sigIdx; obj->addSignalProperty(prop); @@ -1025,9 +1076,11 @@ bool QmlCompiler::buildSignal(QmlParser::Property *prop, QmlParser::Object *obj, } -// Returns true if prop exists on obj, false otherwise -bool QmlCompiler::testProperty(QmlParser::Property *prop, - QmlParser::Object *obj) +/*! + Returns true if (value) property \a prop exists on obj, false otherwise. +*/ +bool QmlCompiler::doesPropertyExist(QmlParser::Property *prop, + QmlParser::Object *obj) { if(isAttachedPropertyName(prop->name) || prop->name == "id") return true; @@ -1051,7 +1104,7 @@ bool QmlCompiler::buildProperty(QmlParser::Property *prop, const BindingContext &ctxt) { if (prop->isEmpty()) - COMPILE_EXCEPTION2(prop, "Empty property assignment"); + COMPILE_EXCEPTION(prop, "Empty property assignment"); const QMetaObject *metaObject = obj->metaObject(); Q_ASSERT(metaObject); @@ -1063,16 +1116,16 @@ bool QmlCompiler::buildProperty(QmlParser::Property *prop, // Attached properties cannot be used on sub-objects. Sub-objects // always exist in a binding sub-context, which is what we test // for here. - COMPILE_EXCEPTION2(prop, "Attached properties cannot be used here"); + COMPILE_EXCEPTION(prop, "Attached properties cannot be used here"); } QmlType *type = QmlMetaType::qmlType(prop->name); if (!type || !type->attachedPropertiesType()) - COMPILE_EXCEPTION2(prop, "Non-existant attached object"); + COMPILE_EXCEPTION(prop, "Non-existant attached object"); if (!prop->value) - COMPILE_EXCEPTION2(prop, "Invalid attached object assignment"); + COMPILE_EXCEPTION(prop, "Invalid attached object assignment"); prop->value->metatype = type->attachedPropertiesType(); } else { @@ -1125,9 +1178,9 @@ bool QmlCompiler::buildProperty(QmlParser::Property *prop, } else if (prop->index == -1) { if (prop->isDefault) { - COMPILE_EXCEPTION2(prop->values.first(), "Cannot assign to non-existant default property"); + COMPILE_EXCEPTION(prop->values.first(), "Cannot assign to non-existant default property"); } else { - COMPILE_EXCEPTION2(prop, "Cannot assign to non-existant property" << prop->name); + COMPILE_EXCEPTION(prop, "Cannot assign to non-existant property" << prop->name); } } else if (prop->value) { @@ -1280,17 +1333,17 @@ bool QmlCompiler::buildIdProperty(QmlParser::Property *prop, if (prop->value || prop->values.count() > 1 || prop->values.at(0)->object) - COMPILE_EXCEPTION2(prop, "Invalid use of id property"); + COMPILE_EXCEPTION(prop, "Invalid use of id property"); QString val = prop->values.at(0)->primitive(); if (!isValidId(val)) - COMPILE_EXCEPTION2(prop, val << "is not a valid object id"); + COMPILE_EXCEPTION(prop, val << "is not a valid object id"); if (compileState.ids.contains(val)) - COMPILE_EXCEPTION2(prop, "id is not unique"); + COMPILE_EXCEPTION(prop, "id is not unique"); - obj->id = val.toUtf8(); + obj->id = val; prop->values.at(0)->type = Value::Id; @@ -1301,18 +1354,16 @@ bool QmlCompiler::buildIdProperty(QmlParser::Property *prop, void QmlCompiler::addId(const QString &id, QmlParser::Object *obj) { - IdReference reference; - reference.id = id; - reference.object = obj; - reference.idx = compileState.ids.count(); - compileState.ids.insert(id, reference); + Q_ASSERT(!compileState.ids.contains(id)); + Q_ASSERT(obj->id == id); + obj->idIndex = compileState.ids.count(); + compileState.ids.insert(id, obj); } void QmlCompiler::addBindingReference(const BindingReference &ref) { - int id = compileState.bindings.count(); - compileState.bindings << ref; - compileState.bindingMap.insert(ref.value, id); + Q_ASSERT(ref.value && !compileState.bindings.contains(ref.value)); + compileState.bindings.insert(ref.value, ref); } void QmlCompiler::saveComponentState() @@ -1368,7 +1419,7 @@ bool QmlCompiler::buildGroupedProperty(QmlParser::Property *prop, // Load the nested property's meta type prop->value->metatype = QmlMetaType::metaObjectForType(prop->type); if (!prop->value->metatype) - COMPILE_EXCEPTION2(prop, "Cannot nest non-QObject property" << prop->name); + COMPILE_EXCEPTION(prop, "Cannot nest non-QObject property" << prop->name); obj->addGroupedProperty(prop); @@ -1408,12 +1459,12 @@ bool QmlCompiler::buildListProperty(QmlParser::Property *prop, // at runtime. if (!listTypeIsInterface) { if (!canCoerce(listType, v->object)) { - COMPILE_EXCEPTION("Cannot assign object to list"); + COMPILE_EXCEPTION(v, "Cannot assign object to list"); } } } else { - COMPILE_EXCEPTION("Cannot assign primitives to lists"); + COMPILE_EXCEPTION(v, "Cannot assign primitives to lists"); } } @@ -1432,19 +1483,19 @@ bool QmlCompiler::buildListProperty(QmlParser::Property *prop, // at runtime. if (!listTypeIsInterface) { if (!canCoerce(listType, v->object)) { - COMPILE_EXCEPTION("Cannot assign object to list"); + COMPILE_EXCEPTION(v, "Cannot assign object to list"); } } } else if (v->value.isScript()) { if (assignedBinding) - COMPILE_EXCEPTION("Can only assign one binding to lists"); + COMPILE_EXCEPTION(v, "Can only assign one binding to lists"); assignedBinding = true; COMPILE_CHECK(buildBinding(v, prop, ctxt)); v->type = Value::PropertyBinding; } else { - COMPILE_EXCEPTION("Cannot assign primitives to lists"); + COMPILE_EXCEPTION(v, "Cannot assign primitives to lists"); } } @@ -1570,7 +1621,7 @@ bool QmlCompiler::buildPropertyObjectAssignment(QmlParser::Property *prop, v->type = Value::ValueSource; } else { - COMPILE_EXCEPTION2(v->object, "Cannot assign object to property"); + COMPILE_EXCEPTION(v->object, "Cannot assign object to property"); } } @@ -1615,12 +1666,12 @@ bool QmlCompiler::checkDynamicMeta(QmlParser::Object *obj) if (prop.isDefaultProperty) { if (seenDefaultProperty) - COMPILE_EXCEPTION("Duplicate default property"); + COMPILE_EXCEPTION(obj, "Duplicate default property"); seenDefaultProperty = true; } if (propNames.contains(prop.name)) - COMPILE_EXCEPTION("Duplicate property name"); + COMPILE_EXCEPTION(obj, "Duplicate property name"); propNames.insert(prop.name); } @@ -1628,13 +1679,13 @@ bool QmlCompiler::checkDynamicMeta(QmlParser::Object *obj) for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) { QByteArray name = obj->dynamicSignals.at(ii).name; if (methodNames.contains(name)) - COMPILE_EXCEPTION("Duplicate signal name"); + COMPILE_EXCEPTION(obj, "Duplicate signal name"); methodNames.insert(name); } for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { QByteArray name = obj->dynamicSlots.at(ii).name; if (methodNames.contains(name)) - COMPILE_EXCEPTION("Duplicate method name"); + COMPILE_EXCEPTION(obj, "Duplicate method name"); methodNames.insert(name); } @@ -1656,7 +1707,7 @@ bool QmlCompiler::mergeDynamicMetaProperties(QmlParser::Object *obj) property = obj->getProperty(p.name); if (property->value) - COMPILE_EXCEPTION2(property, "Invalid property nesting"); + COMPILE_EXCEPTION(property, "Invalid property nesting"); for (int ii = 0; ii < p.defaultValue->values.count(); ++ii) { Value *v = p.defaultValue->values.at(ii); @@ -1687,6 +1738,14 @@ bool QmlCompiler::buildDynamicMeta(QmlParser::Object *obj, DynamicMetaMode mode) for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); + int propIdx = + obj->metaObject()->indexOfProperty(p.name.constData()); + if (-1 != propIdx) { + QMetaProperty prop = obj->metaObject()->property(propIdx); + if (prop.isFinal()) + COMPILE_EXCEPTION(&p, "Cannot override FINAL property"); + } + if (p.isDefaultProperty && (p.type != Object::DynamicProperty::Alias || mode == ResolveAliases)) @@ -1797,14 +1856,8 @@ bool QmlCompiler::buildDynamicMeta(QmlParser::Object *obj, DynamicMetaMode mode) obj->metadata = builder.toRelocatableData(); builder.fromRelocatableData(&obj->extObject, obj->metatype, obj->metadata); - // ### Remove me - obj->extObjectData = &obj->extObject; - - if (mode == IgnoreAliases && hasAlias) { - AliasReference alias; - alias.object = obj; - compileState.aliases << alias; - } + if (mode == IgnoreAliases && hasAlias) + compileState.aliasingObjects << obj; obj->synthdata = dynamicData; @@ -1836,34 +1889,34 @@ bool QmlCompiler::compileAlias(QMetaObjectBuilder &builder, const Object::DynamicProperty &prop) { if (!prop.defaultValue) - COMPILE_EXCEPTION("No property alias location"); + COMPILE_EXCEPTION(obj, "No property alias location"); if (prop.defaultValue->values.count() != 1 || prop.defaultValue->values.at(0)->object || !prop.defaultValue->values.at(0)->value.isScript()) - COMPILE_EXCEPTION2(prop.defaultValue, "Invalid alias location"); + COMPILE_EXCEPTION(prop.defaultValue, "Invalid alias location"); QmlJS::AST::Node *node = prop.defaultValue->values.at(0)->value.asAST(); if (!node) - COMPILE_EXCEPTION("No property alias location"); // ### Can this happen? + COMPILE_EXCEPTION(obj, "No property alias location"); // ### Can this happen? QStringList alias = astNodeToStringList(node); if (alias.count() != 2) - COMPILE_EXCEPTION2(prop.defaultValue, "Invalid alias location"); + COMPILE_EXCEPTION(prop.defaultValue, "Invalid alias location"); if (!compileState.ids.contains(alias.at(0))) - COMPILE_EXCEPTION2(prop.defaultValue, "Invalid alias location"); + COMPILE_EXCEPTION(prop.defaultValue, "Invalid alias location"); - const IdReference &id = compileState.ids[alias.at(0)]; - int propIdx = id.object->metaObject()->indexOfProperty(alias.at(1).toUtf8().constData()); + Object *idObject = compileState.ids[alias.at(0)]; + int propIdx = idObject->metaObject()->indexOfProperty(alias.at(1).toUtf8().constData()); if (-1 == propIdx) - COMPILE_EXCEPTION2(prop.defaultValue, "Invalid alias location"); + COMPILE_EXCEPTION(prop.defaultValue, "Invalid alias location"); - QMetaProperty aliasProperty = id.object->metaObject()->property(propIdx); + QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx); - data.append((const char *)&id.idx, sizeof(id.idx)); + data.append((const char *)&idObject->idIndex, sizeof(idObject->idIndex)); data.append((const char *)&propIdx, sizeof(propIdx)); builder.addSignal(prop.name + "Changed()"); @@ -1881,13 +1934,12 @@ bool QmlCompiler::buildBinding(QmlParser::Value *value, QMetaProperty mp = prop->parent->metaObject()->property(prop->index); if (!mp.isWritable() && !QmlMetaType::isList(prop->type)) - COMPILE_EXCEPTION2(prop, "Invalid property assignment: read-only property"); + COMPILE_EXCEPTION(prop, "Invalid property assignment: read-only property"); BindingReference reference; reference.expression = value->value; reference.property = prop; reference.value = value; - reference.instructionIdx = output->bytecode.count(); reference.bindingContext = ctxt; addBindingReference(reference); @@ -1898,10 +1950,9 @@ void QmlCompiler::genBindingAssignment(QmlParser::Value *binding, QmlParser::Property *prop, QmlParser::Object *obj) { - Q_ASSERT(compileState.bindingMap.contains(binding)); + Q_ASSERT(compileState.bindings.contains(binding)); - const BindingReference &ref = - compileState.bindings.at(compileState.bindingMap.value(binding)); + const BindingReference &ref = compileState.bindings.value(binding); QMetaProperty mp = obj->metaObject()->property(prop->index); @@ -1927,21 +1978,17 @@ bool QmlCompiler::completeComponentBuild() { saveComponentState(); - for (int ii = 0; ii < compileState.aliases.count(); ++ii) { - const AliasReference &alias = compileState.aliases.at(ii); - COMPILE_CHECK(buildDynamicMeta(alias.object, ResolveAliases)); + for (int ii = 0; ii < compileState.aliasingObjects.count(); ++ii) { + Object *aliasObject = compileState.aliasingObjects.at(ii); + COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases)); } - QmlBasicScript::Expression expr; expr.component = compileState.root; - foreach (const IdReference &id, compileState.ids) { - expr.ids.insert(id.id, qMakePair(id.object, id.idx)); - } - - for (int ii = 0; ii < compileState.bindings.count(); ++ii) { - BindingReference &binding = compileState.bindings[ii]; + expr.ids = compileState.ids; + for (QHash<QmlParser::Value*,BindingReference>::Iterator iter = compileState.bindings.begin(); iter != compileState.bindings.end(); ++iter) { + BindingReference &binding = *iter; QmlBasicScript bs; expr.context = binding.bindingContext.object; diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index e09665f..86e6590 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -137,7 +137,7 @@ public: static bool isSignalPropertyName(const QByteArray &); private: - void reset(QmlCompiledData *); + static void reset(QmlCompiledData *); struct BindingContext { BindingContext() @@ -185,7 +185,7 @@ private: QmlParser::Object *obj, QmlParser::Value *value, const BindingContext &ctxt); - bool testProperty(QmlParser::Property *prop, QmlParser::Object *obj); + bool doesPropertyExist(QmlParser::Property *prop, QmlParser::Object *obj); bool testLiteralAssignment(const QMetaProperty &prop, QmlParser::Value *value); enum DynamicMetaMode { IgnoreAliases, ResolveAliases }; @@ -224,25 +224,13 @@ private: QStringList deferredProperties(QmlParser::Object *); - struct IdReference { - QString id; - QmlParser::Object *object; - int instructionIdx; - int idx; - }; void addId(const QString &, QmlParser::Object *); - struct AliasReference { - QmlParser::Object *object; - int instructionIdx; - }; - struct BindingReference { QmlParser::Variant expression; QmlParser::Property *property; QmlParser::Value *value; QByteArray compiledData; - int instructionIdx; BindingContext bindingContext; }; void addBindingReference(const BindingReference &); @@ -252,13 +240,13 @@ private: ComponentCompileState() : parserStatusCount(0), savedObjects(0), pushedProperties(0), root(0) {} - QHash<QString, IdReference> ids; + QHash<QString, QmlParser::Object *> ids; int parserStatusCount; int savedObjects; int pushedProperties; - QList<BindingReference> bindings; - QHash<QmlParser::Value *, int> bindingMap; - QList<AliasReference> aliases; + + QHash<QmlParser::Value *, BindingReference> bindings; + QList<QmlParser::Object *> aliasingObjects; QmlParser::Object *root; }; ComponentCompileState compileState; diff --git a/src/declarative/qml/qmlcomponent.cpp b/src/declarative/qml/qmlcomponent.cpp index 0e68f8a..c7d45fd 100644 --- a/src/declarative/qml/qmlcomponent.cpp +++ b/src/declarative/qml/qmlcomponent.cpp @@ -405,9 +405,10 @@ QString QmlComponent::errorsString() const QString ret; if(!isError()) return ret; - foreach(const QmlError &e, d->errors){ - ret += e.url().toString() + ":" + QString::number(e.line()) + " " - + e.description() + "\n"; + foreach(const QmlError &e, d->errors) { + ret += e.url().toString() + QLatin1String(":") + + QString::number(e.line()) + QLatin1String(" ") + + e.description() + QLatin1String("\n"); } return ret; } @@ -532,7 +533,6 @@ QObject *QmlComponent::beginCreate(QmlContext *context) static_cast<QmlContextPrivate*>(ctxt->d_ptr)->startLine = d->cc->bytecode.at(d->start - 1).line; static_cast<QmlContextPrivate*>(ctxt->d_ptr)->endLine = d->cc->bytecode.at(d->start - 1).createComponent.endLine; } - ctxt->activate(); QmlVME vme; QObject *rv = vme.run(ctxt, d->cc, d->start, d->count); @@ -540,8 +540,6 @@ QObject *QmlComponent::beginCreate(QmlContext *context) if (vme.isError()) d->errors = vme.errors(); - ctxt->deactivate(); - QmlEnginePrivate *ep = d->engine->d_func(); if (ep->rootComponent == this) { ep->rootComponent = 0; diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index b605869..5bc70bc 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -86,8 +86,15 @@ void QmlContextPrivate::destroyed(QObject *obj) } } - for (int ii = 0; ii < notifies.count(); ++ii) { - QMetaObject::activate(q, notifies[ii] + notifyIndex, 0); + // There is no need to emit these notifications if our parent is in the + // process of being deleted (which is *probably* why obj has been destroyed + // anyway), as we're about to get deleted which will invalidate all the + // expressions that could depend on us + QObject *parent = q->parent(); + if (!parent || !QObjectPrivate::get(parent)->wasDeleted) { + for (int ii = 0; ii < notifies.count(); ++ii) { + QMetaObject::activate(q, notifies[ii] + notifyIndex, 0); + } } } @@ -398,56 +405,6 @@ void QmlContext::setContextProperty(const QString &name, QObject *value) } /*! - Activate this bind context. - - \sa QmlEngine::activeContext() QmlContext::activeContext() -*/ -void QmlContext::activate() -{ - QmlEnginePrivate *ep = engine()->d_func(); - ep->activeContexts.push(this); - ep->setCurrentBindContext(this); - ep->contextActivated(this); -} - -/*! - Deactivate this bind context. The previously active bind context will - become active, or, if there was no previously active bind context, no - context will be active. - - \sa QmlEngine::activeContext() QmlContext::activeContext() -*/ -void QmlContext::deactivate() -{ - QmlEnginePrivate *ep = engine()->d_func(); - Q_ASSERT(ep->activeContexts.top() == this); - ep->activeContexts.pop(); - if (ep->activeContexts.isEmpty()) - ep->setCurrentBindContext(0); - else - ep->setCurrentBindContext(ep->activeContexts.top()); - ep->contextDeactivated(this); -} - -/*! - Returns the currently active context, or 0 if no context is active. - - This method is thread-safe. The active context is maintained individually - for each thread. This method is equivalent to - \code - QmlEngine::activeEngine()->activeContext() - \endcode -*/ -QmlContext *QmlContext::activeContext() -{ - QmlEngine *engine = QmlEngine::activeEngine(); - if (engine) - return engine->activeContext(); - else - return 0; -} - -/*! Resolves the URL \a src relative to the URL of the containing component. If \a src is absolute, it is simply returned. If there is no containing component, diff --git a/src/declarative/qml/qmlcontext.h b/src/declarative/qml/qmlcontext.h index 77f6634..877ff0f 100644 --- a/src/declarative/qml/qmlcontext.h +++ b/src/declarative/qml/qmlcontext.h @@ -73,11 +73,6 @@ public: void setContextProperty(const QString &, QObject *); void setContextProperty(const QString &, const QVariant &); - void activate(); - void deactivate(); - - static QmlContext *activeContext(); - QUrl resolvedUrl(const QUrl &); void setBaseUrl(const QUrl &); diff --git a/src/declarative/qml/qmldom.cpp b/src/declarative/qml/qmldom.cpp index e3cb563..293ea6a 100644 --- a/src/declarative/qml/qmldom.cpp +++ b/src/declarative/qml/qmldom.cpp @@ -587,7 +587,7 @@ QmlDomProperty QmlDomDynamicProperty::defaultValue() const int QmlDomDynamicProperty::position() const { if (isValid()) { - return d->property.range.offset; + return d->property.location.range.offset; } else return -1; } @@ -599,7 +599,7 @@ int QmlDomDynamicProperty::position() const int QmlDomDynamicProperty::length() const { if (isValid()) - return d->property.range.length; + return d->property.location.range.length; else return -1; } @@ -769,7 +769,7 @@ QByteArray QmlDomObject::objectType() const Text { id: MyText } \endqml */ -QByteArray QmlDomObject::objectId() const +QString QmlDomObject::objectId() const { if (d->object) return d->object->id; else return QByteArray(); diff --git a/src/declarative/qml/qmldom.h b/src/declarative/qml/qmldom.h index 456202a..339570b 100644 --- a/src/declarative/qml/qmldom.h +++ b/src/declarative/qml/qmldom.h @@ -150,7 +150,7 @@ public: bool isValid() const; QByteArray objectType() const; - QByteArray objectId() const; + QString objectId() const; void setObjectId(const QByteArray &); diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index acbeb26..d724c49 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -1,4 +1,4 @@ - /**************************************************************************** +/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) @@ -90,49 +90,6 @@ struct StaticQtMetaObject : public QObject { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; } }; - -struct QmlEngineStack { - QmlEngineStack(); - - QStack<QmlEngine *> mainThreadEngines; - QThread *mainThread; - - QThreadStorage<QStack<QmlEngine *> *> storage; - - QStack<QmlEngine *> *engines(); -}; - -Q_GLOBAL_STATIC(QmlEngineStack, engineStack); - -QmlEngineStack::QmlEngineStack() -: mainThread(0) -{ -} - -QStack<QmlEngine *> *QmlEngineStack::engines() -{ - if (mainThread== 0) { - if (!QCoreApplication::instance()) - return 0; - mainThread = QCoreApplication::instance()->thread(); - } - - // Note: This is very slightly faster than just using the thread storage - // for everything. - QStack<QmlEngine *> *engines = 0; - if (QThread::currentThread() == mainThread) { - engines = &mainThreadEngines; - } else { - engines = storage.localData(); - if (!engines) { - engines = new QStack<QmlEngine *>; - storage.setLocalData(engines); - } - } - return engines; -} - - QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e) : rootContext(0), currentBindContext(0), currentExpression(0), q(e), isDebugging(false), rootComponent(0), networkAccessManager(0), typeManager(e), @@ -295,30 +252,6 @@ QScriptValue QmlEnginePrivate::propertyObject(const QScriptString &propName, return QScriptValue(); } -void QmlEnginePrivate::contextActivated(QmlContext *) -{ - Q_Q(QmlEngine); - QmlEngineStack *stack = engineStack(); - if (!stack) - return; - QStack<QmlEngine *> *engines = stack->engines(); - if (engines) - engines->push(q); -} - -void QmlEnginePrivate::contextDeactivated(QmlContext *) -{ - QmlEngineStack *stack = engineStack(); - if (!stack) - return; - QStack<QmlEngine *> *engines = stack->engines(); - if (engines) { - Q_ASSERT(engines->top() == q_func()); - engines->pop(); - } -} - - //////////////////////////////////////////////////////////////////// bool QmlEnginePrivate::fetchCache(QmlBasicScriptNodeCache &cache, const QString &propName, QObject *obj) @@ -469,40 +402,12 @@ QmlContext *QmlEngine::rootContext() } /*! - Returns this engine's active context, or 0 if no context is active on this - engine. - - Contexts are activated and deactivated by calling QmlContext::activate() and - QmlContext::deactivate() respectively. - - Context activation holds no special semantic, other than it allows types - instantiated by QML to access "their" context without having it passed as - a parameter in their constructor, as shown below. - \code - class MyClass : ... { - ... - MyClass() { - qWarning() << "I was instantiated in this context:" - << QmlContext::activeContext(); - } - }; - \endcode -*/ -QmlContext *QmlEngine::activeContext() -{ - Q_D(QmlEngine); - if (d->currentBindContext) - return d->currentBindContext; - else - return 0; -} - -/*! - Sets the common QNetworkAccessManager, \a network, used by all QML elements instantiated - by this engine. + Sets the common QNetworkAccessManager, \a network, used by all QML elements + instantiated by this engine. - Any previously set manager is deleted and \a network is owned by the QmlEngine. This - method should only be called before any QmlComponents are instantiated. + Any previously set manager is deleted and \a network is owned by the + QmlEngine. This method should only be called before any QmlComponents are + instantiated. */ void QmlEngine::setNetworkAccessManager(QNetworkAccessManager *network) { @@ -669,30 +574,6 @@ QScriptEngine *QmlEngine::scriptEngine() } /*! - Returns the currently active QmlEngine. - - The active engine is the engine associated with the last activated - QmlContext. This method is thread-safe - the "active" engine is maintained - independently for each thread. -*/ -QmlEngine *QmlEngine::activeEngine() -{ - QmlEngineStack *stack = engineStack(); - if (!stack) return 0; - - QStack<QmlEngine *> *engines = stack->engines(); - if (!engines) { - qWarning("QmlEngine::activeEngine() cannot be called before the construction of QCoreApplication"); - return 0; - } - - if (engines->isEmpty()) - return 0; - else - return engines->top(); -} - -/*! Creates a QScriptValue allowing you to use \a object in QML script. \a engine is the QmlEngine it is to be created in. @@ -777,7 +658,6 @@ QScriptValue QmlEngine::createComponent(QScriptContext *ctxt, QScriptEngine *eng QUrl url = QUrl(activeEngine->d_func()->currentExpression->context() ->resolvedUrl(ctxt->argument(0).toString())); if(!url.isValid()){ - qDebug() << "Error A:" << url << activeEngine->activeContext() << QmlEngine::activeEngine() << activeEngine; url = QUrl(ctxt->argument(0).toString()); } c = new QmlComponent(activeEngine, url, activeEngine); diff --git a/src/declarative/qml/qmlengine.h b/src/declarative/qml/qmlengine.h index 6a418b5..38bf423 100644 --- a/src/declarative/qml/qmlengine.h +++ b/src/declarative/qml/qmlengine.h @@ -70,10 +70,7 @@ public: QmlEngine(QObject *p = 0); virtual ~QmlEngine(); - static QmlEngine *activeEngine(); - QmlContext *rootContext(); - QmlContext *activeContext(); void clearComponentCache(); diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index e0824cc..f459dc5 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -93,9 +93,6 @@ public: void init(); - void contextActivated(QmlContext *); - void contextDeactivated(QmlContext *); - bool fetchCache(QmlBasicScriptNodeCache &cache, const QString &propName, QObject *); bool loadCache(QmlBasicScriptNodeCache &cache, const QString &propName, QmlContextPrivate *context); diff --git a/src/declarative/qml/qmlerror.cpp b/src/declarative/qml/qmlerror.cpp index 149e173..5ee9144 100644 --- a/src/declarative/qml/qmlerror.cpp +++ b/src/declarative/qml/qmlerror.cpp @@ -168,6 +168,21 @@ void QmlError::setColumn(int column) } /*! + Return the error as a human readable string. +*/ +QString QmlError::toString() const +{ + QString rv; + rv = url().toString() + QLatin1String(":") + QString::number(line()); + if(column() != -1) + rv += QLatin1String(":") + QString::number(column()); + + rv += QLatin1String(": ") + description(); + + return rv; +} + +/*! \relates QmlError \fn QDebug operator<<(QDebug debug, const QmlError &error) @@ -176,19 +191,9 @@ void QmlError::setColumn(int column) QDebug operator<<(QDebug debug, const QmlError &error) { - QUrl url = error.url(); - - QString output; - - output = url.toString() + QLatin1String(":") + - QString::number(error.line()); + debug << qPrintable(error.toString()); - if(error.column() != -1) - output += QLatin1String(":") + QString::number(error.column()); - - output += QLatin1String(": ") + error.description(); - - debug << qPrintable(output); + QUrl url = error.url(); if (error.line() > 0 && url.scheme() == QLatin1String("file")) { QString file = url.toLocalFile(); diff --git a/src/declarative/qml/qmlerror.h b/src/declarative/qml/qmlerror.h index 57d2f8f..c1a8720 100644 --- a/src/declarative/qml/qmlerror.h +++ b/src/declarative/qml/qmlerror.h @@ -69,6 +69,8 @@ public: void setLine(int); int column() const; void setColumn(int); + + QString toString() const; private: QmlErrorPrivate *d; }; diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp index 4fe7d0c..2aa1a8a 100644 --- a/src/declarative/qml/qmlexpression.cpp +++ b/src/declarative/qml/qmlexpression.cpp @@ -43,10 +43,7 @@ #include "qmlexpression_p.h" #include "qmlengine_p.h" #include "qmlcontext_p.h" -#include "rewriter/textwriter_p.h" -#include "parser/qmljslexer_p.h" -#include "parser/qmljsparser_p.h" -#include "parser/qmljsnodepool_p.h" +#include "qmlrewrite_p.h" #include "QtCore/qdebug.h" Q_DECLARE_METATYPE(QList<QObject *>); @@ -55,97 +52,6 @@ QT_BEGIN_NAMESPACE DEFINE_BOOL_CONFIG_OPTION(qmlDebugger, QML_DEBUGGER) -namespace { - -using namespace QmlJS; - -class RewriteBinding: protected AST::Visitor -{ - unsigned _position; - TextWriter *_writer; - -public: - QString operator()(const QString &code) - { - Engine engine; - NodePool pool(QString(), &engine); - Lexer lexer(&engine); - Parser parser(&engine); - lexer.setCode(code, 0); - parser.parseStatement(); - return rewrite(code, 0, parser.statement()); - } - -protected: - using AST::Visitor::visit; - - void accept(AST::Node *node) - { - AST::Node::acceptChild(node, this); - } - - QString rewrite(QString code, unsigned position, AST::Statement *node) - { - TextWriter w; - _writer = &w; - _position = position; - - accept(node); - - unsigned startOfStatement = node->firstSourceLocation().begin() - _position; - unsigned endOfStatement = node->lastSourceLocation().end() - _position; - - _writer->replace(startOfStatement, 0, QLatin1String("function() {\n")); - _writer->replace(endOfStatement, 0, QLatin1String("\n}")); - - w.write(&code); - - return code; - } - - virtual bool visit(AST::Block *ast) - { - for (AST::StatementList *it = ast->statements; it; it = it->next) { - if (! it->next) { - // we need to rewrite only the last statement of a block. - accept(it->statement); - } - } - - return false; - } - - virtual bool visit(AST::ExpressionStatement *ast) - { - unsigned startOfExpressionStatement = ast->firstSourceLocation().begin() - _position; - _writer->replace(startOfExpressionStatement, 0, QLatin1String("return ")); - - return false; - } - - virtual bool visit(AST::NumericLiteral *node) - { - if (node->suffix != AST::NumericLiteral::noSuffix) { - const int suffixLength = AST::NumericLiteral::suffixLength[node->suffix]; - const char *suffixSpell = AST::NumericLiteral::suffixSpell[node->suffix]; - QString pre; - pre += QLatin1String("qmlNumberFrom"); - pre += QChar(QLatin1Char(suffixSpell[0])).toUpper(); - pre += QLatin1String(&suffixSpell[1]); - pre += QLatin1Char('('); - _writer->replace(node->literalToken.begin() - _position, 0, pre); - _writer->replace(node->literalToken.end() - _position - suffixLength, - suffixLength, - QLatin1String(")")); - } - - return false; - } -}; - -} // end of anonymous namespace - - QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b) : q(b), ctxt(0), expressionFunctionValid(false), sseData(0), proxy(0), me(0), trackChange(false), line(-1), id(0), log(0) { @@ -332,7 +238,7 @@ QVariant QmlExpressionPrivate::evalQtScript() scriptEngine->currentContext()->pushScope(ctxtPriv->scopeChain.at(i)); if (!expressionFunctionValid) { - RewriteBinding rewriteBinding; + QmlRewrite::RewriteBinding rewriteBinding; const QString code = rewriteBinding(expression); expressionFunction = scriptEngine->evaluate(code, fileName.toString(), line); diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp index 6602021..dea3467 100644 --- a/src/declarative/qml/qmlmetaproperty.cpp +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -643,8 +643,7 @@ void QmlMetaPropertyPrivate::writeSignalProperty(const QVariant &value) if (!expr.isEmpty()) { // XXX scope - (void *)new QmlBoundSignal(QmlContext::activeContext(), expr, object, - coreIdx, object); + (void *)new QmlBoundSignal(qmlContext(object), expr, object, coreIdx, object); } } diff --git a/src/declarative/qml/qmlparser.cpp b/src/declarative/qml/qmlparser.cpp index 8ee3b4e..8eb58c8 100644 --- a/src/declarative/qml/qmlparser.cpp +++ b/src/declarative/qml/qmlparser.cpp @@ -62,8 +62,7 @@ QT_BEGIN_NAMESPACE using namespace QmlParser; QmlParser::Object::Object() -: type(-1), metatype(0), extObjectData(0), defaultProperty(0), - parserStatusCast(-1) +: type(-1), idIndex(-1), metatype(0), defaultProperty(0), parserStatusCast(-1) { } @@ -84,7 +83,7 @@ QmlParser::Object::~Object() const QMetaObject *Object::metaObject() const { - if (extObjectData && metatype) + if (!metadata.isEmpty() && metatype) return &extObject; else return metatype; @@ -147,7 +146,7 @@ QmlParser::Object::DynamicProperty::DynamicProperty(const DynamicProperty &o) type(o.type), name(o.name), defaultValue(o.defaultValue), - range(o.range) + location(o.location) { } diff --git a/src/declarative/qml/qmlparser_p.h b/src/declarative/qml/qmlparser_p.h index d96a43e..d23b4ea 100644 --- a/src/declarative/qml/qmlparser_p.h +++ b/src/declarative/qml/qmlparser_p.h @@ -117,8 +117,10 @@ namespace QmlParser QUrl url; // The name of this type QByteArray typeName; - // The id assigned to the object (if any). - QByteArray id; + // The id assigned to the object (if any). Set by the QmlCompiler + QString id; + // The id index assigned to the object (if any). Set by the QmlCompiler + int idIndex; // Custom parsed data QByteArray custom; // Returns the metaobject for this type, or 0 if not available. @@ -129,7 +131,6 @@ namespace QmlParser const QMetaObject *metatype; // The synthesized metaobject, if QML added signals or properties to // this type. Otherwise null - QMetaObject *extObjectData; QAbstractDynamicMetaObject extObject; QByteArray metadata; // Generated by compiler QByteArray synthdata; // Generated by compiler @@ -168,7 +169,7 @@ namespace QmlParser Type type; QByteArray name; QmlParser::Property *defaultValue; - LocationRange range; + LocationSpan location; }; struct DynamicSignal { DynamicSignal(); diff --git a/src/declarative/qml/qmlrewrite.cpp b/src/declarative/qml/qmlrewrite.cpp new file mode 100644 index 0000000..02bf8fa --- /dev/null +++ b/src/declarative/qml/qmlrewrite.cpp @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** 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 "qmlrewrite_p.h" + +QT_BEGIN_NAMESPACE + +namespace QmlRewrite { + +QString RewriteBinding::operator()(const QString &code) +{ + Engine engine; + NodePool pool(QString(), &engine); + Lexer lexer(&engine); + Parser parser(&engine); + lexer.setCode(code, 0); + parser.parseStatement(); + return rewrite(code, 0, parser.statement()); +} + +void RewriteBinding::accept(AST::Node *node) +{ + AST::Node::acceptChild(node, this); +} + +QString RewriteBinding::rewrite(QString code, unsigned position, + AST::Statement *node) +{ + TextWriter w; + _writer = &w; + _position = position; + + accept(node); + + unsigned startOfStatement = node->firstSourceLocation().begin() - _position; + unsigned endOfStatement = node->lastSourceLocation().end() - _position; + + _writer->replace(startOfStatement, 0, QLatin1String("function() {\n")); + _writer->replace(endOfStatement, 0, QLatin1String("\n}")); + + w.write(&code); + + return code; +} + +bool RewriteBinding::visit(AST::Block *ast) +{ + for (AST::StatementList *it = ast->statements; it; it = it->next) { + if (! it->next) { + // we need to rewrite only the last statement of a block. + accept(it->statement); + } + } + + return false; +} + +bool RewriteBinding::visit(AST::ExpressionStatement *ast) +{ + unsigned startOfExpressionStatement = ast->firstSourceLocation().begin() - _position; + _writer->replace(startOfExpressionStatement, 0, QLatin1String("return ")); + + return false; +} + +bool RewriteBinding::visit(AST::NumericLiteral *node) +{ + if (node->suffix != AST::NumericLiteral::noSuffix) { + const int suffixLength = AST::NumericLiteral::suffixLength[node->suffix]; + const char *suffixSpell = AST::NumericLiteral::suffixSpell[node->suffix]; + QString pre; + pre += QLatin1String("qmlNumberFrom"); + pre += QChar(QLatin1Char(suffixSpell[0])).toUpper(); + pre += QLatin1String(&suffixSpell[1]); + pre += QLatin1Char('('); + _writer->replace(node->literalToken.begin() - _position, 0, pre); + _writer->replace(node->literalToken.end() - _position - suffixLength, + suffixLength, + QLatin1String(")")); + } + + return false; +} + +QString RewriteNumericLiterals::operator()(QString code, unsigned position, AST::Node *node) +{ + TextWriter w; + _writer = &w; + _position = position; + + AST::Node::acceptChild(node, this); + + w.write(&code); + + return code; +} + +bool RewriteNumericLiterals::visit(AST::NumericLiteral *node) +{ + if (node->suffix != AST::NumericLiteral::noSuffix) { + const int suffixLength = AST::NumericLiteral::suffixLength[node->suffix]; + const char *suffixSpell = AST::NumericLiteral::suffixSpell[node->suffix]; + QString pre; + pre += QLatin1String("qmlNumberFrom"); + pre += QChar(QLatin1Char(suffixSpell[0])).toUpper(); + pre += QLatin1String(&suffixSpell[1]); + pre += QLatin1Char('('); + _writer->replace(node->literalToken.begin() - _position, 0, pre); + _writer->replace(node->literalToken.end() - _position - suffixLength, + suffixLength, + QLatin1String(")")); + } + + return false; +} + +} // namespace QmlRewrite + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlrewrite_p.h b/src/declarative/qml/qmlrewrite_p.h new file mode 100644 index 0000000..51a8015 --- /dev/null +++ b/src/declarative/qml/qmlrewrite_p.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QMLREWRITE_P_H +#define QMLREWRITE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "rewriter/textwriter_p.h" +#include "parser/qmljslexer_p.h" +#include "parser/qmljsparser_p.h" +#include "parser/qmljsnodepool_p.h" + +QT_BEGIN_NAMESPACE + +namespace QmlRewrite { +using namespace QmlJS; + +class RewriteBinding: protected AST::Visitor +{ + unsigned _position; + TextWriter *_writer; + +public: + QString operator()(const QString &code); + +protected: + using AST::Visitor::visit; + + void accept(AST::Node *node); + QString rewrite(QString code, unsigned position, AST::Statement *node); + virtual bool visit(AST::Block *ast); + virtual bool visit(AST::ExpressionStatement *ast); + virtual bool visit(AST::NumericLiteral *node); +}; + +class RewriteNumericLiterals: protected AST::Visitor +{ + unsigned _position; + TextWriter *_writer; + +public: + QString operator()(QString code, unsigned position, AST::Node *node); + +protected: + using AST::Visitor::visit; + + virtual bool visit(AST::NumericLiteral *node); +}; + +} // namespace QmlRewrite + +QT_END_NAMESPACE + +#endif // QMLREWRITE_P_H + diff --git a/src/declarative/qml/qmlscriptparser.cpp b/src/declarative/qml/qmlscriptparser.cpp index f26266b..c1c11c7 100644 --- a/src/declarative/qml/qmlscriptparser.cpp +++ b/src/declarative/qml/qmlscriptparser.cpp @@ -49,7 +49,7 @@ #include "parser/qmljsastvisitor_p.h" #include "parser/qmljsast_p.h" -#include "rewriter/textwriter_p.h" +#include "qmlrewrite_p.h" #include <QStack> #include <QCoreApplication> @@ -64,48 +64,6 @@ using namespace QmlParser; namespace { -class RewriteNumericLiterals: protected AST::Visitor -{ - unsigned _position; - TextWriter *_writer; - -public: - QString operator()(QString code, unsigned position, AST::Node *node) - { - TextWriter w; - _writer = &w; - _position = position; - - AST::Node::acceptChild(node, this); - - w.write(&code); - - return code; - } - -protected: - using AST::Visitor::visit; - - virtual bool visit(AST::NumericLiteral *node) - { - if (node->suffix != AST::NumericLiteral::noSuffix) { - const int suffixLength = AST::NumericLiteral::suffixLength[node->suffix]; - const char *suffixSpell = AST::NumericLiteral::suffixSpell[node->suffix]; - QString pre; - pre += QLatin1String("qmlNumberFrom"); - pre += QChar(QLatin1Char(suffixSpell[0])).toUpper(); - pre += QLatin1String(&suffixSpell[1]); - pre += QLatin1Char('('); - _writer->replace(node->literalToken.begin() - _position, 0, pre); - _writer->replace(node->literalToken.end() - _position - suffixLength, - suffixLength, - QLatin1String(")")); - } - - return false; - } -}; - class ProcessAST: protected AST::Visitor { struct State { @@ -196,7 +154,7 @@ protected: const AST::SourceLocation &last) const { return _contents.mid(first.offset, last.offset + last.length - first.offset); } - RewriteNumericLiterals rewriteNumericLiterals; + QmlRewrite::RewriteNumericLiterals rewriteNumericLiterals; QString asString(AST::ExpressionNode *expr) { @@ -572,8 +530,8 @@ bool ProcessAST::visit(AST::UiPublicMember *node) property.isDefaultProperty = node->isDefaultMember; property.type = type; property.name = name.toUtf8(); - property.range.offset = node->firstSourceLocation().offset; - property.range.length = node->semicolonToken.end() - property.range.offset; + property.location = location(node->firstSourceLocation(), + node->lastSourceLocation()); if (node->expression) { // default value property.defaultValue = new Property; diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index 3b33686..f468cd0 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -116,7 +116,6 @@ void QmlVME::runDeferred(QObject *object) return; QmlContext *ctxt = data->context; - ctxt->activate(); QmlCompiledData *comp = data->deferredComponent; int start = data->deferredIdx + 1; int count = data->deferredComponent->bytecode.at(data->deferredIdx).defer.deferCount; @@ -124,17 +123,10 @@ void QmlVME::runDeferred(QObject *object) stack.push(object); run(stack, ctxt, comp, start, count); - ctxt->deactivate(); } QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledData *comp, int start, int count) { - // XXX - All instances of QmlContext::activeContext() here should be - // replaced with the use of ctxt. However, this cannot be done until - // behaviours stop modifying the active context and expecting the - // instantiation to notice. Instead, QmlParserStatus::beginClass() should - // be able to return a QmlContext that is used for expressions and - // sub-instances on that type. Q_ASSERT(comp); Q_ASSERT(ctxt); const QList<QmlCompiledData::TypeReference> &types = comp->types; @@ -169,7 +161,7 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledData case QmlInstruction::CreateObject: { - QObject *o = types.at(instr.create.type).createInstance(QmlContext::activeContext()); + QObject *o = types.at(instr.create.type).createInstance(ctxt); if (!o) { if(types.at(instr.create.type).component) vmeErrors << types.at(instr.create.type).component->errors(); @@ -203,8 +195,6 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledData case QmlInstruction::SetId: { QObject *target = stack.top(); - QmlContext *ctxt = - QmlContext::activeContext(); ctxt->setContextProperty(primitives.at(instr.setId.value), target); } break; @@ -213,7 +203,7 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledData case QmlInstruction::SetDefault: { QObject *target = stack.top(); - QmlContext::activeContext()->addDefaultObject(target); + ctxt->addDefaultObject(target); } break; @@ -515,9 +505,9 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledData target->metaObject()->method(instr.storeSignal.signalIndex); if (signal.parameterTypes().isEmpty()) { - (void *)new QmlBoundSignal(QmlContext::activeContext(), primitives.at(instr.storeSignal.value), target, instr.storeSignal.signalIndex, target); + (void *)new QmlBoundSignal(ctxt, primitives.at(instr.storeSignal.value), target, instr.storeSignal.signalIndex, target); } else { - (void *)new QmlBoundSignalProxy(new QmlContext(QmlContext::activeContext(), target, true), primitives.at(instr.storeSignal.value), target, instr.storeSignal.signalIndex, target); + (void *)new QmlBoundSignalProxy(new QmlContext(ctxt, target, true), primitives.at(instr.storeSignal.value), target, instr.storeSignal.signalIndex, target); } } break; @@ -550,7 +540,7 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledData QmlMetaProperty mp(target, instr.assignBinding.property, (QmlMetaProperty::PropertyCategory)instr.assignBinding.category); - QmlBindableValue *bind = new QmlBindableValue((void *)datas.at(instr.assignBinding.value).constData(), comp, context, QmlContext::activeContext(), 0); + QmlBindableValue *bind = new QmlBindableValue((void *)datas.at(instr.assignBinding.value).constData(), comp, context, ctxt, 0); bindValues.append(bind); QmlBindableValuePrivate *p = static_cast<QmlBindableValuePrivate *>(QObjectPrivate::get(bind)); @@ -570,7 +560,7 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledData QmlMetaProperty mp(target, instr.assignBinding.property, (QmlMetaProperty::PropertyCategory)instr.assignBinding.category); - QmlBindableValue *bind = new QmlBindableValue(primitives.at(instr.assignBinding.value), context, QmlContext::activeContext()); + QmlBindableValue *bind = new QmlBindableValue(primitives.at(instr.assignBinding.value), context, ctxt); bindValues.append(bind); QmlBindableValuePrivate *p = static_cast<QmlBindableValuePrivate *>(QObjectPrivate::get(bind)); diff --git a/src/declarative/util/qmlpalette.cpp b/src/declarative/util/qmlpalette.cpp index eda0ded..40cfa71 100644 --- a/src/declarative/util/qmlpalette.cpp +++ b/src/declarative/util/qmlpalette.cpp @@ -151,6 +151,16 @@ QColor QmlPalette::highlightedText() const return d->palette.color(d->group, QPalette::HighlightedText); } +QColor QmlPalette::lighter(const QColor& color) const +{ + return color.lighter(); +} + +QColor QmlPalette::darker(const QColor& color) const +{ + return color.darker(); +} + void QmlPalette::setColorGroup(QPalette::ColorGroup colorGroup) { Q_D(QmlPalette); diff --git a/src/declarative/util/qmlpalette.h b/src/declarative/util/qmlpalette.h index 1401ad1..7f26f9a 100644 --- a/src/declarative/util/qmlpalette.h +++ b/src/declarative/util/qmlpalette.h @@ -101,6 +101,9 @@ public: bool virtual eventFilter(QObject *watched, QEvent *event); bool virtual event(QEvent *event); + Q_INVOKABLE QColor lighter(const QColor&) const; + Q_INVOKABLE QColor darker(const QColor&) const; + Q_SIGNALS: void paletteChanged(); }; diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index 328717c..990d20a 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -68,7 +68,8 @@ enum PropertyFlags { ResolveUser = 0x00200000, Notify = 0x00400000, Dynamic = 0x00800000, - Constant = 0x00000400 + Constant = 0x00000400, + Final = 0x00000800 }; enum MethodFlags { AccessPrivate = 0x00, @@ -604,6 +605,8 @@ void Generator::generateProperties() if (p.constant) flags |= Constant; + if (p.final) + flags |= Final; fprintf(out, " %4d, %4d, ", strreg(p.name), diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp index 7ad67c9..d2f40ee 100644 --- a/src/tools/moc/moc.cpp +++ b/src/tools/moc/moc.cpp @@ -917,6 +917,9 @@ void Moc::parseProperty(ClassDef *def) if (l[0] == 'C' && l == "CONSTANT") { propDef.constant = true; continue; + } else if(l[0] == 'F' && l == "FINAL") { + propDef.final = true; + continue; } QByteArray v, v2; diff --git a/src/tools/moc/moc.h b/src/tools/moc/moc.h index f459032..d68907f 100644 --- a/src/tools/moc/moc.h +++ b/src/tools/moc/moc.h @@ -115,10 +115,11 @@ struct FunctionDef struct PropertyDef { - PropertyDef():notifyId(-1), constant(false), gspec(ValueSpec){} + PropertyDef():notifyId(-1), constant(false), final(false), gspec(ValueSpec){} QByteArray name, type, read, write, reset, designable, scriptable, editable, stored, user, notify; int notifyId; bool constant; + bool final; enum Specification { ValueSpec, ReferenceSpec, PointerSpec }; Specification gspec; bool stdCppSet() const { |