diff options
author | Liang Qi <liang.qi@qt.io> | 2017-03-10 10:56:21 +0100 |
---|---|---|
committer | J-P Nurmi <jpnurmi@qt.io> | 2017-03-10 10:57:04 +0100 |
commit | 8be6bac83ddf958e9658465630b86afcb0728800 (patch) | |
tree | 6576e0ee428d7dfe0cd85222d56d939ef1047e63 | |
parent | abc657ada6377d12e919113699da6e6960633516 (diff) | |
parent | e91c9feab8a0cf4cff71cc68ab0f001b1531504f (diff) |
Merge remote-tracking branch 'origin/5.8' into 5.9
Conflicts:
src/imports/controls/universal/qtquickcontrols2universalstyleplugin.cpp
src/quicktemplates2/qquicktextarea.cpp
src/quicktemplates2/qquicktextfield.cpp
Change-Id: Ie80a2d3bcbb961a38e3dffa247547d3d860c231a
9 files changed, 146 insertions, 9 deletions
diff --git a/src/imports/controls/material/qtquickcontrols2materialstyleplugin.cpp b/src/imports/controls/material/qtquickcontrols2materialstyleplugin.cpp index 0deb429c..3f3a66b0 100644 --- a/src/imports/controls/material/qtquickcontrols2materialstyleplugin.cpp +++ b/src/imports/controls/material/qtquickcontrols2materialstyleplugin.cpp @@ -99,6 +99,7 @@ void QtQuickControls2MaterialStylePlugin::initializeEngine(QQmlEngine *engine, c qmlRegisterType(typeUrl(QStringLiteral("CheckIndicator.qml")), import, 2, 0, "CheckIndicator"); qmlRegisterType(typeUrl(QStringLiteral("CursorDelegate.qml")), import, 2, 0, "CursorDelegate"); qmlRegisterType(typeUrl(QStringLiteral("ElevationEffect.qml")), import, 2, 0, "ElevationEffect"); + qmlRegisterType(typeUrl(QStringLiteral("RadioIndicator.qml")), import, 2, 0, "RadioIndicator"); qmlRegisterType(typeUrl(QStringLiteral("RectangularGlow.qml")), import, 2, 0, "RectangularGlow"); qmlRegisterType(typeUrl(QStringLiteral("SliderHandle.qml")), import, 2, 0, "SliderHandle"); qmlRegisterType(typeUrl(QStringLiteral("SwitchIndicator.qml")), import, 2, 0, "SwitchIndicator"); diff --git a/src/imports/controls/universal/qtquickcontrols2universalstyleplugin.cpp b/src/imports/controls/universal/qtquickcontrols2universalstyleplugin.cpp index 29f2b7cc..017a1aad 100644 --- a/src/imports/controls/universal/qtquickcontrols2universalstyleplugin.cpp +++ b/src/imports/controls/universal/qtquickcontrols2universalstyleplugin.cpp @@ -92,6 +92,8 @@ void QtQuickControls2UniversalStylePlugin::initializeEngine(QQmlEngine *engine, qmlRegisterType<QQuickUniversalFocusRectangle>(import, 2, 0, "FocusRectangle"); qmlRegisterType<QQuickUniversalBusyIndicator>(import, 2, 0, "BusyIndicatorImpl"); qmlRegisterType<QQuickUniversalProgressBar>(import, 2, 0, "ProgressBarImpl"); + + qmlRegisterType(typeUrl(QStringLiteral("CheckIndicator.qml")), import, 2, 0, "CheckIndicator"); qmlRegisterType(typeUrl(QStringLiteral("RadioIndicator.qml")), import, 2, 0, "RadioIndicator"); qmlRegisterType(typeUrl(QStringLiteral("SwitchIndicator.qml")), import, 2, 0, "SwitchIndicator"); } diff --git a/src/quicktemplates2/qquickapplicationwindow.cpp b/src/quicktemplates2/qquickapplicationwindow.cpp index c094d454..dcf1b5f0 100644 --- a/src/quicktemplates2/qquickapplicationwindow.cpp +++ b/src/quicktemplates2/qquickapplicationwindow.cpp @@ -294,6 +294,8 @@ QQuickApplicationWindow::QQuickApplicationWindow(QWindow *parent) QQuickApplicationWindow::~QQuickApplicationWindow() { Q_D(QQuickApplicationWindow); + d->setActiveFocusControl(nullptr); + disconnect(this, SIGNAL(activeFocusItemChanged()), this, SLOT(_q_updateActiveFocus())); if (d->header) QQuickItemPrivate::get(d->header)->removeItemChangeListener(d, QQuickItemPrivate::Geometry | QQuickItemPrivate::Visibility | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight); diff --git a/src/quicktemplates2/qquickpopup.cpp b/src/quicktemplates2/qquickpopup.cpp index ace82553..9cdb194e 100644 --- a/src/quicktemplates2/qquickpopup.cpp +++ b/src/quicktemplates2/qquickpopup.cpp @@ -427,6 +427,9 @@ void QQuickPopupPrivate::setWindow(QQuickWindow *newWindow) window = newWindow; emit q->windowChanged(newWindow); + + if (complete && visible && window) + transitionManager.transitionEnter(); } void QQuickPopupPrivate::itemDestroyed(QQuickItem *item) @@ -1728,15 +1731,17 @@ void QQuickPopup::classBegin() void QQuickPopup::componentComplete() { Q_D(QQuickPopup); - d->complete = true; if (!parentItem()) { if (QQuickItem *item = qobject_cast<QQuickItem *>(parent())) setParentItem(item); else if (QQuickWindow *window = qobject_cast<QQuickWindow *>(parent())) setParentItem(window->contentItem()); } - if (d->visible) + + if (d->visible && d->window) d->transitionManager.transitionEnter(); + + d->complete = true; d->popupItem->componentComplete(); } diff --git a/src/quicktemplates2/qquicktextarea.cpp b/src/quicktemplates2/qquicktextarea.cpp index 9fbf9764..21d74dd8 100644 --- a/src/quicktemplates2/qquicktextarea.cpp +++ b/src/quicktemplates2/qquicktextarea.cpp @@ -358,11 +358,13 @@ void QQuickTextAreaPrivate::implicitHeightChanged() void QQuickTextAreaPrivate::readOnlyChanged(bool isReadOnly) { + Q_UNUSED(isReadOnly); #if QT_CONFIG(accessibility) if (accessibleAttached) accessibleAttached->set_readOnly(isReadOnly); -#else - Q_UNUSED(isReadOnly) +#endif +#if QT_CONFIG(cursor) + q_func()->setCursor(isReadOnly ? Qt::ArrowCursor : Qt::IBeamCursor); #endif } diff --git a/src/quicktemplates2/qquicktextfield.cpp b/src/quicktemplates2/qquicktextfield.cpp index a15f923f..e6ca2496 100644 --- a/src/quicktemplates2/qquicktextfield.cpp +++ b/src/quicktemplates2/qquicktextfield.cpp @@ -221,11 +221,13 @@ void QQuickTextFieldPrivate::implicitHeightChanged() void QQuickTextFieldPrivate::readOnlyChanged(bool isReadOnly) { + Q_UNUSED(isReadOnly); #if QT_CONFIG(accessibility) if (accessibleAttached) accessibleAttached->set_readOnly(isReadOnly); -#else - Q_UNUSED(isReadOnly) +#endif +#if QT_CONFIG(cursor) + q_func()->setCursor(isReadOnly ? Qt::ArrowCursor : Qt::IBeamCursor); #endif } diff --git a/tests/auto/applicationwindow/data/clearfocusondestruction.qml b/tests/auto/applicationwindow/data/clearfocusondestruction.qml new file mode 100644 index 00000000..3589439e --- /dev/null +++ b/tests/auto/applicationwindow/data/clearfocusondestruction.qml @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.7 +import QtQuick.Controls 2.1 +import QtQuick.Layouts 1.3 +import QtGraphicalEffects 1.0 + +ApplicationWindow { + width: 200 + height: 200 + visible: true + + property alias textfield: textfield + + /* + * The code below is the simplest way we can trigger that the signal + * activeFocusItemChanged() is emitted during destruction of the + * ApplicationWindow. This caused a crash in QQuickApplicationWindow. + */ + FastBlur { + id: fastBlur + anchors.fill: parent + radius: 30 + source: ShaderEffectSource { + id: effectsource + sourceItem: textfield + sourceRect: Qt.rect( 0, 0, fastBlur.width, fastBlur.height ) + } + } + + TextField { + id: textfield + anchors.bottom: parent.bottom + focus: true + } +} diff --git a/tests/auto/applicationwindow/tst_applicationwindow.cpp b/tests/auto/applicationwindow/tst_applicationwindow.cpp index 2a3f849c..b72bb8f2 100644 --- a/tests/auto/applicationwindow/tst_applicationwindow.cpp +++ b/tests/auto/applicationwindow/tst_applicationwindow.cpp @@ -72,6 +72,7 @@ private slots: void activeFocusControl_data(); void activeFocusControl(); void focusAfterPopupClosed(); + void clearFocusOnDestruction(); void layout(); }; @@ -685,6 +686,47 @@ void tst_applicationwindow::focusAfterPopupClosed() QCOMPARE(spy.count(), 2); } +void tst_applicationwindow::clearFocusOnDestruction() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.loadUrl(testFileUrl("clearfocusondestruction.qml")); + QScopedPointer<QQuickWindow> window(qobject_cast<QQuickWindow*>(component.create())); + QVERIFY(window); + + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + QVERIFY(QGuiApplication::focusWindow() == window.data()); + + QQuickItem* contentItem = window->contentItem(); + QVERIFY(contentItem); + QVERIFY(contentItem->hasActiveFocus()); + + QQuickItem* focusScope = window->property("textfield").value<QQuickItem*>(); + QVERIFY(focusScope); + QVERIFY(focusScope->hasActiveFocus()); + + QSignalSpy spy(window.data(), SIGNAL(activeFocusControlChanged())); + // destroy the window, do not crash + window.reset(); + + /* + QQuickWindow::activeFocusItemChanged() is emitted inconsistently and + only for certain use cases. Ideally it should be emitted whenever a + QQuickWindow with a focus item is destroyed, but it doesn't... It might + also be favorable to not emit it for performance reason. + + However, activeFocusControlChanged() is emitted more consistently, which + of course makes it inconsistent with the emission of + activeFocusItemChanged().... + + Therefore, if you have good reasons to change the behavior (and not emit + it) take the test below with a grain of salt. + */ + QCOMPARE(spy.count(), 1); +} + void tst_applicationwindow::layout() { QQmlEngine engine; diff --git a/tests/auto/snippets/tst_snippets.cpp b/tests/auto/snippets/tst_snippets.cpp index e5e3ab9e..f870ec7d 100644 --- a/tests/auto/snippets/tst_snippets.cpp +++ b/tests/auto/snippets/tst_snippets.cpp @@ -53,6 +53,7 @@ private slots: void screenshots_data(); private: + QQuickView view; QMap<QString, QStringPair> snippetPaths; QMap<QString, QStringPair> screenshotSnippetPaths; }; @@ -97,7 +98,15 @@ static void loadAndShow(QQuickView *view, const QString &source) QSignalSpy warnings(view->engine(), SIGNAL(warnings(QList<QQmlError>))); QVERIFY(warnings.isValid()); - view->setSource(QUrl::fromLocalFile(source)); + QUrl url = QUrl::fromLocalFile(source); + QQmlComponent *component = new QQmlComponent(view->engine(), view); + component->loadUrl(url); + + QObject *root = component->beginCreate(view->rootContext()); + QVERIFY(root); + view->setContent(url, component, root); + component->completeCreate(); + QCOMPARE(view->status(), QQuickView::Ready); QVERIFY(view->errors().isEmpty()); QVERIFY(view->rootObject()); @@ -113,7 +122,6 @@ void tst_Snippets::verify() { QFETCH(QString, input); - QQuickView view; loadAndShow(&view, input); QGuiApplication::processEvents(); } @@ -132,7 +140,6 @@ void tst_Snippets::screenshots() QFETCH(QString, input); QFETCH(QString, output); - QQuickView view; loadAndShow(&view, input); QSharedPointer<QQuickItemGrabResult> result = view.contentItem()->grabToImage(); |