diff options
author | J-P Nurmi <jpnurmi@qt.io> | 2018-02-15 11:22:14 +0100 |
---|---|---|
committer | J-P Nurmi <jpnurmi@qt.io> | 2018-02-15 11:22:23 +0100 |
commit | f6fec74d4238e304643b99880bdfd8ee32c8578e (patch) | |
tree | f3880de9e9890cb6b140ba5722d91819b800616f | |
parent | 72d5d88afe64a76f2026e4a45a4858a13917d4f0 (diff) | |
parent | d95e67c291d213cdbf41b23c535b47aa3a553ab5 (diff) |
Merge remote-tracking branch 'origin/5.11' into dev
Change-Id: Id3333e9bb67ced4c6dbae5845512fe1927a7b858
38 files changed, 679 insertions, 355 deletions
diff --git a/dist/changes-5.10.1 b/dist/changes-5.10.1 new file mode 100644 index 00000000..c94cb75d --- /dev/null +++ b/dist/changes-5.10.1 @@ -0,0 +1,49 @@ +Qt 5.10.1 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.10.0. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +http://doc.qt.io/qt-5/index.html + +The Qt version 5.10 series is binary compatible with the 5.9.x series. +Applications compiled for 5.9 will continue to run with 5.10. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +This release contains all fixes included in the Qt 5.9.4 release. + +**************************************************************************** +* Qt 5.10.1 Changes * +**************************************************************************** + +Controls +-------- + + - AbstractButton: + * [QTBUG-65193] Made button's text win over action's when both are + specified. + + - Action: + * [QTBUG-65108] Fixed an issue where a checkable action would toggle + twice when toggling an associated checkable button. + * [QTBUG-65889] Fixed shortcuts in Repeater. + +Styles +------ + + - Imagine: + * [QTBUG-65500] Fixed to respect user font settings from + qtquickcontrols2.conf. + +Third-Party Code +---------------- + + - [QTBUG-65409] Document constants from AngularJS in + src/imports/controls/material/ElevationEffect.qml diff --git a/examples/quickcontrols2/imagine/automotive/doc/src/qtquickcontrols2-automotive.qdoc b/examples/quickcontrols2/imagine/automotive/doc/src/qtquickcontrols2-automotive.qdoc index 2107e6ab..9a8c1883 100644 --- a/examples/quickcontrols2/imagine/automotive/doc/src/qtquickcontrols2-automotive.qdoc +++ b/examples/quickcontrols2/imagine/automotive/doc/src/qtquickcontrols2-automotive.qdoc @@ -26,7 +26,7 @@ ****************************************************************************/ /*! - \example automotive + \example imagine/automotive \title Qt Quick Controls 2 - Imagine Style Example: Automotive \ingroup qtquickcontrols2-examples \brief An automotive user interface using custom Imagine style assets. diff --git a/examples/quickcontrols2/imagine/musicplayer/doc/src/qtquickcontrols2-musicplayer.qdoc b/examples/quickcontrols2/imagine/musicplayer/doc/src/qtquickcontrols2-musicplayer.qdoc index cca44e83..960c683d 100644 --- a/examples/quickcontrols2/imagine/musicplayer/doc/src/qtquickcontrols2-musicplayer.qdoc +++ b/examples/quickcontrols2/imagine/musicplayer/doc/src/qtquickcontrols2-musicplayer.qdoc @@ -26,7 +26,7 @@ ****************************************************************************/ /*! - \example musicplayer + \example imagine/musicplayer \title Qt Quick Controls 2 - Imagine Style Example: Music Player \ingroup qtquickcontrols2-examples \brief An audio player user interface using custom Imagine style assets. diff --git a/src/imports/controls/TextArea.qml b/src/imports/controls/TextArea.qml index 00a97957..04a44eae 100644 --- a/src/imports/controls/TextArea.qml +++ b/src/imports/controls/TextArea.qml @@ -66,7 +66,7 @@ T.TextArea { text: control.placeholderText font: control.font opacity: 0.5 - color: control.palette.text + color: control.color verticalAlignment: control.verticalAlignment visible: !control.length && !control.preeditText && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter) elide: Text.ElideRight diff --git a/src/imports/controls/TextField.qml b/src/imports/controls/TextField.qml index 333c5bba..4b80d8be 100644 --- a/src/imports/controls/TextField.qml +++ b/src/imports/controls/TextField.qml @@ -67,7 +67,7 @@ T.TextField { text: control.placeholderText font: control.font opacity: 0.5 - color: control.palette.text + color: control.color verticalAlignment: control.verticalAlignment visible: !control.length && !control.preeditText && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter) elide: Text.ElideRight diff --git a/src/imports/controls/doc/src/qtquickcontrols2-index.qdoc b/src/imports/controls/doc/src/qtquickcontrols2-index.qdoc index 2ce0eb92..cbe21282 100644 --- a/src/imports/controls/doc/src/qtquickcontrols2-index.qdoc +++ b/src/imports/controls/doc/src/qtquickcontrols2-index.qdoc @@ -102,6 +102,11 @@ \li 2.3 \li 1.0 \row + \li 5.11 + \li 2.11 + \li 2.4 + \li 1.0 + \row \li ... \li ... \li ... diff --git a/src/imports/controls/fusion/TextArea.qml b/src/imports/controls/fusion/TextArea.qml index 56541d89..36d9db04 100644 --- a/src/imports/controls/fusion/TextArea.qml +++ b/src/imports/controls/fusion/TextArea.qml @@ -68,7 +68,7 @@ T.TextArea { opacity: 0.5 text: control.placeholderText font: control.font - color: control.palette.text + color: control.color verticalAlignment: control.verticalAlignment visible: !control.length && !control.preeditText && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter) elide: Text.ElideRight diff --git a/src/imports/controls/fusion/TextField.qml b/src/imports/controls/fusion/TextField.qml index e66857cd..2ea5c967 100644 --- a/src/imports/controls/fusion/TextField.qml +++ b/src/imports/controls/fusion/TextField.qml @@ -68,7 +68,7 @@ T.TextField { opacity: 0.5 text: control.placeholderText font: control.font - color: control.palette.text + color: control.color verticalAlignment: control.verticalAlignment visible: !control.length && !control.preeditText && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter) elide: Text.ElideRight diff --git a/src/imports/controls/fusion/qtquickcontrols2fusionstyleplugin.cpp b/src/imports/controls/fusion/qtquickcontrols2fusionstyleplugin.cpp index 2d1a6e28..5bb1d062 100644 --- a/src/imports/controls/fusion/qtquickcontrols2fusionstyleplugin.cpp +++ b/src/imports/controls/fusion/qtquickcontrols2fusionstyleplugin.cpp @@ -69,7 +69,6 @@ public: QtQuickControls2FusionStylePlugin(QObject *parent = nullptr); void registerTypes(const char *uri) override; - void initializeEngine(QQmlEngine *engine, const char *uri) override; QString name() const override; QQuickTheme *createTheme() const override; @@ -84,11 +83,6 @@ void QtQuickControls2FusionStylePlugin::registerTypes(const char *uri) { qmlRegisterModule(uri, 2, 3); // Qt 5.10->2.3 qmlRegisterModule(uri, 2, QT_VERSION_MINOR - 7); // Qt 5.11->2.4, 5.12->2.5... -} - -void QtQuickControls2FusionStylePlugin::initializeEngine(QQmlEngine *engine, const char *uri) -{ - QQuickStylePlugin::initializeEngine(engine, uri); QByteArray import = QByteArray(uri) + ".impl"; qmlRegisterModule(import, 2, QT_VERSION_MINOR - 7); // Qt 5.11->2.4, 5.12->2.5... diff --git a/src/imports/controls/imagine/TextArea.qml b/src/imports/controls/imagine/TextArea.qml index 49153b5d..9867a0bd 100644 --- a/src/imports/controls/imagine/TextArea.qml +++ b/src/imports/controls/imagine/TextArea.qml @@ -70,7 +70,7 @@ T.TextArea { text: control.placeholderText font: control.font - color: control.palette.text + color: control.color verticalAlignment: control.verticalAlignment visible: !control.length && !control.preeditText && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter) elide: Text.ElideRight diff --git a/src/imports/controls/imagine/TextField.qml b/src/imports/controls/imagine/TextField.qml index 09ef5bcb..17827b95 100644 --- a/src/imports/controls/imagine/TextField.qml +++ b/src/imports/controls/imagine/TextField.qml @@ -70,7 +70,7 @@ T.TextField { text: control.placeholderText font: control.font - color: control.palette.text + color: control.color verticalAlignment: control.verticalAlignment visible: !control.length && !control.preeditText && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter) elide: Text.ElideRight diff --git a/src/imports/controls/imagine/qtquickcontrols2imaginestyleplugin.cpp b/src/imports/controls/imagine/qtquickcontrols2imaginestyleplugin.cpp index 3ab8a472..292b8719 100644 --- a/src/imports/controls/imagine/qtquickcontrols2imaginestyleplugin.cpp +++ b/src/imports/controls/imagine/qtquickcontrols2imaginestyleplugin.cpp @@ -64,7 +64,6 @@ public: QtQuickControls2ImagineStylePlugin(QObject *parent = nullptr); void registerTypes(const char *uri) override; - void initializeEngine(QQmlEngine *engine, const char *uri) override; QString name() const override; QQuickTheme *createTheme() const override; @@ -79,11 +78,6 @@ void QtQuickControls2ImagineStylePlugin::registerTypes(const char *uri) { qmlRegisterModule(uri, 2, QT_VERSION_MINOR - 7); // Qt 5.10 -> 2.3, 5.11 -> 2.4, ... qmlRegisterUncreatableType<QQuickImagineStyle>(uri, 2, 3, "Imagine", tr("Imagine is an attached property")); -} - -void QtQuickControls2ImagineStylePlugin::initializeEngine(QQmlEngine *engine, const char *uri) -{ - QQuickStylePlugin::initializeEngine(engine, uri); QByteArray import = QByteArray(uri) + ".impl"; qmlRegisterModule(import, 2, QT_VERSION_MINOR - 7); // Qt 5.10 -> 2.3, 5.11 -> 2.4, ... diff --git a/src/imports/controls/material/Dial.qml b/src/imports/controls/material/Dial.qml index 3d94df18..54469c92 100644 --- a/src/imports/controls/material/Dial.qml +++ b/src/imports/controls/material/Dial.qml @@ -69,8 +69,8 @@ T.Dial { origin.y: handle.height / 2 } ] - implicitWidth: 14 - implicitHeight: 14 + implicitWidth: 10 + implicitHeight: 10 value: control.value handleHasFocus: control.visualFocus diff --git a/src/imports/controls/material/qtquickcontrols2materialstyleplugin.cpp b/src/imports/controls/material/qtquickcontrols2materialstyleplugin.cpp index 4ea1f426..5e0494d5 100644 --- a/src/imports/controls/material/qtquickcontrols2materialstyleplugin.cpp +++ b/src/imports/controls/material/qtquickcontrols2materialstyleplugin.cpp @@ -64,7 +64,6 @@ public: QtQuickControls2MaterialStylePlugin(QObject *parent = nullptr); void registerTypes(const char *uri) override; - void initializeEngine(QQmlEngine *engine, const char *uri) override; QString name() const override; QQuickTheme *createTheme() const override; @@ -79,11 +78,6 @@ void QtQuickControls2MaterialStylePlugin::registerTypes(const char *uri) { qmlRegisterModule(uri, 2, QT_VERSION_MINOR - 7); // Qt 5.7->2.0, 5.8->2.1, 5.9->2.2... qmlRegisterUncreatableType<QQuickMaterialStyle>(uri, 2, 0, "Material", tr("Material is an attached property")); -} - -void QtQuickControls2MaterialStylePlugin::initializeEngine(QQmlEngine *engine, const char *uri) -{ - QQuickStylePlugin::initializeEngine(engine, uri); QByteArray import = QByteArray(uri) + ".impl"; qmlRegisterModule(import, 2, QT_VERSION_MINOR - 7); // Qt 5.7->2.0, 5.8->2.1, 5.9->2.2... diff --git a/src/imports/controls/qtquickcontrols2plugin.cpp b/src/imports/controls/qtquickcontrols2plugin.cpp index dba18fc8..443f0cb8 100644 --- a/src/imports/controls/qtquickcontrols2plugin.cpp +++ b/src/imports/controls/qtquickcontrols2plugin.cpp @@ -78,7 +78,6 @@ class QtQuickControls2Plugin: public QQuickStylePlugin public: QtQuickControls2Plugin(QObject *parent = nullptr); void registerTypes(const char *uri) override; - void initializeEngine(QQmlEngine *engine, const char *uri) override; QString name() const override; QQuickTheme *createTheme() const override; @@ -165,25 +164,6 @@ void QtQuickControls2Plugin::registerTypes(const char *uri) qmlRegisterType(selector.select(QStringLiteral("MenuBar.qml")), uri, 2, 3, "MenuBar"); qmlRegisterType(selector.select(QStringLiteral("MenuBarItem.qml")), uri, 2, 3, "MenuBarItem"); qmlRegisterUncreatableType<QQuickOverlay>(uri, 2, 3, "Overlay", QStringLiteral("Overlay is only available as an attached property.")); -} - -static QObject *styleSingleton(QQmlEngine *engine, QJSEngine *scriptEngine) -{ - Q_UNUSED(engine); - Q_UNUSED(scriptEngine); - return new QQuickDefaultStyle; -} - -static QObject *colorSingleton(QQmlEngine *engine, QJSEngine *scriptEngine) -{ - Q_UNUSED(engine); - Q_UNUSED(scriptEngine); - return new QQuickColor; -} - -void QtQuickControls2Plugin::initializeEngine(QQmlEngine *engine, const char *uri) -{ - QQuickStylePlugin::initializeEngine(engine, uri); const QByteArray import = QByteArray(uri) + ".impl"; qmlRegisterModule(import, 2, QT_VERSION_MINOR - 7); // Qt 5.7->2.0, 5.8->2.1, 5.9->2.2... @@ -198,7 +178,11 @@ void QtQuickControls2Plugin::initializeEngine(QQmlEngine *engine, const char *ur #if QT_CONFIG(quick_listview) && QT_CONFIG(quick_pathview) qmlRegisterType<QQuickTumblerView>(import, 2, 1, "TumblerView"); #endif - qmlRegisterSingletonType<QQuickDefaultStyle>(import, 2, 1, "Default", styleSingleton); + qmlRegisterSingletonType<QQuickDefaultStyle>(import, 2, 1, "Default", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject* { + Q_UNUSED(engine); + Q_UNUSED(scriptEngine); + return new QQuickDefaultStyle; + }); // QtQuick.Controls.impl 2.2 (Qt 5.9) qmlRegisterType<QQuickClippedText>(import, 2, 2, "ClippedText"); @@ -208,7 +192,11 @@ void QtQuickControls2Plugin::initializeEngine(QQmlEngine *engine, const char *ur // QtQuick.Controls.impl 2.3 (Qt 5.10) qmlRegisterType<QQuickColorImage>(import, 2, 3, "ColorImage"); qmlRegisterType<QQuickIconImage>(import, 2, 3, "IconImage"); - qmlRegisterSingletonType<QQuickColor>(import, 2, 3, "Color", colorSingleton); + qmlRegisterSingletonType<QQuickColor>(import, 2, 3, "Color", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject* { + Q_UNUSED(engine); + Q_UNUSED(scriptEngine); + return new QQuickColor; + }); qmlRegisterType<QQuickIconLabel>(import, 2, 3, "IconLabel"); qmlRegisterType<QQuickCheckLabel>(import, 2, 3, "CheckLabel"); qmlRegisterType<QQuickMnemonicLabel>(import, 2, 3, "MnemonicLabel"); diff --git a/src/imports/controls/universal/Dial.qml b/src/imports/controls/universal/Dial.qml index 539400cd..d2634713 100644 --- a/src/imports/controls/universal/Dial.qml +++ b/src/imports/controls/universal/Dial.qml @@ -56,8 +56,8 @@ T.Dial { } handle: Rectangle { - implicitWidth: 20 - implicitHeight: 20 + implicitWidth: 14 + implicitHeight: 14 x: background.x + background.width / 2 - handle.width / 2 y: background.y + background.height / 2 - handle.height / 2 diff --git a/src/imports/controls/universal/qquickuniversalstyle.cpp b/src/imports/controls/universal/qquickuniversalstyle.cpp index 157d5ddb..dbc409fd 100644 --- a/src/imports/controls/universal/qquickuniversalstyle.cpp +++ b/src/imports/controls/universal/qquickuniversalstyle.cpp @@ -536,66 +536,59 @@ static QByteArray resolveSetting(const QByteArray &env, const QSharedPointer<QSe return value; } -void QQuickUniversalStyle::init() -{ - static bool globalsInitialized = false; - if (!globalsInitialized) { - QSharedPointer<QSettings> settings = QQuickStylePrivate::settings(QStringLiteral("Universal")); - - bool ok = false; - QByteArray themeValue = resolveSetting("QT_QUICK_CONTROLS_UNIVERSAL_THEME", settings, QStringLiteral("Theme")); - Theme themeEnum = toEnumValue<Theme>(themeValue, &ok); - if (ok) - GlobalTheme = m_theme = qquickuniversal_effective_theme(themeEnum); - else if (!themeValue.isEmpty()) - qWarning().nospace().noquote() << "Universal: unknown theme value: " << themeValue; - - QByteArray accentValue = resolveSetting("QT_QUICK_CONTROLS_UNIVERSAL_ACCENT", settings, QStringLiteral("Accent")); - Color accentEnum = toEnumValue<Color>(accentValue, &ok); - if (ok) { - GlobalAccent = m_accent = qquickuniversal_accent_color(accentEnum); - } else if (!accentValue.isEmpty()) { - QColor color(accentValue.constData()); - if (color.isValid()) - GlobalAccent = m_accent = color.rgba(); - else - qWarning().nospace().noquote() << "Universal: unknown accent value: " << accentValue; - } +void QQuickUniversalStyle::initGlobals() +{ + QSharedPointer<QSettings> settings = QQuickStylePrivate::settings(QStringLiteral("Universal")); + + bool ok = false; + QByteArray themeValue = resolveSetting("QT_QUICK_CONTROLS_UNIVERSAL_THEME", settings, QStringLiteral("Theme")); + Theme themeEnum = toEnumValue<Theme>(themeValue, &ok); + if (ok) + GlobalTheme = qquickuniversal_effective_theme(themeEnum); + else if (!themeValue.isEmpty()) + qWarning().nospace().noquote() << "Universal: unknown theme value: " << themeValue; + + QByteArray accentValue = resolveSetting("QT_QUICK_CONTROLS_UNIVERSAL_ACCENT", settings, QStringLiteral("Accent")); + Color accentEnum = toEnumValue<Color>(accentValue, &ok); + if (ok) { + GlobalAccent = qquickuniversal_accent_color(accentEnum); + } else if (!accentValue.isEmpty()) { + QColor color(accentValue.constData()); + if (color.isValid()) + GlobalAccent = color.rgba(); + else + qWarning().nospace().noquote() << "Universal: unknown accent value: " << accentValue; + } - QByteArray foregroundValue = resolveSetting("QT_QUICK_CONTROLS_UNIVERSAL_FOREGROUND", settings, QStringLiteral("Foreground")); - Color foregroundEnum = toEnumValue<Color>(foregroundValue, &ok); - if (ok) { - GlobalForeground = m_foreground = qquickuniversal_accent_color(foregroundEnum); - HasGlobalForeground = m_hasForeground = true; - } else if (!foregroundValue.isEmpty()) { - QColor color(foregroundValue.constData()); - if (color.isValid()) { - GlobalForeground = m_foreground = color.rgba(); - HasGlobalForeground = m_hasForeground = true; - } else { - qWarning().nospace().noquote() << "Universal: unknown foreground value: " << foregroundValue; - } + QByteArray foregroundValue = resolveSetting("QT_QUICK_CONTROLS_UNIVERSAL_FOREGROUND", settings, QStringLiteral("Foreground")); + Color foregroundEnum = toEnumValue<Color>(foregroundValue, &ok); + if (ok) { + GlobalForeground = qquickuniversal_accent_color(foregroundEnum); + HasGlobalForeground = true; + } else if (!foregroundValue.isEmpty()) { + QColor color(foregroundValue.constData()); + if (color.isValid()) { + GlobalForeground = color.rgba(); + HasGlobalForeground = true; + } else { + qWarning().nospace().noquote() << "Universal: unknown foreground value: " << foregroundValue; } + } - QByteArray backgroundValue = resolveSetting("QT_QUICK_CONTROLS_UNIVERSAL_BACKGROUND", settings, QStringLiteral("Background")); - Color backgroundEnum = toEnumValue<Color>(backgroundValue, &ok); - if (ok) { - GlobalBackground = m_background = qquickuniversal_accent_color(backgroundEnum); - HasGlobalBackground = m_hasBackground = true; - } else if (!backgroundValue.isEmpty()) { - QColor color(backgroundValue.constData()); - if (color.isValid()) { - GlobalBackground = m_background = color.rgba(); - HasGlobalBackground = m_hasBackground = true; - } else { - qWarning().nospace().noquote() << "Universal: unknown background value: " << backgroundValue; - } + QByteArray backgroundValue = resolveSetting("QT_QUICK_CONTROLS_UNIVERSAL_BACKGROUND", settings, QStringLiteral("Background")); + Color backgroundEnum = toEnumValue<Color>(backgroundValue, &ok); + if (ok) { + GlobalBackground = qquickuniversal_accent_color(backgroundEnum); + HasGlobalBackground = true; + } else if (!backgroundValue.isEmpty()) { + QColor color(backgroundValue.constData()); + if (color.isValid()) { + GlobalBackground = color.rgba(); + HasGlobalBackground = true; + } else { + qWarning().nospace().noquote() << "Universal: unknown background value: " << backgroundValue; } - - globalsInitialized = true; } - - QQuickAttachedObject::init(); // TODO: lazy init? } bool QQuickUniversalStyle::variantToRgba(const QVariant &var, const char *name, QRgb *rgba) const diff --git a/src/imports/controls/universal/qquickuniversalstyle_p.h b/src/imports/controls/universal/qquickuniversalstyle_p.h index 196048ef..eb9f6d83 100644 --- a/src/imports/controls/universal/qquickuniversalstyle_p.h +++ b/src/imports/controls/universal/qquickuniversalstyle_p.h @@ -200,6 +200,8 @@ public: QColor systemColor(SystemColor role) const; + static void initGlobals(); + Q_SIGNALS: void themeChanged(); void accentChanged(); @@ -211,7 +213,6 @@ protected: void attachedParentChange(QQuickAttachedObject *newParent, QQuickAttachedObject *oldParent) override; private: - void init(); bool variantToRgba(const QVariant &var, const char *name, QRgb *rgba) const; // These reflect whether a color value was explicitly set on the specific diff --git a/src/imports/controls/universal/qtquickcontrols2universalstyleplugin.cpp b/src/imports/controls/universal/qtquickcontrols2universalstyleplugin.cpp index b9934c73..fa55e18a 100644 --- a/src/imports/controls/universal/qtquickcontrols2universalstyleplugin.cpp +++ b/src/imports/controls/universal/qtquickcontrols2universalstyleplugin.cpp @@ -61,7 +61,6 @@ public: QtQuickControls2UniversalStylePlugin(QObject *parent = nullptr); void registerTypes(const char *uri) override; - void initializeEngine(QQmlEngine *engine, const char *uri) override; QString name() const override; QQuickTheme *createTheme() const override; @@ -70,17 +69,13 @@ public: QtQuickControls2UniversalStylePlugin::QtQuickControls2UniversalStylePlugin(QObject *parent) : QQuickStylePlugin(parent) { initResources(); + QQuickUniversalStyle::initGlobals(); } void QtQuickControls2UniversalStylePlugin::registerTypes(const char *uri) { qmlRegisterModule(uri, 2, QT_VERSION_MINOR - 7); // Qt 5.7->2.0, 5.8->2.1, 5.9->2.2... qmlRegisterUncreatableType<QQuickUniversalStyle>(uri, 2, 0, "Universal", tr("Universal is an attached property")); -} - -void QtQuickControls2UniversalStylePlugin::initializeEngine(QQmlEngine *engine, const char *uri) -{ - QQuickStylePlugin::initializeEngine(engine, uri); QByteArray import = QByteArray(uri) + ".impl"; qmlRegisterModule(import, 2, QT_VERSION_MINOR - 7); // Qt 5.7->2.0, 5.8->2.1, 5.9->2.2... diff --git a/src/imports/platform/qquickplatformmenu.cpp b/src/imports/platform/qquickplatformmenu.cpp index 82adb6c3..ec5c4804 100644 --- a/src/imports/platform/qquickplatformmenu.cpp +++ b/src/imports/platform/qquickplatformmenu.cpp @@ -44,6 +44,7 @@ #include <QtGui/qcursor.h> #include <QtGui/qpa/qplatformtheme.h> #include <QtGui/private/qguiapplication_p.h> +#include <QtGui/private/qhighdpiscaling_p.h> #include <QtQml/private/qqmlengine_p.h> #include <QtQml/private/qv4scopedvalue_p.h> #include <QtQml/private/qv4qobjectwrapper_p.h> @@ -705,8 +706,9 @@ void QQuickPlatformMenu::open(QQmlV4Function *args) targetRect.moveTo(pos); #endif } - - m_handle->showPopup(window, targetRect, menuItem ? menuItem->handle() : nullptr); + m_handle->showPopup(window, + QHighDpi::toNativePixels(targetRect, window), + menuItem ? menuItem->handle() : nullptr); } /*! diff --git a/src/imports/templates/qtquicktemplates2plugin.cpp b/src/imports/templates/qtquicktemplates2plugin.cpp index a67fca2c..d775a019 100644 --- a/src/imports/templates/qtquicktemplates2plugin.cpp +++ b/src/imports/templates/qtquicktemplates2plugin.cpp @@ -299,6 +299,7 @@ void QtQuickTemplates2Plugin::registerTypes(const char *uri) qmlRegisterType<QQuickDialog, 3>(uri, 2, 3, "Dialog"); qmlRegisterType<QQuickDialogButtonBox, 3>(uri, 2, 3, "DialogButtonBox"); qRegisterMetaType<QQuickIcon>(); + qmlRegisterType<QQuickLabel, 3>(uri, 2, 3, "Label"); qmlRegisterType<QQuickMenu, 3>(uri, 2, 3, "Menu"); qmlRegisterType<QQuickMenuBar>(uri, 2, 3, "MenuBar"); qmlRegisterType<QQuickMenuBarItem>(uri, 2, 3, "MenuBarItem"); @@ -311,6 +312,8 @@ void QtQuickTemplates2Plugin::registerTypes(const char *uri) qmlRegisterType<QQuickScrollIndicator, 3>(uri, 2, 3, "ScrollIndicator"); qmlRegisterType<QQuickSlider, 3>(uri, 2, 3, "Slider"); qmlRegisterType<QQuickSpinBox, 3>(uri, 2, 3, "SpinBox"); + qmlRegisterType<QQuickTextArea, 3>(uri, 2, 3, "TextArea"); + qmlRegisterType<QQuickTextField, 3>(uri, 2, 3, "TextField"); // NOTE: register the latest revisions of all template/control base classes to // make revisioned properties available to their subclasses (synced with Qt 5.10) diff --git a/src/quicktemplates2/qquickabstractbutton.cpp b/src/quicktemplates2/qquickabstractbutton.cpp index 238669c6..0a8b8ddf 100644 --- a/src/quicktemplates2/qquickabstractbutton.cpp +++ b/src/quicktemplates2/qquickabstractbutton.cpp @@ -328,6 +328,21 @@ void QQuickAbstractButtonPrivate::setText(const QString &newText, bool isExplici q->buttonChange(QQuickAbstractButton::ButtonTextChange); } +void QQuickAbstractButtonPrivate::updateEffectiveIcon() +{ + Q_Q(QQuickAbstractButton); + // We store effectiveIcon because we need to be able to tell if the icon has actually changed. + // If we only stored our icon and the action's icon, and resolved in the getter, we'd have + // no way of knowing what the old value was here. As an added benefit, we only resolve when + // something has changed, as opposed to doing it unconditionally in the icon() getter. + const QQuickIcon newEffectiveIcon = action ? icon.resolve(action->icon()) : icon; + if (newEffectiveIcon == effectiveIcon) + return; + + effectiveIcon = newEffectiveIcon; + emit q->iconChanged(); +} + void QQuickAbstractButtonPrivate::click() { Q_Q(QQuickAbstractButton); @@ -720,17 +735,14 @@ void QQuickAbstractButton::setIndicator(QQuickItem *indicator) QQuickIcon QQuickAbstractButton::icon() const { Q_D(const QQuickAbstractButton); - return d->icon; + return d->effectiveIcon; } void QQuickAbstractButton::setIcon(const QQuickIcon &icon) { Q_D(QQuickAbstractButton); - if (d->icon == icon) - return; - d->icon = icon; - emit iconChanged(); + d->updateEffectiveIcon(); } /*! @@ -792,7 +804,7 @@ void QQuickAbstractButton::setAction(QQuickAction *action) QObjectPrivate::disconnect(oldAction, &QQuickAction::triggered, d, &QQuickAbstractButtonPrivate::click); QObjectPrivate::disconnect(oldAction, &QQuickAction::textChanged, d, &QQuickAbstractButtonPrivate::actionTextChange); - disconnect(oldAction, &QQuickAction::iconChanged, this, &QQuickAbstractButton::setIcon); + QObjectPrivate::disconnect(oldAction, &QQuickAction::iconChanged, d, &QQuickAbstractButtonPrivate::updateEffectiveIcon); disconnect(oldAction, &QQuickAction::checkedChanged, this, &QQuickAbstractButton::setChecked); disconnect(oldAction, &QQuickAction::checkableChanged, this, &QQuickAbstractButton::setCheckable); disconnect(oldAction, &QQuickAction::enabledChanged, this, &QQuickItem::setEnabled); @@ -803,33 +815,11 @@ void QQuickAbstractButton::setAction(QQuickAction *action) QObjectPrivate::connect(action, &QQuickAction::triggered, d, &QQuickAbstractButtonPrivate::click); QObjectPrivate::connect(action, &QQuickAction::textChanged, d, &QQuickAbstractButtonPrivate::actionTextChange); - connect(action, &QQuickAction::iconChanged, this, &QQuickAbstractButton::setIcon); + QObjectPrivate::connect(action, &QQuickAction::iconChanged, d, &QQuickAbstractButtonPrivate::updateEffectiveIcon); connect(action, &QQuickAction::checkedChanged, this, &QQuickAbstractButton::setChecked); connect(action, &QQuickAction::checkableChanged, this, &QQuickAbstractButton::setCheckable); connect(action, &QQuickAction::enabledChanged, this, &QQuickItem::setEnabled); - QQuickIcon actionIcon = action->icon(); - - QString name = actionIcon.name(); - if (!name.isEmpty()) - d->icon.setName(name); - - QUrl source = actionIcon.source(); - if (!source.isEmpty()) - d->icon.setSource(source); - - int width = actionIcon.width(); - if (width > 0) - d->icon.setWidth(width); - - int height = actionIcon.height(); - if (height) - d->icon.setHeight(height); - - QColor color = actionIcon.color(); - if (color != Qt::transparent) - d->icon.setColor(color); - setChecked(action->isChecked()); setCheckable(action->isCheckable()); setEnabled(action->isEnabled()); @@ -840,6 +830,8 @@ void QQuickAbstractButton::setAction(QQuickAction *action) if (oldText != text()) buttonChange(ButtonTextChange); + d->updateEffectiveIcon(); + emit actionChanged(); } diff --git a/src/quicktemplates2/qquickabstractbutton_p_p.h b/src/quicktemplates2/qquickabstractbutton_p_p.h index 1c493cd8..bb74e143 100644 --- a/src/quicktemplates2/qquickabstractbutton_p_p.h +++ b/src/quicktemplates2/qquickabstractbutton_p_p.h @@ -96,6 +96,8 @@ public: void actionTextChange(); void setText(const QString &text, bool isExplicit); + void updateEffectiveIcon(); + void click(); void trigger(); void toggle(bool value); @@ -124,6 +126,7 @@ public: QKeySequence shortcut; #endif QQuickIcon icon; + QQuickIcon effectiveIcon; QPointF pressPoint; QPointF movePoint; Qt::MouseButtons pressButtons; diff --git a/src/quicktemplates2/qquickcheckdelegate.cpp b/src/quicktemplates2/qquickcheckdelegate.cpp index 9fd8c183..b53877df 100644 --- a/src/quicktemplates2/qquickcheckdelegate.cpp +++ b/src/quicktemplates2/qquickcheckdelegate.cpp @@ -166,11 +166,8 @@ void QQuickCheckDelegate::setCheckState(Qt::CheckState state) if (d->checkState == state) return; - if (!d->tristate && state == Qt::PartiallyChecked) - setTristate(true); - bool wasChecked = isChecked(); - d->checked = state != Qt::Unchecked; + d->checked = state == Qt::Checked; d->checkState = state; emit checkStateChanged(); if (d->checked != wasChecked) diff --git a/src/quicktemplates2/qquickcontrol.cpp b/src/quicktemplates2/qquickcontrol.cpp index 3c3b67f8..c2d63f02 100644 --- a/src/quicktemplates2/qquickcontrol.cpp +++ b/src/quicktemplates2/qquickcontrol.cpp @@ -163,11 +163,19 @@ bool QQuickControlPrivate::acceptTouch(const QTouchEvent::TouchPoint &point) } #endif +static void setActiveFocus(QQuickControl *control, Qt::FocusReason reason) +{ + QQuickControlPrivate *d = QQuickControlPrivate::get(control); + if (d->subFocusItem && d->window && d->flags & QQuickItem::ItemIsFocusScope) + QQuickWindowPrivate::get(d->window)->clearFocusInScope(control, d->subFocusItem, reason); + control->forceActiveFocus(reason); +} + void QQuickControlPrivate::handlePress(const QPointF &) { Q_Q(QQuickControl); if ((focusPolicy & Qt::ClickFocus) == Qt::ClickFocus && !QGuiApplication::styleHints()->setFocusOnTouchRelease()) - q->forceActiveFocus(Qt::MouseFocusReason); + setActiveFocus(q, Qt::MouseFocusReason); } void QQuickControlPrivate::handleMove(const QPointF &point) @@ -184,7 +192,7 @@ void QQuickControlPrivate::handleRelease(const QPointF &) { Q_Q(QQuickControl); if ((focusPolicy & Qt::ClickFocus) == Qt::ClickFocus && QGuiApplication::styleHints()->setFocusOnTouchRelease()) - q->forceActiveFocus(Qt::MouseFocusReason); + setActiveFocus(q, Qt::MouseFocusReason); touchId = -1; } @@ -1683,7 +1691,7 @@ void QQuickControl::wheelEvent(QWheelEvent *event) { Q_D(QQuickControl); if ((d->focusPolicy & Qt::WheelFocus) == Qt::WheelFocus) - forceActiveFocus(Qt::MouseFocusReason); + setActiveFocus(this, Qt::MouseFocusReason); event->setAccepted(d->wheelEnabled); } diff --git a/src/quicktemplates2/qquickicon.cpp b/src/quicktemplates2/qquickicon.cpp index 0b0127d3..79af62b1 100644 --- a/src/quicktemplates2/qquickicon.cpp +++ b/src/quicktemplates2/qquickicon.cpp @@ -44,7 +44,8 @@ public: QQuickIconPrivate() : width(0), height(0), - color(Qt::transparent) + color(Qt::transparent), + resolveMask(0) { } @@ -53,6 +54,18 @@ public: int width; int height; QColor color; + + enum ResolveProperties { + NameResolved = 0x0001, + SourceResolved = 0x0002, + WidthResolved = 0x0004, + HeightResolved = 0x0008, + ColorResolved = 0x0010, + AllPropertiesResolved = 0x1ffff + }; + + // This is based on QFont's resolve_mask. + int resolveMask; }; QQuickIcon::QQuickIcon() @@ -101,7 +114,17 @@ QString QQuickIcon::name() const void QQuickIcon::setName(const QString &name) { + if ((d->resolveMask & QQuickIconPrivate::NameResolved) && d->name == name) + return; + d->name = name; + d->resolveMask |= QQuickIconPrivate::NameResolved; +} + +void QQuickIcon::resetName() +{ + d->name = QString(); + d->resolveMask &= ~QQuickIconPrivate::NameResolved; } QUrl QQuickIcon::source() const @@ -111,7 +134,17 @@ QUrl QQuickIcon::source() const void QQuickIcon::setSource(const QUrl &source) { + if ((d->resolveMask & QQuickIconPrivate::SourceResolved) && d->source == source) + return; + d->source = source; + d->resolveMask |= QQuickIconPrivate::SourceResolved; +} + +void QQuickIcon::resetSource() +{ + d->source = QString(); + d->resolveMask &= ~QQuickIconPrivate::SourceResolved; } int QQuickIcon::width() const @@ -121,7 +154,17 @@ int QQuickIcon::width() const void QQuickIcon::setWidth(int width) { + if ((d->resolveMask & QQuickIconPrivate::WidthResolved) && d->width == width) + return; + d->width = width; + d->resolveMask |= QQuickIconPrivate::WidthResolved; +} + +void QQuickIcon::resetWidth() +{ + d->width = 0; + d->resolveMask &= ~QQuickIconPrivate::WidthResolved; } int QQuickIcon::height() const @@ -131,7 +174,17 @@ int QQuickIcon::height() const void QQuickIcon::setHeight(int height) { + if ((d->resolveMask & QQuickIconPrivate::HeightResolved) && d->height == height) + return; + d->height = height; + d->resolveMask |= QQuickIconPrivate::HeightResolved; +} + +void QQuickIcon::resetHeight() +{ + d->height = 0; + d->resolveMask &= ~QQuickIconPrivate::HeightResolved; } QColor QQuickIcon::color() const @@ -141,12 +194,39 @@ QColor QQuickIcon::color() const void QQuickIcon::setColor(const QColor &color) { + if ((d->resolveMask & QQuickIconPrivate::ColorResolved) && d->color == color) + return; + d->color = color; + d->resolveMask |= QQuickIconPrivate::ColorResolved; } void QQuickIcon::resetColor() { d->color = Qt::transparent; + d->resolveMask &= ~QQuickIconPrivate::ColorResolved; +} + +QQuickIcon QQuickIcon::resolve(const QQuickIcon &other) const +{ + QQuickIcon resolved = *this; + + if (!(d->resolveMask & QQuickIconPrivate::NameResolved)) + resolved.setName(other.name()); + + if (!(d->resolveMask & QQuickIconPrivate::SourceResolved)) + resolved.setSource(other.source()); + + if (!(d->resolveMask & QQuickIconPrivate::WidthResolved)) + resolved.setWidth(other.width()); + + if (!(d->resolveMask & QQuickIconPrivate::HeightResolved)) + resolved.setHeight(other.height()); + + if (!(d->resolveMask & QQuickIconPrivate::ColorResolved)) + resolved.setColor(other.color()); + + return resolved; } QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickicon_p.h b/src/quicktemplates2/qquickicon_p.h index 6e28f2a9..2c95bc9d 100644 --- a/src/quicktemplates2/qquickicon_p.h +++ b/src/quicktemplates2/qquickicon_p.h @@ -62,10 +62,10 @@ class QQuickIconPrivate; class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickIcon { Q_GADGET - Q_PROPERTY(QString name READ name WRITE setName FINAL) - Q_PROPERTY(QUrl source READ source WRITE setSource FINAL) - Q_PROPERTY(int width READ width WRITE setWidth FINAL) - Q_PROPERTY(int height READ height WRITE setHeight FINAL) + Q_PROPERTY(QString name READ name WRITE setName RESET resetName FINAL) + Q_PROPERTY(QUrl source READ source WRITE setSource RESET resetSource FINAL) + Q_PROPERTY(int width READ width WRITE setWidth RESET resetWidth FINAL) + Q_PROPERTY(int height READ height WRITE setHeight RESET resetHeight FINAL) Q_PROPERTY(QColor color READ color WRITE setColor RESET resetColor FINAL) public: @@ -81,20 +81,26 @@ public: QString name() const; void setName(const QString &name); + void resetName(); QUrl source() const; void setSource(const QUrl &source); + void resetSource(); int width() const; void setWidth(int width); + void resetWidth(); int height() const; void setHeight(int height); + void resetHeight(); QColor color() const; void setColor(const QColor &color); void resetColor(); + QQuickIcon resolve(const QQuickIcon &other) const; + private: QSharedDataPointer<QQuickIconPrivate> d; }; diff --git a/src/quicktemplates2/qquickpopup.cpp b/src/quicktemplates2/qquickpopup.cpp index 0524c688..97e347d7 100644 --- a/src/quicktemplates2/qquickpopup.cpp +++ b/src/quicktemplates2/qquickpopup.cpp @@ -450,12 +450,11 @@ bool QQuickPopupPrivate::prepareExitTransition() return false; if (transitionState != ExitTransition) { - if (focus) { - // The setFocus(false) call below removes any active focus before we're - // able to check it in finalizeExitTransition. - hadActiveFocusBeforeExitTransition = popupItem->hasActiveFocus(); + // The setFocus(false) call below removes any active focus before we're + // able to check it in finalizeExitTransition. + hadActiveFocusBeforeExitTransition = popupItem->hasActiveFocus(); + if (focus) popupItem->setFocus(false); - } transitionState = ExitTransition; hideOverlay(); emit q->aboutToHide(); diff --git a/src/quicktemplates2/qquickspinbox.cpp b/src/quicktemplates2/qquickspinbox.cpp index 5e74f6ef..525de945 100644 --- a/src/quicktemplates2/qquickspinbox.cpp +++ b/src/quicktemplates2/qquickspinbox.cpp @@ -818,7 +818,7 @@ void QQuickSpinBox::setWrap(bool wrap) This property holds the textual value of the spinbox. - The value of the property is based on \l textFromValue() and \l {Control::} + The value of the property is based on \l textFromValue and \l {Control::} {locale}, and equal to: \badcode var text = spinBox.textFromValue(spinBox.value, spinBox.locale) diff --git a/src/quicktemplates2/qquickstackview_p.cpp b/src/quicktemplates2/qquickstackview_p.cpp index 0167ad97..606d259a 100644 --- a/src/quicktemplates2/qquickstackview_p.cpp +++ b/src/quicktemplates2/qquickstackview_p.cpp @@ -73,6 +73,8 @@ void QQuickStackViewPrivate::setCurrentItem(QQuickStackElement *element) currentItem = item; if (element) element->setVisible(true); + if (item) + item->setFocus(true); emit q->currentItemChanged(); } diff --git a/tests/auto/controls/data/tst_abstractbutton.qml b/tests/auto/controls/data/tst_abstractbutton.qml index b266b183..d611a45a 100644 --- a/tests/auto/controls/data/tst_abstractbutton.qml +++ b/tests/auto/controls/data/tst_abstractbutton.qml @@ -392,6 +392,208 @@ TestCase { compare(spy.count, data.resetChanged ? 1 : 0) } + function test_actionIcon_data() { + var data = [] + + // Save duplicating the rows by reusing them with different properties of the same type. + // This means that the first loop will test icon.name and the second one will test icon.source. + var stringPropertyValueSuffixes = [ + { propertyName: "name", valueSuffix: "IconName" }, + { propertyName: "source", valueSuffix: "IconSource" } + ] + + for (var i = 0; i < stringPropertyValueSuffixes.length; ++i) { + var propertyName = stringPropertyValueSuffixes[i].propertyName + var valueSuffix = stringPropertyValueSuffixes[i].valueSuffix + + var buttonPropertyValue = "Button" + valueSuffix + var buttonPropertyValue2 = "Button" + valueSuffix + "2" + var actionPropertyValue = "Action" + valueSuffix + var actionPropertyValue2 = "Action" + valueSuffix + "2" + + data.push({ tag: "implicit " + propertyName, property: propertyName, + initButton: undefined, initAction: actionPropertyValue, + assignExpected: actionPropertyValue, assignChanged: true, + resetExpected: "", resetChanged: true }) + data.push({ tag: "explicit " + propertyName, property: propertyName, + initButton: buttonPropertyValue, initAction: actionPropertyValue, + assignExpected: buttonPropertyValue, assignChanged: false, + resetExpected: buttonPropertyValue, resetChanged: false }) + data.push({ tag: "empty button " + propertyName, property: propertyName, + initButton: "", initAction: actionPropertyValue, + assignExpected: "", assignChanged: false, + resetExpected: "", resetChanged: false }) + data.push({ tag: "empty action " + propertyName, property: propertyName, + initButton: buttonPropertyValue, initAction: "", + assignExpected: buttonPropertyValue, assignChanged: false, + resetExpected: buttonPropertyValue, resetChanged: false }) + data.push({ tag: "empty both " + propertyName, property: propertyName, + initButton: undefined, initAction: "", + assignExpected: "", assignChanged: false, + resetExpected: "", resetChanged: false }) + data.push({ tag: "modify button " + propertyName, property: propertyName, + initButton: undefined, initAction: actionPropertyValue, + assignExpected: actionPropertyValue, assignChanged: true, + modifyButton: buttonPropertyValue2, + modifyButtonExpected: buttonPropertyValue2, modifyButtonChanged: true, + resetExpected: buttonPropertyValue2, resetChanged: false }) + data.push({ tag: "modify implicit action " + propertyName, property: propertyName, + initButton: undefined, initAction: actionPropertyValue, + assignExpected: actionPropertyValue, assignChanged: true, + modifyAction: actionPropertyValue2, + modifyActionExpected: actionPropertyValue2, modifyActionChanged: true, + resetExpected: "", resetChanged: true }) + data.push({ tag: "modify explicit action " + propertyName, property: propertyName, + initButton: buttonPropertyValue, initAction: actionPropertyValue, + assignExpected: buttonPropertyValue, assignChanged: false, + modifyAction: actionPropertyValue2, + modifyActionExpected: buttonPropertyValue, modifyActionChanged: false, + resetExpected: buttonPropertyValue, resetChanged: false }) + } + + var intPropertyNames = [ + "width", + "height", + ] + + for (i = 0; i < intPropertyNames.length; ++i) { + propertyName = intPropertyNames[i] + + buttonPropertyValue = 20 + buttonPropertyValue2 = 21 + actionPropertyValue = 40 + actionPropertyValue2 = 41 + var defaultValue = 0 + + data.push({ tag: "implicit " + propertyName, property: propertyName, + initButton: undefined, initAction: actionPropertyValue, + assignExpected: actionPropertyValue, assignChanged: true, + resetExpected: defaultValue, resetChanged: true }) + data.push({ tag: "explicit " + propertyName, property: propertyName, + initButton: buttonPropertyValue, initAction: actionPropertyValue, + assignExpected: buttonPropertyValue, assignChanged: false, + resetExpected: buttonPropertyValue, resetChanged: false }) + data.push({ tag: "default button " + propertyName, property: propertyName, + initButton: defaultValue, initAction: actionPropertyValue, + assignExpected: defaultValue, assignChanged: false, + resetExpected: defaultValue, resetChanged: false }) + data.push({ tag: "default action " + propertyName, property: propertyName, + initButton: buttonPropertyValue, initAction: defaultValue, + assignExpected: buttonPropertyValue, assignChanged: false, + resetExpected: buttonPropertyValue, resetChanged: false }) + data.push({ tag: "default both " + propertyName, property: propertyName, + initButton: undefined, initAction: defaultValue, + assignExpected: defaultValue, assignChanged: false, + resetExpected: defaultValue, resetChanged: false }) + data.push({ tag: "modify button " + propertyName, property: propertyName, + initButton: undefined, initAction: actionPropertyValue, + assignExpected: actionPropertyValue, assignChanged: true, + modifyButton: buttonPropertyValue2, + modifyButtonExpected: buttonPropertyValue2, modifyButtonChanged: true, + resetExpected: buttonPropertyValue2, resetChanged: false }) + data.push({ tag: "modify implicit action " + propertyName, property: propertyName, + initButton: undefined, initAction: actionPropertyValue, + assignExpected: actionPropertyValue, assignChanged: true, + modifyAction: actionPropertyValue2, + modifyActionExpected: actionPropertyValue2, modifyActionChanged: true, + resetExpected: defaultValue, resetChanged: true }) + data.push({ tag: "modify explicit action " + propertyName, property: propertyName, + initButton: buttonPropertyValue, initAction: actionPropertyValue, + assignExpected: buttonPropertyValue, assignChanged: false, + modifyAction: actionPropertyValue2, + modifyActionExpected: buttonPropertyValue, modifyActionChanged: false, + resetExpected: buttonPropertyValue, resetChanged: false }) + } + + propertyName = "color" + buttonPropertyValue = "#aa0000" + buttonPropertyValue2 = "#ff0000" + actionPropertyValue = "#0000aa" + actionPropertyValue2 = "#0000ff" + defaultValue = "#00000000" + + data.push({ tag: "implicit " + propertyName, property: propertyName, + initButton: undefined, initAction: actionPropertyValue, + assignExpected: actionPropertyValue, assignChanged: true, + resetExpected: defaultValue, resetChanged: true }) + data.push({ tag: "explicit " + propertyName, property: propertyName, + initButton: buttonPropertyValue, initAction: actionPropertyValue, + assignExpected: buttonPropertyValue, assignChanged: false, + resetExpected: buttonPropertyValue, resetChanged: false }) + data.push({ tag: "default button " + propertyName, property: propertyName, + initButton: defaultValue, initAction: actionPropertyValue, + assignExpected: defaultValue, assignChanged: false, + resetExpected: defaultValue, resetChanged: false }) + data.push({ tag: "default action " + propertyName, property: propertyName, + initButton: buttonPropertyValue, initAction: defaultValue, + assignExpected: buttonPropertyValue, assignChanged: false, + resetExpected: buttonPropertyValue, resetChanged: false }) + data.push({ tag: "default both " + propertyName, property: propertyName, + initButton: undefined, initAction: defaultValue, + assignExpected: defaultValue, assignChanged: false, + resetExpected: defaultValue, resetChanged: false }) + data.push({ tag: "modify button " + propertyName, property: propertyName, + initButton: undefined, initAction: actionPropertyValue, + assignExpected: actionPropertyValue, assignChanged: true, + modifyButton: buttonPropertyValue2, + modifyButtonExpected: buttonPropertyValue2, modifyButtonChanged: true, + resetExpected: buttonPropertyValue2, resetChanged: false }) + data.push({ tag: "modify implicit action " + propertyName, property: propertyName, + initButton: undefined, initAction: actionPropertyValue, + assignExpected: actionPropertyValue, assignChanged: true, + modifyAction: actionPropertyValue2, + modifyActionExpected: actionPropertyValue2, modifyActionChanged: true, + resetExpected: defaultValue, resetChanged: true }) + data.push({ tag: "modify explicit action " + propertyName, property: propertyName, + initButton: buttonPropertyValue, initAction: actionPropertyValue, + assignExpected: buttonPropertyValue, assignChanged: false, + modifyAction: actionPropertyValue2, + modifyActionExpected: buttonPropertyValue, modifyActionChanged: false, + resetExpected: buttonPropertyValue, resetChanged: false }) + + return data; + } + + function test_actionIcon(data) { + var control = createTemporaryObject(button, testCase) + verify(control) + control.icon[data.property] = data.initButton + + var act = action.createObject(control) + act.icon[data.property] = data.initAction + + var spy = signalSpy.createObject(control, {target: control, signalName: "iconChanged"}) + verify(spy.valid) + + // assign action + spy.clear() + control.action = act + compare(control.icon[data.property], data.assignExpected) + compare(spy.count, data.assignChanged ? 1 : 0) + + // modify button + if (data.hasOwnProperty("modifyButton")) { + spy.clear() + control.icon[data.property] = data.modifyButton + compare(control.icon[data.property], data.modifyButtonExpected) + compare(spy.count, data.modifyButtonChanged ? 1 : 0) + } + + // modify action + if (data.hasOwnProperty("modifyAction")) { + spy.clear() + act.icon[data.property] = data.modifyAction + compare(control.icon[data.property], data.modifyActionExpected) + compare(spy.count, data.modifyActionChanged ? 1 : 0) + } + + // reset action + spy.clear() + control.action = null + compare(control.icon[data.property], data.resetExpected) + compare(spy.count, data.resetChanged ? 1 : 0) + } + Component { id: actionButton AbstractButton { @@ -412,8 +614,6 @@ TestCase { // initial values compare(control.text, "Default") - compare(control.icon.name, "default") - compare(control.icon.source, "qrc:/icons/default.png") compare(control.checkable, true) compare(control.checked, true) compare(control.enabled, false) @@ -423,14 +623,10 @@ TestCase { // changes via action control.action.text = "Action" - control.action.icon.name = "action" - control.action.icon.source = "qrc:/icons/action.png" control.action.checkable = false control.action.checked = false control.action.enabled = true compare(control.text, "Action") // propagates - compare(control.icon.name, "action") // propagates - compare(control.icon.source, "qrc:/icons/action.png") // propagates compare(control.checkable, false) // propagates compare(control.checked, false) // propagates compare(control.enabled, true) // propagates @@ -438,31 +634,26 @@ TestCase { // changes via button control.text = "Button" - control.icon.name = "button" - control.icon.source = "qrc:/icons/button.png" control.checkable = true control.checked = true control.enabled = false compare(control.text, "Button") - compare(control.icon.name, "button") - compare(control.icon.source, "qrc:/icons/button.png") compare(control.checkable, true) compare(control.checked, true) compare(control.enabled, false) compare(control.action.text, "Action") // does NOT propagate - compare(control.action.icon.name, "action") // does NOT propagate - compare(control.action.icon.source, "qrc:/icons/action.png") // does NOT propagate compare(control.action.checkable, true) // propagates compare(control.action.checked, true) // propagates compare(control.action.enabled, true) // does NOT propagate compare(textSpy.count, 2) - // remove the action so that only the button's text is left + // remove the action so that only the button's properties are left control.action = null compare(control.text, "Button") compare(textSpy.count, 2) - // setting an action while button has text shouldn't cause a change in the button's effective text + // setting an action while button has a particular property set + // shouldn't cause a change in the button's effective property value var secondAction = createTemporaryObject(action, testCase) verify(secondAction) secondAction.text = "SecondAction" @@ -470,7 +661,7 @@ TestCase { compare(control.text, "Button") compare(textSpy.count, 2) - // test setting an action with empty text + // test setting an action whose properties aren't set var thirdAction = createTemporaryObject(action, testCase) verify(thirdAction) control.action = thirdAction diff --git a/tests/auto/controls/data/tst_drawer.qml b/tests/auto/controls/data/tst_drawer.qml deleted file mode 100644 index 5446b969..00000000 --- a/tests/auto/controls/data/tst_drawer.qml +++ /dev/null @@ -1,118 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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.2 -import QtTest 1.0 -import QtQuick.Controls 2.3 - -TestCase { - id: testCase - width: 400 - height: 400 - visible: true - when: windowShown - name: "Drawer" - - Component { - id: drawer - Drawer { } - } - - function test_defaults() { - var control = createTemporaryObject(drawer, testCase) - compare(control.edge, Qt.LeftEdge) - compare(control.position, 0.0) - compare(control.dragMargin, Qt.styleHints.startDragDistance) - compare(control.parent, Overlay.overlay) - } - - function test_invalidEdge() { - var control = createTemporaryObject(drawer, testCase) - compare(control.edge, Qt.LeftEdge) - - // Test an invalid value - it should warn and ignore it. - ignoreWarning(Qt.resolvedUrl("tst_drawer.qml") + ":65:9: QML Drawer: invalid edge value - valid values are: Qt.TopEdge, Qt.LeftEdge, Qt.RightEdge, Qt.BottomEdge") - control.edge = Drawer.Right - compare(control.edge, Qt.LeftEdge) - } - - Component { - id: rectDrawer - - Drawer { - Rectangle { - width: 200 - height: 400 - color: "steelblue" - } - } - } - - function test_swipeVelocity() { - skip("QTBUG-52003"); - - var control = createTemporaryObject(rectDrawer, testCase) - verify(control.contentItem) - compare(control.edge, Qt.LeftEdge) - compare(control.position, 0.0) - - var dragDistance = Math.max(20, Qt.styleHints.startDragDistance + 5) - var distance = dragDistance * 1.1 - if (distance >= control.width * 0.7) - skip("This test requires a startDragDistance that is less than the opening threshold of the drawer") - - mousePress(control, 0, 0, Qt.LeftButton) - mouseMove(control, distance, 0) - verify(control.position > 0) - tryCompare(control, "position", distance / control.contentItem.width) - mouseRelease(control, distance, 0, Qt.LeftButton) - tryCompare(control, "position", 1.0) - } -} diff --git a/tests/auto/controls/data/tst_stackview.qml b/tests/auto/controls/data/tst_stackview.qml index 6f6497c5..3c0f0273 100644 --- a/tests/auto/controls/data/tst_stackview.qml +++ b/tests/auto/controls/data/tst_stackview.qml @@ -61,7 +61,7 @@ TestCase { name: "StackView" Item { id: item } - TextField { id: textField } + Component { id: textField; TextField { } } Component { id: component; Item { } } Component { @@ -323,22 +323,33 @@ TestCase { compare(item.height, control.height) } - function test_focus() { + function test_focus_data() { + return [ + { tag: "true", focus: true, forceActiveFocus: false }, + { tag: "false", focus: false, forceActiveFocus: false }, + { tag: "forceActiveFocus()", focus: false, forceActiveFocus: true }, + ] + } + + function test_focus(data) { var control = createTemporaryObject(stackView, testCase, {initialItem: item, width: 200, height: 200}) verify(control) - control.forceActiveFocus() - verify(control.activeFocus) + if (data.focus) + control.focus = true + if (data.forceActiveFocus) + control.forceActiveFocus() + compare(control.activeFocus, data.focus || data.forceActiveFocus) - control.push(textField, StackView.Immediate) - compare(control.currentItem, textField) - textField.forceActiveFocus() - verify(textField.activeFocus) + var page = control.push(textField, StackView.Immediate) + verify(page) + compare(control.currentItem, page) + compare(page.activeFocus, control.activeFocus) control.pop(StackView.Immediate) compare(control.currentItem, item) - verify(control.activeFocus) - verify(!textField.activeFocus) + compare(item.activeFocus, data.focus || data.forceActiveFocus) + verify(!page.activeFocus) } function test_find() { diff --git a/tests/auto/focus/tst_focus.cpp b/tests/auto/focus/tst_focus.cpp index 3d4a8875..958b996b 100644 --- a/tests/auto/focus/tst_focus.cpp +++ b/tests/auto/focus/tst_focus.cpp @@ -67,6 +67,9 @@ private slots: void reason(); void visualFocus(); + + void scope_data(); + void scope(); }; void tst_focus::initTestCase() @@ -326,6 +329,86 @@ void tst_focus::visualFocus() QVERIFY(!button->property("showFocus").toBool()); } +void tst_focus::scope_data() +{ + QTest::addColumn<QString>("name"); + + QTest::newRow("Frame") << "Frame"; + QTest::newRow("GroupBox") << "Frame"; + QTest::newRow("Page") << "Page"; + QTest::newRow("Pane") << "Pane"; + QTest::newRow("StackView") << "StackView"; +} + +void tst_focus::scope() +{ + QFETCH(QString, name); + + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData(QString("import QtQuick 2.9; import QtQuick.Controls 2.2; ApplicationWindow { property alias child: child; width: 100; height: 100; %1 { anchors.fill: parent; Item { id: child; width: 10; height: 10 } } }").arg(name).toUtf8(), QUrl()); + + QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(component.create())); + QVERIFY2(window, qPrintable(component.errorString())); + + QQuickControl *control = qobject_cast<QQuickControl *>(window->contentItem()->childItems().first()); + QVERIFY(control); + + control->setFocusPolicy(Qt::WheelFocus); + control->setAcceptedMouseButtons(Qt::LeftButton); + + QQuickItem *child = window->property("child").value<QQuickItem *>(); + QVERIFY(child); + + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + + struct TouchDeviceDeleter + { + static inline void cleanup(QTouchDevice *device) + { + QWindowSystemInterface::unregisterTouchDevice(device); + delete device; + } + }; + + QScopedPointer<QTouchDevice, TouchDeviceDeleter> device(new QTouchDevice); + device->setType(QTouchDevice::TouchScreen); + QWindowSystemInterface::registerTouchDevice(device.data()); + + child->forceActiveFocus(); + QVERIFY(child->hasActiveFocus()); + QVERIFY(control->hasActiveFocus()); + + // Qt::ClickFocus (mouse) + QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(control->width() / 2, control->height() / 2)); + QVERIFY(!child->hasActiveFocus()); + QVERIFY(control->hasActiveFocus()); + + // reset + child->forceActiveFocus(); + QVERIFY(child->hasActiveFocus()); + QVERIFY(control->hasActiveFocus()); + + // Qt::ClickFocus (touch) + QTest::touchEvent(window.data(), device.data()).press(0, QPoint(control->width() / 2, control->height() / 2)); + QTest::touchEvent(window.data(), device.data()).release(0, QPoint(control->width() / 2, control->height() / 2)); + QVERIFY(!child->hasActiveFocus()); + QVERIFY(control->hasActiveFocus()); + + // reset + child->forceActiveFocus(); + QVERIFY(child->hasActiveFocus()); + QVERIFY(control->hasActiveFocus()); + + // Qt::WheelFocus + QWheelEvent wheelEvent(QPoint(control->width() / 2, control->height() / 2), 10, Qt::NoButton, Qt::NoModifier); + QGuiApplication::sendEvent(control, &wheelEvent); + QVERIFY(!child->hasActiveFocus()); + QVERIFY(control->hasActiveFocus()); +} + QTEST_MAIN(tst_focus) #include "tst_focus.moc" diff --git a/tests/auto/qquickdrawer/tst_qquickdrawer.cpp b/tests/auto/qquickdrawer/tst_qquickdrawer.cpp index 9f6a556f..60c5b189 100644 --- a/tests/auto/qquickdrawer/tst_qquickdrawer.cpp +++ b/tests/auto/qquickdrawer/tst_qquickdrawer.cpp @@ -38,6 +38,7 @@ #include <QtTest/qsignalspy.h> #include "../shared/util.h" #include "../shared/visualtestutil.h" +#include "../shared/qtest_quickcontrols.h" #include <QtGui/qstylehints.h> #include <QtGui/qtouchdevice.h> @@ -61,6 +62,9 @@ class tst_QQuickDrawer : public QQmlDataTest private slots: void initTestCase(); + void defaults(); + void invalidEdge(); + void visible_data(); void visible(); @@ -126,6 +130,40 @@ void tst_QQuickDrawer::initTestCase() QWindowSystemInterface::registerTouchDevice(touchDevice.data()); } +void tst_QQuickDrawer::defaults() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.loadUrl(testFileUrl("window.qml")); + + QScopedPointer<QObject> root(component.create()); + QVERIFY2(!root.isNull(), qPrintable(component.errorString())); + + QQuickDrawer *drawer = root->property("drawer").value<QQuickDrawer *>(); + QVERIFY(drawer); + QCOMPARE(drawer->edge(), Qt::LeftEdge); + QCOMPARE(drawer->position(), 0.0); + QCOMPARE(drawer->dragMargin(), qGuiApp->styleHints()->startDragDistance()); +} + +void tst_QQuickDrawer::invalidEdge() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.loadUrl(testFileUrl("window.qml")); + + QScopedPointer<QObject> root(component.create()); + QVERIFY2(!root.isNull(), qPrintable(component.errorString())); + + QQuickDrawer *drawer = root->property("drawer").value<QQuickDrawer *>(); + QVERIFY(drawer); + + // Test an invalid value - it should warn and ignore it. + QTest::ignoreMessage(QtWarningMsg, qUtf8Printable(testFileUrl("window.qml").toString() + ":61:5: QML Drawer: invalid edge value - valid values are: Qt.TopEdge, Qt.LeftEdge, Qt.RightEdge, Qt.BottomEdge")); + drawer->setEdge(static_cast<Qt::Edge>(QQuickDrawer::Right)); + QCOMPARE(drawer->edge(), Qt::LeftEdge); +} + void tst_QQuickDrawer::visible_data() { QTest::addColumn<QString>("source"); @@ -1219,6 +1257,6 @@ void tst_QQuickDrawer::nonModal() QVERIFY(closedSpy.wait()); } -QTEST_MAIN(tst_QQuickDrawer) +QTEST_QUICKCONTROLS_MAIN(tst_QQuickDrawer) #include "tst_qquickdrawer.moc" diff --git a/tests/auto/qquickpopup/tst_qquickpopup.cpp b/tests/auto/qquickpopup/tst_qquickpopup.cpp index a1e5e246..9230116b 100644 --- a/tests/auto/qquickpopup/tst_qquickpopup.cpp +++ b/tests/auto/qquickpopup/tst_qquickpopup.cpp @@ -38,6 +38,7 @@ #include <QtTest/qsignalspy.h> #include "../shared/util.h" #include "../shared/visualtestutil.h" +#include "../shared/qtest_quickcontrols.h" #include <QtGui/qpa/qwindowsysteminterface.h> #include <QtQuickTemplates2/private/qquickapplicationwindow_p.h> @@ -119,7 +120,7 @@ void tst_QQuickPopup::visible() QVERIFY(overlay->childItems().contains(popupItem)); popup->close(); - QVERIFY(!popup->isVisible()); + QTRY_VERIFY(!popup->isVisible()); QVERIFY(!overlay->childItems().contains(popupItem)); popup->setVisible(true); @@ -127,7 +128,7 @@ void tst_QQuickPopup::visible() QVERIFY(overlay->childItems().contains(popupItem)); popup->setVisible(false); - QVERIFY(!popup->isVisible()); + QTRY_VERIFY(!popup->isVisible()); QVERIFY(!overlay->childItems().contains(popupItem)); } @@ -164,7 +165,7 @@ void tst_QQuickPopup::state() QCOMPARE(closedSpy.count(), 0); popup->close(); - QCOMPARE(visibleChangedSpy.count(), 2); + QTRY_COMPARE(visibleChangedSpy.count(), 2); QCOMPARE(aboutToShowSpy.count(), 1); QCOMPARE(aboutToHideSpy.count(), 1); QCOMPARE(openedSpy.count(), 1); @@ -236,6 +237,7 @@ void tst_QQuickPopup::overlay() popup->open(); QVERIFY(popup->isVisible()); QVERIFY(overlay->isVisible()); + QTRY_VERIFY(popup->isOpened()); QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1)); QCOMPARE(overlayPressedSignal.count(), ++overlayPressCount); @@ -243,16 +245,15 @@ void tst_QQuickPopup::overlay() QCOMPARE(overlayAttachedPressedSignal.count(), overlayPressCount); QCOMPARE(overlayAttachedReleasedSignal.count(), overlayReleaseCount); + QTRY_VERIFY(!popup->isVisible()); + QVERIFY(!overlay->isVisible()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1)); QCOMPARE(overlayPressedSignal.count(), overlayPressCount); QCOMPARE(overlayReleasedSignal.count(), overlayReleaseCount); // no modal-popups open QCOMPARE(overlayAttachedPressedSignal.count(), overlayPressCount); QCOMPARE(overlayAttachedReleasedSignal.count(), overlayReleaseCount); - popup->close(); - QVERIFY(!popup->isVisible()); - QVERIFY(!overlay->isVisible()); - popup->setDim(dim); popup->setModal(modal); popup->setClosePolicy(QQuickPopup::CloseOnReleaseOutside); @@ -261,6 +262,7 @@ void tst_QQuickPopup::overlay() popup->open(); QVERIFY(popup->isVisible()); QVERIFY(overlay->isVisible()); + QTRY_VERIFY(popup->isOpened()); QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1)); QCOMPARE(overlayPressedSignal.count(), ++overlayPressCount); @@ -274,8 +276,8 @@ void tst_QQuickPopup::overlay() QCOMPARE(overlayAttachedPressedSignal.count(), overlayPressCount); QCOMPARE(overlayAttachedReleasedSignal.count(), overlayReleaseCount); - QVERIFY(!popup->isVisible()); - QCOMPARE(overlay->isVisible(), popup->isVisible()); + QTRY_VERIFY(!popup->isVisible()); + QVERIFY(!overlay->isVisible()); // touch popup->open(); @@ -307,8 +309,8 @@ void tst_QQuickPopup::overlay() QCOMPARE(overlayAttachedPressedSignal.count(), overlayPressCount); QCOMPARE(overlayAttachedReleasedSignal.count(), overlayReleaseCount); - QVERIFY(!popup->isVisible()); - QCOMPARE(overlay->isVisible(), popup->isVisible()); + QTRY_VERIFY(!popup->isVisible()); + QVERIFY(!overlay->isVisible()); // multi-touch popup->open(); @@ -331,7 +333,7 @@ void tst_QQuickPopup::overlay() QCOMPARE(overlayReleasedSignal.count(), overlayReleaseCount); QTest::touchEvent(window, device.data()).release(0, button->mapToScene(QPointF(1, 1)).toPoint()).stationary(1); - QVERIFY(!popup->isVisible()); + QTRY_VERIFY(!popup->isVisible()); QVERIFY(!overlay->isVisible()); QVERIFY(!button->isPressed()); QCOMPARE(overlayPressedSignal.count(), overlayPressCount); @@ -378,12 +380,12 @@ void tst_QQuickPopup::zOrder() QVERIFY(popup->isVisible()); QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1)); - QVERIFY(!popup2->isVisible()); + QTRY_VERIFY(!popup2->isVisible()); QVERIFY(popup->isVisible()); QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1)); QVERIFY(!popup2->isVisible()); - QVERIFY(!popup->isVisible()); + QTRY_VERIFY(!popup->isVisible()); } void tst_QQuickPopup::windowChange() @@ -483,49 +485,55 @@ void tst_QQuickPopup::closePolicy() popup->open(); QVERIFY(popup->isVisible()); + QTRY_VERIFY(popup->isOpened()); // press outside popup and its parent QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1)); if (closePolicy.testFlag(QQuickPopup::CloseOnPressOutside) || closePolicy.testFlag(QQuickPopup::CloseOnPressOutsideParent)) - QVERIFY(!popup->isVisible()); + QTRY_VERIFY(!popup->isVisible()); else QVERIFY(popup->isVisible()); popup->open(); QVERIFY(popup->isVisible()); + QTRY_VERIFY(popup->isOpened()); // release outside popup and its parent QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1)); if (closePolicy.testFlag(QQuickPopup::CloseOnReleaseOutside)) - QVERIFY(!popup->isVisible()); + QTRY_VERIFY(!popup->isVisible()); else QVERIFY(popup->isVisible()); popup->open(); QVERIFY(popup->isVisible()); + QTRY_VERIFY(popup->isOpened()); // press outside popup but inside its parent - QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(button->x(), button->y())); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(button->x() + 1, button->y() + 1)); if (closePolicy.testFlag(QQuickPopup::CloseOnPressOutside) && !closePolicy.testFlag(QQuickPopup::CloseOnPressOutsideParent)) - QVERIFY(!popup->isVisible()); + QTRY_VERIFY(!popup->isVisible()); else QVERIFY(popup->isVisible()); popup->open(); QVERIFY(popup->isVisible()); + QTRY_VERIFY(popup->isOpened()); // release outside popup but inside its parent - QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(button->x(), button->y())); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(button->x() + 1, button->y() + 1)); if (closePolicy.testFlag(QQuickPopup::CloseOnReleaseOutside) && !closePolicy.testFlag(QQuickPopup::CloseOnReleaseOutsideParent)) - QVERIFY(!popup->isVisible()); + QTRY_VERIFY(!popup->isVisible()); else QVERIFY(popup->isVisible()); popup->open(); QVERIFY(popup->isVisible()); + QTRY_VERIFY(popup->isOpened()); // press inside and release outside - QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(button->x() + popup->x(), button->y() + popup->y())); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(button->x() + popup->x() + 1, + button->y() + popup->y() + 1)); QVERIFY(popup->isVisible()); QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1)); QVERIFY(popup->isVisible()); @@ -533,7 +541,7 @@ void tst_QQuickPopup::closePolicy() // escape QTest::keyClick(window, Qt::Key_Escape); if (closePolicy.testFlag(QQuickPopup::CloseOnEscape)) - QVERIFY(!popup->isVisible()); + QTRY_VERIFY(!popup->isVisible()); else QVERIFY(popup->isVisible()); } @@ -556,14 +564,27 @@ void tst_QQuickPopup::activeFocusOnClose1() focusedPopup->open(); QVERIFY(focusedPopup->isVisible()); + QTRY_VERIFY(focusedPopup->isOpened()); QVERIFY(focusedPopup->hasActiveFocus()); nonFocusedPopup->open(); QVERIFY(nonFocusedPopup->isVisible()); + QTRY_VERIFY(nonFocusedPopup->isOpened()); QVERIFY(focusedPopup->hasActiveFocus()); nonFocusedPopup->close(); - QVERIFY(!nonFocusedPopup->isVisible()); + QTRY_VERIFY(!nonFocusedPopup->isVisible()); + QVERIFY(focusedPopup->hasActiveFocus()); + + // QTBUG-66113: force active focus on a popup that did not request focus + nonFocusedPopup->open(); + nonFocusedPopup->forceActiveFocus(); + QVERIFY(nonFocusedPopup->isVisible()); + QTRY_VERIFY(nonFocusedPopup->isOpened()); + QVERIFY(nonFocusedPopup->hasActiveFocus()); + + nonFocusedPopup->close(); + QTRY_VERIFY(!nonFocusedPopup->isVisible()); QVERIFY(focusedPopup->hasActiveFocus()); } @@ -589,16 +610,18 @@ void tst_QQuickPopup::activeFocusOnClose2() popup1->open(); QVERIFY(popup1->isVisible()); + QTRY_VERIFY(popup1->isOpened()); QVERIFY(popup1->hasActiveFocus()); popup2->open(); QVERIFY(popup2->isVisible()); + QTRY_VERIFY(popup2->isOpened()); QVERIFY(popup2->hasActiveFocus()); // Causes popup1.contentItem.forceActiveFocus() to be called, then closes popup2. QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, closePopup2Button->mapToScene(QPointF(closePopup2Button->width() / 2, closePopup2Button->height() / 2)).toPoint()); - QVERIFY(!popup2->isVisible()); + QTRY_VERIFY(!popup2->isVisible()); QVERIFY(popup1->hasActiveFocus()); } @@ -684,7 +707,7 @@ void tst_QQuickPopup::hover() QVERIFY(!childButton->isHovered()); // hover the child button in a popup - QTest::mouseMove(window, QPoint(2, 2)); + QTest::mouseMove(window, QPoint(popup->x() + popup->width() / 2, popup->y() + popup->height() / 2)); QVERIFY(!parentButton->isHovered()); QVERIFY(childButton->isHovered()); @@ -834,35 +857,35 @@ void tst_QQuickPopup::grabber() QVERIFY(combo); menu->open(); - QCOMPARE(menu->isVisible(), true); + QTRY_COMPARE(menu->isOpened(), true); QCOMPARE(popup->isVisible(), false); QCOMPARE(combo->isVisible(), false); // click a menu item to open the popup QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, QPoint(menu->width() / 2, menu->height() / 2)); - QCOMPARE(menu->isVisible(), false); - QCOMPARE(popup->isVisible(), true); + QTRY_COMPARE(menu->isVisible(), false); + QTRY_COMPARE(popup->isOpened(), true); QCOMPARE(combo->isVisible(), false); combo->open(); QCOMPARE(menu->isVisible(), false); QCOMPARE(popup->isVisible(), true); - QCOMPARE(combo->isVisible(), true); + QTRY_COMPARE(combo->isOpened(), true); // click outside to close both the combo popup and the parent popup QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, QPoint(window->width() - 1, window->height() - 1)); QCOMPARE(menu->isVisible(), false); - QCOMPARE(popup->isVisible(), false); - QCOMPARE(combo->isVisible(), false); + QTRY_COMPARE(popup->isVisible(), false); + QTRY_COMPARE(combo->isVisible(), false); menu->open(); - QCOMPARE(menu->isVisible(), true); + QTRY_COMPARE(menu->isOpened(), true); QCOMPARE(popup->isVisible(), false); QCOMPARE(combo->isVisible(), false); // click outside the menu to close it (QTBUG-56697) QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, QPoint(window->width() - 1, window->height() - 1)); - QCOMPARE(menu->isVisible(), false); + QTRY_COMPARE(menu->isVisible(), false); QCOMPARE(popup->isVisible(), false); QCOMPARE(combo->isVisible(), false); } @@ -881,17 +904,18 @@ void tst_QQuickPopup::cursorShape() popup->open(); QVERIFY(popup->isVisible()); + QTRY_VERIFY(popup->isOpened()); QQuickItem *textField = helper.appWindow->property("textField").value<QQuickItem*>(); QVERIFY(textField); // Move the mouse over the text field. - const QPoint textFieldPos(popup->x() - 10, popup->y() + popup->height() / 2); + const QPoint textFieldPos(popup->x() - 10, textField->height() / 2); QTest::mouseMove(window, textFieldPos); QCOMPARE(window->cursor().shape(), textField->cursor().shape()); // Move the mouse over the popup where it overlaps with the text field. - const QPoint textFieldOverlapPos(popup->x() + 10, popup->y() + popup->height() / 2); + const QPoint textFieldOverlapPos(popup->x() + 10, textField->height() / 2); QTest::mouseMove(window, textFieldOverlapPos); QCOMPARE(window->cursor().shape(), popup->popupItem()->cursor().shape()); @@ -1036,6 +1060,6 @@ void tst_QQuickPopup::orientation() QCOMPARE(popup->popupItem()->position(), position); } -QTEST_MAIN(tst_QQuickPopup) +QTEST_QUICKCONTROLS_MAIN(tst_QQuickPopup) #include "tst_qquickpopup.moc" diff --git a/tests/manual/testbench/controls/Button.qml b/tests/manual/testbench/controls/Button.qml index 6d65b3ee..b1152481 100644 --- a/tests/manual/testbench/controls/Button.qml +++ b/tests/manual/testbench/controls/Button.qml @@ -58,23 +58,18 @@ QtObject { ["pressed"], ["checked"], ["checked", "disabled"], - ["checked", "hovered"], + ["checked"], ["highlighted"], ["highlighted", "disabled"], - ["highlighted", "hovered"], ["highlighted", "pressed"], ["highlighted", "checked"], - ["highlighted", "checkable", "hovered"], ["highlighted", "checkable", "pressed"], ["highlighted", "checkable", "checked"], - ["hovered"], ["flat"], ["flat", "disabled"], - ["flat", "hovered"], ["flat", "pressed"], ["flat", "checked"], ["flat", "checkable"], - ["flat", "checkable", "hovered"], ["flat", "checkable", "pressed"], ["flat", "checkable", "checked", "pressed"], ["flat", "checkable", "highlighted"], @@ -87,6 +82,7 @@ QtObject { enabled: !is("disabled") flat: is("flat") checkable: is("checkable") + checked: is("checked") // Only set it if it's pressed, or the non-pressed examples will have no press effects down: is("pressed") ? true : undefined highlighted: is("highlighted") diff --git a/tests/manual/testbench/controls/RoundButton.qml b/tests/manual/testbench/controls/RoundButton.qml index 75eedf38..6a2bb5c2 100644 --- a/tests/manual/testbench/controls/RoundButton.qml +++ b/tests/manual/testbench/controls/RoundButton.qml @@ -58,23 +58,17 @@ QtObject { ["pressed"], ["checked"], ["checked", "disabled"], - ["checked", "hovered"], ["highlighted"], ["highlighted", "disabled"], - ["highlighted", "hovered"], ["highlighted", "pressed"], ["highlighted", "checked"], - ["highlighted", "checkable", "hovered"], ["highlighted", "checkable", "pressed"], ["highlighted", "checkable", "checked"], - ["hovered"], ["flat"], ["flat", "disabled"], - ["flat", "hovered"], ["flat", "pressed"], ["flat", "checked"], ["flat", "checkable"], - ["flat", "checkable", "hovered"], ["flat", "checkable", "pressed"], ["flat", "checkable", "checked", "pressed"], ["flat", "checkable", "highlighted"], |