summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.qmake.conf2
-rw-r--r--src/controls/ComboBox.qml8
-rw-r--r--src/controls/Private/ScrollViewHelper.qml18
-rw-r--r--src/controls/Private/StackViewSlideDelegate.qml2
-rw-r--r--src/controls/Styles/Android/plugin.cpp9
-rw-r--r--src/controls/Styles/WinRT/plugin.cpp6
-rw-r--r--src/controls/plugin.cpp9
-rw-r--r--src/controls/qquickmenu.cpp75
-rw-r--r--src/controls/qquickmenu_p.h2
-rw-r--r--src/dialogs/DefaultDialogWrapper.qml66
-rw-r--r--src/dialogs/Private/dialogsprivateplugin.cpp9
-rw-r--r--src/dialogs/plugin.cpp9
-rw-r--r--src/dialogs/qquickdialog.cpp25
-rw-r--r--src/extras/Styles/Flat/flatstyleplugin.cpp11
-rw-r--r--src/widgets/qquickqfiledialog_p.h6
-rw-r--r--src/widgets/widgetsplugin.cpp9
-rw-r--r--tests/auto/controls/data/tst_combobox.qml55
-rw-r--r--tests/auto/controls/data/tst_scrollview.qml26
-rw-r--r--tests/auto/dialogs/data/DialogButtonHandler.qml88
-rw-r--r--tests/auto/dialogs/tst_dialogs.cpp140
20 files changed, 455 insertions, 120 deletions
diff --git a/.qmake.conf b/.qmake.conf
index 473c6623..600fb8ae 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -2,4 +2,4 @@ load(qt_build_config)
CONFIG += warning_clean
android|ios|qnx|isEmpty(QT.widgets.name): CONFIG += no_desktop
-MODULE_VERSION = 5.11.2
+MODULE_VERSION = 5.12.0
diff --git a/src/controls/ComboBox.qml b/src/controls/ComboBox.qml
index bd42f76b..7c6f93a7 100644
--- a/src/controls/ComboBox.qml
+++ b/src/controls/ComboBox.qml
@@ -570,11 +570,16 @@ Control {
onSelectedTextChanged: popup.currentText = selectedText
property string selectedText
+ property int triggeredIndex: -1
on__SelectedIndexChanged: {
if (__selectedIndex === -1)
popup.currentText = ""
else
updateSelectedText()
+ if (triggeredIndex >= 0 && triggeredIndex == __selectedIndex) {
+ activated(currentIndex)
+ triggeredIndex = -1
+ }
}
property string textRole: ""
@@ -611,8 +616,7 @@ Control {
modelData :
((popup.modelIsArray ? modelData[popup.textRole] : model[popup.textRole]) || '')
onTriggered: {
- if (index !== currentIndex)
- activated(index)
+ popup.triggeredIndex = index
comboBox.editText = text
}
onTextChanged: if (index === currentIndex) popup.updateSelectedText();
diff --git a/src/controls/Private/ScrollViewHelper.qml b/src/controls/Private/ScrollViewHelper.qml
index 810de91d..53050108 100644
--- a/src/controls/Private/ScrollViewHelper.qml
+++ b/src/controls/Private/ScrollViewHelper.qml
@@ -68,31 +68,29 @@ Item {
anchors.fill: parent
- property bool recursionGuard: false
-
- function doLayout() {
- if (!recursionGuard) {
- recursionGuard = true
+ Timer {
+ id: layoutTimer
+ interval: 0;
+ onTriggered: {
blockUpdates = true;
scrollHelper.contentWidth = flickableItem !== null ? flickableItem.contentWidth : 0
scrollHelper.contentHeight = flickableItem !== null ? flickableItem.contentHeight : 0
scrollHelper.availableWidth = viewport.width
scrollHelper.availableHeight = viewport.height
blockUpdates = false;
- recursionGuard = false
}
}
Connections {
target: viewport
- onWidthChanged: doLayout()
- onHeightChanged: doLayout()
+ onWidthChanged: layoutTimer.running = true
+ onHeightChanged: layoutTimer.running = true
}
Connections {
target: flickableItem
- onContentWidthChanged: doLayout()
- onContentHeightChanged: doLayout()
+ onContentWidthChanged: layoutTimer.running = true
+ onContentHeightChanged: layoutTimer.running = true
onContentXChanged: {
hscrollbar.flash()
vscrollbar.flash()
diff --git a/src/controls/Private/StackViewSlideDelegate.qml b/src/controls/Private/StackViewSlideDelegate.qml
index e64bc38b..dcc14448 100644
--- a/src/controls/Private/StackViewSlideDelegate.qml
+++ b/src/controls/Private/StackViewSlideDelegate.qml
@@ -135,7 +135,7 @@ StackViewDelegate {
to: target.height
duration: 300
}
- property Component replaceTransition: pushTransition
}
+ property Component replaceTransition: pushTransition
}
}
diff --git a/src/controls/Styles/Android/plugin.cpp b/src/controls/Styles/Android/plugin.cpp
index 646fff36..7a09bb9c 100644
--- a/src/controls/Styles/Android/plugin.cpp
+++ b/src/controls/Styles/Android/plugin.cpp
@@ -44,13 +44,6 @@
#include "qquickandroidstyle_p.h"
#include "qquickandroid9patch_p.h"
-static void initResources()
-{
-#ifdef QT_STATIC
- Q_INIT_RESOURCE(qmake_QtQuick_Controls_Styles_Android);
-#endif
-}
-
QT_BEGIN_NAMESPACE
class QtQuickControls1AndroidStylePlugin: public QQmlExtensionPlugin
@@ -59,7 +52,7 @@ class QtQuickControls1AndroidStylePlugin: public QQmlExtensionPlugin
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
- QtQuickControls1AndroidStylePlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); }
+ QtQuickControls1AndroidStylePlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { }
void registerTypes(const char *uri);
};
diff --git a/src/controls/Styles/WinRT/plugin.cpp b/src/controls/Styles/WinRT/plugin.cpp
index e6d0adfe..b205d75e 100644
--- a/src/controls/Styles/WinRT/plugin.cpp
+++ b/src/controls/Styles/WinRT/plugin.cpp
@@ -39,15 +39,9 @@
#include <QtCore/qglobal.h>
-static void initResources()
-{
- Q_INIT_RESOURCE(WinRT);
-}
-
extern "C" {
Q_DECL_EXPORT bool qt_quick_controls_style_init()
{
- initResources();
return true;
}
diff --git a/src/controls/plugin.cpp b/src/controls/plugin.cpp
index 4eb6c466..8aca0c49 100644
--- a/src/controls/plugin.cpp
+++ b/src/controls/plugin.cpp
@@ -71,14 +71,6 @@
#include <QtCore/qlocale.h>
#endif
-static void initResources()
-{
-#ifdef QT_STATIC
- Q_INIT_RESOURCE(qmake_QtQuick_Controls);
- Q_INIT_RESOURCE(qmake_controls);
-#endif
-}
-
QT_BEGIN_NAMESPACE
static const struct {
@@ -129,7 +121,6 @@ static const struct {
QtQuickControls1Plugin::QtQuickControls1Plugin(QObject *parent) : QQmlExtensionPlugin(parent)
{
- initResources();
}
void QtQuickControls1Plugin::registerTypes(const char *uri)
diff --git a/src/controls/qquickmenu.cpp b/src/controls/qquickmenu.cpp
index 3c6d91ef..bfa0f673 100644
--- a/src/controls/qquickmenu.cpp
+++ b/src/controls/qquickmenu.cpp
@@ -789,33 +789,41 @@ void QQuickMenu1::insertItem(int index, QQuickMenuBase1 *menuItem)
void QQuickMenu1::removeItem(QQuickMenuBase1 *menuItem)
{
- if (!menuItem)
- return;
- menuItem->setParentMenu(0);
-
- QQuickMenuItemContainer1 *container = menuItem->parent() != this ? m_containers[menuItem->parent()] : 0;
- if (container)
- container->removeItem(menuItem);
- else
- m_menuItems.removeOne(menuItem);
-
- --m_itemsCount;
- emit itemsChanged();
+ // Removes the item, but if it's a container, the container is kept
+ if (menuItem) {
+ unparentItem(menuItem);
+ emit itemsChanged();
+ }
}
void QQuickMenu1::clear()
{
- m_containers.clear();
- m_containersCount = 0;
+ if (m_itemsCount > 0) {
+ while (m_itemsCount > 0)
+ unparentItem(menuItemAtIndex(0));
- // QTBUG-48927: a proxy menu (ApplicationWindowStyle.qml) must not
- // delete its items, because they are owned by the menubar
- if (m_proxy)
+ // We can delete the containers now, as there cannot be any further items in them.
+ qDeleteAll(m_containers);
+ m_containers.clear();
+ m_containersCount = 0;
+
+ // The containers are also kept in m_menuItems, so we have to clear explicitly.
m_menuItems.clear();
- while (!m_menuItems.empty())
- delete m_menuItems.takeFirst();
- m_itemsCount = 0;
+ emit itemsChanged();
+ }
+}
+
+void QQuickMenu1::unparentItem(QQuickMenuBase1 *menuItem)
+{
+ menuItem->setParentMenu(nullptr);
+ QQuickMenuItemContainer1 *container = (menuItem->parent() != this)
+ ? m_containers[menuItem->parent()] : nullptr;
+ if (container)
+ container->removeItem(menuItem);
+ else
+ m_menuItems.removeOne(menuItem);
+ --m_itemsCount;
}
void QQuickMenu1::setupMenuItem(QQuickMenuBase1 *item, int platformIndex)
@@ -871,8 +879,31 @@ QObject *QQuickMenu1::at_menuItems(QQuickMenuItems *list, int index)
void QQuickMenu1::clear_menuItems(QQuickMenuItems *list)
{
- if (QQuickMenu1 *menu = qobject_cast<QQuickMenu1 *>(list->object))
- menu->clear();
+ if (QQuickMenu1 *menu = qobject_cast<QQuickMenu1 *>(list->object)) {
+ // There may be stray containers that don't appear in m_menuItems. This is because we may
+ // remove a container with removeItem(), which will only remove it from m_menuItems.
+ // Therefore, make sure that all containers are removed from m_menuItems first.
+ for (QQuickMenuItemContainer1 *container : menu->m_containers)
+ menu->m_menuItems.removeOne(container);
+
+ // Delete or unparent the items first. They may have references to the containers.
+ // QTBUG-48927: a proxy menu (ApplicationWindowStyle.qml) must not
+ // delete its items, because they are owned by the menubar
+ // We still do own the containers, though. We create them on append_menuItems, after all.
+ while (!menu->m_menuItems.empty()) {
+ if (menu->m_proxy)
+ menu->unparentItem(menu->m_menuItems[0]);
+ else
+ delete menu->m_menuItems.takeFirst();
+ }
+ menu->m_menuItems.clear();
+
+ qDeleteAll(menu->m_containers);
+ menu->m_containers.clear();
+ menu->m_containersCount = 0;
+
+ menu->m_itemsCount = 0;
+ }
}
QT_END_NAMESPACE
diff --git a/src/controls/qquickmenu_p.h b/src/controls/qquickmenu_p.h
index 800981dd..0594f391 100644
--- a/src/controls/qquickmenu_p.h
+++ b/src/controls/qquickmenu_p.h
@@ -190,6 +190,8 @@ private:
static int count_menuItems(QQuickMenuItems *list);
static QObject *at_menuItems(QQuickMenuItems *list, int index);
static void clear_menuItems(QQuickMenuItems *list);
+
+ void unparentItem(QQuickMenuBase1 *menuItem);
void setupMenuItem(QQuickMenuBase1 *item, int platformIndex = -1);
QPlatformMenu *m_platformMenu;
diff --git a/src/dialogs/DefaultDialogWrapper.qml b/src/dialogs/DefaultDialogWrapper.qml
index b446c316..3ca030c4 100644
--- a/src/dialogs/DefaultDialogWrapper.qml
+++ b/src/dialogs/DefaultDialogWrapper.qml
@@ -47,6 +47,9 @@ import "qml"
AbstractDialog {
id: root
default property alias data: defaultContentItem.data
+
+ signal actionChosen(var action)
+
onVisibilityChanged: if (visible && contentItem) contentItem.forceActiveFocus()
Rectangle {
@@ -63,19 +66,7 @@ AbstractDialog {
defaultContentItem.implicitWidth, buttonsRowImplicitWidth, Screen.pixelDensity * 50) + outerSpacing * 2)
color: palette.window
Keys.onPressed: {
- event.accepted = true
- switch (event.key) {
- case Qt.Key_Escape:
- case Qt.Key_Back:
- reject()
- break
- case Qt.Key_Enter:
- case Qt.Key_Return:
- accept()
- break
- default:
- event.accepted = false
- }
+ event.accepted = handleKey(event.key)
}
SystemPalette { id: palette }
@@ -109,7 +100,7 @@ AbstractDialog {
id: buttonsLeftRepeater
Button {
text: (buttonsLeftRepeater.model && buttonsLeftRepeater.model[index] ? buttonsLeftRepeater.model[index].text : index)
- onClicked: root.click(buttonsLeftRepeater.model[index].standardButton)
+ onClicked: content.handleButton(buttonsLeftRepeater.model[index].standardButton)
}
}
@@ -136,9 +127,54 @@ AbstractDialog {
// TODO maybe: insert gaps if the button requires it (destructive buttons only)
Button {
text: (buttonsRightRepeater.model && buttonsRightRepeater.model[index] ? buttonsRightRepeater.model[index].text : index)
- onClicked: root.click(buttonsRightRepeater.model[index].standardButton)
+ onClicked: content.handleButton(buttonsRightRepeater.model[index].standardButton)
+ }
+ }
+ }
+
+ function handleButton(button) {
+ var action = {
+ "button": button,
+ "key": 0,
+ "accepted": true,
+ }
+ root.actionChosen(action)
+ if (action.accepted) {
+ click(button)
+ }
+ }
+
+ function handleKey(key) {
+ var button = 0
+ switch (key) {
+ case Qt.Key_Escape:
+ case Qt.Key_Back:
+ button = StandardButton.Cancel
+ break
+ case Qt.Key_Enter:
+ case Qt.Key_Return:
+ button = StandardButton.Ok
+ break
+ default:
+ return false
+ }
+ var action = {
+ "button": button,
+ "key": key,
+ "accepted": true,
+ }
+ root.actionChosen(action)
+ if (action.accepted) {
+ switch (button) {
+ case StandardButton.Cancel:
+ reject()
+ break
+ case StandardButton.Ok:
+ accept()
+ break
}
}
+ return true
}
}
function setupButtons() {
diff --git a/src/dialogs/Private/dialogsprivateplugin.cpp b/src/dialogs/Private/dialogsprivateplugin.cpp
index ba8aabe3..a785f388 100644
--- a/src/dialogs/Private/dialogsprivateplugin.cpp
+++ b/src/dialogs/Private/dialogsprivateplugin.cpp
@@ -42,13 +42,6 @@
#include "qquickwritingsystemlistmodel_p.h"
#include "qquickfontlistmodel_p.h"
-static void initResources()
-{
-#ifdef QT_STATIC
- Q_INIT_RESOURCE(qmake_QtQuick_Dialogs_Private);
-#endif
-}
-
QT_BEGIN_NAMESPACE
class QtQuick2DialogsPrivatePlugin : public QQmlExtensionPlugin
@@ -57,7 +50,7 @@ class QtQuick2DialogsPrivatePlugin : public QQmlExtensionPlugin
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
- QtQuick2DialogsPrivatePlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); }
+ QtQuick2DialogsPrivatePlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { }
virtual void registerTypes(const char *uri)
{
Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.Dialogs.Private"));
diff --git a/src/dialogs/plugin.cpp b/src/dialogs/plugin.cpp
index 1e6740d5..8c10786f 100644
--- a/src/dialogs/plugin.cpp
+++ b/src/dialogs/plugin.cpp
@@ -62,13 +62,6 @@
Q_LOGGING_CATEGORY(lcRegistration, "qt.quick.dialogs.registration")
-static void initResources()
-{
-#ifdef QT_STATIC
- Q_INIT_RESOURCE(qmake_QtQuick_Dialogs);
-#endif
-}
-
QT_BEGIN_NAMESPACE
/*!
@@ -92,7 +85,7 @@ class QtQuick2DialogsPlugin : public QQmlExtensionPlugin
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
- QtQuick2DialogsPlugin() : QQmlExtensionPlugin(), m_useResources(true) { initResources(); }
+ QtQuick2DialogsPlugin() : QQmlExtensionPlugin(), m_useResources(true) { }
virtual void initializeEngine(QQmlEngine *engine, const char * uri) {
qCDebug(lcRegistration) << uri << m_decorationComponentUrl;
diff --git a/src/dialogs/qquickdialog.cpp b/src/dialogs/qquickdialog.cpp
index 485eeb43..ef6a9a1f 100644
--- a/src/dialogs/qquickdialog.cpp
+++ b/src/dialogs/qquickdialog.cpp
@@ -154,6 +154,31 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ \qmlsignal Dialog::actionChosen(var action)
+
+ This signal is emitted when the user has pressed any button or a key
+ associated with some role (such as the Enter or Escape keys). The \a
+ action parameter carries information about the event:
+
+ \list
+ \li StandardButton button - The role of the button which was pressed. If a
+ key was pressed instead, this will be \c StandardButton.Ok if accepted
+ and \c StandardButton.Cancel if rejected.
+ \li Qt.Key key - The key which was pressed, or \c 0 if none
+ \li bool accepted - Set this to \c false to stop the event from triggering
+ its predefined action
+ \endlist
+
+ By handling this signal and setting the \c action.accepted field to \c
+ false, it's possible to implement some validation on the dialog contents
+ before accepting it, for example.
+
+ The corresponding handler is \c onActionChosen.
+
+ \since QtQuick.Controls 1.8
+*/
+
+/*!
\qmlproperty bool Dialog::visible
This property holds whether the dialog is visible. By default this is
diff --git a/src/extras/Styles/Flat/flatstyleplugin.cpp b/src/extras/Styles/Flat/flatstyleplugin.cpp
index 5d88134b..7efbb16c 100644
--- a/src/extras/Styles/Flat/flatstyleplugin.cpp
+++ b/src/extras/Styles/Flat/flatstyleplugin.cpp
@@ -45,20 +45,10 @@
#include "qquicktexthandle.h"
-static void initResources()
-{
-#ifndef QT_STATIC
- Q_INIT_RESOURCE(flatstyle);
-#else
- Q_INIT_RESOURCE(qmake_QtQuick_Controls_Styles_Flat);
-#endif
-}
-
#ifndef QT_STATIC
extern "C" {
Q_DECL_EXPORT bool qt_quick_controls_style_init()
{
- initResources();
return true;
}
@@ -74,7 +64,6 @@ QT_BEGIN_NAMESPACE
QtQuickExtrasStylesPlugin::QtQuickExtrasStylesPlugin(QObject *parent) :
QQmlExtensionPlugin(parent)
{
- initResources();
}
void QtQuickExtrasStylesPlugin::registerTypes(const char *uri)
diff --git a/src/widgets/qquickqfiledialog_p.h b/src/widgets/qquickqfiledialog_p.h
index d977e345..4988c1e0 100644
--- a/src/widgets/qquickqfiledialog_p.h
+++ b/src/widgets/qquickqfiledialog_p.h
@@ -51,11 +51,13 @@
// We mean it.
//
-#include <QFileDialog>
-#include "../dialogs/qquickabstractfiledialog_p.h"
+#include <QtWidgets/qtwidgetsglobal.h>
#if QT_CONFIG(filedialog)
+#include <QFileDialog>
+#include "../dialogs/qquickabstractfiledialog_p.h"
+
QT_BEGIN_NAMESPACE
class QQuickQFileDialog : public QQuickAbstractFileDialog
diff --git a/src/widgets/widgetsplugin.cpp b/src/widgets/widgetsplugin.cpp
index 65233756..3289e6fd 100644
--- a/src/widgets/widgetsplugin.cpp
+++ b/src/widgets/widgetsplugin.cpp
@@ -44,13 +44,6 @@
#include "qquickqcolordialog_p.h"
#include "qquickqfontdialog_p.h"
-static void initResources()
-{
-#ifdef QT_STATIC
- Q_INIT_RESOURCE(qmake_QtQuick_PrivateWidgets);
-#endif
-}
-
QT_BEGIN_NAMESPACE
/*!
@@ -78,7 +71,7 @@ class QtQuick2PrivateWidgetsPlugin : public QQmlExtensionPlugin
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
- QtQuick2PrivateWidgetsPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); }
+ QtQuick2PrivateWidgetsPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { }
virtual void registerTypes(const char *uri)
{
Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.PrivateWidgets"));
diff --git a/tests/auto/controls/data/tst_combobox.qml b/tests/auto/controls/data/tst_combobox.qml
index 415d3ad3..bccac8d2 100644
--- a/tests/auto/controls/data/tst_combobox.qml
+++ b/tests/auto/controls/data/tst_combobox.qml
@@ -418,6 +418,61 @@ TestCase {
comboBox.destroy()
}
+ function test_activated_index_QTBUG_43050(){
+ if (Qt.platform.os === "osx")
+ skip("When the menu pops up on OS X, it does not return and the test fails after time out")
+ if (Qt.platform.os === "windows")
+ skip("Test randomly fails under Windows")
+
+ var comboBox = Qt.createQmlObject('import QtQuick.Controls 1.2; \
+ ComboBox { \
+ property bool indexWasUpdated: false; \
+ model: 4; \
+ onActivated: indexWasUpdated = (index === currentIndex); \
+ }', container, '');
+ var menuIndex = getMenuIndex(comboBox)
+ verify(menuIndex !== -1)
+ comboBox.forceActiveFocus()
+ verify(!comboBox.data[menuIndex].__popupVisible)
+ keyPress(Qt.Key_Space)
+ verify(comboBox.data[menuIndex].__popupVisible)
+
+ waitForRendering(comboBox)
+ keyPress(Qt.Key_Down)
+ keyPress(Qt.Key_Down)
+ verify(!comboBox.indexWasUpdated)
+ keyPress(Qt.Key_Enter)
+ verify(comboBox.indexWasUpdated)
+
+ comboBox.destroy()
+ }
+
+ function test_update_index_on_activated_QTBUG_51113(){
+ if (Qt.platform.os === "osx")
+ skip("When the menu pops up on OS X, it does not return and the test fails after time out")
+ if (Qt.platform.os === "windows")
+ skip("Test randomly fails under Windows")
+
+ var comboBox = Qt.createQmlObject('import QtQuick.Controls 1.2; \
+ ComboBox { \
+ model: 4; \
+ onActivated: if (index == 1) currentIndex = 3; \
+ }', container, '');
+ var menuIndex = getMenuIndex(comboBox)
+ verify(menuIndex !== -1)
+ comboBox.forceActiveFocus()
+ verify(!comboBox.data[menuIndex].__popupVisible)
+ keyPress(Qt.Key_Space)
+ verify(comboBox.data[menuIndex].__popupVisible)
+
+ waitForRendering(comboBox)
+ keyPress(Qt.Key_Down)
+ keyPress(Qt.Key_Enter)
+ compare(comboBox.currentIndex, 3)
+
+ comboBox.destroy()
+ }
+
function test_activeFocusOnTab() {
if (Qt.styleHints.tabFocusBehavior != Qt.TabFocusAllControls)
skip("This function doesn't support NOT iterating all.")
diff --git a/tests/auto/controls/data/tst_scrollview.qml b/tests/auto/controls/data/tst_scrollview.qml
index 42398115..d3bfac4b 100644
--- a/tests/auto/controls/data/tst_scrollview.qml
+++ b/tests/auto/controls/data/tst_scrollview.qml
@@ -212,21 +212,27 @@ TestCase {
bigItem.height = 100
bigItem.width = 100
- verify(!scrollView.__horizontalScrollBar.visible, "Scrollbar showing when contents already fit")
- verify(!scrollView.__verticalScrollBar.visible, "Scrollbar showing when contents already fit")
+ tryVerify(function() { return !scrollView.__horizontalScrollBar.visible }, 50,
+ "Scrollbar showing when contents already fit")
+ tryVerify(function() { return !scrollView.__verticalScrollBar.visible }, 50,
+ "Scrollbar showing when contents already fit")
bigItem.height = 1000
bigItem.width = 1000
- verify(scrollView.__horizontalScrollBar.visible, "Scrollbar not showing when contents are too big")
- verify(scrollView.__verticalScrollBar.visible, "Scrollbar not showing when contents are too big")
+ tryVerify(function() { return scrollView.__horizontalScrollBar.visible }, 50,
+ "Scrollbar not showing when contents are too big")
+ tryVerify(function() { return scrollView.__verticalScrollBar.visible }, 50,
+ "Scrollbar not showing when contents are too big")
//always off
bigItem.height = 1000
scrollView.verticalScrollBarPolicy = Qt.ScrollBarAlwaysOff
- verify(!scrollView.__verticalScrollBar.visible, "Scrollbar showing when disabled")
+ tryVerify(function() { return !scrollView.__verticalScrollBar.visible }, 50,
+ "Scrollbar showing when disabled")
bigItem.height = 100
- verify(!scrollView.__verticalScrollBar.visible, "Scrollbar showing when disabled")
+ tryVerify(function() { return !scrollView.__verticalScrollBar.visible }, 50,
+ "Scrollbar showing when disabled")
//always on
scrollView.verticalScrollBarPolicy = Qt.ScrollBarAlwaysOn
@@ -258,12 +264,14 @@ TestCase {
verify(scrollView !== null, "view created is null")
verify(scrollView.flickableItem.contentY === 0)
+ tryVerify(function() { return scrollView.__verticalScrollBar.visible });
+
mouseClick(scrollView, scrollView.width -2, scrollView.height/2, Qt.LeftButton)
- verify(Math.round(scrollView.flickableItem.contentY) === 100)
+ tryVerify(function() { return Math.round(scrollView.flickableItem.contentY) === 100 });
- verify(scrollView.flickableItem.contentX === 0)
+ tryVerify(function() { return scrollView.flickableItem.contentX === 0 })
mouseClick(scrollView, scrollView.width/2, scrollView.height - 2, Qt.LeftButton)
- verify(Math.round(scrollView.flickableItem.contentX) === 100)
+ tryVerify(function() { return Math.round(scrollView.flickableItem.contentX) === 100 })
}
function test_viewport() {
diff --git a/tests/auto/dialogs/data/DialogButtonHandler.qml b/tests/auto/dialogs/data/DialogButtonHandler.qml
new file mode 100644
index 00000000..e19f88c8
--- /dev/null
+++ b/tests/auto/dialogs/data/DialogButtonHandler.qml
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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.3
+import QtQuick.Controls 1.2
+import QtQuick.Dialogs 1.2
+
+Dialog {
+ property bool handlerWasCalled: false
+ property var buttonCode
+ property var keyCode
+ property bool mustBlock: false
+ property string actionCalled: ""
+
+ visible: true
+ title: "Blue sky dialog"
+ standardButtons: buttonsFromTest
+
+ Item {
+ implicitWidth: 300
+ implicitHeight: 200
+ }
+
+ onActionChosen: {
+ handlerWasCalled = true
+ buttonCode = action.button
+ keyCode = action.key
+ if (mustBlock) {
+ action.accepted = false
+ }
+ }
+
+ onAccepted: actionCalled = "accepted"
+ onApply: actionCalled = "apply"
+ onDiscard: actionCalled = "discard"
+ onHelp: actionCalled = "help"
+ onNo: actionCalled = "no"
+ onRejected: actionCalled = "rejected"
+ onReset: actionCalled = "reset"
+ onYes: actionCalled = "yes"
+}
diff --git a/tests/auto/dialogs/tst_dialogs.cpp b/tests/auto/dialogs/tst_dialogs.cpp
index 1f802113..8303ff83 100644
--- a/tests/auto/dialogs/tst_dialogs.cpp
+++ b/tests/auto/dialogs/tst_dialogs.cpp
@@ -51,6 +51,10 @@ private slots:
void dialogImplicitWidth_data();
void dialogImplicitWidth();
void dialogContentResize();
+ void dialogButtonHandler_data();
+ void dialogButtonHandler();
+ void dialogKeyHandler_data();
+ void dialogKeyHandler();
// FileDialog
void fileDialogDefaultModality();
@@ -113,6 +117,142 @@ void tst_dialogs::dialogContentResize()
QVERIFY(userContent->height() > 200);
}
+void tst_dialogs::dialogButtonHandler_data()
+{
+ QTest::addColumn<int>("standardButtons");
+ QTest::addColumn<bool>("mustBlock");
+ QTest::addColumn<QString>("expectedAction");
+
+ QTest::newRow("Cancel, ignored") <<
+ int(QQuickAbstractDialog::Cancel) <<
+ false <<
+ "rejected";
+ QTest::newRow("Cancel, blocked") <<
+ int(QQuickAbstractDialog::Cancel) <<
+ true <<
+ "";
+ QTest::newRow("OK, ignored") <<
+ int(QQuickAbstractDialog::Ok) <<
+ false <<
+ "accepted";
+ QTest::newRow("OK, blocked") <<
+ int(QQuickAbstractDialog::Ok) <<
+ true <<
+ "";
+}
+
+void tst_dialogs::dialogButtonHandler()
+{
+ QFETCH(int, standardButtons);
+ QFETCH(bool, mustBlock);
+ QFETCH(QString, expectedAction);
+
+ QQmlEngine engine;
+ engine.rootContext()->setContextProperty("buttonsFromTest", standardButtons);
+ QQmlComponent component(&engine);
+ component.loadUrl(testFileUrl("DialogButtonHandler.qml"));
+ QObject *root = component.create();
+ QScopedPointer<QObject> cleanup(root);
+ QVERIFY2(root, qPrintable(component.errorString()));
+
+ root->setProperty("visible", true);
+ root->setProperty("mustBlock", mustBlock);
+
+ QQuickWindow *window = root->findChild<QQuickWindow*>();
+ QTest::qWaitForWindowExposed(window);
+
+ /* Hack to find the created buttons: since they are created by a
+ * QQuickRepeater, they don't appear on the hierarchy tree; therefore, we
+ * first need to find the repeater, and then to get its child. */
+ const QList<QQuickItem*> children = root->findChildren<QQuickItem*>();
+ QQuickItem *buttonWidget = nullptr;
+ for (QQuickItem *child: children) {
+ if (qstrcmp(child->metaObject()->className(), "QQuickRepeater") == 0 &&
+ child->property("count").toInt() > 0) {
+ int index = 0;
+ QMetaObject::invokeMethod(child,
+ "itemAt",
+ Q_RETURN_ARG(QQuickItem *, buttonWidget),
+ Q_ARG(int, index));
+ break;
+ }
+ }
+ QVERIFY(buttonWidget);
+
+ const QPointF buttonCenterF(buttonWidget->width() / 2,
+ buttonWidget->height() / 2);
+ const QPoint buttonCenter = buttonWidget->mapToScene(buttonCenterF).toPoint();
+
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, buttonCenter);
+ QTRY_VERIFY(root->property("handlerWasCalled").toBool());
+
+ QCOMPARE(root->property("buttonCode").toInt(), standardButtons);
+ QCOMPARE(root->property("keyCode").toInt(), 0);
+
+ QCOMPARE(root->property("actionCalled").toString(), expectedAction);
+}
+
+void tst_dialogs::dialogKeyHandler_data()
+{
+ QTest::addColumn<int>("key");
+ QTest::addColumn<bool>("mustBlock");
+ QTest::addColumn<int>("expectedButton");
+ QTest::addColumn<QString>("expectedAction");
+
+ QTest::newRow("Escape, ignored") <<
+ int(Qt::Key_Escape) <<
+ false <<
+ int(QQuickAbstractDialog::Cancel) <<
+ "rejected";
+ QTest::newRow("Cancel, blocked") <<
+ int(Qt::Key_Escape) <<
+ true <<
+ int(QQuickAbstractDialog::Cancel) <<
+ "";
+ QTest::newRow("Enter, ignored") <<
+ int(Qt::Key_Enter) <<
+ false <<
+ int(QQuickAbstractDialog::Ok) <<
+ "accepted";
+ QTest::newRow("Enter, blocked") <<
+ int(Qt::Key_Enter) <<
+ true <<
+ int(QQuickAbstractDialog::Ok) <<
+ "";
+}
+
+void tst_dialogs::dialogKeyHandler()
+{
+ QFETCH(int, key);
+ QFETCH(bool, mustBlock);
+ QFETCH(int, expectedButton);
+ QFETCH(QString, expectedAction);
+
+ QQmlEngine engine;
+ QQuickAbstractDialog::StandardButtons buttons =
+ QQuickAbstractDialog::Ok | QQuickAbstractDialog::Cancel;
+ engine.rootContext()->setContextProperty("buttonsFromTest", int(buttons));
+ QQmlComponent component(&engine);
+ component.loadUrl(testFileUrl("DialogButtonHandler.qml"));
+ QObject *root = component.create();
+ QScopedPointer<QObject> cleanup(root);
+ QVERIFY2(root, qPrintable(component.errorString()));
+
+ root->setProperty("visible", true);
+ root->setProperty("mustBlock", mustBlock);
+
+ QQuickWindow *window = root->findChild<QQuickWindow*>();
+ QTest::qWaitForWindowExposed(window);
+
+ QTest::keyClick(window, Qt::Key(key));
+ QTRY_VERIFY(root->property("handlerWasCalled").toBool());
+
+ QCOMPARE(root->property("buttonCode").toInt(), expectedButton);
+ QCOMPARE(root->property("keyCode").toInt(), key);
+
+ QCOMPARE(root->property("actionCalled").toString(), expectedAction);
+}
+
void tst_dialogs::fileDialogDefaultModality()
{
QQuickView *window = new QQuickView;