Merge remote-tracking branch 'origin/5.11' into dev

Change-Id: Id3333e9bb67ced4c6dbae5845512fe1927a7b858
This commit is contained in:
J-P Nurmi 2018-02-15 11:22:14 +01:00
commit f6fec74d42
38 changed files with 679 additions and 355 deletions

49
dist/changes-5.10.1 vendored Normal file
View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -101,6 +101,11 @@
\li 2.10
\li 2.3
\li 1.0
\row
\li 5.11
\li 2.11
\li 2.4
\li 1.0
\row
\li ...
\li ...

View File

@ -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

View File

@ -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

View File

@ -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...

View File

@ -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

View File

@ -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

View File

@ -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, ...

View File

@ -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

View File

@ -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...

View File

@ -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");

View File

@ -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

View File

@ -536,66 +536,59 @@ static QByteArray resolveSetting(const QByteArray &env, const QSharedPointer<QSe
return value;
}
void QQuickUniversalStyle::init()
void QQuickUniversalStyle::initGlobals()
{
static bool globalsInitialized = false;
if (!globalsInitialized) {
QSharedPointer<QSettings> settings = QQuickStylePrivate::settings(QStringLiteral("Universal"));
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;
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 = 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;
}
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 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;
}
}
globalsInitialized = true;
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;
}
QQuickAttachedObject::init(); // TODO: lazy init?
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 = 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;
}
}
}
bool QQuickUniversalStyle::variantToRgba(const QVariant &var, const char *name, QRgb *rgba) const

View File

@ -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

View File

@ -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...

View File

@ -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);
}
/*!

View File

@ -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)

View File

@ -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();
}

View File

@ -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;

View File

@ -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)

View File

@ -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);
}

View File

@ -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

View File

@ -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;
};

View File

@ -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();

View File

@ -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)

View File

@ -73,6 +73,8 @@ void QQuickStackViewPrivate::setCurrentItem(QQuickStackElement *element)
currentItem = item;
if (element)
element->setVisible(true);
if (item)
item->setFocus(true);
emit q->currentItemChanged();
}

View File

@ -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

View File

@ -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)
}
}

View File

@ -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() {

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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")

View File

@ -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"],