From 16916560c13bf4c096461426c37eccbc8841a13c Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Fri, 14 Aug 2015 15:51:43 +0200 Subject: [PATCH 01/27] Fix memory leak when QQuickPixmapReply::Event is delete before being used It can happen that QQuickPixmapReply::postReply is called, and before QQuickPixmapReply::event is called the object gets deleted. That means that the texture factory will never be deleted. To fix that we delete it in the destructor of QQuickPixmapReply::Event and set it to 0 in QQuickPixmapReply::event after assigning to the next data structure that will take care of it Change-Id: Ibea62f5a10a53cca586de7c5f03f00aabfb88b2e Reviewed-by: Robin Burchell --- src/quick/util/qquickpixmapcache.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp index ddf2ae2393..a1c9205539 100644 --- a/src/quick/util/qquickpixmapcache.cpp +++ b/src/quick/util/qquickpixmapcache.cpp @@ -148,6 +148,7 @@ public: class Event : public QEvent { public: Event(ReadError, const QString &, const QSize &, AutoTransform, QQuickTextureFactory *factory); + ~Event(); ReadError error; QString errorString; @@ -339,6 +340,11 @@ QQuickPixmapReply::Event::Event(ReadError e, const QString &s, const QSize &iSiz { } +QQuickPixmapReply::Event::~Event() +{ + delete textureFactory; +} + QNetworkAccessManager *QQuickPixmapReader::networkAccessManager() { if (!accessManager) { @@ -965,6 +971,7 @@ bool QQuickPixmapReply::event(QEvent *event) data->pixmapStatus = (de->error == NoError) ? QQuickPixmap::Ready : QQuickPixmap::Error; if (data->pixmapStatus == QQuickPixmap::Ready) { data->textureFactory = de->textureFactory; + de->textureFactory = 0; data->implicitSize = de->implicitSize; data->appliedTransform = de->autoTransform; PIXMAP_PROFILE(pixmapLoadingFinished(data->url, From c1477c4660b2480d95dab6c084dd38b5a8a972ff Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Tue, 18 Aug 2015 15:54:41 +0200 Subject: [PATCH 02/27] qml: Don't build OpenGL support if OpenGL is not available in Qt. This is an amended backport of change 668ccf18d in dev. Change-Id: I168a4d5a55c34592599a557bef941ce1629c8178 Reviewed-by: Friedemann Kleint --- tools/qml/main.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/qml/main.cpp b/tools/qml/main.cpp index 0553553e85..06ed37a00e 100644 --- a/tools/qml/main.cpp +++ b/tools/qml/main.cpp @@ -196,7 +196,7 @@ public Q_SLOTS: exit(2);//Different return code from qFatal } } -#ifdef QT_GUI_LIB +#if defined(QT_GUI_LIB) && !defined(QT_NO_OPENGL) void onOpenGlContextCreated(QOpenGLContext *context); #endif }; @@ -218,17 +218,17 @@ void LoadWatcher::contain(QObject *o, const QUrl &containPath) void LoadWatcher::checkForWindow(QObject *o) { -#ifdef QT_GUI_LIB +#if defined(QT_GUI_LIB) && !defined(QT_NO_OPENGL) if (verboseMode && o->isWindowType() && o->inherits("QQuickWindow")) { connect(o, SIGNAL(openglContextCreated(QOpenGLContext*)), this, SLOT(onOpenGlContextCreated(QOpenGLContext*))); } #else Q_UNUSED(o) -#endif // QT_GUI_LIB +#endif // QT_GUI_LIB && !QT_NO_OPENGL } -#ifdef QT_GUI_LIB +#if defined(QT_GUI_LIB) && !defined(QT_NO_OPENGL) void LoadWatcher::onOpenGlContextCreated(QOpenGLContext *context) { context->makeCurrent(qobject_cast(sender())); @@ -244,7 +244,7 @@ void LoadWatcher::onOpenGlContextCreated(QOpenGLContext *context) puts(output.constData()); context->doneCurrent(); } -#endif // QT_GUI_LIB +#endif // QT_GUI_LIB && !QT_NO_OPENGL void quietMessageHandler(QtMsgType type, const QMessageLogContext &ctxt, const QString &msg) { From 9459256cde79f2e40db3514b6925923a209bbf52 Mon Sep 17 00:00:00 2001 From: Samuel Gaist Date: Wed, 19 Aug 2015 16:02:32 +0200 Subject: [PATCH 03/27] Doc: fix verb redundancy Change-Id: Ifa76a814dba5271b852c2eaf8a59a2ebb5aee808 Reviewed-by: Leena Miettinen --- src/qml/types/qqmlobjectmodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qml/types/qqmlobjectmodel.cpp b/src/qml/types/qqmlobjectmodel.cpp index 1d892beabf..7081e96070 100644 --- a/src/qml/types/qqmlobjectmodel.cpp +++ b/src/qml/types/qqmlobjectmodel.cpp @@ -165,7 +165,7 @@ public: \inqmlmodule QtQuick \brief Defines a set of objects to be used as a model - The VisualItemModel type encapsulates contains the objects to be used + The VisualItemModel type contains the objects to be used as a model. This element is now primarily available as ObjectModel in the QtQml.Models module. From 27bee8076f50a948ffb9997e2a0673854681437d Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Thu, 20 Aug 2015 08:48:04 +0200 Subject: [PATCH 04/27] Don't try to link to SQLite plugin when building samegame statically. Disable the linking to a SQL driver that isn't a plugin Task-number: QTBUG-42926 Change-Id: I6d51fce7bb924d8b778fe36fa9f908c6fda3da13 Reviewed-by: Thiago Macieira Reviewed-by: Mark Brand --- examples/quick/demos/samegame/samegame.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/quick/demos/samegame/samegame.pro b/examples/quick/demos/samegame/samegame.pro index 51e6f00321..e041dd61dd 100644 --- a/examples/quick/demos/samegame/samegame.pro +++ b/examples/quick/demos/samegame/samegame.pro @@ -7,4 +7,4 @@ RESOURCES += samegame.qrc target.path = $$[QT_INSTALL_EXAMPLES]/quick/demos/samegame INSTALLS += target -QTPLUGIN += qsqlite +!contains(sql-drivers, sqlite): QTPLUGIN += qsqlite From 6067b74bb7baadbd28bfdfa8e2d63b775c972b0f Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 24 Aug 2015 15:29:03 +0200 Subject: [PATCH 05/27] Fix hue clamping in Context2D It goes from 0..359, not 0..255. Task-number: QTBUG-47894 Change-Id: I0612a9d5e4999afae7703b5c49741b94fb0da07f Reviewed-by: Mitch Curtis --- src/quick/items/context2d/qquickcontext2d.cpp | 2 +- .../qquickcanvasitem/data/tst_context.qml | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp index 4aa3b1c8d0..c71a354e0c 100644 --- a/src/quick/items/context2d/qquickcontext2d.cpp +++ b/src/quick/items/context2d/qquickcontext2d.cpp @@ -189,7 +189,7 @@ QColor qt_color_from_string(const QV4::Value &name) if (isRgb) return QColor::fromRgba(qRgba(qClamp(rh, 0, 255), qClamp(gs, 0, 255), qClamp(bl, 0, 255), qClamp(alpha, 0, 255))); else if (isHsl) - return QColor::fromHsl(qClamp(rh, 0, 255), qClamp(gs, 0, 255), qClamp(bl, 0, 255), qClamp(alpha, 0, 255)); + return QColor::fromHsl(qClamp(rh, 0, 359), qClamp(gs, 0, 255), qClamp(bl, 0, 255), qClamp(alpha, 0, 255)); } return QColor(); } diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_context.qml b/tests/auto/quick/qquickcanvasitem/data/tst_context.qml index f266c16d76..566ad9d3d5 100644 --- a/tests/auto/quick/qquickcanvasitem/data/tst_context.qml +++ b/tests/auto/quick/qquickcanvasitem/data/tst_context.qml @@ -182,4 +182,22 @@ Canvas { } } } + + TestCase { + name: "Colors" + when: canvas.available + + function test_colors() { + wait(100); + compare(contextSpy.count, 1); + + var ctx = canvas.getContext("2d"); + // QTBUG-47894 + ctx.strokeStyle = 'hsl(255, 100%, 50%)'; + var c1 = ctx.strokeStyle.toString(); + ctx.strokeStyle = 'hsl(320, 100%, 50%)'; + var c2 = ctx.strokeStyle.toString(); + verify(c1 !== c2); + } + } } From 6d5caee804ca80eb81c364624847f70e62caa92e Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 11 Aug 2015 12:47:28 +0200 Subject: [PATCH 06/27] Fix profiling of QML/JS compilation The compilation of .js resources was missed and the compile times were underestimated because the dependency resolution and error checking wasn't factored in. In particular we only profiled the done() step for QQmlTypeData. However, JavaScript compilation also occurs in the dataReceived() step of QQmlScriptBlob and QQmlTypeData will already parse the program into an AST at that step. Compile steps can be nested now, but considering the fact that significant time may be spent before and after compiling dependencies for a parent module, this seems to be the best way to model them. Furthermore, in order to not needlessly convert QUrl to QString at runtime, the compilation profiler saves the files now as QUrl. Change-Id: I215a87787f9117c069ecd77b2d913cc0b0ff3c89 Reviewed-by: Simon Hausmann --- .../qmldbg_profiler/qqmlprofileradapter.cpp | 2 +- src/qml/debugger/qqmlprofiler_p.h | 11 ++++++----- src/qml/qml/qqmltypeloader.cpp | 8 ++++++-- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp index 349c181d13..245900abae 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp +++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp @@ -81,7 +81,7 @@ static void qQmlProfilerDataToByteArrays(const QQmlProfilerData *d, QListdetailString; + ds << (d->detailString.isEmpty() ? d->detailUrl.toString() : d->detailString); break; case QQmlProfilerDefinitions::RangeLocation: ds << (d->detailUrl.isEmpty() ? d->detailString : d->detailUrl.toString()) << d->x diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h index 3c8337c969..7e29c3ede6 100644 --- a/src/qml/debugger/qqmlprofiler_p.h +++ b/src/qml/debugger/qqmlprofiler_p.h @@ -99,8 +99,9 @@ struct Q_AUTOTEST_EXPORT QQmlProfilerData int messageType; //bit field of QQmlProfilerService::Message int detailType; + // RangeData prefers detailString; RangeLocation prefers detailUrl. QString detailString; //used by RangeData and possibly by RangeLocation - QUrl detailUrl; //used by RangeLocation, overrides detailString + QUrl detailUrl; //used by RangeLocation and possibly by RangeData int x; //used by RangeLocation int y; //used by RangeLocation @@ -120,11 +121,11 @@ public: // Have toByteArrays() construct another RangeData event from the same QString later. // This is somewhat pointless but important for backwards compatibility. - void startCompiling(const QString &name) + void startCompiling(const QUrl &url) { m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), (1 << RangeStart | 1 << RangeLocation | 1 << RangeData), - 1 << Compiling, name, 1, 1)); + 1 << Compiling, url, 1, 1)); } void startHandlingSignal(const QQmlSourceLocation &location) @@ -217,10 +218,10 @@ struct QQmlHandlingSignalProfiler : public QQmlProfilerHelper { }; struct QQmlCompilingProfiler : public QQmlProfilerHelper { - QQmlCompilingProfiler(QQmlProfiler *profiler, const QString &name) : + QQmlCompilingProfiler(QQmlProfiler *profiler, const QUrl &url) : QQmlProfilerHelper(profiler) { - Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCompiling, profiler, startCompiling(name)); + Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCompiling, profiler, startCompiling(url)); } ~QQmlCompilingProfiler() diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 408f17ffde..eb65f732dd 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -647,6 +647,8 @@ void QQmlDataBlob::notifyComplete(QQmlDataBlob *blob) { Q_ASSERT(m_waitingFor.contains(blob)); Q_ASSERT(blob->status() == Error || blob->status() == Complete); + QQmlCompilingProfiler prof(QQmlEnginePrivate::get(typeLoader()->engine())->profiler, + blob->url()); m_inCallback = true; @@ -1194,6 +1196,8 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, QQmlFile *file) void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::Data &d) { QML_MEMORY_SCOPE_URL(blob->url()); + QQmlCompilingProfiler prof(QQmlEnginePrivate::get(engine())->profiler, blob->url()); + blob->m_inCallback = true; blob->dataReceived(d); @@ -1212,6 +1216,8 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::Data &d) void QQmlTypeLoader::setCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit) { QML_MEMORY_SCOPE_URL(blob->url()); + QQmlCompilingProfiler prof(QQmlEnginePrivate::get(engine())->profiler, blob->url()); + blob->m_inCallback = true; blob->initializeFromCachedUnit(unit); @@ -2253,8 +2259,6 @@ void QQmlTypeData::compile() m_compiledData = new QQmlCompiledData(typeLoader()->engine()); - QQmlCompilingProfiler prof(QQmlEnginePrivate::get(typeLoader()->engine())->profiler, finalUrlString()); - QQmlTypeCompiler compiler(QQmlEnginePrivate::get(typeLoader()->engine()), m_compiledData, this, m_document.data()); if (!compiler.compile()) { setError(compiler.compilationErrors()); From ce5c468f36286e251d3dfee3496faf240dc0e92d Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 13 Aug 2015 18:15:43 +0200 Subject: [PATCH 07/27] std::sort JS profiling data instead of insert-sorting it The original FunctionCall struct is much smaller than the resulting FunctionCallProperties, and thus not as expensive to copy. Repeatedly calling upper_bound on a QVector is not such a great idea, either. Since the usage of QVector instead of QList for the results is new in Qt 5.6, the insert-sorting got slower, making this change a fix for a performance regression. Change-Id: I7154d8cf129b7fbe6e02424fbe16442042a5c3c2 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4profiling.cpp | 29 +++++++++++++++++------------ src/qml/jsruntime/qv4profiling_p.h | 1 + 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/qml/jsruntime/qv4profiling.cpp b/src/qml/jsruntime/qv4profiling.cpp index 9b77599904..b62f367601 100644 --- a/src/qml/jsruntime/qv4profiling.cpp +++ b/src/qml/jsruntime/qv4profiling.cpp @@ -37,8 +37,8 @@ QT_BEGIN_NAMESPACE -using namespace QV4; -using namespace QV4::Profiling; +namespace QV4 { +namespace Profiling { FunctionCallProperties FunctionCall::resolve() const { @@ -63,26 +63,28 @@ Profiler::Profiler(QV4::ExecutionEngine *engine) : featuresEnabled(0), m_engine( m_timer.start(); } -struct FunctionCallComparator { - bool operator()(const FunctionCallProperties &p1, const FunctionCallProperties &p2) - { return p1.start < p2.start; } -}; - void Profiler::stopProfiling() { featuresEnabled = 0; reportData(); } +bool operator<(const FunctionCall &call1, const FunctionCall &call2) +{ + return call1.m_start < call2.m_start || + (call1.m_start == call2.m_start && (call1.m_end < call2.m_end || + (call1.m_end == call2.m_end && call1.m_function < call2.m_function))); +} + void Profiler::reportData() { + std::sort(m_data.begin(), m_data.end()); QVector resolved; resolved.reserve(m_data.size()); - FunctionCallComparator comp; - foreach (const FunctionCall &call, m_data) { - FunctionCallProperties props = call.resolve(); - resolved.insert(std::upper_bound(resolved.begin(), resolved.end(), props, comp), props); - } + + foreach (const FunctionCall &call, m_data) + resolved.append(call.resolve()); + emit dataReady(resolved, m_memory_data); m_data.clear(); m_memory_data.clear(); @@ -111,4 +113,7 @@ void Profiler::startProfiling(quint64 features) } } +} // namespace Profiling +} // namespace QV4 + QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4profiling_p.h b/src/qml/jsruntime/qv4profiling_p.h index cc00af0193..505d393a3d 100644 --- a/src/qml/jsruntime/qv4profiling_p.h +++ b/src/qml/jsruntime/qv4profiling_p.h @@ -104,6 +104,7 @@ public: FunctionCallProperties resolve() const; private: + friend bool operator<(const FunctionCall &call1, const FunctionCall &call2); Function *m_function; qint64 m_start; From bad007360a0f6fba304d8f4c99826a1250fd886c Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 13 Aug 2015 18:14:52 +0200 Subject: [PATCH 08/27] Remove this piece of code This was required with the old v8 engine, but removing the lines doesn't seem to cause any regressions in our tests, so let's get rid of them, and have proper JS scoping rules in place. Change-Id: Ib22b4e820bceff9fe26291dae1bf7b55b12a5cde Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlcontextwrapper.cpp | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/qml/qml/qqmlcontextwrapper.cpp b/src/qml/qml/qqmlcontextwrapper.cpp index 1007029416..99a5fe56ce 100644 --- a/src/qml/qml/qqmlcontextwrapper.cpp +++ b/src/qml/qml/qqmlcontextwrapper.cpp @@ -100,23 +100,14 @@ ReturnedValue QmlContextWrapper::get(const Managed *m, String *name, bool *hasPr QV4::ExecutionEngine *v4 = resource->engine(); QV4::Scope scope(v4); - // In V8 the JS global object would come _before_ the QML global object, - // so simulate that here. - bool hasProp; - QV4::ScopedValue result(scope, v4->globalObject->get(name, &hasProp)); - if (hasProp) { - if (hasProperty) - *hasProperty = hasProp; - return result->asReturnedValue(); - } - if (resource->d()->isNullWrapper) return Object::get(m, name, hasProperty); if (v4->callingQmlContext() != resource->d()->context) return Object::get(m, name, hasProperty); - result = Object::get(m, name, &hasProp); + bool hasProp; + QV4::ScopedValue result(scope, Object::get(m, name, &hasProp)); if (hasProp) { if (hasProperty) *hasProperty = hasProp; From c962f3c8e874f21743684a52ee520939ae1be938 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 13 Aug 2015 22:08:49 +0200 Subject: [PATCH 09/27] Fix autotest The test was not getting a new warning as assumed, but still reading the old warning from a few lines before. This mirrors the intended behavior. Change-Id: I7211923e378db34cdc5f8c1c78f3cfb1bea548d2 Reviewed-by: Simon Hausmann --- .../qquickworkerscript/tst_qquickworkerscript.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp b/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp index f4765d0e8d..8ad2b6ba2b 100644 --- a/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp +++ b/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp @@ -338,19 +338,17 @@ void tst_QQuickWorkerScript::script_global() delete worker; } + qquickworkerscript_lastWarning = QString(); + { + QtMessageHandler previousMsgHandler = qInstallMessageHandler(qquickworkerscript_warningsHandler); + QQmlComponent component(&m_engine, testFileUrl("worker_global2.qml")); QQuickWorkerScript *worker = qobject_cast(component.create()); QVERIFY(worker != 0); - QString value("Hello"); - - QtMessageHandler previousMsgHandler = qInstallMessageHandler(qquickworkerscript_warningsHandler); - - QVERIFY(QMetaObject::invokeMethod(worker, "testSend", Q_ARG(QVariant, value))); - QTRY_COMPARE(qquickworkerscript_lastWarning, - testFileUrl("script_global.js").toString() + QLatin1String(":2: Invalid write to global property \"world\"")); + testFileUrl("script_global2.js").toString() + QLatin1String(":1: Invalid write to global property \"world\"")); qInstallMessageHandler(previousMsgHandler); From 9eab0161f465c35b996fad9451ad07c5b0c2b38d Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 14 Aug 2015 09:20:42 +0200 Subject: [PATCH 10/27] Create less BindingWrappers Instead create QmlContext's directly as they are the only thing used from the binding wrapper. Change-Id: If3a987134dee9e85b6a76ed74aacd76b19279117 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4script.cpp | 16 ++-------------- src/qml/jsruntime/qv4script_p.h | 4 ---- src/qml/qml/qqmlobjectcreator.cpp | 23 ++++++++++++----------- src/qml/qml/qqmlobjectcreator_p.h | 4 ++-- 4 files changed, 16 insertions(+), 31 deletions(-) diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index 14b8b878bd..7067d10e22 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -104,18 +104,6 @@ Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::ExecutionContext *scope, Functio internalClass->engine->popContext(); } -Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::ExecutionContext *scope, QV4::QmlContextWrapper *qml) - : Heap::FunctionObject(scope, scope->d()->engine->id_eval(), /*createProto = */ false) -{ - Q_ASSERT(scope->inUse()); - - Scope s(scope); - Scoped protectThis(s, this); - - this->scope = scope->newQmlContext(qml); - internalClass->engine->popContext(); -} - ReturnedValue QmlBindingWrapper::call(const Managed *that, CallData *callData) { const QmlBindingWrapper *This = static_cast(that); @@ -152,8 +140,8 @@ Heap::FunctionObject *QmlBindingWrapper::createQmlCallableForFunction(QQmlContex QV4::Scope valueScope(engine); QV4::Scoped qmlScopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(engine, qmlContext, scopeObject)); ScopedContext global(valueScope, valueScope.engine->rootContext()); - QV4::Scoped wrapper(valueScope, engine->memoryManager->alloc(global, qmlScopeObject)); - QV4::Scoped wrapperContext(valueScope, wrapper->context()); + QV4::Scoped wrapperContext(valueScope, global->newQmlContext(qmlScopeObject)); + engine->popContext(); if (!signalParameters.isEmpty()) { if (error) diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h index 22714496f8..fad011f88a 100644 --- a/src/qml/jsruntime/qv4script_p.h +++ b/src/qml/jsruntime/qv4script_p.h @@ -88,8 +88,6 @@ struct ContextStateSaver { namespace Heap { struct QmlBindingWrapper : Heap::FunctionObject { QmlBindingWrapper(QV4::ExecutionContext *scope, Function *f, QV4::QmlContextWrapper *qml); - // Constructor for QML functions and signal handlers, resulting binding wrapper is not callable! - QmlBindingWrapper(QV4::ExecutionContext *scope, QV4::QmlContextWrapper *qml); }; } @@ -99,8 +97,6 @@ struct Q_QML_EXPORT QmlBindingWrapper : FunctionObject { static ReturnedValue call(const Managed *that, CallData *callData); - Heap::QmlContext *context() const { return static_cast(d()->scope.ptr); } - static Heap::FunctionObject *createQmlCallableForFunction(QQmlContextData *qmlContext, QObject *scopeObject, QV4::Function *runtimeFunction, const QList &signalParameters = QList(), QString *error = 0); }; diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 0b977f2551..b55973cdc8 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -120,7 +120,7 @@ void QQmlObjectCreator::init(QQmlContextData *providedParentContext) _ddata = 0; _propertyCache = 0; _vmeMetaObject = 0; - _qmlBindingWrapper = 0; + _qmlContext = 0; } QQmlObjectCreator::~QQmlObjectCreator() @@ -236,9 +236,9 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance) Q_ASSERT(!sharedState->allJavaScriptObjects); sharedState->allJavaScriptObjects = valueScope.alloc(compiledData->totalObjectCount); - QV4::Value *qmlBindingWrapper = valueScope.alloc(1); + QV4::QmlContext *qmlContext = static_cast(valueScope.alloc(1)); - qSwap(_qmlBindingWrapper, qmlBindingWrapper); + qSwap(_qmlContext, qmlContext); qSwap(_propertyCache, cache); qSwap(_qobject, instance); @@ -267,7 +267,7 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance) qSwap(_qobject, instance); qSwap(_propertyCache, cache); - qSwap(_qmlBindingWrapper, qmlBindingWrapper); + qSwap(_qmlContext, qmlContext); qSwap(_scopeObject, scopeObject); phase = ObjectsCreated; @@ -985,15 +985,16 @@ void QQmlObjectCreator::registerObjectWithContextById(int objectIndex, QObject * context->setIdProperty(idEntry.value(), instance); } -QV4::Heap::ExecutionContext *QQmlObjectCreator::currentQmlContext() +QV4::Heap::QmlContext *QQmlObjectCreator::currentQmlContext() { - if (!_qmlBindingWrapper->objectValue()) { + if (!_qmlContext->objectValue()) { QV4::Scope valueScope(v4); QV4::Scoped qmlScope(valueScope, QV4::QmlContextWrapper::qmlScope(v4, context, _scopeObject)); QV4::ScopedContext global(valueScope, v4->rootContext()); - *_qmlBindingWrapper = v4->memoryManager->alloc(global, qmlScope); + _qmlContext->setM(global->newQmlContext(qmlScope)); + v4->popContext(); } - return static_cast(_qmlBindingWrapper->objectValue())->context(); + return _qmlContext->d(); } QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isContextObject) @@ -1140,13 +1141,13 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo ++sharedState->allJavaScriptObjects; QV4::Scope valueScope(v4); - QV4::Value *qmlBindingWrapper = valueScope.alloc(1); + QV4::QmlContext *qmlContext = static_cast(valueScope.alloc(1)); - qSwap(_qmlBindingWrapper, qmlBindingWrapper); + qSwap(_qmlContext, qmlContext); bool result = populateInstance(index, instance, /*binding target*/instance, /*value type property*/0, bindingsToSkip); - qSwap(_qmlBindingWrapper, qmlBindingWrapper); + qSwap(_qmlContext, qmlContext); qSwap(_scopeObject, scopeObject); return result ? instance : 0; diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index c88c15b525..433bbf5bf2 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -107,7 +107,7 @@ private: void registerObjectWithContextById(int objectIndex, QObject *instance) const; - QV4::Heap::ExecutionContext *currentQmlContext(); + QV4::Heap::QmlContext *currentQmlContext(); enum Phase { Startup, @@ -143,7 +143,7 @@ private: QQmlRefPointer _propertyCache; QQmlVMEMetaObject *_vmeMetaObject; QQmlListProperty _currentList; - QV4::Value *_qmlBindingWrapper; + QV4::QmlContext *_qmlContext; friend struct QQmlObjectCreatorRecursionWatcher; }; From de1ecd10ab7af694f8a3e427c6be83738879d11e Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 7 Aug 2015 08:46:26 +0200 Subject: [PATCH 11/27] Fix compiler warnings on recent clang Add some Q_DECL_OVERRIDE and a cast Change-Id: I834d16049805b5fc6e64a64d26cd6c92ac873163 Reviewed-by: Simon Hausmann --- src/quick/util/qquickglobal.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quick/util/qquickglobal.cpp b/src/quick/util/qquickglobal.cpp index 391e0b7347..25dd09c01f 100644 --- a/src/quick/util/qquickglobal.cpp +++ b/src/quick/util/qquickglobal.cpp @@ -374,7 +374,7 @@ public: return QMatrix4x4(matVals); } - const QMetaObject *getMetaObjectForMetaType(int type) + const QMetaObject *getMetaObjectForMetaType(int type) Q_DECL_OVERRIDE { switch (type) { case QMetaType::QColor: From 89c3c79c257fe53122cce1c739453bc45b5926b8 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Tue, 25 Aug 2015 09:08:58 +0200 Subject: [PATCH 12/27] Fix warning in tst_qquickdesignersupport.cpp Taking the address of a temporary is not allowed. It is against the standard to pass a non-const reference to a temporary object. Change-Id: Ib333fa9a366725b8f0491a4216597fa5baeef7ff Reviewed-by: Friedemann Kleint --- .../quick/qquickdesignersupport/tst_qquickdesignersupport.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/auto/quick/qquickdesignersupport/tst_qquickdesignersupport.cpp b/tests/auto/quick/qquickdesignersupport/tst_qquickdesignersupport.cpp index 49535783c1..1104ce1d98 100644 --- a/tests/auto/quick/qquickdesignersupport/tst_qquickdesignersupport.cpp +++ b/tests/auto/quick/qquickdesignersupport/tst_qquickdesignersupport.cpp @@ -394,7 +394,8 @@ void tst_qquickdesignersupport::statesPropertyChanges() //Create new PropertyChanges QQuickPropertyChanges *newPropertyChange = new QQuickPropertyChanges(); newPropertyChange->setParent(state01); - QQuickStatePrivate::operations_append(&state01->changes(), newPropertyChange); + QQmlListProperty changes = state01->changes(); + QQuickStatePrivate::operations_append(&changes, newPropertyChange); newPropertyChange->setObject(rootItem); From c34534ef2019dd47ea3f2c6d9c55da26ef3a3d71 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Tue, 25 Aug 2015 10:48:33 +0200 Subject: [PATCH 13/27] Fix sha1 of test262 While .gitmodules was pointing at the new URL, the sha1 for the submodule was pointing to the old github repository. Change-Id: Ie0b9f39e13a6e759249aaaf0e90c5a242bb36134 Reviewed-by: Simon Hausmann --- tests/manual/v4/test262 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/manual/v4/test262 b/tests/manual/v4/test262 index 0b5af3dcec..9741ac4655 160000 --- a/tests/manual/v4/test262 +++ b/tests/manual/v4/test262 @@ -1 +1 @@ -Subproject commit 0b5af3dcec772bb06b4d685a20b2859cda59d189 +Subproject commit 9741ac4655808ac46c127e3d1d8ba3d27ada618e From 8843f9375632fe999b31d16a39e879590d3d9d07 Mon Sep 17 00:00:00 2001 From: Topi Reinio Date: Tue, 25 Aug 2015 14:31:59 +0200 Subject: [PATCH 14/27] Doc: Rename sections in Touch Interaction example documentation A section title 'Flickable' caused mislinking when using \l {Flickable}, and the intention is to link to the Flickable QML type reference. Change-Id: I2945fc675f0adcf0fe97d1d5f2ed0301c6e9f64b Reviewed-by: Leena Miettinen --- .../touchinteraction/doc/src/touchinteraction.qdoc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/quick/touchinteraction/doc/src/touchinteraction.qdoc b/examples/quick/touchinteraction/doc/src/touchinteraction.qdoc index 760e14adca..e66d5c5654 100644 --- a/examples/quick/touchinteraction/doc/src/touchinteraction.qdoc +++ b/examples/quick/touchinteraction/doc/src/touchinteraction.qdoc @@ -36,7 +36,7 @@ \include examples-run.qdocinc - \section1 Multipoint Flames + \section1 Multipoint Flames Example \e{Multipoint Flames} demonstrates distinguishing different fingers in a \l MultiPointTouchArea, by assigning a different colored flame to each touch @@ -49,7 +49,7 @@ whether it is currently pressed, as follows: \snippet touchinteraction/multipointtouch/multiflame.qml 1 - \section1 Bear-Whack + \section1 Bear-Whack Example \e{Bear-Whack} demonstrates using \l MultiPointTouchArea to add multiple finger support to a simple game. The interaction with the game @@ -58,19 +58,19 @@ embedded into it: \snippet touchinteraction/multipointtouch/content/AugmentedTouchPoint.qml 0 - \section1 Flick Resize + \section1 Flick Resize Example \e{Flick Resize} uses a \l PinchArea to implement a \e{pinch-to-resize} behavior. This is easily achieved by listening to the PinchArea signals and responding to user input. \snippet touchinteraction/pincharea/flickresize.qml 0 - \section1 Flickable + \section1 Flickable Example \e Flickable is a simple example demonstrating the \l Flickable type. \snippet touchinteraction/flickable/basic-flickable.qml 0 - \section1 Corkboards + \section1 Corkboards Example \e Corkboards shows another use for \l Flickable, with QML types within the flickable object that respond to mouse and keyboard interaction. This From 1faca908dddb90824d94bed6a1561f4f192328d3 Mon Sep 17 00:00:00 2001 From: Julien Brianceau Date: Thu, 27 Aug 2015 14:37:50 +0200 Subject: [PATCH 15/27] XHR: Server side errors are not network errors XMLHttpRequest specs state that only 'network errors' should result in a request error, and a server side error like HTTP 500 Internal Server Error (which results in QNetworkReply::InternalServerError) is an indication of the HTTP server response rather than a network error. Change-Id: I94bf678a8487e3d31007dc5119d6fb4e87ea3102 Reviewed-by: Simon Hausmann Reviewed-by: Valery Kotov --- src/qml/qml/qqmlxmlhttprequest.cpp | 6 +++++- tests/auto/qml/qqmlxmlhttprequest/data/status.500.reply | 3 +++ .../auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 tests/auto/qml/qqmlxmlhttprequest/data/status.500.reply diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index 0870e2b2c5..de7741675b 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -1358,7 +1358,11 @@ void QQmlXMLHttpRequest::error(QNetworkReply::NetworkError error) error == QNetworkReply::AuthenticationRequiredError || error == QNetworkReply::ContentReSendError || error == QNetworkReply::UnknownContentError || - error == QNetworkReply::ProtocolInvalidOperationError) { + error == QNetworkReply::ProtocolInvalidOperationError || + error == QNetworkReply::InternalServerError || + error == QNetworkReply::OperationNotImplementedError || + error == QNetworkReply::ServiceUnavailableError || + error == QNetworkReply::UnknownServerError) { m_state = Loading; dispatchCallback(); } else { diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/status.500.reply b/tests/auto/qml/qqmlxmlhttprequest/data/status.500.reply new file mode 100644 index 0000000000..cbe2424f34 --- /dev/null +++ b/tests/auto/qml/qqmlxmlhttprequest/data/status.500.reply @@ -0,0 +1,3 @@ +HTTP/1.0 500 Internal Server Error +Connection: close +Content-type: text/html; charset=UTF-8 diff --git a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp index ae0350278a..47bf151a37 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp +++ b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp @@ -989,6 +989,7 @@ void tst_qqmlxmlhttprequest::responseText_data() QTest::newRow("empty body") << testFileUrl("status.200.reply") << QUrl() << ""; QTest::newRow("Not Found") << testFileUrl("status.404.reply") << testFileUrl("testdocument.html") << "QML Rocks!\n"; QTest::newRow("Bad Request") << testFileUrl("status.400.reply") << testFileUrl("testdocument.html") << "QML Rocks!\n"; + QTest::newRow("Internal server error") << testFileUrl("status.500.reply") << testFileUrl("testdocument.html") << "QML Rocks!\n"; } void tst_qqmlxmlhttprequest::nonUtf8() From 9ee31a6ae852eb347951e371958dd435409c9941 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Sat, 29 Aug 2015 18:35:12 +0200 Subject: [PATCH 16/27] Doc: fix the "Grouped Properties" example snippet Change-Id: Id41084b5abd7a83aab519a73b7377deb30302511 Task-number: QTBUG-48009 Reviewed-by: Mitch Curtis --- src/qml/doc/src/cppintegration/exposecppattributes.qdoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qml/doc/src/cppintegration/exposecppattributes.qdoc b/src/qml/doc/src/cppintegration/exposecppattributes.qdoc index e1db5c9d57..f4f688520a 100644 --- a/src/qml/doc/src/cppintegration/exposecppattributes.qdoc +++ b/src/qml/doc/src/cppintegration/exposecppattributes.qdoc @@ -328,11 +328,11 @@ public: : QObject(parent), m_author(new MessageAuthor(this)) { } - Message *author() const { + MessageAuthor *author() const { return m_author; } private: - Message *m_author; + MessageAuthor *m_author; }; \endcode From d43333cd1e83d72c0db5b39d9f0eb00d93fdb934 Mon Sep 17 00:00:00 2001 From: Marco Benelli Date: Thu, 23 Jul 2015 10:39:25 +0200 Subject: [PATCH 17/27] Warn if a composite type is not ready and continue. Change-Id: Ib28f484188466831e4c64aee0e36a27dd4842b06 Reviewed-by: Thomas Hartmann --- tools/qmlplugindump/main.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/qmlplugindump/main.cpp b/tools/qmlplugindump/main.cpp index 96c23ae268..6248d3dc64 100644 --- a/tools/qmlplugindump/main.cpp +++ b/tools/qmlplugindump/main.cpp @@ -461,6 +461,12 @@ public: void dumpComposite(QQmlEngine *engine, const QQmlType *compositeType, QSet &defaultReachableNames) { QQmlComponent e(engine, compositeType->sourceUrl()); + if (!e.isReady()) { + std::cerr << "WARNING: skipping module " << compositeType->elementName().toStdString() + << std::endl << e.errorString().toStdString() << std::endl; + return; + } + QObject *object = e.create(); if (!object) @@ -899,6 +905,7 @@ void printDebugMessage(QtMsgType, const QMessageLogContext &, const QString &msg // In case of QtFatalMsg the calling code will abort() when appropriate. } + int main(int argc, char *argv[]) { #if defined(Q_OS_WIN) && !defined(Q_CC_MINGW) @@ -1039,6 +1046,7 @@ int main(int argc, char *argv[]) if (calculateDependencies) getDependencies(engine, pluginImportUri, pluginImportVersion, &dependencies); compactDependencies(&dependencies); + // load the QtQml 2.2 builtins and the dependencies { QByteArray code("import QtQml 2.2"); From 70592075464dad3f8fef173422a30a06eaed3d80 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Tue, 21 Jul 2015 11:03:42 +0200 Subject: [PATCH 18/27] Doc: broken links and missing doc for functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number. QTBUG-43810 Change-Id: I14e03317d7470f33a899ba05b62b3d68fdb03734 Reviewed-by: Topi Reiniƶ --- src/qml/jsapi/qjsvalue.cpp | 12 ++++++++++++ src/qml/qml/qqmlabstracturlinterceptor.cpp | 10 ++++++++++ src/quick/doc/src/dynamicview-tutorial.qdoc | 4 ++-- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp index 50669c46a8..1d9dc2b6db 100644 --- a/src/qml/jsapi/qjsvalue.cpp +++ b/src/qml/jsapi/qjsvalue.cpp @@ -211,6 +211,18 @@ QJSValue::QJSValue(const QJSValue& other) } } +/*! + \fn QJSValue::QJSValue(QJSValue && other) + + Move constructor. Moves from \a other into this QJSValue object. +*/ + +/*! + \fn QJSValue &operator=(QJSValue && other) + + Move-assigns \a other to this QJSValue object. +*/ + /*! Destroys this QJSValue. */ diff --git a/src/qml/qml/qqmlabstracturlinterceptor.cpp b/src/qml/qml/qqmlabstracturlinterceptor.cpp index cb57bc2146..dce41b0caa 100644 --- a/src/qml/qml/qqmlabstracturlinterceptor.cpp +++ b/src/qml/qml/qqmlabstracturlinterceptor.cpp @@ -82,3 +82,13 @@ Your implementation of this function must be thread-safe, as it can be called from multiple threads at the same time. */ +/*! + \fn QQmlAbstractUrlInterceptor::QQmlAbstractUrlInterceptor() + + Constructor for QQmlAbstractUrlInterceptor. +*/ +/*! + \fn QQmlAbstractUrlInterceptor::~QQmlAbstractUrlInterceptor() + + Destructor for QQmlAbstractUrlInterceptor. +*/ diff --git a/src/quick/doc/src/dynamicview-tutorial.qdoc b/src/quick/doc/src/dynamicview-tutorial.qdoc index f87f94f264..2b5bb6e0c1 100644 --- a/src/quick/doc/src/dynamicview-tutorial.qdoc +++ b/src/quick/doc/src/dynamicview-tutorial.qdoc @@ -208,8 +208,8 @@ item and then transfer the item to the items group before moving it to the pre-d repeat until the unsorted group is empty. To find the insert position for an item we request a handle for the item from the unsorted group -with the \l {DelegateModel::}{get} function. Through the model property on this -handle we can access the same model data that is available in a delegate instance of that item and +with the \l {DelegateModelGroup::}{get()} function. Through the model property on this handle we can +access the same model data that is available in a delegate instance of that item and compare against other items to determine relative position. \snippet tutorials/dynamicview/dynamicview4/dynamicview.qml 3 From d1b20513798ed441afddb87fd4e7facce78349e1 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Tue, 25 Aug 2015 15:43:56 +0200 Subject: [PATCH 19/27] Don't consider QLocale a value type. This fixes a regression where all of the properties of Qt.inputMethod.locale were undefined. Change-Id: Id33890a78296709baad6aeda96d74ca8cb39c61d Task-number: QTBUG-47916 Reviewed-by: Mitch Curtis Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlvaluetype.cpp | 3 +- .../qml/qqmlvaluetypes/data/locale_read.qml | 22 +++++++++++ .../qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp | 38 +++++++++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 tests/auto/qml/qqmlvaluetypes/data/locale_read.qml diff --git a/src/qml/qml/qqmlvaluetype.cpp b/src/qml/qml/qqmlvaluetype.cpp index 10eaae0c77..6825e5f004 100644 --- a/src/qml/qml/qqmlvaluetype.cpp +++ b/src/qml/qml/qqmlvaluetype.cpp @@ -82,7 +82,8 @@ bool QQmlValueTypeFactoryImpl::isValueType(int idx) && idx != QVariant::StringList && idx != QMetaType::QObjectStar && idx != QMetaType::VoidStar - && idx != QMetaType::QVariant) { + && idx != QMetaType::QVariant + && idx != QMetaType::QLocale) { return true; } diff --git a/tests/auto/qml/qqmlvaluetypes/data/locale_read.qml b/tests/auto/qml/qqmlvaluetypes/data/locale_read.qml new file mode 100644 index 0000000000..5ae6b41259 --- /dev/null +++ b/tests/auto/qml/qqmlvaluetypes/data/locale_read.qml @@ -0,0 +1,22 @@ +import QtQuick 2.0 + +Item { + property string amText: Qt.inputMethod.locale.amText + property string decimalPoint: Qt.inputMethod.locale.decimalPoint + property string exponential: Qt.inputMethod.locale.exponential + property int firstDayOfWeek: Qt.inputMethod.locale.firstDayOfWeek + property string groupSeparator: Qt.inputMethod.locale.groupSeparator + property int measurementSystem: Qt.inputMethod.locale.measurementSystem + property string name: Qt.inputMethod.locale.name + property string nativeCountryName: Qt.inputMethod.locale.nativeCountryName + property string nativeLanguageName: Qt.inputMethod.locale.nativeLanguageName + property string negativeSign: Qt.inputMethod.locale.negativeSign + property string percent: Qt.inputMethod.locale.percent + property string pmText: Qt.inputMethod.locale.pmText + property string positiveSign: Qt.inputMethod.locale.positiveSign + property int textDirection: Qt.inputMethod.locale.textDirection + property var uiLanguages: Qt.inputMethod.locale.uiLanguages + property var weekDays: Qt.inputMethod.locale.weekDays + property string zeroDigit: Qt.inputMethod.locale.zeroDigit +} + diff --git a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp index 578004b0a1..f93190cab6 100644 --- a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp +++ b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include "../../shared/util.h" #include "testtypes.h" @@ -67,6 +68,7 @@ private slots: void font(); void color(); void variant(); + void locale(); void bindingAssignment(); void bindingRead(); @@ -316,6 +318,42 @@ void tst_qqmlvaluetypes::variant() } } +void tst_qqmlvaluetypes::locale() +{ + { + QQmlComponent component(&engine, testFileUrl("locale_read.qml")); + QScopedPointer object(component.create()); + QVERIFY(!object.isNull()); + + QVERIFY(QQml_guiProvider()->inputMethod()); + QInputMethod *inputMethod = qobject_cast(QQml_guiProvider()->inputMethod()); + QLocale locale = inputMethod->locale(); + + QCOMPARE(object->property("amText").toString(), locale.amText()); + QCOMPARE(object->property("decimalPoint").toString().at(0), locale.decimalPoint()); + QCOMPARE(object->property("exponential").toString().at(0), locale.exponential()); + // Sunday is 0 in JavaScript. + QCOMPARE(object->property("firstDayOfWeek").toInt(), int(locale.firstDayOfWeek() == Qt::Sunday ? 0 : locale.firstDayOfWeek())); + QCOMPARE(object->property("groupSeparator").toString().at(0), locale.groupSeparator()); + QCOMPARE(object->property("measurementSystem").toInt(), int(locale.measurementSystem())); + QCOMPARE(object->property("name").toString(), locale.name()); + QCOMPARE(object->property("nativeCountryName").toString(), locale.nativeCountryName()); + QCOMPARE(object->property("nativeLanguageName").toString(), locale.nativeLanguageName()); + QCOMPARE(object->property("negativeSign").toString().at(0), locale.negativeSign()); + QCOMPARE(object->property("percent").toString().at(0), locale.percent()); + QCOMPARE(object->property("pmText").toString(), locale.pmText()); + QCOMPARE(object->property("positiveSign").toString().at(0), locale.positiveSign()); + QCOMPARE(object->property("textDirection").toInt(), int(locale.textDirection())); + QCOMPARE(object->property("uiLanguages").toStringList(), locale.uiLanguages()); + QList weekDays; + foreach (const QVariant &weekDay, object->property("weekDays").toList()) { + weekDays.append(Qt::DayOfWeek(weekDay.toInt())); + } + QCOMPARE(weekDays, locale.weekdays()); + QCOMPARE(object->property("zeroDigit").toString().at(0), locale.zeroDigit()); + } +} + void tst_qqmlvaluetypes::sizereadonly() { { From 8b09653cb22807f09ec4e6c0ffc7dcf7f11bc1a0 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 7 Aug 2015 10:52:36 +0200 Subject: [PATCH 20/27] Shortcut: add sequenceString property If you set sequence to a StandardKey, then read back the property, you will get an int, which is not suitable for display. Now you can use sequenceString for tooltips, preference dialogs for setting shortcuts, and such. [ChangeLog][QtQuick] Added Shortcut.sequenceString property to read back the key sequence as a displayable string Change-Id: I63ee46f8a2c2da1b1c803282baa894fb1667fe67 Reviewed-by: Gabriel de Dietrich --- src/quick/util/qquickshortcut.cpp | 14 ++++++++++++++ src/quick/util/qquickshortcut_p.h | 3 +++ src/quick/util/qquickutilmodule.cpp | 2 ++ 3 files changed, 19 insertions(+) diff --git a/src/quick/util/qquickshortcut.cpp b/src/quick/util/qquickshortcut.cpp index 36c6933af4..9f32b6c180 100644 --- a/src/quick/util/qquickshortcut.cpp +++ b/src/quick/util/qquickshortcut.cpp @@ -133,6 +133,20 @@ void QQuickShortcut::setSequence(const QVariant &sequence) emit sequenceChanged(); } +/*! + \qmlproperty string QtQuick::Shortcut::sequenceString + \since 5.6 + + This property provides the shortcut's key sequence as a string, + for display purposes (tooltips, for example). + + \sa sequence +*/ +QString QQuickShortcut::sequenceString() const +{ + return m_shortcut.toString(QKeySequence::NativeText); +} + /*! \qmlproperty bool QtQuick::Shortcut::enabled diff --git a/src/quick/util/qquickshortcut_p.h b/src/quick/util/qquickshortcut_p.h index e16ac9df20..db02f8afae 100644 --- a/src/quick/util/qquickshortcut_p.h +++ b/src/quick/util/qquickshortcut_p.h @@ -57,6 +57,7 @@ class QQuickShortcut : public QObject, public QQmlParserStatus Q_OBJECT Q_INTERFACES(QQmlParserStatus) Q_PROPERTY(QVariant sequence READ sequence WRITE setSequence NOTIFY sequenceChanged FINAL) + Q_PROPERTY(QString sequenceString READ sequenceString NOTIFY sequenceChanged FINAL REVISION 1) Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged FINAL) Q_PROPERTY(bool autoRepeat READ autoRepeat WRITE setAutoRepeat NOTIFY autoRepeatChanged FINAL) Q_PROPERTY(Qt::ShortcutContext context READ context WRITE setContext NOTIFY contextChanged FINAL) @@ -68,6 +69,8 @@ public: QVariant sequence() const; void setSequence(const QVariant &sequence); + Q_REVISION(1) QString sequenceString() const; + bool isEnabled() const; void setEnabled(bool enabled); diff --git a/src/quick/util/qquickutilmodule.cpp b/src/quick/util/qquickutilmodule.cpp index 4f6e49fa7a..0af2343504 100644 --- a/src/quick/util/qquickutilmodule.cpp +++ b/src/quick/util/qquickutilmodule.cpp @@ -114,4 +114,6 @@ void QQuickUtilModule::defineModule() qmlRegisterType("QtQuick", 2, 4, "TextMetrics"); qmlRegisterType("QtQuick", 2, 5, "Shortcut"); + + qmlRegisterType("QtQuick", 2, 6, "Shortcut"); } From ba3a9fd2d0592c288ebc64c6c659fb4ace6e317f Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 21 Aug 2015 16:24:52 +0200 Subject: [PATCH 21/27] Photosurface demo: add Shortcuts for open and quit, tooltip for open Demonstrates the new Shortcut.sequenceString property. Change-Id: I6c523a46b595610b310070214c31f3fbd79a3d28 Reviewed-by: Gabriel de Dietrich --- .../quick/demos/photosurface/photosurface.qml | 46 +++++++++++++++++-- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/examples/quick/demos/photosurface/photosurface.qml b/examples/quick/demos/photosurface/photosurface.qml index e5cfd827dc..22cef62157 100644 --- a/examples/quick/demos/photosurface/photosurface.qml +++ b/examples/quick/demos/photosurface/photosurface.qml @@ -37,7 +37,7 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ -import QtQuick 2.5 +import QtQuick 2.6 import QtQuick.Dialogs 1.0 import QtQuick.Window 2.1 import Qt.labs.folderlistmodel 1.0 @@ -172,7 +172,7 @@ Window { height: flick.height * (flick.height / flick.contentHeight) - (width - anchors.margins) * 2 y: flick.contentY * (flick.height / flick.contentHeight) NumberAnimation on opacity { id: vfade; to: 0; duration: 500 } - onYChanged: { opacity = 1.0; fadeTimer.restart() } + onYChanged: { opacity = 1.0; scrollFadeTimer.restart() } } Rectangle { @@ -188,10 +188,10 @@ Window { width: flick.width * (flick.width / flick.contentWidth) - (height - anchors.margins) * 2 x: flick.contentX * (flick.width / flick.contentWidth) NumberAnimation on opacity { id: hfade; to: 0; duration: 500 } - onXChanged: { opacity = 1.0; fadeTimer.restart() } + onXChanged: { opacity = 1.0; scrollFadeTimer.restart() } } - Timer { id: fadeTimer; interval: 1000; onTriggered: { hfade.start(); vfade.start() } } + Timer { id: scrollFadeTimer; interval: 1000; onTriggered: { hfade.start(); vfade.start() } } Image { anchors.top: parent.top @@ -202,6 +202,42 @@ Window { anchors.fill: parent anchors.margins: -10 onClicked: fileDialog.open() + hoverEnabled: true + onPositionChanged: { + tooltip.visible = false + hoverTimer.start() + } + onExited: { + tooltip.visible = false + hoverTimer.stop() + } + Timer { + id: hoverTimer + interval: 1000 + onTriggered: { + tooltip.x = parent.mouseX + tooltip.y = parent.mouseY + tooltip.visible = true + } + } + Rectangle { + id: tooltip + border.color: "black" + color: "beige" + width: tooltipText.implicitWidth + 8 + height: tooltipText.implicitHeight + 8 + visible: false + Text { + id: tooltipText + anchors.centerIn: parent + text: "Open an image directory (" + openShortcut.sequenceString + ")" + } + } + } + Shortcut { + id: openShortcut + sequence: StandardKey.Open + onActivated: fileDialog.open() } } @@ -217,5 +253,7 @@ Window { "With a mouse: drag normally, use the vertical wheel to zoom, horizontal wheel to rotate, or hold Ctrl while using the vertical wheel to rotate" } + Shortcut { sequence: StandardKey.Quit; onActivated: Qt.quit() } + Component.onCompleted: fileDialog.open() } From 91a96d1de9c3d3f8d598ee8fbcf2d1868635ec46 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Thu, 3 Sep 2015 13:32:24 +0200 Subject: [PATCH 22/27] Temporarily blacklist importsPath change on Windows The test started failing with no changes in declarative, so the best theory at this point is a networking related change in qtbase. Change-Id: If361253847d781126d3877080648f5ccc07808cd Reviewed-by: Simon Hausmann --- tests/auto/qml/qqmllanguage/BLACKLIST | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 tests/auto/qml/qqmllanguage/BLACKLIST diff --git a/tests/auto/qml/qqmllanguage/BLACKLIST b/tests/auto/qml/qqmllanguage/BLACKLIST new file mode 100644 index 0000000000..c1c7e56df9 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/BLACKLIST @@ -0,0 +1,2 @@ +[importsPath] +windows From 83a5364cf8feacc48186df4fb3cadcc9f37afce0 Mon Sep 17 00:00:00 2001 From: Frank Meerkoetter Date: Mon, 31 Aug 2015 20:57:19 +0200 Subject: [PATCH 23/27] Cleanup Remove unnecessarry casts + reorder for better readability Change-Id: Ib0c6032f9d6a8a552eeff1c42b921f2ad24e00f0 Reviewed-by: Lars Knoll --- src/qml/jsruntime/qv4argumentsobject.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp index 39dce8efe0..2f6cf40beb 100644 --- a/src/qml/jsruntime/qv4argumentsobject.cpp +++ b/src/qml/jsruntime/qv4argumentsobject.cpp @@ -77,8 +77,8 @@ void ArgumentsObject::fullyCreate() if (fullyCreated()) return; - uint numAccessors = qMin((int)context()->function->formalParameterCount(), context()->callData->argc); uint argCount = context()->callData->argc; + uint numAccessors = qMin(context()->function->formalParameterCount(), argCount); ArrayData::realloc(this, Heap::ArrayData::Sparse, argCount, true); context()->engine->requireArgumentsAccessors(numAccessors); @@ -86,7 +86,7 @@ void ArgumentsObject::fullyCreate() Scoped md(scope, d()->mappedArguments); if (!md || md->size() < numAccessors) d()->mappedArguments = md->reallocate(engine(), d()->mappedArguments, numAccessors); - for (uint i = 0; i < (uint)numAccessors; ++i) { + for (uint i = 0; i < numAccessors; ++i) { mappedArguments()->data[i] = context()->callData->args[i]; arraySet(i, context()->engine->argumentsAccessors + i, Attr_Accessor); } From 217bca42934ecf9a5fab74bbddbfa852c9b1bfe6 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Tue, 1 Sep 2015 18:04:44 +0200 Subject: [PATCH 24/27] QQuickView/QQuickWidget::errors(): fix crash Change-Id: Ie37ed5fac642931b658d2b738ddd45d23cda54c6 Reviewed-by: Robin Burchell Reviewed-by: Mitch Curtis --- src/quick/items/qquickview.cpp | 2 +- src/quickwidgets/qquickwidget.cpp | 2 +- tests/auto/quick/qquickview/tst_qquickview.cpp | 4 ++++ tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp | 1 + 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/quick/items/qquickview.cpp b/src/quick/items/qquickview.cpp index 0b3cfa17b5..b0b24ca69a 100644 --- a/src/quick/items/qquickview.cpp +++ b/src/quick/items/qquickview.cpp @@ -370,7 +370,7 @@ QList QQuickView::errors() const QQmlError error; error.setDescription(QLatin1String("QQuickView: invalid qml engine.")); errs << error; - } else if (d->component->status() == QQmlComponent::Ready && !d->root) { + } else if (d->component && d->component->status() == QQmlComponent::Ready && !d->root) { QQmlError error; error.setDescription(QLatin1String("QQuickView: invalid root object.")); errs << error; diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp index 5755271fe1..70c9309ab0 100644 --- a/src/quickwidgets/qquickwidget.cpp +++ b/src/quickwidgets/qquickwidget.cpp @@ -566,7 +566,7 @@ QList QQuickWidget::errors() const QQmlError error; error.setDescription(QLatin1String("QQuickWidget: invalid qml engine.")); errs << error; - } else if (d->component->status() == QQmlComponent::Ready && !d->root) { + } else if (d->component && d->component->status() == QQmlComponent::Ready && !d->root) { QQmlError error; error.setDescription(QLatin1String("QQuickWidget: invalid root object.")); errs << error; diff --git a/tests/auto/quick/qquickview/tst_qquickview.cpp b/tests/auto/quick/qquickview/tst_qquickview.cpp index 2f054e278a..69e27984c7 100644 --- a/tests/auto/quick/qquickview/tst_qquickview.cpp +++ b/tests/auto/quick/qquickview/tst_qquickview.cpp @@ -180,6 +180,10 @@ void tst_QQuickView::resizemodeitem() void tst_QQuickView::errors() { + { + QQuickView view; + QVERIFY(view.errors().isEmpty()); // don't crash + } { QQuickView view; QQmlTestMessageHandler messageHandler; diff --git a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp index 11696e288f..7cc5dfa7c6 100644 --- a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp +++ b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp @@ -223,6 +223,7 @@ void tst_qquickwidget::errors() { QQuickWidget *view = new QQuickWidget; QScopedPointer cleanupView(view); + QVERIFY(view->errors().isEmpty()); // don't crash QQmlTestMessageHandler messageHandler; view->setSource(testFileUrl("error1.qml")); From cef14c0ff9a0caaa5b65ab89825534b3fcbd4764 Mon Sep 17 00:00:00 2001 From: Frank Meerkoetter Date: Sat, 29 Aug 2015 22:25:51 +0200 Subject: [PATCH 25/27] Allocate QML defined properties without extra room QV4::MemberData is used to allocate storage for QML defined properties. QV4::MemberData::reallocate() is multiplying each allocation by two as a growth strategy. This is a waste of memory for QML defined properties. This commits extends the QV4::MemberData with an additional method to allow exactly sized allocations. Change-Id: I5c0a3a5a3852d39af9e1afb512380fb1400d2448 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4memberdata.cpp | 28 +++++++++++++++++++--------- src/qml/jsruntime/qv4memberdata_p.h | 3 ++- src/qml/qml/qqmlvmemetaobject.cpp | 2 +- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp index 5ec5cb1f58..20f8d9ec0f 100644 --- a/src/qml/jsruntime/qv4memberdata.cpp +++ b/src/qml/jsruntime/qv4memberdata.cpp @@ -46,20 +46,30 @@ void MemberData::markObjects(Heap::Base *that, ExecutionEngine *e) m->data[i].mark(e); } -Heap::MemberData *MemberData::reallocate(ExecutionEngine *e, Heap::MemberData *old, uint idx) +static Heap::MemberData *reallocateHelper(ExecutionEngine *e, Heap::MemberData *old, uint n) { - uint s = old ? old->size : 0; - if (idx < s) - return old; - - int newAlloc = qMax((uint)4, 2*idx); - uint alloc = sizeof(Heap::MemberData) + (newAlloc)*sizeof(Value); + uint alloc = sizeof(Heap::MemberData) + (n)*sizeof(Value); Scope scope(e); Scoped newMemberData(scope, e->memoryManager->allocManaged(alloc)); if (old) - memcpy(newMemberData->d(), old, sizeof(Heap::MemberData) + s*sizeof(Value)); + memcpy(newMemberData->d(), old, sizeof(Heap::MemberData) + old->size * sizeof(Value)); else new (newMemberData->d()) Heap::MemberData; - newMemberData->d()->size = newAlloc; + newMemberData->d()->size = n; return newMemberData->d(); } + +Heap::MemberData *MemberData::allocate(ExecutionEngine *e, uint n) +{ + return reallocateHelper(e, 0, n); +} + +Heap::MemberData *MemberData::reallocate(ExecutionEngine *e, Heap::MemberData *old, uint n) +{ + uint s = old ? old->size : 0; + if (n < s) + return old; + + // n is multiplied by two to leave room for growth + return reallocateHelper(e, old, qMax((uint)4, 2*n)); +} diff --git a/src/qml/jsruntime/qv4memberdata_p.h b/src/qml/jsruntime/qv4memberdata_p.h index 4c7cfa47cb..50b8ddb3d1 100644 --- a/src/qml/jsruntime/qv4memberdata_p.h +++ b/src/qml/jsruntime/qv4memberdata_p.h @@ -61,7 +61,8 @@ struct MemberData : Managed Value *data() { return d()->data; } inline uint size() const { return d()->size; } - static Heap::MemberData *reallocate(QV4::ExecutionEngine *e, Heap::MemberData *old, uint idx); + static Heap::MemberData *allocate(QV4::ExecutionEngine *e, uint n); + static Heap::MemberData *reallocate(QV4::ExecutionEngine *e, Heap::MemberData *old, uint n); static void markObjects(Heap::Base *that, ExecutionEngine *e); }; diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index 0ffeddbabc..4b19d1af04 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -1086,7 +1086,7 @@ void QQmlVMEMetaObject::allocateProperties() { Q_ASSERT(cache && cache->engine); QV4::ExecutionEngine *v4 = cache->engine; - QV4::Heap::MemberData *data = QV4::MemberData::reallocate(v4, 0, metaData->propertyCount); + QV4::Heap::MemberData *data = QV4::MemberData::allocate(v4, metaData->propertyCount); properties.set(v4, data); for (uint i = 0; i < data->size; ++i) data->data[i] = QV4::Encode::undefined(); From 7ee93972d0f907725ad47f9a08b65a14ca48e9c0 Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Fri, 4 Sep 2015 13:31:43 +0200 Subject: [PATCH 26/27] Item views: Don't emit 'currentItemChanged' if the current item didn't really change Change-Id: I8892bb9b6ab6737d4a6f6f8aab836f863668682e Reviewed-by: J-P Nurmi --- src/quick/items/qquickitemview.cpp | 3 ++- tests/auto/quick/qquickgridview/data/gridview-initCurrent.qml | 3 +++ tests/auto/quick/qquickgridview/tst_qquickgridview.cpp | 3 +++ tests/auto/quick/qquicklistview/data/listview-initCurrent.qml | 3 +++ tests/auto/quick/qquicklistview/tst_qquicklistview.cpp | 3 +++ 5 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index d4c8c3f8ee..b618daf64b 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -1699,7 +1699,8 @@ void QQuickItemViewPrivate::updateCurrent(int modelIndex) updateHighlight(); if (oldCurrentIndex != currentIndex) emit q->currentIndexChanged(); - if (oldCurrentItem != currentItem) + if (oldCurrentItem != currentItem + && (!oldCurrentItem || !currentItem || oldCurrentItem->item != currentItem->item)) emit q->currentItemChanged(); releaseItem(oldCurrentItem); } diff --git a/tests/auto/quick/qquickgridview/data/gridview-initCurrent.qml b/tests/auto/quick/qquickgridview/data/gridview-initCurrent.qml index af35d2fa1b..0a6184c9de 100644 --- a/tests/auto/quick/qquickgridview/data/gridview-initCurrent.qml +++ b/tests/auto/quick/qquickgridview/data/gridview-initCurrent.qml @@ -6,6 +6,7 @@ Rectangle { property int current: grid.currentIndex property bool showHeader: false property bool showFooter: false + property int currentItemChangedCount: 0 width: 240 height: 320 @@ -63,5 +64,7 @@ Rectangle { model: testModel header: root.showHeader ? headerFooter : null footer: root.showFooter ? headerFooter : null + + onCurrentItemChanged: { root.currentItemChangedCount++ } } } diff --git a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp index 87042ca7ba..3699bef56d 100644 --- a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp +++ b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp @@ -1886,9 +1886,12 @@ void tst_QQuickGridView::currentIndex() QTRY_COMPARE(gridview->highlightItem()->y(), hlPosY); // insert item before currentIndex + window->rootObject()->setProperty("currentItemChangedCount", QVariant(0)); gridview->setCurrentIndex(28); + QTRY_COMPARE(window->rootObject()->property("currentItemChangedCount").toInt(), 1); model.insertItem(0, "Foo", "1111"); QTRY_COMPARE(window->rootObject()->property("current").toInt(), 29); + QCOMPARE(window->rootObject()->property("currentItemChangedCount").toInt(), 1); // check removing highlight by setting currentIndex to -1; gridview->setCurrentIndex(-1); diff --git a/tests/auto/quick/qquicklistview/data/listview-initCurrent.qml b/tests/auto/quick/qquicklistview/data/listview-initCurrent.qml index a02b66b8af..8aff649a67 100644 --- a/tests/auto/quick/qquicklistview/data/listview-initCurrent.qml +++ b/tests/auto/quick/qquicklistview/data/listview-initCurrent.qml @@ -6,6 +6,7 @@ Rectangle { property int current: list.currentIndex property bool showHeader: false property bool showFooter: false + property int currentItemChangedCount: 0 width: 240 height: 320 @@ -60,5 +61,7 @@ Rectangle { model: testModel header: root.showHeader ? headerFooter : null footer: root.showFooter ? headerFooter : null + + onCurrentItemChanged: { root.currentItemChangedCount++ } } } diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp index 472ffdc4b6..8e7f93849c 100644 --- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp +++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp @@ -2718,9 +2718,12 @@ void tst_QQuickListView::currentIndex() QTRY_COMPARE(listview->highlightItem()->y(), hlPos); // insert item before currentIndex + window->rootObject()->setProperty("currentItemChangedCount", QVariant(0)); listview->setCurrentIndex(28); + QTRY_COMPARE(window->rootObject()->property("currentItemChangedCount").toInt(), 1); model.insertItem(0, "Foo", "1111"); QTRY_COMPARE(window->rootObject()->property("current").toInt(), 29); + QCOMPARE(window->rootObject()->property("currentItemChangedCount").toInt(), 1); // check removing highlight by setting currentIndex to -1; listview->setCurrentIndex(-1); From 42f58e557034bb95005db465f078212cfc1b693a Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 18 Jun 2015 23:21:22 +0200 Subject: [PATCH 27/27] TextInput & TextEdit: allow controls to override the implicit size Change-Id: I4b5eae46a9fef574249eee9061858bdf874c54be Reviewed-by: Liang Qi Reviewed-by: Gabriel de Dietrich --- src/quick/items/qquicktextedit.cpp | 16 ++++++++++------ src/quick/items/qquicktextedit_p_p.h | 1 + src/quick/items/qquicktextinput.cpp | 14 +++++++++----- src/quick/items/qquicktextinput_p_p.h | 1 + 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp index dc4e301a36..0a26f0119f 100644 --- a/src/quick/items/qquicktextedit.cpp +++ b/src/quick/items/qquicktextedit.cpp @@ -2115,6 +2115,7 @@ QQuickTextEditPrivate::ExtraData::ExtraData() , explicitLeftPadding(false) , explicitRightPadding(false) , explicitBottomPadding(false) + , explicitImplicitSize(false) { } @@ -2345,7 +2346,8 @@ void QQuickTextEdit::updateSize() const bool wasInLayout = d->inLayout; d->inLayout = true; - setImplicitWidth(naturalWidth + leftPadding() + rightPadding()); + if (!d->extra.isAllocated() || !d->extra->explicitImplicitSize) + setImplicitWidth(naturalWidth + leftPadding() + rightPadding()); d->inLayout = wasInLayout; if (d->inLayout) // probably the result of a binding loop, but by letting it return; // get this far we'll get a warning to that effect. @@ -2364,11 +2366,13 @@ void QQuickTextEdit::updateSize() QFontMetricsF fm(d->font); qreal newHeight = d->document->isEmpty() ? qCeil(fm.height()) : d->document->size().height(); - // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed. - if (!widthValid() && !d->requireImplicitWidth) - setImplicitSize(newWidth + leftPadding() + rightPadding(), newHeight + topPadding() + bottomPadding()); - else - setImplicitHeight(newHeight + topPadding() + bottomPadding()); + if (!d->extra.isAllocated() || !d->extra->explicitImplicitSize) { + // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed. + if (!widthValid() && !d->requireImplicitWidth) + setImplicitSize(newWidth + leftPadding() + rightPadding(), newHeight + topPadding() + bottomPadding()); + else + setImplicitHeight(newHeight + topPadding() + bottomPadding()); + } d->xoff = leftPadding() + qMax(qreal(0), QQuickTextUtil::alignedX(d->document->size().width(), width() - leftPadding() - rightPadding(), effectiveHAlign())); d->yoff = topPadding() + QQuickTextUtil::alignedY(d->document->size().height(), height() - topPadding() - bottomPadding(), d->vAlign); diff --git a/src/quick/items/qquicktextedit_p_p.h b/src/quick/items/qquicktextedit_p_p.h index a763f9e56e..90ed7f071e 100644 --- a/src/quick/items/qquicktextedit_p_p.h +++ b/src/quick/items/qquicktextedit_p_p.h @@ -94,6 +94,7 @@ public: bool explicitLeftPadding : 1; bool explicitRightPadding : 1; bool explicitBottomPadding : 1; + bool explicitImplicitSize : 1; }; QLazilyAllocated extra; diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index c29acf3c83..041baa4199 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -2518,6 +2518,7 @@ QQuickTextInputPrivate::ExtraData::ExtraData() , explicitLeftPadding(false) , explicitRightPadding(false) , explicitBottomPadding(false) + , explicitImplicitSize(false) { } @@ -2820,7 +2821,8 @@ void QQuickTextInputPrivate::updateLayout() line.setLineWidth(INT_MAX); const bool wasInLayout = inLayout; inLayout = true; - q->setImplicitWidth(qCeil(line.naturalTextWidth()) + q->leftPadding() + q->rightPadding()); + if (!extra.isAllocated() || !extra->explicitImplicitSize) + q->setImplicitWidth(qCeil(line.naturalTextWidth()) + q->leftPadding() + q->rightPadding()); inLayout = wasInLayout; if (inLayout) // probably the result of a binding loop, but by letting it return; // get this far we'll get a warning to that effect. @@ -2851,10 +2853,12 @@ void QQuickTextInputPrivate::updateLayout() q->polish(); q->update(); - if (!requireImplicitWidth && !q->widthValid()) - q->setImplicitSize(width + q->leftPadding() + q->rightPadding(), height + q->topPadding() + q->bottomPadding()); - else - q->setImplicitHeight(height + q->topPadding() + q->bottomPadding()); + if (!extra.isAllocated() || !extra->explicitImplicitSize) { + if (!requireImplicitWidth && !q->widthValid()) + q->setImplicitSize(width + q->leftPadding() + q->rightPadding(), height + q->topPadding() + q->bottomPadding()); + else + q->setImplicitHeight(height + q->topPadding() + q->bottomPadding()); + } updateBaselineOffset(); diff --git a/src/quick/items/qquicktextinput_p_p.h b/src/quick/items/qquicktextinput_p_p.h index cf0a6f5273..4946adc7e7 100644 --- a/src/quick/items/qquicktextinput_p_p.h +++ b/src/quick/items/qquicktextinput_p_p.h @@ -84,6 +84,7 @@ public: bool explicitLeftPadding : 1; bool explicitRightPadding : 1; bool explicitBottomPadding : 1; + bool explicitImplicitSize : 1; }; QLazilyAllocated extra;