diff options
16 files changed, 164 insertions, 20 deletions
diff --git a/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp b/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp index 2945b6c..7c55009 100644 --- a/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp +++ b/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp @@ -143,7 +143,9 @@ void QDeclarativeItemModule::defineModule() qmlRegisterType<QAction>(); qmlRegisterType<QDeclarativePen>(); qmlRegisterType<QDeclarativeFlickableVisibleArea>(); +#ifndef QT_NO_GRAPHICSEFFECT qmlRegisterType<QGraphicsEffect>(); +#endif qmlRegisterUncreatableType<QDeclarativeKeyNavigationAttached>("Qt",4,7,"KeyNavigation",QDeclarativeKeyNavigationAttached::tr("KeyNavigation is only available via attached properties")); qmlRegisterUncreatableType<QDeclarativeKeysAttached>("Qt",4,7,"Keys",QDeclarativeKeysAttached::tr("Keys is only available via attached properties")); diff --git a/src/declarative/qml/qdeclarativebinding.cpp b/src/declarative/qml/qdeclarativebinding.cpp index d44e7fb..8043ea9 100644 --- a/src/declarative/qml/qdeclarativebinding.cpp +++ b/src/declarative/qml/qdeclarativebinding.cpp @@ -193,7 +193,18 @@ void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags) data->error.setColumn(-1); data->error.setDescription(QLatin1String("Unable to assign [undefined] to ") + QLatin1String(QMetaType::typeName(data->property.propertyType()))); - } else if (data->property.object() && + } else if (!scriptValue.isRegExp() && scriptValue.isFunction()) { + + QUrl url = QUrl(data->url); + int line = data->line; + if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>")); + + data->error.setUrl(url); + data->error.setLine(line); + data->error.setColumn(-1); + data->error.setDescription(QLatin1String("Unable to assign a function to a property.")); + + } else if (data->property.object() && !QDeclarativePropertyPrivate::write(data->property, value, flags)) { QUrl url = QUrl(data->url); diff --git a/src/declarative/qml/qdeclarativedata_p.h b/src/declarative/qml/qdeclarativedata_p.h index 4a56536..e916273 100644 --- a/src/declarative/qml/qdeclarativedata_p.h +++ b/src/declarative/qml/qdeclarativedata_p.h @@ -152,11 +152,11 @@ public: template<class T> void QDeclarativeGuard<T>::addGuard() { - if (QObjectPrivate::get(o)->wasDeleted) { - if (prev) remGuard(); + Q_ASSERT(!prev); + + if (QObjectPrivate::get(o)->wasDeleted) return; - } - + QDeclarativeData *data = QDeclarativeData::get(o, true); next = data->guards; if (next) reinterpret_cast<QDeclarativeGuard<T> *>(next)->prev = &next; @@ -167,6 +167,8 @@ void QDeclarativeGuard<T>::addGuard() template<class T> void QDeclarativeGuard<T>::remGuard() { + Q_ASSERT(prev); + if (next) reinterpret_cast<QDeclarativeGuard<T> *>(next)->prev = prev; *prev = next; next = 0; diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp index 8a61f1e..3f4a735 100644 --- a/src/declarative/qml/qdeclarativeengine.cpp +++ b/src/declarative/qml/qdeclarativeengine.cpp @@ -870,14 +870,10 @@ void QDeclarativeData::destroyed(QObject *object) if (ownContext && context) context->destroy(); - QDeclarativeGuard<QObject> *guard = guards; - while (guard) { - QDeclarativeGuard<QObject> *g = guard; - guard = guard->next; - g->o = 0; - g->prev = 0; - g->next = 0; - g->objectDestroyed(object); + while (guards) { + QDeclarativeGuard<QObject> *guard = guards; + *guard = (QObject *)0; + guard->objectDestroyed(object); } if (scriptValue) diff --git a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp index 671a262..33e47fb 100644 --- a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp +++ b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp @@ -368,6 +368,9 @@ void QDeclarativeObjectScriptClass::setProperty(QObject *obj, QString error = QLatin1String("Cannot assign [undefined] to ") + QLatin1String(QMetaType::typeName(lastData->propType)); context->throwError(error); + } else if (!value.isRegExp() && value.isFunction()) { + QString error = QLatin1String("Cannot assign a function to a property."); + context->throwError(error); } else { QVariant v; if (lastData->flags & QDeclarativePropertyCache::Data::IsQList) diff --git a/src/declarative/qml/qdeclarativevmemetaobject.cpp b/src/declarative/qml/qdeclarativevmemetaobject.cpp index 45f04a0..13e9c26 100644 --- a/src/declarative/qml/qdeclarativevmemetaobject.cpp +++ b/src/declarative/qml/qdeclarativevmemetaobject.cpp @@ -106,8 +106,7 @@ QDeclarativeVMEVariant::~QDeclarativeVMEVariant() void QDeclarativeVMEVariant::cleanup() { if (type == QVariant::Invalid) { - } else if (type == QMetaType::QObjectStar || - type == QMetaType::Int || + } else if (type == QMetaType::Int || type == QMetaType::Bool || type == QMetaType::Double) { type = QVariant::Invalid; diff --git a/src/declarative/util/qdeclarativepropertychanges.cpp b/src/declarative/util/qdeclarativepropertychanges.cpp index 4b2d5a0..c7e3bc5 100644 --- a/src/declarative/util/qdeclarativepropertychanges.cpp +++ b/src/declarative/util/qdeclarativepropertychanges.cpp @@ -51,6 +51,7 @@ #include <qdeclarativecontext.h> #include <qdeclarativeguard_p.h> #include <qdeclarativeproperty_p.h> +#include <qdeclarativecontext_p.h> #include <QtCore/qdebug.h> @@ -302,12 +303,18 @@ void QDeclarativePropertyChangesPrivate::decode() QDeclarativeProperty prop = property(name); //### better way to check for signal property? if (prop.type() & QDeclarativeProperty::SignalProperty) { QDeclarativeExpression *expression = new QDeclarativeExpression(qmlContext(q), data.toString(), object); + QDeclarativeData *ddata = QDeclarativeData::get(q); + if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty()) + expression->setSourceLocation(ddata->outerContext->url.toString(), ddata->lineNumber); QDeclarativeReplaceSignalHandler *handler = new QDeclarativeReplaceSignalHandler; handler->property = prop; handler->expression = expression; signalReplacements << handler; } else if (isScript) { QDeclarativeExpression *expression = new QDeclarativeExpression(qmlContext(q), data.toString(), object); + QDeclarativeData *ddata = QDeclarativeData::get(q); + if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty()) + expression->setSourceLocation(ddata->outerContext->url.toString(), ddata->lineNumber); expressions << qMakePair(name, expression); } else { properties << qMakePair(name, data); @@ -437,9 +444,11 @@ QDeclarativePropertyChanges::ActionList QDeclarativePropertyChanges::actions() if (d->isExplicit) { a.toValue = d->expressions.at(ii).second->evaluate(); } else { + QDeclarativeExpression *e = d->expressions.at(ii).second; QDeclarativeBinding *newBinding = - new QDeclarativeBinding(d->expressions.at(ii).second->expression(), object(), qmlContext(this)); + new QDeclarativeBinding(e->expression(), object(), qmlContext(this)); newBinding->setTarget(prop); + newBinding->setSourceLocation(e->sourceFile(), e->lineNumber()); a.toBinding = newBinding; a.deletableToBinding = true; } diff --git a/tests/auto/declarative/qdeclarativeconnection/data/connection-unknownsignals-ignored.qml b/tests/auto/declarative/qdeclarativeconnection/data/connection-unknownsignals-ignored.qml new file mode 100644 index 0000000..764d5ab --- /dev/null +++ b/tests/auto/declarative/qdeclarativeconnection/data/connection-unknownsignals-ignored.qml @@ -0,0 +1,8 @@ +import Qt 4.7 + +Item { + id: screen + + Connections { target: screen; onNotFooBar1: {} ignoreUnknownSignals: true } + Connections { objectName: "connections"; onNotFooBar2: {} ignoreUnknownSignals: true } +} diff --git a/tests/auto/declarative/qdeclarativeconnection/data/connection-unknownsignals-notarget.qml b/tests/auto/declarative/qdeclarativeconnection/data/connection-unknownsignals-notarget.qml new file mode 100644 index 0000000..09e7812 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeconnection/data/connection-unknownsignals-notarget.qml @@ -0,0 +1,7 @@ +import Qt 4.7 + +Item { + id: screen + + Connections { objectName: "connections"; target: null; onNotFooBar: {} } +} diff --git a/tests/auto/declarative/qdeclarativeconnection/data/connection-unknownsignals-parent.qml b/tests/auto/declarative/qdeclarativeconnection/data/connection-unknownsignals-parent.qml new file mode 100644 index 0000000..478503d --- /dev/null +++ b/tests/auto/declarative/qdeclarativeconnection/data/connection-unknownsignals-parent.qml @@ -0,0 +1,7 @@ +import Qt 4.7 + +Item { + id: screen + + Connections { objectName: "connections"; onFooBar: {} } +} diff --git a/tests/auto/declarative/qdeclarativeconnection/data/connection-unknownsignals.qml b/tests/auto/declarative/qdeclarativeconnection/data/connection-unknownsignals.qml new file mode 100644 index 0000000..d4e8d7e --- /dev/null +++ b/tests/auto/declarative/qdeclarativeconnection/data/connection-unknownsignals.qml @@ -0,0 +1,7 @@ +import Qt 4.7 + +Item { + id: screen + + Connections { objectName: "connections"; target: screen; onFooBar: {} } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/functionAssignment.1.qml b/tests/auto/declarative/qdeclarativeecmascript/data/functionAssignment.1.qml new file mode 100644 index 0000000..09540f1 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/functionAssignment.1.qml @@ -0,0 +1,5 @@ +import Qt.test 1.0 + +MyQmlObject { + property variant a: function myFunction() { return 2; } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/functionAssignment.2.qml b/tests/auto/declarative/qdeclarativeecmascript/data/functionAssignment.2.qml new file mode 100644 index 0000000..948b39c --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/functionAssignment.2.qml @@ -0,0 +1,13 @@ +import Qt.test 1.0 + +MyQmlObject { + property variant a + property bool runTest: false + onRunTestChanged: { + function myFunction() { + console.log("hello world"); + } + a = myFunction; + } + +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/qtcreatorbug_1289.qml b/tests/auto/declarative/qdeclarativeecmascript/data/qtcreatorbug_1289.qml new file mode 100644 index 0000000..b6d31d5 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/qtcreatorbug_1289.qml @@ -0,0 +1,13 @@ +import Qt 4.7 + +QtObject { + id: root + property QtObject object: QtObject { + id: nested + property QtObject nestedObject + } + + Component.onCompleted: { + nested.nestedObject = root; + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp index 6cde46b..49ee335 100644 --- a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp +++ b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp @@ -142,8 +142,10 @@ private slots: void libraryScriptAssert(); void variantsAssignedUndefined(); void qtbug_9792(); + void qtcreatorbug_1289(); void noSpuriousWarningsAtShutdown(); void canAssignNullToQObject(); + void functionAssignment(); void callQtInvokables(); private: @@ -2205,6 +2207,27 @@ void tst_qdeclarativeecmascript::qtbug_9792() delete object; } +// Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly +void tst_qdeclarativeecmascript::qtcreatorbug_1289() +{ + QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml")); + + QObject *o = component.create(); + QVERIFY(o != 0); + + QObject *nested = qvariant_cast<QObject *>(o->property("object")); + QVERIFY(nested != 0); + + QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o); + + delete nested; + nested = qvariant_cast<QObject *>(o->property("object")); + QVERIFY(nested == 0); + + // If the bug is present, the next line will crash + delete o; +} + // Test that we shut down without stupid warnings void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown() { @@ -2269,6 +2292,44 @@ void tst_qdeclarativeecmascript::canAssignNullToQObject() } } +void tst_qdeclarativeecmascript::functionAssignment() +{ + { + QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml")); + + QString url = component.url().toString(); + QString warning = url + ":4: Unable to assign a function to a property."; + QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); + + MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create()); + QVERIFY(o != 0); + + QVERIFY(!o->property("a").isValid()); + + delete o; + } + + { + QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml")); + + MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create()); + QVERIFY(o != 0); + + QVERIFY(!o->property("a").isValid()); + + QString url = component.url().toString(); + QString warning = url + ":10: Error: Cannot assign a function to a property."; + QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); + + o->setProperty("runTest", true); + + QVERIFY(!o->property("a").isValid()); + + delete o; + } +} + + QTEST_MAIN(tst_qdeclarativeecmascript) #include "tst_qdeclarativeecmascript.moc" diff --git a/tools/qml/main.cpp b/tools/qml/main.cpp index 9ccc3d2..f2c0530 100644 --- a/tools/qml/main.cpp +++ b/tools/qml/main.cpp @@ -125,7 +125,7 @@ void usage() qWarning(" -sizeviewtorootobject .................... the view resizes to the changes in the content"); qWarning(" -sizerootobjecttoview .................... the content resizes to the changes in the view"); qWarning(" -qmlbrowser .............................. use a QML-based file browser"); - qWarning(" -nolog ................................... do not show log window"); + qWarning(" -warnings ................................ show warnings in a separate log window"); qWarning(" -recordfile <output> ..................... set video recording file"); qWarning(" - ImageMagick 'convert' for GIF)"); qWarning(" - png file for raw frames"); @@ -229,7 +229,8 @@ int main(int argc, char ** argv) bool stayOnTop = false; bool maximized = false; bool useNativeFileBrowser = true; - bool showLogWidget = true; + + bool showLogWidget = false; bool sizeToView = true; #if defined(Q_OS_SYMBIAN) @@ -290,8 +291,8 @@ int main(int argc, char ** argv) useGL = true; } else if (arg == "-qmlbrowser") { useNativeFileBrowser = false; - } else if (arg == "-nolog") { - showLogWidget = false; + } else if (arg == "-warnings") { + showLogWidget = true; } else if (arg == "-I" || arg == "-L") { if (arg == "-L") qWarning("-L option provided for compatibility only, use -I instead"); |