diff options
author | Michael Brasser <michael.brasser@nokia.com> | 2009-10-11 22:48:10 (GMT) |
---|---|---|
committer | Michael Brasser <michael.brasser@nokia.com> | 2009-10-11 22:48:10 (GMT) |
commit | 76b29d542e13184da81129ea3f7373ffd71ceedc (patch) | |
tree | c18a7af8ae2f70d6fcda5b74cd00161241596beb | |
parent | ac507b4752dcd065038130d224910a6dc64f8f37 (diff) | |
parent | 76448b41bb9c6212d2534f0597f9973c881c77bd (diff) | |
download | Qt-76b29d542e13184da81129ea3f7373ffd71ceedc.zip Qt-76b29d542e13184da81129ea3f7373ffd71ceedc.tar.gz Qt-76b29d542e13184da81129ea3f7373ffd71ceedc.tar.bz2 |
Merge branch 'kinetic-declarativeui' of git@scm.dev.nokia.troll.no:qt/kinetic into kinetic-declarativeui
29 files changed, 497 insertions, 428 deletions
diff --git a/examples/declarative/gridview/gridview.qml b/examples/declarative/gridview/gridview.qml index 2e5110a..93931c7 100644 --- a/examples/declarative/gridview/gridview.qml +++ b/examples/declarative/gridview/gridview.qml @@ -4,57 +4,35 @@ Rectangle { width: 300; height: 400; color: "white" ListModel { - id: AppModel - ListElement { - name: "Music" - icon: "AudioPlayer_48.png" - } - ListElement { - name: "Movies" - icon: "VideoPlayer_48.png" - } - ListElement { - name: "Camera" - icon: "Camera_48.png" - } - ListElement { - name: "Calendar" - icon: "DateBook_48.png" - } - ListElement { - name: "Messaging" - icon: "EMail_48.png" - } - ListElement { - name: "Todo List" - icon: "TodoList_48.png" - } - ListElement { - name: "Contacts" - icon: "AddressBook_48.png" - } + id: appModel + ListElement { name: "Music"; icon: "pics/AudioPlayer_48.png" } + ListElement { name: "Movies"; icon: "pics/VideoPlayer_48.png" } + ListElement { name: "Camera"; icon: "pics/Camera_48.png" } + ListElement { name: "Calendar"; icon: "pics/DateBook_48.png" } + ListElement { name: "Messaging"; icon: "pics/EMail_48.png" } + ListElement { name: "Todo List"; icon: "pics/TodoList_48.png" } + ListElement { name: "Contacts"; icon: "pics/AddressBook_48.png" } } Component { - id: AppDelegate + id: appDelegate Item { width: 100; height: 100 - Image { id: Icon; y: 20; anchors.horizontalCenter: parent.horizontalCenter; source: icon } - Text { anchors.top: Icon.bottom; anchors.horizontalCenter: parent.horizontalCenter; text: name } + Image { id: myIcon; y: 20; anchors.horizontalCenter: parent.horizontalCenter; source: icon } + Text { anchors.top: myIcon.bottom; anchors.horizontalCenter: parent.horizontalCenter; text: name } } } Component { - id: AppHighlight - Rectangle { width: 80; height: 80; color: "#FFFF88" } + id: appHighlight + Rectangle { width: 80; height: 80; color: "lightsteelblue" } } GridView { - id: List1 anchors.fill: parent cellWidth: 100; cellHeight: 100 - model: AppModel; delegate: AppDelegate - highlight: AppHighlight + model: appModel; delegate: appDelegate + highlight: appHighlight focus: true } } diff --git a/examples/declarative/listview/recipes.qml b/examples/declarative/listview/recipes.qml index 4ccb344..3410f56 100644 --- a/examples/declarative/listview/recipes.qml +++ b/examples/declarative/listview/recipes.qml @@ -1,128 +1,136 @@ import Qt 4.6 - import "content" + // This example illustrates expanding a list item to show a more detailed view + Rectangle { id: page width: 400; height: 240; color: "black" - resources: [ - // Delegate for the recipes. This delegate has two modes: - // 1. the list mode (default), which just shows the picture and title of the recipe. - // 2. the details mode, which also shows the ingredients and method. - Component { - id: recipeDelegate - Item { - id: wrapper - width: list.width - // Create a property to contain the visibility of the details. - // We can bind multiple element's opacity to this one property, - // rather than having a "PropertyChanges" line for each element we - // want to fade. - property real detailsOpacity : 0 - - // A simple rounded rectangle for the background - Rectangle { - id: background - x: 1; y: 2; width: parent.width-2; height: parent.height-4 - color: "#FEFFEE"; border.color: "#FFBE4F"; radius: 5 - } - // This mouse region covers the entire delegate. - // When clicked it changes mode to 'Details'. If we are already - // in Details mode, then no change will happen. - MouseRegion { - id: pageMouse - anchors.fill: parent - onClicked: { wrapper.state = 'Details' } - } - // Layout the page. Picture, title and ingredients at the top, method at the - // bottom. Note that elements that should not be visible in the list - // mode have their opacity set to wrapper.detailsOpacity. - Row { - id: topLayout - x: 10; y: 10; height: recipePic.height; width: parent.width - spacing: 10 - Image { - id: recipePic - source: picture; width: 48; height: 48 - } - Column { - height: recipePic.height; width: background.width-recipePic.width-20 - spacing: 5 - Text { id: name; text: title; font.bold: true; font.pointSize: 16 } - Text { - text: "Ingredients"; font.pointSize: 12; font.bold: true - opacity: wrapper.detailsOpacity - } - Text { - text: ingredients; wrap: true; width: parent.width - opacity: wrapper.detailsOpacity - } - } + + // Delegate for the recipes. This delegate has two modes: + // 1. the list mode (default), which just shows the picture and title of the recipe. + // 2. the details mode, which also shows the ingredients and method. + Component { + id: recipeDelegate + Item { + id: wrapper + width: list.width + + // Create a property to contain the visibility of the details. + // We can bind multiple element's opacity to this one property, + // rather than having a "PropertyChanges" line for each element we + // want to fade. + property real detailsOpacity : 0 + + // A simple rounded rectangle for the background + Rectangle { + id: background + x: 1; y: 2; width: parent.width - 2; height: parent.height - 4 + color: "#FEFFEE"; border.color: "#FFBE4F"; radius: 5 + } + + // This mouse region covers the entire delegate. + // When clicked it changes mode to 'Details'. If we are already + // in Details mode, then no change will happen. + MouseRegion { + id: pageMouse + anchors.fill: parent + onClicked: wrapper.state = 'Details'; + } + + // Layout the page. Picture, title and ingredients at the top, method at the + // bottom. Note that elements that should not be visible in the list + // mode have their opacity set to wrapper.detailsOpacity. + Row { + id: topLayout + x: 10; y: 10; height: recipePic.height; width: parent.width + spacing: 10 + + Image { + id: recipePic + source: picture; width: 48; height: 48 } - Item { - id: details - x: 10; width: parent.width-20 - anchors.top: topLayout.bottom; anchors.topMargin: 10 - anchors.bottom: parent.bottom; anchors.bottomMargin: 10 - opacity: wrapper.detailsOpacity + + Column { + height: recipePic.height; width: background.width-recipePic.width-20 + spacing: 5 + Text { id: name; text: title; font.bold: true; font.pointSize: 16 } Text { - id: methodTitle - text: "Method"; font.pointSize: 12; font.bold: true - anchors.top: parent.top - } - Flickable { - id: flick - anchors.top: methodTitle.bottom; anchors.bottom: parent.bottom - width: parent.width; viewportHeight: methodText.height; clip: true - Text { id: methodText; text: method; wrap: true; width: details.width } - } - Image { - anchors.right: flick.right; anchors.top: flick.top - source: "content/pics/moreUp.png"; opacity: flick.atYBeginning ? 0 : 1 + text: "Ingredients"; font.pointSize: 12; font.bold: true + opacity: wrapper.detailsOpacity } - Image { - anchors.right: flick.right; anchors.bottom: flick.bottom - source: "content/pics/moreDown.png"; opacity: flick.atYEnd ? 0 : 1 + Text { + text: ingredients; wrap: true; width: parent.width + opacity: wrapper.detailsOpacity } } - // A button to close the detailed view, i.e. set the state back to default (''). - MediaButton { - anchors.right: background.right; anchors.rightMargin: 5 - y: 10; opacity: wrapper.detailsOpacity - text: "Close"; onClicked: { wrapper.state = '' } + } + + Item { + id: details + x: 10; width: parent.width-20 + anchors.top: topLayout.bottom; anchors.topMargin: 10 + anchors.bottom: parent.bottom; anchors.bottomMargin: 10 + opacity: wrapper.detailsOpacity + + Text { + id: methodTitle + text: "Method"; font.pointSize: 12; font.bold: true + anchors.top: parent.top + } + Flickable { + id: flick + anchors.top: methodTitle.bottom; anchors.bottom: parent.bottom + width: parent.width; viewportHeight: methodText.height; clip: true + Text { id: methodText; text: method; wrap: true; width: details.width } } - // Make the default height equal the hight of the picture, plus margin. - height: 68 - states: [ - State { - name: "Details" - PropertyChanges { target: background; color: "white" } - // Make the picture bigger - PropertyChanges { target: recipePic; width: 128; height: 128 } - // Make details visible - PropertyChanges { target: wrapper; detailsOpacity: 1; x: 0 } - // Make the detailed view fill the entire list area - PropertyChanges { target: wrapper; height: list.height } - // Move the list so that this item is at the top. - PropertyChanges { target: wrapper.ListView.view; explicit: true; viewportY: wrapper.y } - // Disallow flicking while we're in detailed view - PropertyChanges { target: wrapper.ListView.view; interactive: false } - } - ] - transitions: [ - Transition { - // Make the state changes smooth - ParallelAnimation { - ColorAnimation { property: "color"; duration: 500 } - NumberAnimation { - duration: 300; properties: "detailsOpacity,x,viewportY,height,width" - } - } + Image { + anchors.right: flick.right; anchors.top: flick.top + source: "content/pics/moreUp.png"; opacity: flick.atYBeginning ? 0 : 1 + } + Image { + anchors.right: flick.right; anchors.bottom: flick.bottom + source: "content/pics/moreDown.png"; opacity: flick.atYEnd ? 0 : 1 + } + } + + // A button to close the detailed view, i.e. set the state back to default (''). + MediaButton { + anchors.right: background.right; anchors.rightMargin: 5 + y: 10; opacity: wrapper.detailsOpacity + text: "Close"; onClicked: wrapper.state = ''; + } + + // Make the default height equal the hight of the picture, plus margin. + height: 68 + + states: State { + name: "Details" + PropertyChanges { target: background; color: "white" } + // Make the picture bigger + PropertyChanges { target: recipePic; width: 128; height: 128 } + // Make details visible + PropertyChanges { target: wrapper; detailsOpacity: 1; x: 0 } + // Make the detailed view fill the entire list area + PropertyChanges { target: wrapper; height: list.height } + // Move the list so that this item is at the top. + PropertyChanges { target: wrapper.ListView.view; explicit: true; viewportY: wrapper.y } + // Disallow flicking while we're in detailed view + PropertyChanges { target: wrapper.ListView.view; interactive: false } + } + + transitions: Transition { + // Make the state changes smooth + ParallelAnimation { + ColorAnimation { property: "color"; duration: 500 } + NumberAnimation { + duration: 300; properties: "detailsOpacity,x,viewportY,height,width" } - ] + } } } - ] + } + // The actual list ListView { id: list diff --git a/examples/declarative/snow/ImageBatch.qml b/examples/declarative/snow/ImageBatch.qml index 62f986c..86e11f7 100644 --- a/examples/declarative/snow/ImageBatch.qml +++ b/examples/declarative/snow/ImageBatch.qml @@ -35,14 +35,14 @@ GridView { XmlRole { name: "url"; query: "media:content/@url/string()" } } - Item { + delegate: Item { id: root property bool isSelected: GridView.isCurrentItem && grid.isSelected transformOrigin: "Center" width: grid.imageWidth; height: grid.imageHeight; Image { id: flickrImage; source: url; fillMode: "PreserveAspectFit"; smooth: true; anchors.fill: parent; - opacity: (status == 1)?1:0; opacity: Behavior { NumberAnimation { properties: "opacity" } } } + opacity: (status == Image.Ready)?1:0; /*opacity: Behavior { NumberAnimation { properties: "opacity" } }*/ } Loading { anchors.centerIn: parent; visible: flickrImage.status!=1 } states: State { diff --git a/examples/declarative/webview/newwindows.qml b/examples/declarative/webview/newwindows.qml index 59e3b3e..e2ed58f 100644 --- a/examples/declarative/webview/newwindows.qml +++ b/examples/declarative/webview/newwindows.qml @@ -7,22 +7,23 @@ import Qt 4.6 Row { id: pages - height: 200 - resources: [ - Component { - id: webViewPage - Rectangle { - width: webView.width - height: webView.height - WebView { - id: webView - newWindowComponent: webViewPage - newWindowParent: pages - url: "newwindows.html" - } - } + height: 200; width: 500 + + Component { + id: webViewPage + Rectangle { + width: webView.width + height: webView.height + border.color: "gray" + + WebView { + id: webView + newWindowComponent: webViewPage + newWindowParent: pages + url: "newwindows.html" + } } - ] - width: 500 + } + Loader { sourceComponent: webViewPage } } diff --git a/examples/declarative/xmldata/daringfireball.qml b/examples/declarative/xmldata/daringfireball.qml index bea38c8..938bdd5 100644 --- a/examples/declarative/xmldata/daringfireball.qml +++ b/examples/declarative/xmldata/daringfireball.qml @@ -2,59 +2,44 @@ import Qt 4.6 Rectangle { color: "white" - width: 600 - height: 600 - resources: [ - XmlListModel { - id: feedModel - source: "http://daringfireball.net/index.xml" - query: "/feed/entry" - namespaceDeclarations: "declare default element namespace 'http://www.w3.org/2005/Atom';" - XmlRole { - name: "title" - query: "title/string()" - } - XmlRole { - name: "tagline" - query: "author/name/string()" + width: 600; height: 600 + + XmlListModel { + id: feedModel + source: "http://daringfireball.net/index.xml" + query: "/feed/entry" + namespaceDeclarations: "declare default element namespace 'http://www.w3.org/2005/Atom';" + XmlRole { name: "title"; query: "title/string()" } + XmlRole { name: "tagline"; query: "author/name/string()" } + XmlRole { name: "content"; query: "content/string()" } + } + + Component { + id: feedDelegate + Item { + height: childrenRect.height + 20 + Text { + id: titleText + x: 10 + text: title; font.bold: true } - XmlRole { - name: "content" - query: "content/string()" + Text { + text: 'by ' + tagline + anchors.left: titleText.right; anchors.leftMargin: 10 + font.italic: true } - }, - Component { - id: feedDelegate - Item { - height: childrenRect.height + 20 - Text { - x: 10 - id: titleText - text: title - font.bold: true - } - Text { - text: 'by ' + tagline - anchors.left: titleText.right - anchors.leftMargin: 10 - font.italic: true - } - Text { - x: 10 - text: content - anchors.top: titleText.bottom - width: 580 - wrap: true - onLinkActivated: { print('link clicked: ' + link) } - } + Text { + x: 10 + text: content + anchors.top: titleText.bottom + width: 580; wrap: true + onLinkActivated: { print('link clicked: ' + link) } } } - ] + } + ListView { - id: list anchors.fill: parent - clip: true - model: feedModel - delegate: feedDelegate + model: feedModel; delegate: feedDelegate } } diff --git a/examples/declarative/xmldata/yahoonews.qml b/examples/declarative/xmldata/yahoonews.qml index 6d43f46..7d8b8a2 100644 --- a/examples/declarative/xmldata/yahoonews.qml +++ b/examples/declarative/xmldata/yahoonews.qml @@ -5,100 +5,74 @@ Rectangle { GradientStop { position: 0; color: "black" } GradientStop { position: 1.0; color: "#AAAAAA" } } - width: 600 - height: 600 - resources: [ - XmlListModel { - id: feedModel - source: "http://rss.news.yahoo.com/rss/oceania" - query: "/rss/channel/item" - XmlRole { - name: "title" - query: "title/string()" - } - XmlRole { - name: "link" - query: "link/string()" - } - XmlRole { - name: "description" - query: "description/string()" + width: 600; height: 600 + + XmlListModel { + id: feedModel + source: "http://rss.news.yahoo.com/rss/oceania" + query: "/rss/channel/item" + XmlRole { name: "title"; query: "title/string()" } + XmlRole { name: "link"; query: "link/string()" } + XmlRole { name: "description"; query: "description/string()" } + } + + Component { + id: feedDelegate + Item { + id: delegate + height: wrapper.height + 10 + + MouseRegion { + anchors.fill: wrapper + onPressed: delegate.ListView.view.currentIndex = index; + onClicked: if (wrapper.state == 'Details') wrapper.state = ''; else wrapper.state = 'Details'; } - }, - Component { - id: feedDelegate - Item { - id: delegate - height: wrapper.height + 10 - MouseRegion { - anchors.fill: wrapper - onPressed: { delegate.ListView.view.currentIndex = index; } - onClicked: { if (wrapper.state == 'Details') { wrapper.state = '';} else {wrapper.state = 'Details';} } + + Rectangle { + id: wrapper + y: 5; height: titleText.height + 10; width: 580 + color: "#F0F0F0"; radius: 5 + Text { + id: titleText + x: 10; y: 5 + text: '<a href=\'' + link + '\'>' + title + '</a>' + font.bold: true; font.family: "Helvetica"; font.pointSize: 14 + onLinkActivated: { print('link clicked: ' + link) } } - Rectangle { - id: wrapper - y: 5 - height: titleText.height + 10 - width: 580 - color: "#F0F0F0" - radius: 5 - Text { - x: 10 - y: 5 - id: titleText - text: '<a href=\'' + link + '\'>' + title + '</a>' - font.bold: true - font.family: "Helvetica" - font.pointSize: 14 - onLinkActivated: { print('link clicked: ' + link) } - } - Text { - x: 10 - id: description - text: description - width: 560 - wrap: true - font.family: "Helvetica" - anchors.top: titleText.bottom - anchors.topMargin: 5 - opacity: 0 + + Text { + x: 10 + id: descriptionText + text: description + width: 560 + wrap: true + font.family: "Helvetica" + anchors.top: titleText.bottom + anchors.topMargin: 5 + opacity: 0 + } + + states: State { + name: "Details" + PropertyChanges { target: wrapper; height: childrenRect.height + 10 } + PropertyChanges { target: descriptionText; opacity: 1 } + } + + transitions: Transition { + from: "*"; to: "Details"; reversible: true + SequentialAnimation { + NumberAnimation { duration: 200; properties: "height"; easing: "easeOutQuad" } + NumberAnimation { duration: 200; properties: "opacity" } } - states: [ - State { - name: "Details" - PropertyChanges { target: wrapper; height: childrenRect.height + 10 } - PropertyChanges { target: description; opacity: 1 } - } - ] - transitions: [ - Transition { - from: "*" - to: "Details" - reversible: true - SequentialAnimation { - NumberAnimation { - duration: 200 - properties: "height" - easing: "easeOutQuad" - } - NumberAnimation { - duration: 200 - properties: "opacity" - } - } - } - ] } } } - ] + } + ListView { id: list - x: 10 - y: 10 - width: parent.width - 20 - height: parent.height - 20 - clip: true + x: 10; y: 10 + width: parent.width - 20; height: parent.height - 20 model: feedModel delegate: feedDelegate } diff --git a/src/declarative/qml/qmlbinding.cpp b/src/declarative/qml/qmlbinding.cpp index 907dcfa..2435c40 100644 --- a/src/declarative/qml/qmlbinding.cpp +++ b/src/declarative/qml/qmlbinding.cpp @@ -67,8 +67,8 @@ QmlBindingPrivate::QmlBindingPrivate() { } -QmlBinding::QmlBinding(void *data, QmlRefCount *rc, QObject *obj, QmlContext *ctxt, QObject *parent) -: QmlExpression(ctxt, data, rc, obj, *new QmlBindingPrivate) +QmlBinding::QmlBinding(void *data, QmlRefCount *rc, QObject *obj, QmlContext *ctxt, const QUrl &url, int lineNumber, QObject *parent) +: QmlExpression(ctxt, data, rc, obj, url, lineNumber, *new QmlBindingPrivate) { setParent(parent); } diff --git a/src/declarative/qml/qmlbinding.h b/src/declarative/qml/qmlbinding.h index bc5a42f..6a3e92a 100644 --- a/src/declarative/qml/qmlbinding.h +++ b/src/declarative/qml/qmlbinding.h @@ -93,7 +93,8 @@ class Q_DECLARATIVE_EXPORT QmlBinding : public QmlExpression, Q_OBJECT public: QmlBinding(const QString &, QObject *, QmlContext *, QObject *parent=0); - QmlBinding(void *, QmlRefCount *, QObject *, QmlContext *, QObject *parent); + QmlBinding(void *, QmlRefCount *, QObject *, QmlContext *, const QUrl &, int, + QObject *parent); ~QmlBinding(); void setTarget(const QmlMetaProperty &); diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 71f86d9..6fad513 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -833,6 +833,8 @@ void QmlCompiler::genObject(QmlParser::Object *obj) QmlInstruction script; script.type = QmlInstruction::StoreScript; script.line = -1; // ### + script.storeScript.fileName = output->indexForString(obj->scriptBlocksFile.at(ii)); + script.storeScript.lineNumber = obj->scriptBlocksLineNumber.at(ii); script.storeScript.value = output->indexForString(obj->scriptBlocks.at(ii)); output->bytecode << script; } @@ -1054,6 +1056,8 @@ bool QmlCompiler::buildComponent(QmlParser::Object *obj, bool QmlCompiler::buildScript(QmlParser::Object *obj, QmlParser::Object *script) { QString scriptCode; + QString sourceUrl; + int lineNumber = 1; if (script->properties.count() == 1 && script->properties.begin().key() == QByteArray("source")) { @@ -1066,8 +1070,7 @@ bool QmlCompiler::buildScript(QmlParser::Object *obj, QmlParser::Object *script) source->values.at(0)->object || !source->values.at(0)->value.isString()) COMPILE_EXCEPTION(source, "Invalid Script source value"); - QString sourceUrl = - output->url.resolved(QUrl(source->values.at(0)->value.asString())).toString(); + sourceUrl = output->url.resolved(QUrl(source->values.at(0)->value.asString())).toString(); for (int ii = 0; ii < unit->resources.count(); ++ii) { if (unit->resources.at(ii)->url == sourceUrl) { @@ -1079,10 +1082,14 @@ bool QmlCompiler::buildScript(QmlParser::Object *obj, QmlParser::Object *script) } else if (!script->properties.isEmpty()) { COMPILE_EXCEPTION(*script->properties.begin(), "Properties cannot be set on Script block"); } else if (script->defaultProperty) { + sourceUrl = output->url.toString(); + QmlParser::Location currentLocation; for (int ii = 0; ii < script->defaultProperty->values.count(); ++ii) { Value *v = script->defaultProperty->values.at(ii); + if (lineNumber == 1) + lineNumber = v->location.start.line; if (v->object || !v->value.isString()) COMPILE_EXCEPTION(v, "Invalid Script block"); @@ -1105,8 +1112,11 @@ bool QmlCompiler::buildScript(QmlParser::Object *obj, QmlParser::Object *script) } } - if (!scriptCode.isEmpty()) + if (!scriptCode.isEmpty()) { obj->scriptBlocks.append(scriptCode); + obj->scriptBlocksFile.append(sourceUrl); + obj->scriptBlocksLineNumber.append(lineNumber); + } return true; } @@ -2272,10 +2282,13 @@ bool QmlCompiler::compileAlias(QMetaObjectBuilder &builder, data.append((const char *)&idObject->idIndex, sizeof(idObject->idIndex)); data.append((const char *)&propIdx, sizeof(propIdx)); + const char *typeName = aliasProperty.typeName(); + if (aliasProperty.isEnumType()) + typeName = "int"; // Avoid introducing a dependency on the aliased metaobject + builder.addSignal(prop.name + "Changed()"); QMetaPropertyBuilder propBuilder = - builder.addProperty(prop.name, aliasProperty.typeName(), - builder.methodCount() - 1); + builder.addProperty(prop.name, typeName, builder.methodCount() - 1); propBuilder.setScriptable(true); return true; } @@ -2351,7 +2364,7 @@ void QmlCompiler::genBindingAssignment(QmlParser::Value *binding, store.assignBinding.value = output->indexForByteArray(ref.compiledData); store.assignBinding.context = ref.bindingContext.stack; store.assignBinding.owner = ref.bindingContext.owner; - store.line = prop->location.end.line; + store.line = binding->location.start.line; Q_ASSERT(ref.bindingContext.owner == 0 || (ref.bindingContext.owner != 0 && valueTypeProperty)); diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index f6795aa..43a4741 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -61,8 +61,11 @@ QmlContextPrivate::QmlContextPrivate() { } -void QmlContextPrivate::addScript(const QString &script, QObject *scopeObject) +void QmlContextPrivate::addScript(const QString &script, QObject *scopeObject, + const QString &fileName, int lineNumber) { + Q_Q(QmlContext); + if (!engine) return; @@ -70,29 +73,15 @@ void QmlContextPrivate::addScript(const QString &script, QObject *scopeObject) QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); QScriptContext *scriptContext = scriptEngine->pushCleanContext(); - scriptContext->pushScope(scriptValue); + scriptContext->pushScope(enginePriv->contextClass->newContext(q, scopeObject)); - if (scopeObject) - scriptContext->pushScope(enginePriv->objectClass->newQObject(scopeObject)); - QScriptValue scope = scriptEngine->newObject(); scriptContext->setActivationObject(scope); - QScriptValue val = scriptEngine->evaluate(script); + QScriptValue val = scriptEngine->evaluate(script, fileName, lineNumber); - if (scriptEngine->hasUncaughtException()) { - if (scriptEngine->uncaughtException().isError()){ - QScriptValue exception = scriptEngine->uncaughtException(); - if (!exception.property(QLatin1String("fileName")).toString().isEmpty()){ - qWarning() << exception.property(QLatin1String("fileName")).toString() - << scriptEngine->uncaughtExceptionLineNumber() - << exception.toString(); - - } else { - qmlInfo(scopeObject) << exception.toString(); - } - } - } + if (scriptEngine->hasUncaughtException()) + QmlExpressionPrivate::printException(scriptEngine); scriptEngine->popContext(); @@ -139,10 +128,6 @@ void QmlContextPrivate::init() if (parent) parent->d_func()->childContexts.insert(q); - - //set scope chain - QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); - scriptValue = QmlEnginePrivate::get(engine)->contextClass->newContext(q); } void QmlContextPrivate::addDefaultObject(QObject *object, Priority priority) diff --git a/src/declarative/qml/qmlcontext_p.h b/src/declarative/qml/qmlcontext_p.h index d18bfda..9a77e94 100644 --- a/src/declarative/qml/qmlcontext_p.h +++ b/src/declarative/qml/qmlcontext_p.h @@ -91,10 +91,9 @@ public: QObjectList defaultObjects; int highPriorityCount; - QScriptValue scriptValue; - QList<QScriptValue> scripts; - void addScript(const QString &script, QObject *scope); + void addScript(const QString &script, QObject *scope, + const QString &fileName = QString(), int lineNumber = 1); QUrl url; diff --git a/src/declarative/qml/qmlcontextscriptclass.cpp b/src/declarative/qml/qmlcontextscriptclass.cpp index 6d2c58c..939d008 100644 --- a/src/declarative/qml/qmlcontextscriptclass.cpp +++ b/src/declarative/qml/qmlcontextscriptclass.cpp @@ -47,8 +47,9 @@ QT_BEGIN_NAMESPACE struct ContextData : public QScriptDeclarativeClass::Object { - ContextData(QmlContext *c) : context(c) {} + ContextData(QmlContext *c, QObject *o) : context(c), scopeObject(o) {} QGuard<QmlContext> context; + QGuard<QObject> scopeObject; }; /* @@ -57,7 +58,7 @@ struct ContextData : public QScriptDeclarativeClass::Object { */ QmlContextScriptClass::QmlContextScriptClass(QmlEngine *bindEngine) : QScriptDeclarativeClass(QmlEnginePrivate::getScriptEngine(bindEngine)), engine(bindEngine), - lastData(0), lastPropertyIndex(-1), lastDefaultObject(-1) + lastScopeObject(0), lastContext(0), lastData(0), lastPropertyIndex(-1), lastDefaultObject(-1) { } @@ -65,11 +66,11 @@ QmlContextScriptClass::~QmlContextScriptClass() { } -QScriptValue QmlContextScriptClass::newContext(QmlContext *context) +QScriptValue QmlContextScriptClass::newContext(QmlContext *context, QObject *scopeObject) { QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); - return newObject(scriptEngine, this, new ContextData(context)); + return newObject(scriptEngine, this, new ContextData(context, scopeObject)); } QmlContext *QmlContextScriptClass::contextFromValue(const QScriptValue &v) @@ -81,24 +82,27 @@ QmlContext *QmlContextScriptClass::contextFromValue(const QScriptValue &v) return data->context; } -#include <QDebug> QScriptClass::QueryFlags QmlContextScriptClass::queryProperty(Object *object, const Identifier &name, QScriptClass::QueryFlags flags) { Q_UNUSED(flags); + lastScopeObject = 0; lastContext = 0; lastData = 0; lastPropertyIndex = -1; lastDefaultObject = -1; QmlContext *bindContext = ((ContextData *)object)->context.data(); + QObject *scopeObject = ((ContextData *)object)->scopeObject.data(); if (!bindContext) return 0; while (bindContext) { - QScriptClass::QueryFlags rv = queryProperty(bindContext, name, flags); + QScriptClass::QueryFlags rv = + queryProperty(bindContext, scopeObject, name, flags); + scopeObject = 0; // Only applies to the first context if (rv) return rv; bindContext = bindContext->parentContext(); } @@ -107,7 +111,8 @@ QmlContextScriptClass::queryProperty(Object *object, const Identifier &name, } QScriptClass::QueryFlags -QmlContextScriptClass::queryProperty(QmlContext *bindContext, const Identifier &name, +QmlContextScriptClass::queryProperty(QmlContext *bindContext, QObject *scopeObject, + const Identifier &name, QScriptClass::QueryFlags flags) { QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); @@ -129,6 +134,24 @@ QmlContextScriptClass::queryProperty(QmlContext *bindContext, const Identifier & } } + for (int ii = 0; ii < cp->scripts.count(); ++ii) { + lastFunction = QScriptDeclarativeClass::function(cp->scripts.at(ii), name); + if (lastFunction.isValid()) { + lastContext = bindContext; + return QScriptClass::HandlesReadAccess; + } + } + + if (scopeObject) { + QScriptClass::QueryFlags rv = + ep->objectClass->queryProperty(scopeObject, name, flags, 0); + if (rv) { + lastScopeObject = scopeObject; + lastContext = bindContext; + return rv; + } + } + for (int ii = 0; ii < cp->defaultObjects.count(); ++ii) { QScriptClass::QueryFlags rv = ep->objectClass->queryProperty(cp->defaultObjects.at(ii), name, flags, 0); @@ -140,13 +163,6 @@ QmlContextScriptClass::queryProperty(QmlContext *bindContext, const Identifier & } } - for (int ii = 0; ii < cp->scripts.count(); ++ii) { - lastFunction = QScriptDeclarativeClass::function(cp->scripts.at(ii), name); - if (lastFunction.isValid()) { - lastContext = bindContext; - return QScriptClass::HandlesReadAccess; - } - } return 0; } @@ -160,8 +176,11 @@ QScriptValue QmlContextScriptClass::property(Object *object, const Identifier &n QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); QmlContextPrivate *cp = QmlContextPrivate::get(bindContext); + if (lastScopeObject) { - if (lastData) { + return ep->objectClass->property(lastScopeObject, name); + + } else if (lastData) { if (lastData->type) return ep->typeNameClass->newObject(cp->defaultObjects.at(0), lastData->type); @@ -197,7 +216,7 @@ QScriptValue QmlContextScriptClass::property(Object *object, const Identifier &n void QmlContextScriptClass::setProperty(Object *object, const Identifier &name, const QScriptValue &value) { - Q_ASSERT(lastDefaultObject != -1); + Q_ASSERT(lastScopeObject || lastDefaultObject != -1); QmlContext *bindContext = lastContext; Q_ASSERT(bindContext); @@ -205,7 +224,11 @@ void QmlContextScriptClass::setProperty(Object *object, const Identifier &name, QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); QmlContextPrivate *cp = QmlContextPrivate::get(bindContext); - ep->objectClass->setProperty(cp->defaultObjects.at(lastDefaultObject), name, value); + if (lastScopeObject) { + ep->objectClass->setProperty(lastScopeObject, name, value); + } else { + ep->objectClass->setProperty(cp->defaultObjects.at(lastDefaultObject), name, value); + } } QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcontextscriptclass_p.h b/src/declarative/qml/qmlcontextscriptclass_p.h index 761a115..126c8fe 100644 --- a/src/declarative/qml/qmlcontextscriptclass_p.h +++ b/src/declarative/qml/qmlcontextscriptclass_p.h @@ -67,7 +67,7 @@ public: QmlContextScriptClass(QmlEngine *); ~QmlContextScriptClass(); - QScriptValue newContext(QmlContext *); + QScriptValue newContext(QmlContext *, QObject * = 0); QmlContext *contextFromValue(const QScriptValue &); @@ -78,11 +78,13 @@ protected: virtual void setProperty(Object *, const Identifier &name, const QScriptValue &); private: - QScriptClass::QueryFlags queryProperty(QmlContext *, const Identifier &, + QScriptClass::QueryFlags queryProperty(QmlContext *, QObject *scopeObject, + const Identifier &, QScriptClass::QueryFlags flags); QmlEngine *engine; + QObject *lastScopeObject; QmlContext *lastContext; QmlTypeNameCache::Data *lastData; int lastPropertyIndex; diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp index 23e1700..0de64d9 100644 --- a/src/declarative/qml/qmlexpression.cpp +++ b/src/declarative/qml/qmlexpression.cpp @@ -89,8 +89,11 @@ void QmlExpressionPrivate::init(QmlContext *ctxt, const QString &expr, } void QmlExpressionPrivate::init(QmlContext *ctxt, void *expr, QmlRefCount *rc, - QObject *me) + QObject *me, const QUrl &url, int lineNumber) { + data->fileName = url.toString(); + data->line = lineNumber; + quint32 *exprData = (quint32 *)expr; Q_ASSERT(*exprData == BasicScriptEngineData || *exprData == PreTransformedQtScriptData); @@ -107,14 +110,12 @@ void QmlExpressionPrivate::init(QmlContext *ctxt, void *expr, QmlRefCount *rc, QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); if (!dd->programs.at(progIdx)) { - dd->programs[progIdx] = new QScriptProgram(scriptEngine->compile(data->expression)); + dd->programs[progIdx] = + new QScriptProgram(scriptEngine->compile(data->expression, data->fileName, data->line)); } - QmlContextPrivate *ctxtPriv = ctxt->d_func(); QScriptContext *scriptContext = scriptEngine->pushCleanContext(); - scriptContext->pushScope(ctxtPriv->scriptValue); - if (me) - scriptContext->pushScope(ep->objectClass->newQObject(me)); + scriptContext->pushScope(ep->contextClass->newContext(ctxt, me)); data->expressionFunction = scriptEngine->evaluate(*dd->programs[progIdx]); @@ -145,11 +146,12 @@ QmlExpression::QmlExpression() /*! \internal */ QmlExpression::QmlExpression(QmlContext *ctxt, void *expr, QmlRefCount *rc, QObject *me, + const QUrl &url, int lineNumber, QmlExpressionPrivate &dd) : QObject(dd, 0) { Q_D(QmlExpression); - d->init(ctxt, expr, rc, me); + d->init(ctxt, expr, rc, me, url, lineNumber); } /*! @@ -251,6 +253,28 @@ QVariant QmlExpressionPrivate::evalSSE() return rv; } +void QmlExpressionPrivate::printException(QScriptEngine *scriptEngine) +{ + if (scriptEngine->hasUncaughtException() && + scriptEngine->uncaughtException().isError()) { + + QString fileName; + int lineNumber = scriptEngine->uncaughtExceptionLineNumber(); + + QScriptValue exception = scriptEngine->uncaughtException(); + QLatin1String fileNameProp("fileName"); + + if (!exception.property(fileNameProp).toString().isEmpty()){ + fileName = exception.property(fileNameProp).toString(); + } else { + fileName = QLatin1String("<Unknown File>"); + } + + qWarning().nospace() << qPrintable(fileName) << ":" << lineNumber << ": " + << qPrintable(exception.toString()); + } +} + QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope) { #ifdef Q_ENABLE_PERFORMANCE_LOG @@ -270,10 +294,7 @@ QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope) if (!data->expressionFunctionValid) { QScriptContext *scriptContext = scriptEngine->pushCleanContext(); - scriptContext->pushScope(ctxtPriv->scriptValue); - - if (data->me) - scriptContext->pushScope(ep->objectClass->newQObject(data->me)); + scriptContext->pushScope(ep->contextClass->newContext(data->context(), data->me)); if (data->expressionRewritten) { data->expressionFunction = scriptEngine->evaluate(data->expression, @@ -291,19 +312,8 @@ QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope) QScriptValue svalue = data->expressionFunction.call(); - if (scriptEngine->hasUncaughtException()) { - if (scriptEngine->uncaughtException().isError()){ - QScriptValue exception = scriptEngine->uncaughtException(); - QLatin1String fileNameProp("fileName"); - if (!exception.property(fileNameProp).toString().isEmpty()){ - qWarning() << exception.property(fileNameProp).toString() - << scriptEngine->uncaughtExceptionLineNumber() - << exception.toString(); - } else { - qWarning() << exception.toString(); - } - } - } + if (scriptEngine->hasUncaughtException()) + printException(scriptEngine); if (secondaryScope) ctxtPriv->defaultObjects.removeAt(ctxtPriv->highPriorityCount); diff --git a/src/declarative/qml/qmlexpression.h b/src/declarative/qml/qmlexpression.h index c295a1c..b85e0a7 100644 --- a/src/declarative/qml/qmlexpression.h +++ b/src/declarative/qml/qmlexpression.h @@ -89,8 +89,8 @@ Q_SIGNALS: protected: QmlExpression(QmlContext *, const QString &, QObject *, QmlExpressionPrivate &dd); - QmlExpression(QmlContext *, void *, QmlRefCount *rc, QObject *me, - QmlExpressionPrivate &dd); + QmlExpression(QmlContext *, void *, QmlRefCount *rc, QObject *me, const QUrl &, + int, QmlExpressionPrivate &dd); private Q_SLOTS: void __q_notify(); diff --git a/src/declarative/qml/qmlexpression_p.h b/src/declarative/qml/qmlexpression_p.h index 33016e6..d9bb27b 100644 --- a/src/declarative/qml/qmlexpression_p.h +++ b/src/declarative/qml/qmlexpression_p.h @@ -136,7 +136,7 @@ public: }; void init(QmlContext *, const QString &, QObject *); - void init(QmlContext *, void *, QmlRefCount *, QObject *); + void init(QmlContext *, void *, QmlRefCount *, QObject *, const QUrl &, int); QmlExpressionData *data; @@ -150,6 +150,8 @@ public: static QmlExpressionPrivate *get(QmlExpression *expr) { return static_cast<QmlExpressionPrivate *>(QObjectPrivate::get(expr)); } + + static void printException(QScriptEngine *); }; QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h index 88dff2d..5265d42 100644 --- a/src/declarative/qml/qmlinstruction_p.h +++ b/src/declarative/qml/qmlinstruction_p.h @@ -246,6 +246,8 @@ public: } storeString; struct { int value; + int fileName; + int lineNumber; } storeScript; struct { int propertyIndex; diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp index 7a7e074..8643301 100644 --- a/src/declarative/qml/qmlmetaproperty.cpp +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -698,30 +698,6 @@ QVariant QmlMetaProperty::read() const return QVariant(); } -void QmlMetaPropertyPrivate::writeSignalProperty(const QVariant &value) -{ - QString expr = value.toString(); - const QObjectList &children = object->children(); - - for (int ii = 0; ii < children.count(); ++ii) { - QmlBoundSignal *sig = QmlBoundSignal::cast(children.at(ii)); - if (sig && sig->index() == core.coreIndex) { - if (expr.isEmpty()) { - sig->disconnect(); - sig->deleteLater(); - } else { - sig->expression()->setExpression(expr); - } - return; - } - } - - if (!expr.isEmpty()) { - // XXX scope - (void *)new QmlBoundSignal(qmlContext(object), expr, object, q->method(), object); - } -} - QVariant QmlMetaPropertyPrivate::readValueProperty() { uint type = q->type(); @@ -1001,11 +977,7 @@ void QmlMetaProperty::write(const QVariant &value, QmlMetaProperty::WriteFlags f if (!d->object) return; - if (type() & SignalProperty) { - - d->writeSignalProperty(value); - - } else if (d->core.isValid()) { + if (type() & Property && d->core.isValid()) { d->writeValueProperty(value, flags); diff --git a/src/declarative/qml/qmlmetaproperty_p.h b/src/declarative/qml/qmlmetaproperty_p.h index a856b90..b74aa2d 100644 --- a/src/declarative/qml/qmlmetaproperty_p.h +++ b/src/declarative/qml/qmlmetaproperty_p.h @@ -96,8 +96,6 @@ public: int propertyType() const; QmlMetaProperty::PropertyCategory propertyCategory() const; - void writeSignalProperty(const QVariant &); - QVariant readValueProperty(); void writeValueProperty(const QVariant &, QmlMetaProperty::WriteFlags); static bool writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object, const QVariant &value, int flags); diff --git a/src/declarative/qml/qmlparser_p.h b/src/declarative/qml/qmlparser_p.h index e11e164..88d7d77 100644 --- a/src/declarative/qml/qmlparser_p.h +++ b/src/declarative/qml/qmlparser_p.h @@ -168,6 +168,8 @@ namespace QmlParser // Script blocks that were nested under this object QStringList scriptBlocks; + QStringList scriptBlocksFile; + QList<int> scriptBlocksLineNumber; // The bytes to cast instances by to get to the QmlParserStatus // interface. -1 indicates the type doesn't support this interface. diff --git a/src/declarative/qml/qmlpropertycache_p.h b/src/declarative/qml/qmlpropertycache_p.h index f1b1219..91b0c53 100644 --- a/src/declarative/qml/qmlpropertycache_p.h +++ b/src/declarative/qml/qmlpropertycache_p.h @@ -132,7 +132,7 @@ QmlPropertyCache::Data::Data() { } -bool QmlPropertyCache::Data::operator==(const QmlPropertyCache::Data::Data &other) +bool QmlPropertyCache::Data::operator==(const QmlPropertyCache::Data &other) { return flags == other.flags && propType == other.propType && diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index 93c02b3..d4921b6 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -549,7 +549,9 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, case QmlInstruction::StoreScript: { QObject *target = stack.top(); - cp->addScript(primitives.at(instr.storeScript.value), target); + cp->addScript(primitives.at(instr.storeScript.value), target, + primitives.at(instr.storeScript.fileName), + instr.storeScript.lineNumber); } break; @@ -579,12 +581,11 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, if (stack.count() == 1 && bindingSkipList.testBit(coreIndex)) break; - QmlBinding *bind = new QmlBinding((void *)datas.at(instr.assignBinding.value).constData(), comp, context, ctxt, 0); + QmlBinding *bind = new QmlBinding((void *)datas.at(instr.assignBinding.value).constData(), comp, context, ctxt, comp->url, instr.line, 0); bindValues.append(bind); bind->m_mePtr = &bindValues.values[bindValues.count - 1]; bind->setTarget(mp); bind->addToObject(target); - bind->setSourceLocation(comp->url, instr.line); } break; diff --git a/tests/auto/declarative/qmlecmascript/data/scope.2.qml b/tests/auto/declarative/qmlecmascript/data/scope.2.qml new file mode 100644 index 0000000..433a22e --- /dev/null +++ b/tests/auto/declarative/qmlecmascript/data/scope.2.qml @@ -0,0 +1,42 @@ +import Qt 4.6 + +Item { + property int a: 0 + property int b: 0 + + Script { + function b() { return 11; } + function c() { return 33; } + } + + Object { + id: a + property int value: 19 + } + + Object { + id: c + property int value: 24 + } + + Object { + id: nested + property int a: 1 + property int test: a.value + property int test2: b() + property int test3: c.value + } + + + // id takes precedence over local, and root properties + property int test1: a.value + property alias test2: nested.test + + // methods takes precedence over local, and root properties + property int test3: b() + property alias test4: nested.test2 + + // id takes precedence over methods + property int test5: c.value + property alias test6: nested.test3 +} diff --git a/tests/auto/declarative/qmlecmascript/data/scriptErrors.js b/tests/auto/declarative/qmlecmascript/data/scriptErrors.js new file mode 100644 index 0000000..1d7b357 --- /dev/null +++ b/tests/auto/declarative/qmlecmascript/data/scriptErrors.js @@ -0,0 +1,2 @@ +// Comment +a = 10 diff --git a/tests/auto/declarative/qmlecmascript/data/scriptErrors.qml b/tests/auto/declarative/qmlecmascript/data/scriptErrors.qml new file mode 100644 index 0000000..3fb8ff7 --- /dev/null +++ b/tests/auto/declarative/qmlecmascript/data/scriptErrors.qml @@ -0,0 +1,10 @@ +import Qt 4.6 + +Object { + Script { source: "scriptErrors.js" } + Script { function getValue() { a = 10; return 0; } } + + property int x: a.value + property int y: getValue(); +} + diff --git a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp index dde3bb7..5e04f7c 100644 --- a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp +++ b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp @@ -61,6 +61,7 @@ private slots: void objectToString(); void selfDeletingBinding(); void extendedObjectPropertyLookup(); + void scriptErrors(); private: QmlEngine engine; @@ -537,20 +538,35 @@ void tst_qmlecmascript::nonExistantAttachedObject() void tst_qmlecmascript::scope() { - QmlComponent component(&engine, TEST_FILE("scope.qml")); - QObject *object = component.create(); - QVERIFY(object != 0); + { + QmlComponent component(&engine, TEST_FILE("scope.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + + QCOMPARE(object->property("test1").toInt(), 1); + QCOMPARE(object->property("test2").toInt(), 2); + QCOMPARE(object->property("test3").toString(), QString("1Test")); + QCOMPARE(object->property("test4").toString(), QString("2Test")); + QCOMPARE(object->property("test5").toInt(), 1); + QCOMPARE(object->property("test6").toInt(), 1); + QCOMPARE(object->property("test7").toInt(), 2); + QCOMPARE(object->property("test8").toInt(), 2); + QCOMPARE(object->property("test9").toInt(), 1); + QCOMPARE(object->property("test10").toInt(), 3); + } + + { + QmlComponent component(&engine, TEST_FILE("scope.2.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); - QCOMPARE(object->property("test1").toInt(), 1); - QCOMPARE(object->property("test2").toInt(), 2); - QCOMPARE(object->property("test3").toString(), QString("1Test")); - QCOMPARE(object->property("test4").toString(), QString("2Test")); - QCOMPARE(object->property("test5").toInt(), 1); - QCOMPARE(object->property("test6").toInt(), 1); - QCOMPARE(object->property("test7").toInt(), 2); - QCOMPARE(object->property("test8").toInt(), 2); - QCOMPARE(object->property("test9").toInt(), 1); - QCOMPARE(object->property("test10").toInt(), 3); + QCOMPARE(object->property("test1").toInt(), 19); + QCOMPARE(object->property("test2").toInt(), 19); + QCOMPARE(object->property("test3").toInt(), 11); + QCOMPARE(object->property("test4").toInt(), 11); + QCOMPARE(object->property("test5").toInt(), 24); + QCOMPARE(object->property("test6").toInt(), 24); + } } /* @@ -724,6 +740,25 @@ void tst_qmlecmascript::extendedObjectPropertyLookup() QVERIFY(object != 0); } +/* +Test file/lineNumbers for binding/Script errors. +*/ +void tst_qmlecmascript::scriptErrors() +{ + QmlComponent component(&engine, TEST_FILE("scriptErrors.qml")); + QString url = component.url().toString(); + + QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\""; + QString warning2 = url + ":7: TypeError: Result of expression 'a' [undefined] is not an object."; + QString warning3 = url + ":5: Error: Invalid write to global property \"a\""; + + QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData()); + QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData()); + QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData()); + QObject *object = component.create(); + QVERIFY(object != 0); +} + QTEST_MAIN(tst_qmlecmascript) #include "tst_qmlecmascript.moc" diff --git a/tests/auto/declarative/qmllanguage/data/Alias2.qml b/tests/auto/declarative/qmllanguage/data/Alias2.qml new file mode 100644 index 0000000..b7e81a5 --- /dev/null +++ b/tests/auto/declarative/qmllanguage/data/Alias2.qml @@ -0,0 +1,9 @@ +import Test 1.0 +import Qt 4.6 + +Object { + property var other + other: MyTypeObject { id: obj } + property alias enumAlias: obj.enumProperty; +} + diff --git a/tests/auto/declarative/qmllanguage/data/alias.4.qml b/tests/auto/declarative/qmllanguage/data/alias.4.qml new file mode 100644 index 0000000..bd6a769 --- /dev/null +++ b/tests/auto/declarative/qmllanguage/data/alias.4.qml @@ -0,0 +1,6 @@ +import Test 1.0 + +Alias2 { + enumAlias: MyTypeObject.EnumVal2 +} + diff --git a/tests/auto/declarative/qmllanguage/tst_qmllanguage.cpp b/tests/auto/declarative/qmllanguage/tst_qmllanguage.cpp index 3825b62..135a207 100644 --- a/tests/auto/declarative/qmllanguage/tst_qmllanguage.cpp +++ b/tests/auto/declarative/qmllanguage/tst_qmllanguage.cpp @@ -612,6 +612,15 @@ void tst_qmllanguage::aliasProperties() delete object; } + // Enum aliases + { + QmlComponent component(&engine, TEST_FILE("alias.4.qml")); + VERIFY_ERRORS(0); + QObject *object = component.create(); + QVERIFY(object != 0); + + QCOMPARE(object->property("enumAlias").toInt(), 1); + } } class TestType : public QObject { |