diff options
Diffstat (limited to 'tests')
242 files changed, 12755 insertions, 1979 deletions
diff --git a/tests/auto/accessibility/accessibility.pro b/tests/auto/accessibility/accessibility.pro index ca751265..bef6eae4 100644 --- a/tests/auto/accessibility/accessibility.pro +++ b/tests/auto/accessibility/accessibility.pro @@ -4,7 +4,7 @@ SOURCES += tst_accessibility.cpp osx:CONFIG -= app_bundle -QT += core-private gui-private qml-private quick-private labstemplates-private testlib +QT += core-private gui-private qml-private quick-private quicktemplates2-private testlib include (../shared/util.pri) diff --git a/tests/auto/accessibility/data/abstractbutton.qml b/tests/auto/accessibility/data/abstractbutton.qml new file mode 100644 index 00000000..368f4582 --- /dev/null +++ b/tests/auto/accessibility/data/abstractbutton.qml @@ -0,0 +1,6 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.0 + +AbstractButton { + text: "AbstractButton" +} diff --git a/tests/auto/accessibility/data/busyindicator.qml b/tests/auto/accessibility/data/busyindicator.qml index 4ac1b9ca..b15ea80a 100644 --- a/tests/auto/accessibility/data/busyindicator.qml +++ b/tests/auto/accessibility/data/busyindicator.qml @@ -1,12 +1,4 @@ import QtQuick 2.5 -import QtQuick.Window 2.2 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 -Window { - visible: true - - BusyIndicator { - id: busyindicator - objectName: "busyindicator" - } -} +BusyIndicator { } diff --git a/tests/auto/accessibility/data/button.qml b/tests/auto/accessibility/data/button.qml index d6acfdb0..0fd14210 100644 --- a/tests/auto/accessibility/data/button.qml +++ b/tests/auto/accessibility/data/button.qml @@ -1,13 +1,6 @@ import QtQuick 2.5 -import QtQuick.Window 2.2 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 -Window { - visible: true - - Button { - id: button - objectName: "button" - text: "Button" - } +Button { + text: "Button" } diff --git a/tests/auto/accessibility/data/checkbox.qml b/tests/auto/accessibility/data/checkbox.qml index 4752dcae..e70d7d83 100644 --- a/tests/auto/accessibility/data/checkbox.qml +++ b/tests/auto/accessibility/data/checkbox.qml @@ -1,13 +1,6 @@ import QtQuick 2.5 -import QtQuick.Window 2.2 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 -Window { - visible: true - - CheckBox { - id: checkbox - objectName: "checkbox" - text: "CheckBox" - } +CheckBox { + text: "CheckBox" } diff --git a/tests/auto/accessibility/data/checkdelegate.qml b/tests/auto/accessibility/data/checkdelegate.qml new file mode 100644 index 00000000..0a1a4a4f --- /dev/null +++ b/tests/auto/accessibility/data/checkdelegate.qml @@ -0,0 +1,6 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.0 + +CheckDelegate { + text: "CheckDelegate" +} diff --git a/tests/auto/accessibility/data/combobox.qml b/tests/auto/accessibility/data/combobox.qml new file mode 100644 index 00000000..42e4d47b --- /dev/null +++ b/tests/auto/accessibility/data/combobox.qml @@ -0,0 +1,6 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.0 + +ComboBox { + model: ["ComboBox"] +} diff --git a/tests/auto/accessibility/data/container.qml b/tests/auto/accessibility/data/container.qml new file mode 100644 index 00000000..806ebe78 --- /dev/null +++ b/tests/auto/accessibility/data/container.qml @@ -0,0 +1,4 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.0 + +Container { } diff --git a/tests/auto/accessibility/data/control.qml b/tests/auto/accessibility/data/control.qml index 42fe7435..4831a6c6 100644 --- a/tests/auto/accessibility/data/control.qml +++ b/tests/auto/accessibility/data/control.qml @@ -1,12 +1,4 @@ import QtQuick 2.5 -import QtQuick.Window 2.2 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 -Window { - visible: true - - Control { - id: control - objectName: "control" - } -} +Control { } diff --git a/tests/auto/accessibility/data/dayofweekrow-2.qml b/tests/auto/accessibility/data/dayofweekrow-2.qml index 26569836..265f975a 100644 --- a/tests/auto/accessibility/data/dayofweekrow-2.qml +++ b/tests/auto/accessibility/data/dayofweekrow-2.qml @@ -1,12 +1,4 @@ import QtQuick 2.5 -import QtQuick.Window 2.2 import Qt.labs.calendar 1.0 -Window { - visible: true - - DayOfWeekRow { - id: dayofweekrow - objectName: "dayofweekrow" - } -} +DayOfWeekRow { } diff --git a/tests/auto/accessibility/data/dayofweekrow.qml b/tests/auto/accessibility/data/dayofweekrow.qml index c799aba1..a3ab92dd 100644 --- a/tests/auto/accessibility/data/dayofweekrow.qml +++ b/tests/auto/accessibility/data/dayofweekrow.qml @@ -1,13 +1,6 @@ import QtQuick 2.5 -import QtQuick.Window 2.2 import Qt.labs.calendar 1.0 -Window { - visible: true - - DayOfWeekRow { - id: dayofweekrow - objectName: "dayofweekrow" - Accessible.name: "DayOfWeekRow" - } +DayOfWeekRow { + Accessible.name: "DayOfWeekRow" } diff --git a/tests/auto/accessibility/data/dial.qml b/tests/auto/accessibility/data/dial.qml index af107c08..39b85550 100644 --- a/tests/auto/accessibility/data/dial.qml +++ b/tests/auto/accessibility/data/dial.qml @@ -1,12 +1,4 @@ import QtQuick 2.5 -import QtQuick.Window 2.2 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 -Window { - visible: true - - Dial { - id: dial - objectName: "dial" - } -} +Dial { } diff --git a/tests/auto/accessibility/data/drawer.qml b/tests/auto/accessibility/data/drawer.qml new file mode 100644 index 00000000..12652164 --- /dev/null +++ b/tests/auto/accessibility/data/drawer.qml @@ -0,0 +1,4 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.0 + +Drawer { } diff --git a/tests/auto/accessibility/data/frame.qml b/tests/auto/accessibility/data/frame.qml new file mode 100644 index 00000000..6fcbab23 --- /dev/null +++ b/tests/auto/accessibility/data/frame.qml @@ -0,0 +1,4 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.0 + +Frame { } diff --git a/tests/auto/accessibility/data/groupbox.qml b/tests/auto/accessibility/data/groupbox.qml new file mode 100644 index 00000000..c48b4847 --- /dev/null +++ b/tests/auto/accessibility/data/groupbox.qml @@ -0,0 +1,6 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.0 + +GroupBox { + title: "GroupBox" +} diff --git a/tests/auto/accessibility/data/itemdelegate.qml b/tests/auto/accessibility/data/itemdelegate.qml new file mode 100644 index 00000000..9b647315 --- /dev/null +++ b/tests/auto/accessibility/data/itemdelegate.qml @@ -0,0 +1,6 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.0 + +ItemDelegate { + text: "ItemDelegate" +} diff --git a/tests/auto/accessibility/data/label.qml b/tests/auto/accessibility/data/label.qml index 19a08984..bb87a4e9 100644 --- a/tests/auto/accessibility/data/label.qml +++ b/tests/auto/accessibility/data/label.qml @@ -1,13 +1,6 @@ import QtQuick 2.5 -import QtQuick.Window 2.2 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 -Window { - visible: true - - Label { - id: label - objectName: "label" - text: "Label" - } +Label { + text: "Label" } diff --git a/tests/auto/accessibility/data/menu.qml b/tests/auto/accessibility/data/menu.qml index 8903bd0b..def3020b 100644 --- a/tests/auto/accessibility/data/menu.qml +++ b/tests/auto/accessibility/data/menu.qml @@ -1,12 +1,4 @@ import QtQuick 2.5 -import QtQuick.Window 2.2 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 -Window { - visible: true - - Menu { - id: menu - objectName: "menu" - } -} +Menu { } diff --git a/tests/auto/accessibility/data/menuitem.qml b/tests/auto/accessibility/data/menuitem.qml new file mode 100644 index 00000000..70c2ff33 --- /dev/null +++ b/tests/auto/accessibility/data/menuitem.qml @@ -0,0 +1,6 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.0 + +MenuItem { + text: "MenuItem" +} diff --git a/tests/auto/accessibility/data/monthgrid-2.qml b/tests/auto/accessibility/data/monthgrid-2.qml index 76af6646..603a208b 100644 --- a/tests/auto/accessibility/data/monthgrid-2.qml +++ b/tests/auto/accessibility/data/monthgrid-2.qml @@ -1,13 +1,6 @@ import QtQuick 2.5 -import QtQuick.Window 2.2 import Qt.labs.calendar 1.0 -Window { - visible: true - - MonthGrid { - id: monthgrid - objectName: "monthgrid" - title: "MonthGrid" - } +MonthGrid { + title: "MonthGrid" } diff --git a/tests/auto/accessibility/data/monthgrid.qml b/tests/auto/accessibility/data/monthgrid.qml index 7c8d6451..92a45f0f 100644 --- a/tests/auto/accessibility/data/monthgrid.qml +++ b/tests/auto/accessibility/data/monthgrid.qml @@ -1,14 +1,7 @@ import QtQuick 2.5 -import QtQuick.Window 2.2 import Qt.labs.calendar 1.0 -Window { - visible: true - - MonthGrid { - id: monthgrid - objectName: "monthgrid" - title: "MonthGrid" - Accessible.name: title - } +MonthGrid { + title: "MonthGrid" + Accessible.name: title } diff --git a/tests/auto/accessibility/data/page.qml b/tests/auto/accessibility/data/page.qml new file mode 100644 index 00000000..59139855 --- /dev/null +++ b/tests/auto/accessibility/data/page.qml @@ -0,0 +1,6 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.0 + +Page { + title: "Page" +} diff --git a/tests/auto/accessibility/data/pageindicator.qml b/tests/auto/accessibility/data/pageindicator.qml index 8fce79f3..bb69a27a 100644 --- a/tests/auto/accessibility/data/pageindicator.qml +++ b/tests/auto/accessibility/data/pageindicator.qml @@ -1,12 +1,4 @@ import QtQuick 2.5 -import QtQuick.Window 2.2 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 -Window { - visible: true - - PageIndicator { - id: pageindicator - objectName: "pageindicator" - } -} +PageIndicator { } diff --git a/tests/auto/accessibility/data/pane.qml b/tests/auto/accessibility/data/pane.qml new file mode 100644 index 00000000..1de210ec --- /dev/null +++ b/tests/auto/accessibility/data/pane.qml @@ -0,0 +1,4 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.0 + +Pane { } diff --git a/tests/auto/accessibility/data/popup.qml b/tests/auto/accessibility/data/popup.qml index e95ef2b7..05e968e5 100644 --- a/tests/auto/accessibility/data/popup.qml +++ b/tests/auto/accessibility/data/popup.qml @@ -1,12 +1,4 @@ import QtQuick 2.5 -import QtQuick.Window 2.2 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 -Window { - visible: true - - Popup { - id: popup - objectName: "popup" - } -} +Popup { } diff --git a/tests/auto/accessibility/data/progressbar.qml b/tests/auto/accessibility/data/progressbar.qml index 3a6ccfc2..5e9b11f1 100644 --- a/tests/auto/accessibility/data/progressbar.qml +++ b/tests/auto/accessibility/data/progressbar.qml @@ -1,15 +1,8 @@ import QtQuick 2.5 -import QtQuick.Window 2.2 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 -Window { - visible: true - - ProgressBar { - id: progressbar - objectName: "progressbar" - from: 0 - to: 100 - value: 50 - } +ProgressBar { + from: 0 + to: 100 + value: 50 } diff --git a/tests/auto/accessibility/data/radiobutton.qml b/tests/auto/accessibility/data/radiobutton.qml index 54f240fa..58bdf225 100644 --- a/tests/auto/accessibility/data/radiobutton.qml +++ b/tests/auto/accessibility/data/radiobutton.qml @@ -1,13 +1,6 @@ import QtQuick 2.5 -import QtQuick.Window 2.2 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 -Window { - visible: true - - RadioButton { - id: radiobutton - objectName: "radiobutton" - text: "RadioButton" - } +RadioButton { + text: "RadioButton" } diff --git a/tests/auto/accessibility/data/radiodelegate.qml b/tests/auto/accessibility/data/radiodelegate.qml new file mode 100644 index 00000000..93ccafde --- /dev/null +++ b/tests/auto/accessibility/data/radiodelegate.qml @@ -0,0 +1,6 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.0 + +RadioDelegate { + text: "RadioDelegate" +} diff --git a/tests/auto/accessibility/data/rangeslider.qml b/tests/auto/accessibility/data/rangeslider.qml index 9262f3cd..45b1d4ae 100644 --- a/tests/auto/accessibility/data/rangeslider.qml +++ b/tests/auto/accessibility/data/rangeslider.qml @@ -1,18 +1,11 @@ import QtQuick 2.5 -import QtQuick.Window 2.2 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 -Window { - visible: true - - RangeSlider { - id: rangeSlider - objectName: "rangeslider" - from: 0 - to: 100 - first.value: 25 - second.value: 75 - stepSize: 1 - orientation: "Horizontal" - } +RangeSlider { + from: 0 + to: 100 + first.value: 25 + second.value: 75 + stepSize: 1 + orientation: Qt.Horizontal } diff --git a/tests/auto/accessibility/data/scrollbar.qml b/tests/auto/accessibility/data/scrollbar.qml index ab6ee421..f0598b4b 100644 --- a/tests/auto/accessibility/data/scrollbar.qml +++ b/tests/auto/accessibility/data/scrollbar.qml @@ -1,12 +1,4 @@ import QtQuick 2.5 -import QtQuick.Window 2.2 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 -Window { - visible: true - - ScrollBar { - id: scrollbar - objectName: "scrollbar" - } -} +ScrollBar { } diff --git a/tests/auto/accessibility/data/scrollindicator.qml b/tests/auto/accessibility/data/scrollindicator.qml index ba2ee3f9..4cb81c4e 100644 --- a/tests/auto/accessibility/data/scrollindicator.qml +++ b/tests/auto/accessibility/data/scrollindicator.qml @@ -1,12 +1,4 @@ import QtQuick 2.5 -import QtQuick.Window 2.2 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 -Window { - visible: true - - ScrollIndicator { - id: scrollindicator - objectName: "scrollindicator" - } -} +ScrollIndicator { } diff --git a/tests/auto/accessibility/data/slider.qml b/tests/auto/accessibility/data/slider.qml index 3b906336..775ce7d0 100644 --- a/tests/auto/accessibility/data/slider.qml +++ b/tests/auto/accessibility/data/slider.qml @@ -1,17 +1,10 @@ import QtQuick 2.5 -import QtQuick.Window 2.2 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 -Window { - visible: true - - Slider { - id: slider - objectName: "slider" - from: 0 - to: 100 - value: 50 - stepSize: 1 - orientation: "Horizontal" - } +Slider { + from: 0 + to: 100 + value: 50 + stepSize: 1 + orientation: Qt.Horizontal } diff --git a/tests/auto/accessibility/data/spinbox.qml b/tests/auto/accessibility/data/spinbox.qml index abaee9ca..029cbc65 100644 --- a/tests/auto/accessibility/data/spinbox.qml +++ b/tests/auto/accessibility/data/spinbox.qml @@ -1,16 +1,9 @@ import QtQuick 2.5 -import QtQuick.Window 2.2 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 -Window { - visible: true - - SpinBox { - id: spinbox - objectName: "spinbox" - from: 0 - to: 100 - value: 50 - stepSize: 1 - } +SpinBox { + from: 0 + to: 100 + value: 50 + stepSize: 1 } diff --git a/tests/auto/accessibility/data/stackview.qml b/tests/auto/accessibility/data/stackview.qml new file mode 100644 index 00000000..cf3b76c2 --- /dev/null +++ b/tests/auto/accessibility/data/stackview.qml @@ -0,0 +1,4 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.0 + +StackView { } diff --git a/tests/auto/accessibility/data/swipedelegate.qml b/tests/auto/accessibility/data/swipedelegate.qml new file mode 100644 index 00000000..a8acb5e0 --- /dev/null +++ b/tests/auto/accessibility/data/swipedelegate.qml @@ -0,0 +1,6 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.0 + +SwipeDelegate { + text: "SwipeDelegate" +} diff --git a/tests/auto/accessibility/data/swipeview.qml b/tests/auto/accessibility/data/swipeview.qml new file mode 100644 index 00000000..018ab772 --- /dev/null +++ b/tests/auto/accessibility/data/swipeview.qml @@ -0,0 +1,4 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.0 + +SwipeView { } diff --git a/tests/auto/accessibility/data/switch.qml b/tests/auto/accessibility/data/switch.qml index 88d9af72..8bb43893 100644 --- a/tests/auto/accessibility/data/switch.qml +++ b/tests/auto/accessibility/data/switch.qml @@ -1,13 +1,6 @@ import QtQuick 2.5 -import QtQuick.Window 2.2 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 -Window { - visible: true - - Switch { - //id: switch - objectName: "switch" - text: "Switch" - } +Switch { + text: "Switch" } diff --git a/tests/auto/accessibility/data/switchdelegate.qml b/tests/auto/accessibility/data/switchdelegate.qml new file mode 100644 index 00000000..9f2324c0 --- /dev/null +++ b/tests/auto/accessibility/data/switchdelegate.qml @@ -0,0 +1,6 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.0 + +SwitchDelegate { + text: "SwitchDelegate" +} diff --git a/tests/auto/accessibility/data/tabbar.qml b/tests/auto/accessibility/data/tabbar.qml index 0951a84c..4b1f73a1 100644 --- a/tests/auto/accessibility/data/tabbar.qml +++ b/tests/auto/accessibility/data/tabbar.qml @@ -1,12 +1,4 @@ import QtQuick 2.5 -import QtQuick.Window 2.2 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 -Window { - visible: true - - TabBar { - id: tabbar - objectName: "tabbar" - } -} +TabBar { } diff --git a/tests/auto/accessibility/data/tabbutton.qml b/tests/auto/accessibility/data/tabbutton.qml index cdae7a49..6b979bc8 100644 --- a/tests/auto/accessibility/data/tabbutton.qml +++ b/tests/auto/accessibility/data/tabbutton.qml @@ -1,17 +1,6 @@ import QtQuick 2.5 -import QtQuick.Window 2.2 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 -Window { - visible: true - - TabBar { - id: tabbar - objectName: "TabBar" - TabButton { - id: tabbutton - objectName: "tabbutton" - text: "TabButton" - } - } +TabButton { + text: "TabButton" } diff --git a/tests/auto/accessibility/data/textarea.qml b/tests/auto/accessibility/data/textarea.qml index 31330fa8..93b5b220 100644 --- a/tests/auto/accessibility/data/textarea.qml +++ b/tests/auto/accessibility/data/textarea.qml @@ -1,13 +1,6 @@ import QtQuick 2.5 -import QtQuick.Window 2.2 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 -Window { - visible: true - - TextArea { - id: textarea - objectName: "textarea" - text: "TextArea" - } +TextArea { + text: "TextArea" } diff --git a/tests/auto/accessibility/data/textfield.qml b/tests/auto/accessibility/data/textfield.qml index 29c7b62b..06ba1a58 100644 --- a/tests/auto/accessibility/data/textfield.qml +++ b/tests/auto/accessibility/data/textfield.qml @@ -1,13 +1,6 @@ import QtQuick 2.5 -import QtQuick.Window 2.2 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 -Window { - visible: true - - TextField { - id: textfield - objectName: "textfield" - text: "TextField" - } +TextField { + text: "TextField" } diff --git a/tests/auto/accessibility/data/toolbar.qml b/tests/auto/accessibility/data/toolbar.qml index bb19b839..7b3ba07f 100644 --- a/tests/auto/accessibility/data/toolbar.qml +++ b/tests/auto/accessibility/data/toolbar.qml @@ -1,12 +1,4 @@ import QtQuick 2.5 -import QtQuick.Window 2.2 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 -Window { - visible: true - - ToolBar { - id: toolbar - objectName: "toolbar" - } -} +ToolBar { } diff --git a/tests/auto/accessibility/data/toolbutton.qml b/tests/auto/accessibility/data/toolbutton.qml index a4bbf7a3..79f155ec 100644 --- a/tests/auto/accessibility/data/toolbutton.qml +++ b/tests/auto/accessibility/data/toolbutton.qml @@ -1,13 +1,6 @@ import QtQuick 2.5 -import QtQuick.Window 2.2 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 -Window { - visible: true - - ToolButton { - id: toolbutton - objectName: "toolbutton" - text: "ToolButton" - } +ToolButton { + text: "ToolButton" } diff --git a/tests/auto/accessibility/data/tooltip.qml b/tests/auto/accessibility/data/tooltip.qml new file mode 100644 index 00000000..1d1bae28 --- /dev/null +++ b/tests/auto/accessibility/data/tooltip.qml @@ -0,0 +1,6 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.0 + +ToolTip { + text: "ToolTip" +} diff --git a/tests/auto/accessibility/data/tumbler.qml b/tests/auto/accessibility/data/tumbler.qml new file mode 100644 index 00000000..11c737d7 --- /dev/null +++ b/tests/auto/accessibility/data/tumbler.qml @@ -0,0 +1,4 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.0 + +Tumbler { } diff --git a/tests/auto/accessibility/data/weeknumbercolumn-2.qml b/tests/auto/accessibility/data/weeknumbercolumn-2.qml index bc3b1739..7d682315 100644 --- a/tests/auto/accessibility/data/weeknumbercolumn-2.qml +++ b/tests/auto/accessibility/data/weeknumbercolumn-2.qml @@ -1,12 +1,4 @@ import QtQuick 2.5 -import QtQuick.Window 2.2 import Qt.labs.calendar 1.0 -Window { - visible: true - - WeekNumberColumn { - id: weeknumbercolumn - objectName: "weeknumbercolumn" - } -} +WeekNumberColumn { } diff --git a/tests/auto/accessibility/data/weeknumbercolumn.qml b/tests/auto/accessibility/data/weeknumbercolumn.qml index 7fadb5da..6b024872 100644 --- a/tests/auto/accessibility/data/weeknumbercolumn.qml +++ b/tests/auto/accessibility/data/weeknumbercolumn.qml @@ -1,13 +1,6 @@ import QtQuick 2.5 -import QtQuick.Window 2.2 import Qt.labs.calendar 1.0 -Window { - visible: true - - WeekNumberColumn { - id: weeknumbercolumn - objectName: "weeknumbercolumn" - Accessible.name: "WeekNumberColumn" - } +WeekNumberColumn { + Accessible.name: "WeekNumberColumn" } diff --git a/tests/auto/accessibility/tst_accessibility.cpp b/tests/auto/accessibility/tst_accessibility.cpp index 8c05e2f2..99f6391e 100644 --- a/tests/auto/accessibility/tst_accessibility.cpp +++ b/tests/auto/accessibility/tst_accessibility.cpp @@ -34,27 +34,21 @@ ** ****************************************************************************/ -#include <qtest.h> -#include <QtTest/QSignalSpy> +#include <QtTest/qtest.h> #include <QtQml/qqmlengine.h> #include <QtQml/qqmlcomponent.h> #include <QtQml/qqmlcontext.h> -#include <QtQuick/qquickview.h> #include <QtQuick/private/qquickitem_p.h> -#include <QtLabsTemplates/private/qquickpopup_p.h> +#include <QtQuickTemplates2/private/qquickpopup_p.h> #include "../shared/util.h" -#include "../shared/visualtestutil.h" #ifndef QT_NO_ACCESSIBILITY #include <QtQuick/private/qquickaccessibleattached_p.h> #endif -using namespace QQuickVisualTestUtil; - class tst_accessibility : public QQmlDataTest { Q_OBJECT -public: private slots: void a11y_data(); @@ -70,35 +64,47 @@ void tst_accessibility::a11y_data() QTest::addColumn<int>("role"); QTest::addColumn<QString>("text"); + QTest::newRow("AbstractButton") << "abstractbutton" << 0x0000002B << "AbstractButton"; //QAccessible::Button QTest::newRow("BusyIndicator") << "busyindicator" << 0x00000027 << ""; //QAccessible::Indicator QTest::newRow("Button") << "button" << 0x0000002B << "Button"; //QAccessible::Button QTest::newRow("CheckBox") << "checkbox" << 0x0000002C << "CheckBox"; //QAccessible::CheckBox - // Frame - // GroupBox + QTest::newRow("CheckDelegate") << "checkdelegate" << 0x0000002C << "CheckDelegate"; //QAccessible::CheckBox + QTest::newRow("ComboBox") << "combobox" << 0x0000002E << "ComboBox"; //QAccessible::ComboBox + QTest::newRow("Container") << "container" << 0x00000000 << ""; //QAccessible::NoRole + QTest::newRow("Control") << "control" << 0x00000000 << ""; //QAccessible::NoRole + QTest::newRow("Dial") << "dial" << 0x00000031 << ""; //QAccessible::Dial + QTest::newRow("Drawer") << "drawer" << 0x00000012 << ""; //QAccessible::Dialog + QTest::newRow("Frame") << "frame" << 0x00000013 << ""; //QAccessible::Border + QTest::newRow("GroupBox") << "groupbox" << 0x00000014 << "GroupBox"; //QAccessible::Grouping + QTest::newRow("ItemDelegate") << "itemdelegate" << 0x00000022 << "ItemDelegate"; //QAccessible::ListItem QTest::newRow("Label") << "label" << 0x00000029 << "Label"; //QAccessible::StaticText QTest::newRow("Menu") << "menu" << 0x0000000B << ""; //QAccessible::PopupMenu + QTest::newRow("MenuItem") << "menuitem" << 0x0000000C << "MenuItem"; //QAccessible::MenuItem + QTest::newRow("Page") << "page" << 0x00000025 << "Page"; //QAccessible::PageTab QTest::newRow("PageIndicator") << "pageindicator" << 0x00000027 << ""; //QAccessible::Indicator - QTest::newRow("Popup") << "popup" << 0x00000080 << ""; //QAccessible::LayeredPane + QTest::newRow("Pane") << "pane" << 0x00000010 << ""; //QAccessible::Pane + QTest::newRow("Popup") << "popup" << 0x00000012 << ""; //QAccessible::Dialog QTest::newRow("ProgressBar") << "progressbar" << 0x00000030 << ""; //QAccessible::ProgressBar QTest::newRow("RadioButton") << "radiobutton" << 0x0000002D << "RadioButton"; //QAccessible::RadioButton + QTest::newRow("RadioDelegate") << "radiodelegate" << 0x0000002D << "RadioDelegate"; //QAccessible::RadioButton QTest::newRow("RangeSlider") << "rangeslider" << 0x00000033 << ""; //QAccessible::Slider QTest::newRow("ScrollBar") << "scrollbar" << 0x00000003 << ""; //QAccessible::ScrollBar QTest::newRow("ScrollIndicator") << "scrollindicator" << 0x00000027 << ""; //QAccessible::Indicator QTest::newRow("Slider") << "slider" << 0x00000033 << ""; //QAccessible::Slider QTest::newRow("SpinBox") << "spinbox" << 0x00000034 << ""; //QAccessible::SpinBox - // StackView + QTest::newRow("StackView") << "stackview" << 0x00000080 << ""; //QAccessible::LayeredPane + QTest::newRow("SwipeDelegate") << "swipedelegate" << 0x00000022 << "SwipeDelegate"; //QAccessible::ListItem + QTest::newRow("SwipeView") << "swipeview" << 0x0000003C << ""; //QAccessible::Pane QTest::newRow("Switch") << "switch" << 0x0000002B << "Switch"; //QAccessible::Button + QTest::newRow("SwitchDelegate") << "switchdelegate" << 0x00000022 << "SwitchDelegate"; //QAccessible::ListItem QTest::newRow("TabBar") << "tabbar" << 0x0000003C << ""; //QAccessible::PageTabList QTest::newRow("TabButton") << "tabbutton" << 0x00000025 << "TabButton"; //QAccessible::PageTab QTest::newRow("TextArea") << "textarea" << 0x0000002A << ""; //QAccessible::Accessible.EditableText QTest::newRow("TextField") << "textfield" << 0x0000002A << ""; //QAccessible::Accessible.EditableText QTest::newRow("ToolBar") << "toolbar" << 0x00000016 << ""; //QAccessible::ToolBar QTest::newRow("ToolButton") << "toolbutton" << 0x0000002B << "ToolButton"; //QAccessible::Button - - QTest::newRow("Dial") << "dial" << 0x00000031 << ""; //QAccessible::Dial - // Drawer - // SwipeView - // Tumbler + QTest::newRow("ToolTip") << "tooltip" << 0x0000000D << "ToolTip"; //QAccessible::ToolTip + QTest::newRow("Tumbler") << "tumbler" << 0x00000000 << ""; //QAccessible::NoRole (TODO) QTest::newRow("DayOfWeekRow") << "dayofweekrow" << 0x0 << "DayOfWeekRow"; //QAccessible::NoRole QTest::newRow("MonthGrid") << "monthgrid" << 0x0 << "MonthGrid"; //QAccessible::NoRole @@ -119,7 +125,6 @@ void tst_accessibility::a11y() QFETCH(int, role); QFETCH(QString, text); - QQmlComponent component(&engine); QString fn = name; #ifdef QT_NO_ACCESSIBILITY if (name == QLatin1Literal("dayofweekrow") @@ -127,20 +132,16 @@ void tst_accessibility::a11y() || name == QLatin1Literal("weeknumbercolumn")) fn += QLatin1Literal("-2"); #endif + + QQmlComponent component(&engine); component.loadUrl(testFileUrl(fn + ".qml")); - QObject* created = component.create(); - QVERIFY2(created, qPrintable(component.errorString())); - QScopedPointer<QObject> cleanup(created); - QVERIFY(!cleanup.isNull()); - QQuickWindow* window = qobject_cast<QQuickWindow*>(created); - QVERIFY(window); - window->show(); - QVERIFY(QTest::qWaitForWindowActive(window)); + QScopedPointer<QObject> object(component.create()); + QVERIFY2(!object.isNull(), qPrintable(component.errorString())); - QQuickItem *item = findItem<QQuickItem>(window->contentItem(), name); + QQuickItem *item = qobject_cast<QQuickItem *>(object.data()); if (!item) { - QQuickPopup *popup = window->contentItem()->findChild<QQuickPopup *>(name); + QQuickPopup *popup = qobject_cast<QQuickPopup *>(object.data()); if (popup) item = popup->popupItem(); } diff --git a/tests/auto/activeFocusOnTab/tst_activeFocusOnTab.cpp b/tests/auto/activeFocusOnTab/tst_activeFocusOnTab.cpp deleted file mode 100644 index c618a2d5..00000000 --- a/tests/auto/activeFocusOnTab/tst_activeFocusOnTab.cpp +++ /dev/null @@ -1,494 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <qtest.h> -#include <QtTest/QSignalSpy> -#include <QtQml/qqmlengine.h> -#include <QtQml/qqmlcomponent.h> -#include <QtQml/qqmlcontext.h> -#include <QtQuick/qquickview.h> -#include <QtQuick/private/qquickitem_p.h> -#include <QtGui/private/qguiapplication_p.h> -#include <QtGui/qstylehints.h> -#include "../shared/util.h" -#include "../shared/visualtestutil.h" - -using namespace QQuickVisualTestUtil; - -class tst_activeFocusOnTab : public QQmlDataTest -{ - Q_OBJECT -public: - tst_activeFocusOnTab(); - -private slots: - void initTestCase(); - void cleanup(); - - void allControls(); - void textControls(); -private: - QQmlEngine engine; - bool qt_tab_all_controls() { - return QGuiApplication::styleHints()->tabFocusBehavior() == Qt::TabFocusAllControls; - } -}; - -tst_activeFocusOnTab::tst_activeFocusOnTab() -{ -} - -void tst_activeFocusOnTab::initTestCase() -{ - QQmlDataTest::initTestCase(); -} - -void tst_activeFocusOnTab::cleanup() -{ -} - -void tst_activeFocusOnTab::allControls() -{ - if (!qt_tab_all_controls()) - QSKIP("This platform iterates only text controls. Cannot test iterating all controls."); - - QQuickView *window = new QQuickView(0); - window->setBaseSize(QSize(800,600)); - - window->setSource(testFileUrl("activeFocusOnTab.qml")); - window->show(); - window->requestActivate(); - QVERIFY(QTest::qWaitForWindowActive(window)); - QVERIFY(QGuiApplication::focusWindow() == window); - - // original: button1 - QQuickItem *item = findItem<QQuickItem>(window->rootObject(), "button1"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // Tab: button1->button2 - QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "button2"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // Tab: button2->checkbox - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "checkbox"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // Tab: checkbox->checkbox1 - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "checkbox1"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // Tab: checkbox1->checkbox2 - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "checkbox2"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // Tab: checkbox2->radiobutton - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "radiobutton"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // Tab: radiobutton->radiobutton1 - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "radiobutton1"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // Tab: radiobutton1->radiobutton2 - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "radiobutton2"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // Tab: radiobutton2->rangeslider.first.handle - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "rangeslider"); - QVERIFY(item); - item = item->property("first").value<QObject*>()->property("handle").value<QQuickItem*>(); - QVERIFY(item->hasActiveFocus()); - - // Tab: rangeslider.first.handle->rangeslider.second.handle - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "rangeslider"); - QVERIFY(item); - item = item->property("second").value<QObject*>()->property("handle").value<QQuickItem*>(); - QVERIFY(item->hasActiveFocus()); - - // Tab: rangeslider.second.handle->slider - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "slider"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // Tab: slider->spinbox - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "spinbox"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // Tab: spinbox->switch - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "switch"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // Tab: switch->tabbutton1 - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "tabbutton1"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // Tab: tabbutton1->tabbutton2 - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "tabbutton2"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // Tab: tabbutton2->textfield - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "textfield"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // Tab: textfield->toolbutton - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "toolbutton"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // Tab: toolbutton->textarea - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "textarea"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // BackTab: textarea->toolbutton - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "toolbutton"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // BackTab: toolbutton->textfield - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "textfield"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // BackTab: textfield->tabbutton2 - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "tabbutton2"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // BackTab: tabbutton2->tabbutton2 - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "tabbutton1"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // BackTab: tabbutton1->switch - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "switch"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // BackTab: switch->spinbox - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "spinbox"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // BackTab: spinbox->slider - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "slider"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // BackTab: slider->rangeslider.second.handle - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "rangeslider"); - QVERIFY(item); - item = item->property("second").value<QObject*>()->property("handle").value<QQuickItem*>(); - QVERIFY(item->hasActiveFocus()); - - // BackTab: rangeslider.second.handle->rangeslider.first.handle - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "rangeslider"); - QVERIFY(item); - item = item->property("first").value<QObject*>()->property("handle").value<QQuickItem*>(); - QVERIFY(item->hasActiveFocus()); - - // BackTab: rangeslider.first.handle->radiobutton2 - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "radiobutton2"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // BackTab: radiobutton2->radiobutton1 - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "radiobutton1"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // BackTab: radiobutton1->radiobutton - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "radiobutton"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // BackTab: radiobutton->checkbox2 - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "checkbox2"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // BackTab: checkbox2->checkbox1 - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "checkbox1"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // BackTab: checkbox1->checkbox - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "checkbox"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // BackTab: checkbox->button2 - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "button2"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // BackTab: button2->button1 - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "button1"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // BackTab: button1->textarea - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "textarea"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // BackTab: textarea->toolbutton - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "toolbutton"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - delete window; -} - -void tst_activeFocusOnTab::textControls() -{ - if (qt_tab_all_controls()) - QSKIP("This platform iterates all controls. Cannot test iterating text controls only."); - - QQuickView *window = new QQuickView(0); - window->setBaseSize(QSize(800,600)); - - window->setSource(testFileUrl("activeFocusOnTab.qml")); - window->show(); - window->requestActivate(); - QVERIFY(QTest::qWaitForWindowActive(window)); - QVERIFY(QGuiApplication::focusWindow() == window); - - // original: textfield - QQuickItem *item = findItem<QQuickItem>(window->rootObject(), "textfield"); - QVERIFY(item); - item->forceActiveFocus(); - QVERIFY(item->hasActiveFocus()); - - // Tab: textfield->textarea - QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "textarea"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // BackTab: textarea->textfield - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "textfield"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // BackTab: textfield->spinbox - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "spinbox"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - // BackTab: spinbox->textarea - key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1); - QGuiApplication::sendEvent(window, &key); - QVERIFY(key.isAccepted()); - - item = findItem<QQuickItem>(window->rootObject(), "textarea"); - QVERIFY(item); - QVERIFY(item->hasActiveFocus()); - - delete window; -} - -QTEST_MAIN(tst_activeFocusOnTab) - -#include "tst_activeFocusOnTab.moc" diff --git a/tests/auto/applicationwindow/applicationwindow.pro b/tests/auto/applicationwindow/applicationwindow.pro index eabe81bf..8eb1c933 100644 --- a/tests/auto/applicationwindow/applicationwindow.pro +++ b/tests/auto/applicationwindow/applicationwindow.pro @@ -4,7 +4,7 @@ SOURCES += tst_applicationwindow.cpp osx:CONFIG -= app_bundle -QT += core-private gui-private qml-private quick-private labstemplates-private labscontrols-private testlib +QT += core-private gui-private qml-private quick-private quicktemplates2-private quickcontrols2-private testlib include (../shared/util.pri) diff --git a/tests/auto/applicationwindow/data/activeFocusControl.qml b/tests/auto/applicationwindow/data/activeFocusControl.qml index 51b3241f..b407a91b 100644 --- a/tests/auto/applicationwindow/data/activeFocusControl.qml +++ b/tests/auto/applicationwindow/data/activeFocusControl.qml @@ -39,7 +39,7 @@ ****************************************************************************/ import QtQuick 2.6 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 ApplicationWindow { width: 400 diff --git a/tests/auto/applicationwindow/data/activefocusontab.qml b/tests/auto/applicationwindow/data/activefocusontab.qml index 1ff677fc..6cbd132f 100644 --- a/tests/auto/applicationwindow/data/activefocusontab.qml +++ b/tests/auto/applicationwindow/data/activefocusontab.qml @@ -39,7 +39,7 @@ ****************************************************************************/ import QtQuick 2.6 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 ApplicationWindow { title: "Test Application Window" diff --git a/tests/auto/applicationwindow/data/attachedProperties.qml b/tests/auto/applicationwindow/data/attachedProperties.qml index 72707537..0e518a0b 100644 --- a/tests/auto/applicationwindow/data/attachedProperties.qml +++ b/tests/auto/applicationwindow/data/attachedProperties.qml @@ -40,7 +40,7 @@ import QtQuick 2.6 import QtQuick.Window 2.2 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 ApplicationWindow { property alias childControl: childControl diff --git a/tests/auto/applicationwindow/data/basicapplicationwindow.qml b/tests/auto/applicationwindow/data/basicapplicationwindow.qml index 72266cf6..afac65f3 100644 --- a/tests/auto/applicationwindow/data/basicapplicationwindow.qml +++ b/tests/auto/applicationwindow/data/basicapplicationwindow.qml @@ -39,7 +39,7 @@ ****************************************************************************/ import QtQuick 2.6 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 ApplicationWindow { title: "Test Application Window" diff --git a/tests/auto/applicationwindow/data/defaultFocus.qml b/tests/auto/applicationwindow/data/defaultFocus.qml index ff4e4e4c..ed2a9303 100644 --- a/tests/auto/applicationwindow/data/defaultFocus.qml +++ b/tests/auto/applicationwindow/data/defaultFocus.qml @@ -39,7 +39,7 @@ ****************************************************************************/ import QtQuick 2.6 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 ApplicationWindow { visible: true diff --git a/tests/auto/applicationwindow/data/fill.qml b/tests/auto/applicationwindow/data/fill.qml index 2a9c7bad..02d413b7 100644 --- a/tests/auto/applicationwindow/data/fill.qml +++ b/tests/auto/applicationwindow/data/fill.qml @@ -39,7 +39,7 @@ ****************************************************************************/ import QtQuick 2.6 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 ApplicationWindow { width: 400 diff --git a/tests/auto/applicationwindow/data/focusAfterPopupClosed.qml b/tests/auto/applicationwindow/data/focusAfterPopupClosed.qml new file mode 100644 index 00000000..629e0cf9 --- /dev/null +++ b/tests/auto/applicationwindow/data/focusAfterPopupClosed.qml @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 2.0 + +ApplicationWindow { + width: 200 + height: 200 + visible: true + + signal focusScopeKeyPressed + + property alias toolButton: toolButton + property alias focusScope: focusScope + + header: ToolBar { + ToolButton { + id: toolButton + text: qsTr("File") + onClicked: fileMenu.open() + focusPolicy: Qt.TabFocus + + Menu { + id: fileMenu + y: parent.height + + MenuItem { + text: qsTr("New") + } + MenuItem { + text: qsTr("Open") + } + MenuItem { + text: qsTr("Close") + } + } + } + } + + FocusScope { + id: focusScope + focus: true + anchors.fill: parent + + Keys.onSpacePressed: focusScopeKeyPressed() + } +} + diff --git a/tests/auto/applicationwindow/data/font.qml b/tests/auto/applicationwindow/data/font.qml index 277ee1f2..0bc744b1 100644 --- a/tests/auto/applicationwindow/data/font.qml +++ b/tests/auto/applicationwindow/data/font.qml @@ -39,8 +39,8 @@ ****************************************************************************/ import QtQuick 2.6 -import Qt.labs.controls 1.0 -import Qt.labs.templates 1.0 as T +import QtQuick.Controls 2.0 +import QtQuick.Templates 2.0 as T ApplicationWindow { objectName: "appWin" diff --git a/tests/auto/applicationwindow/data/layout.qml b/tests/auto/applicationwindow/data/layout.qml new file mode 100644 index 00000000..2174b78e --- /dev/null +++ b/tests/auto/applicationwindow/data/layout.qml @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 2.0 + +ApplicationWindow { + width: 200 + height: 200 + visible: true + + header: ToolBar { } + footer: ToolBar { } +} diff --git a/tests/auto/applicationwindow/data/locale.qml b/tests/auto/applicationwindow/data/locale.qml index 59c42f85..d6d46a0d 100644 --- a/tests/auto/applicationwindow/data/locale.qml +++ b/tests/auto/applicationwindow/data/locale.qml @@ -39,8 +39,8 @@ ****************************************************************************/ import QtQuick 2.6 -import Qt.labs.controls 1.0 -import Qt.labs.templates 1.0 as T +import QtQuick.Controls 2.0 +import QtQuick.Templates 2.0 as T ApplicationWindow { objectName: "appWin" diff --git a/tests/auto/applicationwindow/tst_applicationwindow.cpp b/tests/auto/applicationwindow/tst_applicationwindow.cpp index d2937a6d..2f91f664 100644 --- a/tests/auto/applicationwindow/tst_applicationwindow.cpp +++ b/tests/auto/applicationwindow/tst_applicationwindow.cpp @@ -42,13 +42,13 @@ #include <QtQuick/qquickview.h> #include <QtQuick/private/qquickitem_p.h> #include <QtGui/private/qguiapplication_p.h> -#include <QtLabsTemplates/private/qquickapplicationwindow_p.h> -#include <QtLabsTemplates/private/qquickoverlay_p.h> -#include <QtLabsTemplates/private/qquickcontrol_p.h> -#include <QtLabsTemplates/private/qquicklabel_p.h> -#include <QtLabsTemplates/private/qquicktextarea_p.h> -#include <QtLabsTemplates/private/qquicktextfield_p.h> -#include <QtLabsControls/private/qquickproxytheme_p.h> +#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h> +#include <QtQuickTemplates2/private/qquickoverlay_p.h> +#include <QtQuickTemplates2/private/qquickcontrol_p.h> +#include <QtQuickTemplates2/private/qquicklabel_p.h> +#include <QtQuickTemplates2/private/qquicktextarea_p.h> +#include <QtQuickTemplates2/private/qquicktextfield_p.h> +#include <QtQuickControls2/private/qquickproxytheme_p.h> #include "../shared/util.h" #include "../shared/visualtestutil.h" @@ -71,6 +71,8 @@ private slots: void locale(); void activeFocusControl_data(); void activeFocusControl(); + void focusAfterPopupClosed(); + void layout(); }; void tst_applicationwindow::qmlCreation() @@ -316,7 +318,7 @@ void tst_applicationwindow::attachedProperties() QVERIFY(!childWindowControl->property("attached_activeFocusControl").value<QQuickItem *>()); QVERIFY(!childWindowControl->property("attached_header").value<QQuickItem *>()); QVERIFY(!childWindowControl->property("attached_footer").value<QQuickItem *>()); - QVERIFY(!childWindowControl->property("attached_overlay").value<QQuickItem *>()); + QCOMPARE(childWindowControl->property("attached_overlay").value<QQuickItem *>(), QQuickOverlay::overlay(childWindow)); QQuickItem *childWindowItem = object->property("childWindowItem").value<QQuickItem *>(); QVERIFY(childWindowItem); @@ -325,7 +327,7 @@ void tst_applicationwindow::attachedProperties() QVERIFY(!childWindowItem->property("attached_activeFocusControl").value<QQuickItem *>()); QVERIFY(!childWindowItem->property("attached_header").value<QQuickItem *>()); QVERIFY(!childWindowItem->property("attached_footer").value<QQuickItem *>()); - QVERIFY(!childWindowItem->property("attached_overlay").value<QQuickItem *>()); + QCOMPARE(childWindowItem->property("attached_overlay").value<QQuickItem *>(), QQuickOverlay::overlay(childWindow)); QObject *childWindowObject = object->property("childWindowObject").value<QObject *>(); QVERIFY(childWindowObject); @@ -420,7 +422,7 @@ void tst_applicationwindow::attachedProperties() QCOMPARE(childItem->property("attached_footer").value<QQuickItem *>(), childAppWindow->footer()); QCOMPARE(childItem->property("attached_overlay").value<QQuickItem *>(), childAppWindow->overlay()); - childControl->setParentItem(Q_NULLPTR); + childControl->setParentItem(nullptr); QVERIFY(!childControl->window()); QVERIFY(!childControl->property("attached_window").value<QQuickApplicationWindow *>()); QVERIFY(!childControl->property("attached_contentItem").value<QQuickItem *>()); @@ -429,7 +431,7 @@ void tst_applicationwindow::attachedProperties() QVERIFY(!childControl->property("attached_footer").value<QQuickItem *>()); QVERIFY(!childControl->property("attached_overlay").value<QQuickItem *>()); - childItem->setParentItem(Q_NULLPTR); + childItem->setParentItem(nullptr); QVERIFY(!childItem->window()); QVERIFY(!childItem->property("attached_window").value<QQuickApplicationWindow *>()); QVERIFY(!childItem->property("attached_contentItem").value<QQuickItem *>()); @@ -505,9 +507,8 @@ class TestTheme : public QQuickProxyTheme public: TestTheme(QPlatformTheme *theme) : QQuickProxyTheme(theme), m_font("Courier") { QGuiApplicationPrivate::platform_theme = this; } - ~TestTheme() { QGuiApplicationPrivate::platform_theme = theme(); } - const QFont *font(Font type = SystemFont) const Q_DECL_OVERRIDE + const QFont *font(Font type = SystemFont) const override { Q_UNUSED(type); return &m_font; @@ -522,7 +523,7 @@ void tst_applicationwindow::defaultFont() QQmlEngine engine; QQmlComponent component(&engine); - component.setData("import Qt.labs.controls 1.0; ApplicationWindow { }", QUrl()); + component.setData("import QtQuick.Controls 2.0; ApplicationWindow { }", QUrl()); QScopedPointer<QQuickApplicationWindow> window; window.reset(static_cast<QQuickApplicationWindow *>(component.create())); @@ -640,6 +641,97 @@ void tst_applicationwindow::activeFocusControl() QCOMPARE(window->activeFocusControl(), activeFocusControl); } +void tst_applicationwindow::focusAfterPopupClosed() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.loadUrl(testFileUrl("focusAfterPopupClosed.qml")); + QScopedPointer<QQuickWindow> window(qobject_cast<QQuickWindow*>(component.create())); + QVERIFY(window); + + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + QVERIFY(QGuiApplication::focusWindow() == window.data()); + + QQuickItem* contentItem = window->contentItem(); + QVERIFY(contentItem); + QVERIFY(contentItem->hasActiveFocus()); + + QQuickItem* focusScope = window->property("focusScope").value<QQuickItem*>(); + QVERIFY(focusScope); + QVERIFY(focusScope->hasActiveFocus()); + + QSignalSpy spy(window.data(), SIGNAL(focusScopeKeyPressed())); + QTest::keyClick(window.data(), Qt::Key_Space); + QCOMPARE(spy.count(), 1); + + // Open the menu. + QQuickItem* toolButton = window->property("toolButton").value<QQuickItem*>(); + QVERIFY(toolButton); + QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, + toolButton->mapFromScene(QPointF(toolButton->width() / 2, toolButton->height() / 2)).toPoint()); + QVERIFY(!focusScope->hasActiveFocus()); + + // The FocusScope shouldn't receive any key events while the menu is open. + QTest::keyClick(window.data(), Qt::Key_Space); + QCOMPARE(spy.count(), 1); + + // Close the menu. The FocusScope should regain focus. + QTest::keyClick(window.data(), Qt::Key_Escape); + QVERIFY(focusScope->hasActiveFocus()); + + QTest::keyClick(window.data(), Qt::Key_Space); + QCOMPARE(spy.count(), 2); +} + +void tst_applicationwindow::layout() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.loadUrl(testFileUrl("layout.qml")); + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + + QQuickApplicationWindow* window = qobject_cast<QQuickApplicationWindow*>(object.data()); + QVERIFY(window); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + QQuickItem *content = window->contentItem(); + QVERIFY(content); + QQuickItem *header = window->header(); + QVERIFY(header); + QQuickItem *footer = window->footer(); + QVERIFY(footer); + + QCOMPARE(header->x(), 0.0); + QCOMPARE(header->y(), -header->height()); + QCOMPARE(header->width(), qreal(window->width())); + QVERIFY(header->height() > 0); + + QCOMPARE(footer->x(), 0.0); + QCOMPARE(footer->y(), content->height()); + QCOMPARE(footer->width(), qreal(window->width())); + QVERIFY(footer->height() > 0.0); + + QCOMPARE(content->x(), 0.0); + QCOMPARE(content->y(), header->height()); + QCOMPARE(content->width(), qreal(window->width())); + QCOMPARE(content->height(), window->height() - header->height() - footer->height()); + + header->setVisible(false); + QCOMPARE(content->x(), 0.0); + QCOMPARE(content->y(), 0.0); + QCOMPARE(content->width(), qreal(window->width())); + QCOMPARE(content->height(), window->height() - footer->height()); + + footer->setVisible(false); + QCOMPARE(content->x(), 0.0); + QCOMPARE(content->y(), 0.0); + QCOMPARE(content->width(), qreal(window->width())); + QCOMPARE(content->height(), qreal(window->height())); +} + QTEST_MAIN(tst_applicationwindow) #include "tst_applicationwindow.moc" diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index ec9d4111..91850968 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -1,15 +1,22 @@ TEMPLATE = subdirs SUBDIRS += \ accessibility \ - activeFocusOnTab \ applicationwindow \ calendar \ controls \ - material \ + drawer \ menu \ popup \ pressandhold \ + qquickmaterialstyle \ + qquickmaterialstyleconf \ + qquickstyle \ + qquickstyleselector \ + qquickuniversalstyle \ + qquickuniversalstyleconf \ sanity \ - snippets \ - styles \ - universal + snippets + +# QTBUG-50295 +!linux: SUBDIRS += \ + focus diff --git a/tests/auto/calendar/data/tst_dayofweekrow.qml b/tests/auto/calendar/data/tst_dayofweekrow.qml index 4d332110..09070612 100644 --- a/tests/auto/calendar/data/tst_dayofweekrow.qml +++ b/tests/auto/calendar/data/tst_dayofweekrow.qml @@ -64,7 +64,7 @@ TestCase { compare(control.contentItem.children[0].text, "Sun") control.locale = Qt.locale("no_NO") - compare(control.contentItem.children[0].text, "ma.") + compare(control.contentItem.children[0].text, "man.") control.locale = Qt.locale("fi_FI") compare(control.contentItem.children[0].text, "ma") diff --git a/tests/auto/cmake/CMakeLists.txt b/tests/auto/cmake/CMakeLists.txt index 3d77b9e5..0c6723dc 100644 --- a/tests/auto/cmake/CMakeLists.txt +++ b/tests/auto/cmake/CMakeLists.txt @@ -9,4 +9,5 @@ find_package(Qt5Core REQUIRED) include("${_Qt5CTestMacros}") test_module_includes( + QuickControls2 QQuickStyle ) diff --git a/tests/auto/controls/controls.pro b/tests/auto/controls/controls.pro index d1dd6814..8f2f8e69 100644 --- a/tests/auto/controls/controls.pro +++ b/tests/auto/controls/controls.pro @@ -1,12 +1,5 @@ -TEMPLATE = app -TARGET = tst_controls -CONFIG += qmltestcase - -SOURCES += \ - $$PWD/tst_controls.cpp - -OTHER_FILES += \ - $$PWD/data/* - -TESTDATA += \ - $$PWD/data/tst_* +TEMPLATE = subdirs +SUBDIRS += \ + default \ + material \ + universal diff --git a/tests/auto/controls/data/ControlSpy.qml b/tests/auto/controls/data/SignalSequenceSpy.qml index 45d603b8..798b8b9c 100644 --- a/tests/auto/controls/data/ControlSpy.qml +++ b/tests/auto/controls/data/SignalSequenceSpy.qml @@ -42,6 +42,11 @@ import QtQuick 2.5 QtObject { property QtObject target: null + // We could just listen to all signals (try { signal.connect(/*...*/) } catch (e)) + // if it weren't for the fact the spy is often declared as a property of the control, + // which creates a "spyChanged" signal, which leads to an unexpected spyChanged signal + // emission. However, we don't know what the property will be called, so the signals + // have to be listed explicitly. property var signals: [] property var expectedSequence: [] property int sequenceIndex: 0 @@ -86,7 +91,7 @@ QtObject { return; if (sequenceIndex >= expectedSequence.length) { - console.warn("ControlSpy: Received unexpected signal '" + signalName + "' (none expected).") + console.warn("SignalSequenceSpy: Received unexpected signal '" + signalName + "' (none expected).") sequenceFailure = true return } @@ -104,7 +109,7 @@ QtObject { var expectedValues = expectedSignalData[1] for (var p in expectedValues) { if (target[p] != expectedValues[p]) { - console.warn("ControlSpy: Value mismatch for property '" + p + "' after '" + signalName + "' signal." + + console.warn("SignalSequenceSpy: Value mismatch for property '" + p + "' after '" + signalName + "' signal." + __mismatchValuesFormat(target[p], expectedValues[p])) sequenceFailure = true return @@ -114,7 +119,7 @@ QtObject { return } } - console.warn("ControlSpy: Received unexpected signal." + + console.warn("SignalSequenceSpy: Received unexpected signal (is \"" + expectedSignal + "\" listed in the signals array?)" + __mismatchValuesFormat(signalName, expectedSignal)) sequenceFailure = true } diff --git a/tests/auto/controls/data/TumblerDatePicker.qml b/tests/auto/controls/data/TumblerDatePicker.qml index a929a53f..18d7fb97 100644 --- a/tests/auto/controls/data/TumblerDatePicker.qml +++ b/tests/auto/controls/data/TumblerDatePicker.qml @@ -39,7 +39,7 @@ ****************************************************************************/ import QtQuick 2.6 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 Row { id: datePicker diff --git a/tests/auto/controls/data/tst_abstractbutton.qml b/tests/auto/controls/data/tst_abstractbutton.qml index 4e635d63..ba5ee94c 100644 --- a/tests/auto/controls/data/tst_abstractbutton.qml +++ b/tests/auto/controls/data/tst_abstractbutton.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.templates 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase @@ -55,6 +55,11 @@ TestCase { AbstractButton {} } + Component { + id: item + Item { } + } + function test_text() { var control = button.createObject(testCase); verify(control); @@ -68,12 +73,34 @@ TestCase { control.destroy(); } - function test_highlighted() { + function test_baseline() { + var control = button.createObject(testCase, {padding: 6}) + verify(control) + compare(control.baselineOffset, 0) + control.contentItem = item.createObject(control, {baselineOffset: 12}) + compare(control.baselineOffset, 18) + control.destroy() + } + + function test_implicitSize() { var control = button.createObject(testCase) verify(control) - compare(control.highlighted, false) - control.highlighted = true - compare(control.highlighted, true) + compare(control.implicitWidth, 0) + compare(control.implicitHeight, 0) + + control.contentItem = item.createObject(control, {implicitWidth: 10, implicitHeight: 20}) + compare(control.implicitWidth, 10) + compare(control.implicitHeight, 20) + + control.background = item.createObject(control, {implicitWidth: 20, implicitHeight: 30}) + compare(control.implicitWidth, 20) + compare(control.implicitHeight, 30) + + control.padding = 100 + compare(control.implicitWidth, 210) + compare(control.implicitHeight, 220) + + control.destroy() } } diff --git a/tests/auto/controls/data/tst_busyindicator.qml b/tests/auto/controls/data/tst_busyindicator.qml index d4cb9d31..142ec70a 100644 --- a/tests/auto/controls/data/tst_busyindicator.qml +++ b/tests/auto/controls/data/tst_busyindicator.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_button.qml b/tests/auto/controls/data/tst_button.qml index 45fad8cb..9038f1d6 100644 --- a/tests/auto/controls/data/tst_button.qml +++ b/tests/auto/controls/data/tst_button.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase @@ -52,16 +52,21 @@ TestCase { Component { id: button - Button { - id: control + Button { } + } - property ControlSpy spy: ControlSpy { - target: control - signals: ["pressed", "released", "canceled", "clicked", "doubleClicked", "pressedChanged"] - } + Component { + id: signalSequenceSpy + SignalSequenceSpy { + signals: ["pressed", "released", "canceled", "clicked", "doubleClicked", "pressedChanged", "downChanged", "checkedChanged"] } } + Component { + id: signalSpy + SignalSpy { } + } + function test_text() { var control = button.createObject(testCase) verify(control) @@ -79,58 +84,70 @@ TestCase { var control = button.createObject(testCase) verify(control) + var sequenceSpy = signalSequenceSpy.createObject(control, {target: control}) + // click - control.spy.expectedSequence = [["pressedChanged", { "pressed": true }], "pressed"] + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true }], + ["downChanged", { "down": true }], + "pressed"] mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton) compare(control.pressed, true) - verify(control.spy.success) + verify(sequenceSpy.success) - control.spy.expectedSequence = [["pressedChanged", { "pressed": false }], + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false }], + ["downChanged", { "down": false }], "released", "clicked"] mouseRelease(control, control.width / 2, control.height / 2, Qt.LeftButton) compare(control.pressed, false) - verify(control.spy.success) + verify(sequenceSpy.success) // release outside - control.spy.expectedSequence = [["pressedChanged", { "pressed": true }], "pressed"] + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true }], + ["downChanged", { "down": true }], + "pressed"] mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton) compare(control.pressed, true) - verify(control.spy.success) + verify(sequenceSpy.success) - control.spy.expectedSequence = [["pressedChanged", { "pressed": false }]] + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false }], + ["downChanged", { "down": false }]] mouseMove(control, control.width * 2, control.height * 2, 0, Qt.LeftButton) compare(control.pressed, false) - verify(control.spy.success) + verify(sequenceSpy.success) - control.spy.expectedSequence = [["canceled", { "pressed": false }]] + sequenceSpy.expectedSequence = [["canceled", { "pressed": false }]] mouseRelease(control, control.width * 2, control.height * 2, Qt.LeftButton) compare(control.pressed, false) - verify(control.spy.success) + verify(sequenceSpy.success) // right button - control.spy.expectedSequence = [] + sequenceSpy.expectedSequence = [] mousePress(control, control.width / 2, control.height / 2, Qt.RightButton) compare(control.pressed, false) mouseRelease(control, control.width / 2, control.height / 2, Qt.RightButton) compare(control.pressed, false) - verify(control.spy.success) + verify(sequenceSpy.success) // double click - control.spy.expectedSequence = [["pressedChanged", { "pressed": true }], + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true }], + ["downChanged", { "down": true }], "pressed", ["pressedChanged", { "pressed": false }], + ["downChanged", { "down": false }], "released", "clicked", ["pressedChanged", { "pressed": true }], + ["downChanged", { "down": true }], "pressed", "doubleClicked", ["pressedChanged", { "pressed": false }], + ["downChanged", { "down": false }], "released", "clicked"] mouseDoubleClickSequence(control, control.width / 2, control.height / 2, Qt.LeftButton) - verify(control.spy.success) + verify(sequenceSpy.success) control.destroy() } @@ -142,22 +159,26 @@ TestCase { control.forceActiveFocus() verify(control.activeFocus) + var sequenceSpy = signalSequenceSpy.createObject(control, {target: control}) + // click - control.spy.expectedSequence = [["pressedChanged", { "pressed": true }], + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true }], + ["downChanged", { "down": true }], "pressed", ["pressedChanged", { "pressed": false }], + ["downChanged", { "down": false }], "released", "clicked"] keyClick(Qt.Key_Space) - verify(control.spy.success) + verify(sequenceSpy.success) // no change - control.spy.expectedSequence = [] + sequenceSpy.expectedSequence = [] var keys = [Qt.Key_Enter, Qt.Key_Return, Qt.Key_Escape, Qt.Key_Tab] for (var i = 0; i < keys.length; ++i) { - control.spy.reset() + sequenceSpy.reset() keyClick(keys[i]) - verify(control.spy.success) + verify(sequenceSpy.success) } control.destroy() @@ -167,8 +188,6 @@ TestCase { return "actual event:" + JSON.stringify(actual) + ", expected event:" + JSON.stringify(expected) } - SignalSpy { id: clickSpy; signalName: "clicked" } - function test_autoRepeat() { var control = button.createObject(testCase) verify(control) @@ -180,47 +199,77 @@ TestCase { control.forceActiveFocus() verify(control.activeFocus) - clickSpy.target = control + var clickSpy = signalSpy.createObject(control, {target: control, signalName: "clicked"}) verify(clickSpy.valid) + var pressSpy = signalSpy.createObject(control, {target: control, signalName: "pressed"}) + verify(pressSpy.valid) + var releaseSpy = signalSpy.createObject(control, {target: control, signalName: "released"}) + verify(releaseSpy.valid) - var repeatCount = 2 - var repeatSequence = [["pressedChanged", { "pressed": true }], - "pressed", - "released", - "clicked", - "pressed", - "released", - "clicked", - "pressed"] - - // auto-repeat a couple of mouse clicks - control.spy.expectedSequence = repeatSequence + // auto-repeat mouse click mousePress(control) compare(control.pressed, true) - tryCompare(clickSpy, "count", repeatCount) - verify(control.spy.success) - - control.spy.expectedSequence = [["pressedChanged", { "pressed": false }], - "released", - "clicked"] + clickSpy.wait() + clickSpy.wait() + compare(pressSpy.count, clickSpy.count + 1) + compare(releaseSpy.count, clickSpy.count) mouseRelease(control) compare(control.pressed, false) - verify(control.spy.success) + compare(clickSpy.count, pressSpy.count) + compare(releaseSpy.count, pressSpy.count) - // auto-repeat a couple of key clicks clickSpy.clear() - control.spy.expectedSequence = repeatSequence + pressSpy.clear() + releaseSpy.clear() + + // auto-repeat key click keyPress(Qt.Key_Space) compare(control.pressed, true) - tryCompare(clickSpy, "count", repeatCount) - verify(control.spy.success) - - control.spy.expectedSequence = [["pressedChanged", { "pressed": false }], - "released", - "clicked"] + clickSpy.wait() + clickSpy.wait() + compare(pressSpy.count, clickSpy.count + 1) + compare(releaseSpy.count, clickSpy.count) keyRelease(Qt.Key_Space) compare(control.pressed, false) - verify(control.spy.success) + compare(clickSpy.count, pressSpy.count) + compare(releaseSpy.count, pressSpy.count) + + clickSpy.clear() + pressSpy.clear() + releaseSpy.clear() + + mousePress(control) + compare(control.pressed, true) + clickSpy.wait() + compare(pressSpy.count, clickSpy.count + 1) + compare(releaseSpy.count, clickSpy.count) + + // move inside during repeat -> continue repeat + mouseMove(control, control.width / 4, control.height / 4) + clickSpy.wait() + compare(pressSpy.count, clickSpy.count + 1) + compare(releaseSpy.count, clickSpy.count) + + clickSpy.clear() + pressSpy.clear() + releaseSpy.clear() + + // move outside during repeat -> stop repeat + mouseMove(control, -1, -1) + // NOTE: The following wait() is NOT a reliable way to test that the + // auto-repeat timer is not running, but there's no way dig into the + // private APIs from QML. If this test ever fails in the future, it + // indicates that the auto-repeat timer logic is broken. + wait(125) + compare(clickSpy.count, 0) + compare(pressSpy.count, 0) + compare(releaseSpy.count, 0) + + mouseRelease(control, -1, -1) + compare(control.pressed, false) + compare(clickSpy.count, 0) + compare(pressSpy.count, 0) + compare(releaseSpy.count, 0) control.destroy() } @@ -228,7 +277,65 @@ TestCase { function test_baseline() { var control = button.createObject(testCase) verify(control) - compare(control.baselineOffset, control.label.y + control.label.baselineOffset) + compare(control.baselineOffset, control.contentItem.y + control.contentItem.baselineOffset) + control.destroy() + } + + function test_checkable() { + var control = button.createObject(testCase) + verify(control) + verify(control.hasOwnProperty("checkable")) + verify(!control.checkable) + + var sequenceSpy = signalSequenceSpy.createObject(control, {target: control}) + + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true }], + ["downChanged", { "down": true }], + "pressed", + ["pressedChanged", { "pressed": false }], + ["downChanged", { "down": false }], + "released", + "clicked"] + mouseClick(control) + verify(!control.checked) + verify(sequenceSpy.success) + + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true }], + ["downChanged", { "down": true }], + "pressed", + ["pressedChanged", { "pressed": false }], + ["downChanged", { "down": false }], + ["checkedChanged", { "checked": true }], + "released", + "clicked"] + control.checkable = true + mouseClick(control) + verify(control.checked) + verify(sequenceSpy.success) + + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true }], + ["downChanged", { "down": true }], + "pressed", + ["pressedChanged", { "pressed": false }], + ["downChanged", { "down": false }], + ["checkedChanged", { "checked": false }], + "released", + "clicked"] + mouseClick(control) + verify(!control.checked) + verify(sequenceSpy.success) + + control.destroy() + } + + function test_highlighted() { + var control = button.createObject(testCase) + verify(control) + verify(!control.highlighted) + + control.highlighted = true + verify(control.highlighted) + control.destroy() } } diff --git a/tests/auto/controls/data/tst_buttongroup.qml b/tests/auto/controls/data/tst_buttongroup.qml index b640a868..754e4f0b 100644 --- a/tests/auto/controls/data/tst_buttongroup.qml +++ b/tests/auto/controls/data/tst_buttongroup.qml @@ -40,8 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 -import Qt.labs.templates 1.0 as T +import QtQuick.Controls 2.0 TestCase { id: testCase @@ -56,30 +55,9 @@ TestCase { ButtonGroup { } } - SignalSpy { - id: checkedButtonSpy - signalName: "checkedButtonChanged" - } - - SignalSpy { - id: buttonsSpy - signalName: "buttonsChanged" - } - - function init() { - verify(!checkedButtonSpy.target) - compare(checkedButtonSpy.count, 0) - - verify(!buttonsSpy.target) - compare(buttonsSpy.count, 0) - } - - function cleanup() { - checkedButtonSpy.target = null - checkedButtonSpy.clear() - - buttonsSpy.target = null - buttonsSpy.clear() + Component { + id: signalSpy + SignalSpy { } } function test_null() { @@ -106,7 +84,7 @@ TestCase { var group = buttonGroup.createObject(testCase) verify(group) - checkedButtonSpy.target = group + var checkedButtonSpy = signalSpy.createObject(testCase, {target: group, signalName: "checkedButtonChanged"}) verify(checkedButtonSpy.valid) verify(!group.checkedButton) @@ -177,7 +155,7 @@ TestCase { var group = buttonGroup.createObject(testCase) verify(group) - buttonsSpy.target = group + var buttonsSpy = signalSpy.createObject(testCase, {target: group, signalName: "buttonsChanged"}) verify(buttonsSpy.valid) compare(group.buttons.length, 0) @@ -212,7 +190,7 @@ TestCase { group.buttons = [] compare(group.buttons.length, 0) - compare(group.checkedButton, null) + tryCompare(group, "checkedButton", null) compare(buttonsSpy.count, 5) group.destroy() @@ -302,7 +280,7 @@ TestCase { var group = buttonGroup.createObject(testCase) verify(group) - buttonsSpy.target = group + var buttonsSpy = signalSpy.createObject(testCase, {target: group, signalName: "buttonsChanged"}) verify(buttonsSpy.valid) var button1 = button.createObject(testCase, {objectName: "button1", checked: true}) @@ -321,4 +299,31 @@ TestCase { group.destroy() } + + Component { + id: repeater + Column { + id: column + property ButtonGroup group: ButtonGroup { buttons: column.children } + property alias repeater: r + Repeater { + id: r + model: 3 + delegate: RadioDelegate { + checked: index == 0 + objectName: index + } + } + } + } + + function test_repeater() { + var container = repeater.createObject(testCase) + verify(container) + + verify(container.group.checkedButton) + compare(container.group.checkedButton.objectName, "0") + + container.destroy() + } } diff --git a/tests/auto/controls/data/tst_checkbox.qml b/tests/auto/controls/data/tst_checkbox.qml index 4efc7223..044b0006 100644 --- a/tests/auto/controls/data/tst_checkbox.qml +++ b/tests/auto/controls/data/tst_checkbox.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase @@ -52,13 +52,13 @@ TestCase { Component { id: checkBox - CheckBox { - id: control + CheckBox { } + } - property ControlSpy spy: ControlSpy { - target: control - signals: ["pressed", "released", "canceled", "clicked", "pressedChanged", "checkedChanged", "checkStateChanged"] - } + Component { + id: signalSequenceSpy + SignalSequenceSpy { + signals: ["pressed", "released", "canceled", "clicked", "pressedChanged", "checkedChanged", "checkStateChanged"] } } @@ -79,24 +79,26 @@ TestCase { var control = checkBox.createObject(testCase) verify(control) - control.spy.expectedSequence = [] + var sequenceSpy = signalSequenceSpy.createObject(control, {target: control}) + + sequenceSpy.expectedSequence = [] compare(control.checked, false) compare(control.checkState, Qt.Unchecked) - verify(control.spy.success) + verify(sequenceSpy.success) - control.spy.expectedSequence = [["checkStateChanged", { "checked": true, "checkState": Qt.Checked }], + sequenceSpy.expectedSequence = [["checkStateChanged", { "checked": true, "checkState": Qt.Checked }], ["checkedChanged", { "checked": true, "checkState": Qt.Checked }]] control.checked = true compare(control.checked, true) compare(control.checkState, Qt.Checked) - verify(control.spy.success) + verify(sequenceSpy.success) - control.spy.expectedSequence = [["checkStateChanged", { "checked": false, "checkState": Qt.Unchecked }], + sequenceSpy.expectedSequence = [["checkStateChanged", { "checked": false, "checkState": Qt.Unchecked }], ["checkedChanged", { "checked": false, "checkState": Qt.Unchecked }]] control.checked = false compare(control.checked, false) compare(control.checkState, Qt.Unchecked) - verify(control.spy.success) + verify(sequenceSpy.success) control.destroy() } @@ -105,24 +107,26 @@ TestCase { var control = checkBox.createObject(testCase) verify(control) - control.spy.expectedSequence = [] + var sequenceSpy = signalSequenceSpy.createObject(control, {target: control}) + + sequenceSpy.expectedSequence = [] compare(control.checked, false) compare(control.checkState, Qt.Unchecked) - verify(control.spy.success) + verify(sequenceSpy.success) - control.spy.expectedSequence = [["checkStateChanged", { "checked": true, "checkState": Qt.Checked }], + sequenceSpy.expectedSequence = [["checkStateChanged", { "checked": true, "checkState": Qt.Checked }], ["checkedChanged", { "checked": true, "checkState": Qt.Checked }]] control.checkState = Qt.Checked compare(control.checked, true) compare(control.checkState, Qt.Checked) - verify(control.spy.success) + verify(sequenceSpy.success) - control.spy.expectedSequence = [["checkStateChanged", { "checked": false, "checkState": Qt.Unchecked }], + sequenceSpy.expectedSequence = [["checkStateChanged", { "checked": false, "checkState": Qt.Unchecked }], ["checkedChanged", { "checked": false, "checkState": Qt.Unchecked }]] control.checkState = Qt.Unchecked compare(control.checked, false) compare(control.checkState, Qt.Unchecked) - verify(control.spy.success) + verify(sequenceSpy.success) control.destroy() } @@ -131,67 +135,69 @@ TestCase { var control = checkBox.createObject(testCase) verify(control) + var sequenceSpy = signalSequenceSpy.createObject(control, {target: control}) + // check - control.spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false, "checkState": Qt.Unchecked }], + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false, "checkState": Qt.Unchecked }], "pressed"] mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton) compare(control.pressed, true) - verify(control.spy.success) + verify(sequenceSpy.success) - control.spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false, "checkState": Qt.Unchecked }], - "released", - "clicked", + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false, "checkState": Qt.Unchecked }], ["checkStateChanged", { "pressed": false, "checked": true, "checkState": Qt.Checked }], - ["checkedChanged", { "pressed": false, "checked": true, "checkState": Qt.Checked }]] + ["checkedChanged", { "pressed": false, "checked": true, "checkState": Qt.Checked }], + "released", + "clicked"] mouseRelease(control, control.width / 2, control.height / 2, Qt.LeftButton) compare(control.checked, true) compare(control.checkState, Qt.Checked) compare(control.pressed, false) - verify(control.spy.success) + verify(sequenceSpy.success) // uncheck - control.spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true, "checkState": Qt.Checked }], + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true, "checkState": Qt.Checked }], "pressed"] mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton) compare(control.pressed, true) - verify(control.spy.success) - control.spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": true, "checkState": Qt.Checked }], - "released", - "clicked", + verify(sequenceSpy.success) + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": true, "checkState": Qt.Checked }], ["checkStateChanged", { "pressed": false, "checked": false, "checkState": Qt.Unchecked }], - ["checkedChanged", { "pressed": false, "checked": false, "checkState": Qt.Unchecked }]] + ["checkedChanged", { "pressed": false, "checked": false, "checkState": Qt.Unchecked }], + "released", + "clicked"] mouseRelease(control, control.width / 2, control.height / 2, Qt.LeftButton) compare(control.checked, false) compare(control.checkState, Qt.Unchecked) compare(control.pressed, false) - verify(control.spy.success) + verify(sequenceSpy.success) // release outside - control.spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false, "checkState": Qt.Unchecked }], + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false, "checkState": Qt.Unchecked }], "pressed"] mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton) compare(control.pressed, true) - verify(control.spy.success) - control.spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false, "checkState": Qt.Unchecked }]] + verify(sequenceSpy.success) + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false, "checkState": Qt.Unchecked }]] mouseMove(control, control.width * 2, control.height * 2, 0, Qt.LeftButton) compare(control.pressed, false) - verify(control.spy.success) - control.spy.expectedSequence = [["canceled", { "pressed": false, "checked": false, "checkState": Qt.Unchecked }]] + verify(sequenceSpy.success) + sequenceSpy.expectedSequence = [["canceled", { "pressed": false, "checked": false, "checkState": Qt.Unchecked }]] mouseRelease(control, control.width * 2, control.height * 2, Qt.LeftButton) compare(control.checked, false) compare(control.checkState, Qt.Unchecked) compare(control.pressed, false) - verify(control.spy.success) + verify(sequenceSpy.success) // right button - control.spy.expectedSequence = [] + sequenceSpy.expectedSequence = [] mousePress(control, control.width / 2, control.height / 2, Qt.RightButton) compare(control.pressed, false) mouseRelease(control, control.width / 2, control.height / 2, Qt.RightButton) compare(control.checked, false) compare(control.checkState, Qt.Unchecked) compare(control.pressed, false) - verify(control.spy.success) + verify(sequenceSpy.success) control.destroy() } @@ -200,45 +206,47 @@ TestCase { var control = checkBox.createObject(testCase) verify(control) - control.spy.expectedSequence = [] + var sequenceSpy = signalSequenceSpy.createObject(control, {target: control}) + + sequenceSpy.expectedSequence = [] control.forceActiveFocus() verify(control.activeFocus) - verify(control.spy.success) + verify(sequenceSpy.success) // check - control.spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false, "checkState": Qt.Unchecked }], + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false, "checkState": Qt.Unchecked }], "pressed", ["pressedChanged", { "pressed": false, "checked": false, "checkState": Qt.Unchecked }], - "released", - "clicked", ["checkStateChanged", { "pressed": false, "checked": true, "checkState": Qt.Checked }], - ["checkedChanged", { "pressed": false, "checked": true, "checkState": Qt.Checked }]] + ["checkedChanged", { "pressed": false, "checked": true, "checkState": Qt.Checked }], + "released", + "clicked"] keyClick(Qt.Key_Space) compare(control.checked, true) compare(control.checkState, Qt.Checked) - verify(control.spy.success) + verify(sequenceSpy.success) // uncheck - control.spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true, "checkState": Qt.Checked }], + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true, "checkState": Qt.Checked }], "pressed", ["pressedChanged", { "pressed": false, "checked": true, "checkState": Qt.Checked }], - "released", - "clicked", ["checkStateChanged", { "pressed": false, "checked": false, "checkState": Qt.Unchecked }], - ["checkedChanged", { "pressed": false, "checked": false, "checkState": Qt.Unchecked }]] + ["checkedChanged", { "pressed": false, "checked": false, "checkState": Qt.Unchecked }], + "released", + "clicked"] keyClick(Qt.Key_Space) compare(control.checked, false) compare(control.checkState, Qt.Unchecked) - verify(control.spy.success) + verify(sequenceSpy.success) // no change - control.spy.expectedSequence = [] + sequenceSpy.expectedSequence = [] var keys = [Qt.Key_Enter, Qt.Key_Return, Qt.Key_Escape, Qt.Key_Tab] for (var i = 0; i < keys.length; ++i) { - control.spy.reset() + sequenceSpy.reset() keyClick(keys[i]) compare(control.checked, false) - verify(control.spy.success) + verify(sequenceSpy.success) } control.destroy() @@ -323,7 +331,9 @@ TestCase { function test_tristate() { var control = checkBox.createObject(testCase) - control.spy.expectedSequence = [] + var sequenceSpy = signalSequenceSpy.createObject(control, {target: control}) + + sequenceSpy.expectedSequence = [] control.forceActiveFocus() verify(control.activeFocus) @@ -331,89 +341,89 @@ TestCase { compare(control.checked, false) compare(control.checkState, Qt.Unchecked) - control.spy.expectedSequence = [["checkStateChanged", { "pressed": false, "checked": true, "checkState": Qt.PartiallyChecked }], + sequenceSpy.expectedSequence = [["checkStateChanged", { "pressed": false, "checked": true, "checkState": Qt.PartiallyChecked }], ["checkedChanged", { "pressed": false, "checked": true, "checkState": Qt.PartiallyChecked }]] control.checkState = Qt.PartiallyChecked compare(control.tristate, true) compare(control.checked, true) compare(control.checkState, Qt.PartiallyChecked) - verify(control.spy.success) + verify(sequenceSpy.success) // key: partial -> checked - control.spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true, "checkState": Qt.PartiallyChecked }], + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true, "checkState": Qt.PartiallyChecked }], "pressed", ["pressedChanged", { "pressed": false, "checked": true, "checkState": Qt.PartiallyChecked }], + ["checkStateChanged", { "pressed": false, "checked": true, "checkState": Qt.Checked }], "released", - "clicked", - ["checkStateChanged", { "pressed": false, "checked": true, "checkState": Qt.Checked }]] + "clicked"] keyClick(Qt.Key_Space) compare(control.checked, true) compare(control.checkState, Qt.Checked) - verify(control.spy.success) + verify(sequenceSpy.success) // key: checked -> unchecked - control.spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true, "checkState": Qt.Checked }], + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true, "checkState": Qt.Checked }], "pressed", ["pressedChanged", { "pressed": false, "checked": true, "checkState": Qt.Checked }], - "released", - "clicked", ["checkStateChanged", { "pressed": false, "checked": false, "checkState": Qt.Unchecked }], - ["checkedChanged", { "pressed": false, "checked": false, "checkState": Qt.Unchecked }]] + ["checkedChanged", { "pressed": false, "checked": false, "checkState": Qt.Unchecked }], + "released", + "clicked"] keyClick(Qt.Key_Space) compare(control.checked, false) compare(control.checkState, Qt.Unchecked) - verify(control.spy.success) + verify(sequenceSpy.success) // key: unchecked -> partial - control.spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false, "checkState": Qt.Unchecked }], + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false, "checkState": Qt.Unchecked }], "pressed", ["pressedChanged", { "pressed": false, "checked": false, "checkState": Qt.Unchecked }], - "released", - "clicked", ["checkStateChanged", { "pressed": false, "checked": true, "checkState": Qt.PartiallyChecked }], - ["checkedChanged", { "pressed": false, "checked": true, "checkState": Qt.PartiallyChecked }]] + ["checkedChanged", { "pressed": false, "checked": true, "checkState": Qt.PartiallyChecked }], + "released", + "clicked"] keyClick(Qt.Key_Space) compare(control.checked, true) compare(control.checkState, Qt.PartiallyChecked) - verify(control.spy.success) + verify(sequenceSpy.success) // mouse: partial -> checked - control.spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true, "checkState": Qt.PartiallyChecked }], + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true, "checkState": Qt.PartiallyChecked }], "pressed", ["pressedChanged", { "pressed": false, "checked": true, "checkState": Qt.PartiallyChecked }], + ["checkStateChanged", { "pressed": false, "checked": true, "checkState": Qt.Checked }], "released", - "clicked", - ["checkStateChanged", { "pressed": false, "checked": true, "checkState": Qt.Checked }]] + "clicked"] mouseClick(control) compare(control.checked, true) compare(control.checkState, Qt.Checked) - verify(control.spy.success) + verify(sequenceSpy.success) // mouse: checked -> unchecked - control.spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true, "checkState": Qt.Checked }], + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true, "checkState": Qt.Checked }], "pressed", ["pressedChanged", { "pressed": false, "checked": true, "checkState": Qt.Checked }], - "released", - "clicked", ["checkStateChanged", { "pressed": false, "checked": false, "checkState": Qt.Unchecked }], - ["checkedChanged", { "pressed": false, "checked": false, "checkState": Qt.Unchecked }]] + ["checkedChanged", { "pressed": false, "checked": false, "checkState": Qt.Unchecked }], + "released", + "clicked"] mouseClick(control) compare(control.checked, false) compare(control.checkState, Qt.Unchecked) - verify(control.spy.success) + verify(sequenceSpy.success) // mouse: unchecked -> partial - control.spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false, "checkState": Qt.Unchecked }], + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false, "checkState": Qt.Unchecked }], "pressed", ["pressedChanged", { "pressed": false, "checked": false, "checkState": Qt.Unchecked }], - "released", - "clicked", ["checkStateChanged", { "pressed": false, "checked": true, "checkState": Qt.PartiallyChecked }], - ["checkedChanged", { "pressed": false, "checked": true, "checkState": Qt.PartiallyChecked }]] + ["checkedChanged", { "pressed": false, "checked": true, "checkState": Qt.PartiallyChecked }], + "released", + "clicked"] mouseClick(control) compare(control.checked, true) compare(control.checkState, Qt.PartiallyChecked) - verify(control.spy.success) + verify(sequenceSpy.success) control.destroy() } @@ -421,7 +431,7 @@ TestCase { function test_baseline() { var control = checkBox.createObject(testCase) verify(control) - compare(control.baselineOffset, control.label.y + control.label.baselineOffset) + compare(control.baselineOffset, control.contentItem.y + control.contentItem.baselineOffset) control.destroy() } } diff --git a/tests/auto/controls/data/tst_checkdelegate.qml b/tests/auto/controls/data/tst_checkdelegate.qml new file mode 100644 index 00000000..a471b1d6 --- /dev/null +++ b/tests/auto/controls/data/tst_checkdelegate.qml @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtTest 1.0 +import QtQuick.Controls 2.0 + +TestCase { + id: testCase + width: 200 + height: 200 + visible: true + when: windowShown + name: "CheckDelegate" + + Component { + id: checkDelegate + CheckDelegate {} + } + + // TODO: data-fy tst_checkbox (rename to tst_check?) so we don't duplicate its tests here? + + function test_defaults() { + var control = checkDelegate.createObject(testCase); + verify(control); + verify(!control.checked); + control.destroy(); + } + + function test_checked() { + var control = checkDelegate.createObject(testCase); + verify(control); + + mouseClick(control); + verify(control.checked); + + mouseClick(control); + verify(!control.checked); + + control.destroy(); + } + + function test_baseline() { + var control = checkDelegate.createObject(testCase); + verify(control); + compare(control.baselineOffset, control.contentItem.y + control.contentItem.baselineOffset); + control.destroy(); + } +} diff --git a/tests/auto/controls/data/tst_combobox.qml b/tests/auto/controls/data/tst_combobox.qml index 0a2c3101..607de2e8 100644 --- a/tests/auto/controls/data/tst_combobox.qml +++ b/tests/auto/controls/data/tst_combobox.qml @@ -39,35 +39,30 @@ ****************************************************************************/ import QtQuick 2.2 +import QtQuick.Window 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase width: 200 height: 200 + visible: true + when: windowShown name: "ComboBox" - ApplicationWindow { - id: window - visible: true - width: 400 - height: 400 - font.pixelSize: 25 - } - - SignalSpy { - id: activatedSpy - signalName: "activated" + Component { + id: signalSpy + SignalSpy { } } - SignalSpy { - id: highlightedSpy - signalName: "highlighted" + Component { + id: comboBox + ComboBox { } } Component { - id: comboBox + id: emptyBox ComboBox { delegate: ItemDelegate { width: popup.width @@ -75,29 +70,8 @@ TestCase { } } - function initTestCase() { - window.requestActivate() - tryCompare(window, "active", true) - } - - function init() { - verify(!activatedSpy.target) - compare(activatedSpy.count, 0) - - verify(!highlightedSpy.target) - compare(highlightedSpy.count, 0) - } - - function cleanup() { - activatedSpy.target = null - activatedSpy.clear() - - highlightedSpy.target = null - highlightedSpy.clear() - } - function test_defaults() { - var control = comboBox.createObject(window.contentItem) + var control = comboBox.createObject(testCase) verify(control) compare(control.count, 0) @@ -107,13 +81,14 @@ TestCase { compare(control.highlightedIndex, -1) compare(control.currentText, "") verify(control.delegate) + verify(control.indicator) verify(control.popup) control.destroy() } function test_array() { - var control = comboBox.createObject(window.contentItem) + var control = comboBox.createObject(testCase) verify(control) var items = [ "Banana", "Apple", "Coconut" ] @@ -139,7 +114,7 @@ TestCase { } function test_objects() { - var control = comboBox.createObject(window.contentItem) + var control = emptyBox.createObject(testCase) verify(control) var items = [ @@ -169,7 +144,7 @@ TestCase { } function test_number() { - var control = comboBox.createObject(window.contentItem) + var control = comboBox.createObject(testCase) verify(control) control.model = 10 @@ -202,7 +177,7 @@ TestCase { } function test_listModel() { - var control = comboBox.createObject(window.contentItem) + var control = comboBox.createObject(testCase) verify(control) control.model = listmodel @@ -246,7 +221,7 @@ TestCase { } function test_textRole(data) { - var control = comboBox.createObject(window.contentItem) + var control = emptyBox.createObject(testCase) verify(control) control.model = data.model @@ -274,7 +249,7 @@ TestCase { } function test_textAt() { - var control = comboBox.createObject(window.contentItem) + var control = comboBox.createObject(testCase) verify(control) control.model = ["Apple", "Orange", "Banana"] @@ -316,7 +291,7 @@ TestCase { } function test_find(data) { - var control = comboBox.createObject(window.contentItem) + var control = comboBox.createObject(testCase) verify(control) control.model = ["Banana", "banana", "Coconut", "Apple", "Cocomuffin"] @@ -326,14 +301,15 @@ TestCase { control.destroy() } + function test_arrowKeys() { - var control = comboBox.createObject(window.contentItem, {model: 3}) + var control = comboBox.createObject(testCase, {model: 3}) verify(control) - activatedSpy.target = control + var activatedSpy = signalSpy.createObject(control, {target: control, signalName: "activated"}) verify(activatedSpy.valid) - highlightedSpy.target = control + var highlightedSpy = signalSpy.createObject(control, {target: control, signalName: "highlighted"}) verify(highlightedSpy.valid) waitForRendering(control) @@ -450,29 +426,30 @@ TestCase { keyClick(Qt.Key_Space) compare(control.currentIndex, 1) - compare(control.highlightedIndex, -1) + tryCompare(control, "highlightedIndex", -1) control.destroy() } - function test_keys_data() { + function test_keys_space_enter_escape_data() { return [ { tag: "space-space", key1: Qt.Key_Space, key2: Qt.Key_Space, showPopup: true, showPress: true, hidePopup: true, hidePress: true }, { tag: "space-enter", key1: Qt.Key_Space, key2: Qt.Key_Enter, showPopup: true, showPress: true, hidePopup: true, hidePress: true }, { tag: "space-return", key1: Qt.Key_Space, key2: Qt.Key_Return, showPopup: true, showPress: true, hidePopup: true, hidePress: true }, { tag: "space-escape", key1: Qt.Key_Space, key2: Qt.Key_Escape, showPopup: true, showPress: true, hidePopup: true, hidePress: false }, { tag: "space-0", key1: Qt.Key_Space, key2: Qt.Key_0, showPopup: true, showPress: true, hidePopup: false, hidePress: false }, - { tag: "enter-enter", key1: Qt.Key_Enter, key2: Qt.Key_Enter, showPopup: false, showPress: false, hidePopup: true, hidePress: false }, { tag: "return-return", key1: Qt.Key_Return, key2: Qt.Key_Return, showPopup: false, showPress: false, hidePopup: true, hidePress: false }, - { tag: "escape-escape", key1: Qt.Key_Escape, key2: Qt.Key_Escape, showPopup: false, showPress: false, hidePopup: true, hidePress: false }, + { tag: "escape-escape", key1: Qt.Key_Escape, key2: Qt.Key_Escape, showPopup: false, showPress: false, hidePopup: true, hidePress: false } ] } - function test_keys(data) { - var control = comboBox.createObject(window.contentItem, {model: 3}) + function test_keys_space_enter_escape(data) { + var control = comboBox.createObject(testCase, {model: 3}) verify(control) + waitForRendering(control) + control.forceActiveFocus() verify(control.activeFocus) @@ -490,7 +467,6 @@ TestCase { // hide popup keyPress(data.key2) compare(control.pressed, data.hidePress) - compare(control.popup.visible, data.showPopup) keyRelease(data.key2) compare(control.pressed, false) tryCompare(control.popup, "visible", !data.hidePopup) @@ -498,8 +474,164 @@ TestCase { control.destroy() } + function test_keys_home_end() { + var control = comboBox.createObject(testCase, {model: 5}) + verify(control) + + control.forceActiveFocus() + verify(control.activeFocus) + compare(control.currentIndex, 0) + compare(control.highlightedIndex, -1) + + var activatedCount = 0 + var activatedSpy = signalSpy.createObject(control, {target: control, signalName: "activated"}) + verify(activatedSpy.valid) + + var highlightedCount = 0 + var highlightedSpy = signalSpy.createObject(control, {target: control, signalName: "highlighted"}) + verify(highlightedSpy.valid) + + var currentIndexCount = 0 + var currentIndexSpy = signalSpy.createObject(control, {target: control, signalName: "currentIndexChanged"}) + verify(currentIndexSpy.valid) + + var highlightedIndexCount = 0 + var highlightedIndexSpy = signalSpy.createObject(control, {target: control, signalName: "highlightedIndexChanged"}) + verify(highlightedIndexSpy.valid) + + // end (popup closed) + keyClick(Qt.Key_End) + compare(control.currentIndex, 4) + compare(currentIndexSpy.count, ++currentIndexCount) + + compare(control.highlightedIndex, -1) + compare(highlightedIndexSpy.count, highlightedIndexCount) + + compare(activatedSpy.count, ++activatedCount) + compare(activatedSpy.signalArguments[activatedCount-1][0], 4) + + compare(highlightedSpy.count, highlightedCount) + + // repeat (no changes/signals) + keyClick(Qt.Key_End) + compare(currentIndexSpy.count, currentIndexCount) + compare(highlightedIndexSpy.count, highlightedIndexCount) + compare(activatedSpy.count, activatedCount) + compare(highlightedSpy.count, highlightedCount) + + // home (popup closed) + keyClick(Qt.Key_Home) + compare(control.currentIndex, 0) + compare(currentIndexSpy.count, ++currentIndexCount) + + compare(control.highlightedIndex, -1) + compare(highlightedIndexSpy.count, highlightedIndexCount) + + compare(activatedSpy.count, ++activatedCount) + compare(activatedSpy.signalArguments[activatedCount-1][0], 0) + + compare(highlightedSpy.count, highlightedCount) + + // repeat (no changes/signals) + keyClick(Qt.Key_Home) + compare(currentIndexSpy.count, currentIndexCount) + compare(highlightedIndexSpy.count, highlightedIndexCount) + compare(activatedSpy.count, activatedCount) + compare(highlightedSpy.count, highlightedCount) + + control.popup.open() + compare(control.highlightedIndex, 0) + compare(highlightedIndexSpy.count, ++highlightedIndexCount) + compare(highlightedSpy.count, highlightedCount) + + // end (popup open) + keyClick(Qt.Key_End) + compare(control.currentIndex, 0) + compare(currentIndexSpy.count, currentIndexCount) + + compare(control.highlightedIndex, 4) + compare(highlightedIndexSpy.count, ++highlightedIndexCount) + + compare(activatedSpy.count, activatedCount) + + compare(highlightedSpy.count, ++highlightedCount) + compare(highlightedSpy.signalArguments[highlightedCount-1][0], 4) + + // repeat (no changes/signals) + keyClick(Qt.Key_End) + compare(currentIndexSpy.count, currentIndexCount) + compare(highlightedIndexSpy.count, highlightedIndexCount) + compare(activatedSpy.count, activatedCount) + compare(highlightedSpy.count, highlightedCount) + + // home (popup open) + keyClick(Qt.Key_Home) + compare(control.currentIndex, 0) + compare(currentIndexSpy.count, currentIndexCount) + + compare(control.highlightedIndex, 0) + compare(highlightedIndexSpy.count, ++highlightedIndexCount) + + compare(activatedSpy.count, activatedCount) + + compare(highlightedSpy.count, ++highlightedCount) + compare(highlightedSpy.signalArguments[highlightedCount-1][0], 0) + + // repeat (no changes/signals) + keyClick(Qt.Key_Home) + compare(currentIndexSpy.count, currentIndexCount) + compare(highlightedIndexSpy.count, highlightedIndexCount) + compare(activatedSpy.count, activatedCount) + compare(highlightedSpy.count, highlightedCount) + + control.destroy() + } + + function test_keySearch() { + var control = comboBox.createObject(testCase, {model: ["Banana", "Coco", "Coconut", "Apple", "Cocomuffin"]}) + verify(control) + + control.forceActiveFocus() + verify(control.activeFocus) + + compare(control.currentIndex, 0) + compare(control.currentText, "Banana") + + keyPress(Qt.Key_C) + compare(control.currentIndex, 1) + compare(control.currentText, "Coco") + + // no match + keyPress(Qt.Key_N) + compare(control.currentIndex, 1) + compare(control.currentText, "Coco") + + keyPress(Qt.Key_C) + compare(control.currentIndex, 2) + compare(control.currentText, "Coconut") + + keyPress(Qt.Key_C) + compare(control.currentIndex, 4) + compare(control.currentText, "Cocomuffin") + + // wrap + keyPress(Qt.Key_C) + compare(control.currentIndex, 1) + compare(control.currentText, "Coco") + + keyPress(Qt.Key_A) + compare(control.currentIndex, 3) + compare(control.currentText, "Apple") + + keyPress(Qt.Key_B) + compare(control.currentIndex, 0) + compare(control.currentText, "Banana") + + control.destroy() + } + function test_popup() { - var control = comboBox.createObject(window.contentItem, {model: 3}) + var control = comboBox.createObject(testCase, {model: 3}) verify(control) // show below @@ -517,7 +649,7 @@ TestCase { tryCompare(control.popup, "visible", false) // show above - control.y = window.height - control.height + control.y = control.Window.height - control.height mousePress(control) compare(control.pressed, true) compare(control.popup.visible, false) @@ -526,17 +658,25 @@ TestCase { compare(control.popup.visible, true) verify(control.popup.contentItem.y < control.y) + // follow the control outside the horizontal window bounds + control.x = -control.width / 2 + compare(control.x, -control.width / 2) + compare(control.popup.contentItem.parent.x, -control.width / 2) + control.x = testCase.width - control.width / 2 + compare(control.x, testCase.width - control.width / 2) + compare(control.popup.contentItem.parent.x, testCase.width - control.width / 2) + control.destroy() } function test_mouse() { - var control = comboBox.createObject(window.contentItem, {model: 3}) + var control = comboBox.createObject(testCase, {model: 3}) verify(control) - activatedSpy.target = control + var activatedSpy = signalSpy.createObject(control, {target: control, signalName: "activated"}) verify(activatedSpy.valid) - highlightedSpy.target = control + var highlightedSpy = signalSpy.createObject(control, {target: control, signalName: "highlighted"}) verify(highlightedSpy.valid) mouseClick(control) @@ -573,17 +713,18 @@ TestCase { } function test_focus() { - var control = comboBox.createObject(window.contentItem, {model: 3}) + var control = comboBox.createObject(testCase, {model: 3}) verify(control) + waitForRendering(control) + // click - gain focus - show popup mouseClick(control) verify(control.activeFocus) compare(control.popup.visible, true) // lose focus - hide popup - window.contentItem.forceActiveFocus() - verify(window.contentItem.activeFocus) + control.focus = false verify(!control.activeFocus) tryCompare(control.popup, "visible", false) @@ -648,11 +789,9 @@ TestCase { width: _combobox.width text: _combobox.textRole ? (Array.isArray(_combobox.model) ? modelData[_combobox.textRole] : model[_combobox.textRole]) : modelData objectName: "delegate" - checkable: true autoExclusive: true checked: _combobox.currentIndex === index highlighted: _combobox.highlightedIndex === index - pressed: highlighted && _combobox.pressed } } } @@ -672,52 +811,72 @@ TestCase { } function test_font() { // QTBUG_50984, QTBUG-51696 - var control = component.createObject(window.contentItem) + var control = component.createObject(testCase) verify(control) verify(control.button) verify(control.combobox) waitForRendering(control) - control.forceActiveFocus() - verify(control.activeFocus) - compare(control.font.pixelSize, 30) compare(control.button.font.pixelSize, 20) compare(control.combobox.font.pixelSize, 30) - verify(control.combobox.popup) - var popup = control.combobox.popup - popup.open() +// verify(control.combobox.popup) +// var popup = control.combobox.popup +// popup.open() - verify(popup.contentItem) +// verify(popup.contentItem) - var listview = popup.contentItem - verify(listview.contentItem) - waitForRendering(listview) +// var listview = popup.contentItem +// verify(listview.contentItem) +// waitForRendering(listview) - var idx1 = getChild(listview.contentItem, "delegate", -1) - compare(listview.contentItem.children[idx1].font.pixelSize, 25) - var idx2 = getChild(listview.contentItem, "delegate", idx1) - compare(listview.contentItem.children[idx2].font.pixelSize, 25) +// var idx1 = getChild(listview.contentItem, "delegate", -1) +// compare(listview.contentItem.children[idx1].font.pixelSize, 25) +// var idx2 = getChild(listview.contentItem, "delegate", idx1) +// compare(listview.contentItem.children[idx2].font.pixelSize, 25) - compare(listview.contentItem.children[idx1].font.pixelSize, 25) - compare(listview.contentItem.children[idx2].font.pixelSize, 25) +// compare(listview.contentItem.children[idx1].font.pixelSize, 25) +// compare(listview.contentItem.children[idx2].font.pixelSize, 25) control.font.pixelSize = control.font.pixelSize + 10 compare(control.combobox.font.pixelSize, 40) - waitForRendering(listview) - compare(listview.contentItem.children[idx1].font.pixelSize, 25) - compare(listview.contentItem.children[idx2].font.pixelSize, 25) +// waitForRendering(listview) +// compare(listview.contentItem.children[idx1].font.pixelSize, 25) +// compare(listview.contentItem.children[idx2].font.pixelSize, 25) control.combobox.font.pixelSize = control.combobox.font.pixelSize + 5 compare(control.combobox.font.pixelSize, 45) - waitForRendering(listview) +// waitForRendering(listview) + +// idx1 = getChild(listview.contentItem, "delegate", -1) +// compare(listview.contentItem.children[idx1].font.pixelSize, 25) +// idx2 = getChild(listview.contentItem, "delegate", idx1) +// compare(listview.contentItem.children[idx2].font.pixelSize, 25) + + control.destroy() + } + + function test_wheel() { + var control = comboBox.createObject(testCase, {model: 2, wheelEnabled: true}) + verify(control) + + var delta = 120 + + mouseWheel(control, control.width / 2, control.height / 2, -delta, -delta) + compare(control.currentIndex, 1) + + // reached bounds -> no change + mouseWheel(control, control.width / 2, control.height / 2, -delta, -delta) + compare(control.currentIndex, 1) + + mouseWheel(control, control.width / 2, control.height / 2, delta, delta) + compare(control.currentIndex, 0) - idx1 = getChild(listview.contentItem, "delegate", -1) - compare(listview.contentItem.children[idx1].font.pixelSize, 25) - idx2 = getChild(listview.contentItem, "delegate", idx1) - compare(listview.contentItem.children[idx2].font.pixelSize, 25) + // reached bounds -> no change + mouseWheel(control, control.width / 2, control.height / 2, delta, delta) + compare(control.currentIndex, 0) control.destroy() } @@ -733,7 +892,7 @@ TestCase { // QTBUG-51645 function test_activation(data) { - var control = comboBox.createObject(window.contentItem, {currentIndex: 1, model: ["Apple", "Orange", "Banana"]}) + var control = comboBox.createObject(testCase, {currentIndex: 1, model: ["Apple", "Orange", "Banana"]}) verify(control) waitForRendering(control) @@ -781,4 +940,110 @@ TestCase { loader.destroy() } + + // QTBUG-52615 + function test_currentIndex() { + var control = comboBox.createObject(testCase, {currentIndex: -1, model: 3}) + verify(control) + + compare(control.currentIndex, -1) + + control.destroy() + } + + ListModel { + id: resetmodel + ListElement { text: "First" } + ListElement { text: "Second" } + ListElement { text: "Third" } + } + + // QTBUG-54573 + function test_modelReset() { + var control = comboBox.createObject(testCase, {model: resetmodel}) + verify(control) + control.popup.open() + + var listview = control.popup.contentItem + verify(listview) + + waitForRendering(listview) + compare(listview.contentItem.children.length, resetmodel.count + 1) // + highlight item + + resetmodel.clear() + resetmodel.append({text: "Fourth"}) + resetmodel.append({text: "Fifth"}) + + waitForRendering(listview) + compare(listview.contentItem.children.length, resetmodel.count + 1) // + highlight item + + control.destroy() + } + + // QTBUG-55118 + function test_currentText() { + var control = comboBox.createObject(testCase, {model: listmodel}) + verify(control) + + compare(control.currentIndex, 0) + compare(control.currentText, "First") + + listmodel.setProperty(0, "text", "1st") + compare(control.currentText, "1st") + + control.currentIndex = 1 + compare(control.currentText, "Second") + + listmodel.setProperty(0, "text", "First") + compare(control.currentText, "Second") + + control.destroy() + } + + // QTBUG-55030 + function test_highlightRange() { + var control = comboBox.createObject(testCase, {model: 100}) + verify(control) + + control.currentIndex = 50 + compare(control.currentIndex, 50) + compare(control.highlightedIndex, -1) + + var openedSpy = signalSpy.createObject(control, {target: control.popup, signalName: "opened"}) + verify(openedSpy.valid) + + control.popup.open() + compare(control.highlightedIndex, 50) + tryCompare(openedSpy, "count", 1) + + var listview = control.popup.contentItem + verify(listview) + + var first = listview.itemAt(0, listview.contentY) + verify(first) + compare(first.text, "50") + + var closedSpy = signalSpy.createObject(control, {target: control.popup, signalName: "closed"}) + verify(closedSpy.valid) + + control.popup.close() + tryCompare(closedSpy, "count", 1) + compare(control.highlightedIndex, -1) + + control.currentIndex = 99 + compare(control.currentIndex, 99) + compare(control.highlightedIndex, -1) + + control.popup.open() + compare(control.highlightedIndex, 99) + tryCompare(openedSpy, "count", 2) + + var last = listview.itemAt(0, listview.contentY + listview.height - 1) + verify(last) + compare(last.text, "99") + + openedSpy.target = null + closedSpy.target = null + control.destroy() + } } diff --git a/tests/auto/controls/data/tst_container.qml b/tests/auto/controls/data/tst_container.qml new file mode 100644 index 00000000..d1ff54e0 --- /dev/null +++ b/tests/auto/controls/data/tst_container.qml @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtTest 1.0 +import QtQuick.Controls 2.0 +import QtQuick.Templates 2.0 as T + +TestCase { + id: testCase + width: 400 + height: 400 + visible: true + when: windowShown + name: "Container" + + Component { + id: container + Container { } + } + + Component { + id: rectangle + Rectangle { } + } + + function test_implicitSize() { + var control = container.createObject(testCase) + verify(control) + + compare(control.implicitWidth, 0) + compare(control.implicitHeight, 0) + + control.contentItem = rectangle.createObject(control, {implicitWidth: 10, implicitHeight: 20}) + compare(control.implicitWidth, 10) + compare(control.implicitHeight, 20) + + control.background = rectangle.createObject(control, {implicitWidth: 20, implicitHeight: 30}) + compare(control.implicitWidth, 20) + compare(control.implicitHeight, 30) + + control.padding = 100 + compare(control.implicitWidth, 210) + compare(control.implicitHeight, 220) + + control.destroy() + } +} diff --git a/tests/auto/controls/data/tst_control.qml b/tests/auto/controls/data/tst_control.qml index dd9abefe..3018498e 100644 --- a/tests/auto/controls/data/tst_control.qml +++ b/tests/auto/controls/data/tst_control.qml @@ -40,8 +40,8 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 -import Qt.labs.templates 1.0 as T +import QtQuick.Controls 2.0 +import QtQuick.Templates 2.0 as T TestCase { id: testCase @@ -53,27 +53,22 @@ TestCase { Component { id: component - T.Control { } + Control { } } Component { - id: signalSpy - SignalSpy { } + id: rectangle + Rectangle { } } - SignalSpy { - id: mirroredSpy - signalName: "mirroredChanged" - } - - SignalSpy { - id: availableWidthSpy - signalName: "availableWidthChanged" + Component { + id: button + T.Button { } } - SignalSpy { - id: availableHeightSpy - signalName: "availableHeightChanged" + Component { + id: signalSpy + SignalSpy { } } function test_padding() { @@ -140,10 +135,10 @@ TestCase { var control = component.createObject(testCase) verify(control) - availableWidthSpy.target = control - availableHeightSpy.target = control - + var availableWidthSpy = signalSpy.createObject(control, {target: control, signalName: "availableWidthChanged"}) verify(availableWidthSpy.valid) + + var availableHeightSpy = signalSpy.createObject(control, {target: control, signalName: "availableHeightChanged"}) verify(availableHeightSpy.valid) var availableWidthChanges = 0 @@ -212,7 +207,7 @@ TestCase { var control = component.createObject(testCase) verify(control) - mirroredSpy.target = control + var mirroredSpy = signalSpy.createObject(control, {target: control, signalName: "mirroredChanged"}) verify(mirroredSpy.valid) control.locale = Qt.locale("en_US") @@ -334,20 +329,10 @@ TestCase { compare(control2.font.family, "Arial") compare(control2.item2_2.font.family, control2.font.family) - compare(control2.item2_2.font.pointSize, control2.font.pointSize) - compare(control2.item2_2.font.weight, control2.font.weight) compare(control2.item2_3.font.family, control2.font.family) - compare(control2.item2_3.font.pointSize, control2.font.pointSize) - compare(control2.item2_3.font.weight, control2.font.weight) compare(control2.item2_4.font.family, control2.font.family) - compare(control2.item2_4.font.pointSize, control2.font.pointSize) - compare(control2.item2_4.font.weight, control2.font.weight) compare(control2.item2_5.font.family, control2.font.family) - compare(control2.item2_5.font.pointSize, control2.font.pointSize) - compare(control2.item2_5.font.weight, control2.font.weight) compare(control2.item2_6.font.family, control2.font.family) - compare(control2.item2_6.font.pointSize, control2.font.pointSize) - compare(control2.item2_6.font.weight, control2.font.weight) control2.font.pointSize = 48 compare(control2.item2_2.font.pointSize, 48) @@ -491,20 +476,10 @@ TestCase { compare(control3.font.family, "Arial") compare(control3.item3_3.font.family, control3.font.family) - compare(control3.item3_3.font.pointSize, control3.font.pointSize) - compare(control3.item3_3.font.weight, control3.font.weight) compare(control3.item3_4.font.family, control3.font.family) - compare(control3.item3_4.font.pointSize, control3.font.pointSize) - compare(control3.item3_4.font.weight, control3.font.weight) compare(control3.item3_5.font.family, control3.font.family) - compare(control3.item3_5.font.pointSize, control3.font.pointSize) - compare(control3.item3_5.font.weight, control3.font.weight) compare(control3.item3_7.font.family, control3.font.family) - compare(control3.item3_7.font.pointSize, control3.font.pointSize) - compare(control3.item3_7.font.weight, control3.font.weight) compare(control3.item3_8.font.family, control3.font.family) - compare(control3.item3_8.font.pointSize, control3.font.pointSize) - compare(control3.item3_8.font.weight, control3.font.weight) control3.font.pointSize = 48 compare(control3.item3_3.font.pointSize, 48) @@ -872,28 +847,68 @@ TestCase { compare(control.mirroredspy_5.count, 1) } - function test_focusReason_data() { + function test_hover_data() { return [ - { tag: "Control", qml: "import Qt.labs.controls 1.0; Control { }" }, - { tag: "TextField", qml: "import Qt.labs.controls 1.0; TextField { }" }, - { tag: "TextArea", qml: "import Qt.labs.controls 1.0; TextArea { }" }, - { tag: "SpinBox", qml: "import Qt.labs.controls 1.0; SpinBox { }" }, - { tag: "ComboBox", qml: "import Qt.labs.controls 1.0; ComboBox { }" } + { tag: "normal", target: component, pressed: false }, + { tag: "pressed", target: button, pressed: true } ] } - function test_focusReason(data) { - var control = Qt.createQmlObject(data.qml, testCase) + function test_hover(data) { + var control = data.target.createObject(testCase, {width: 100, height: 100}) verify(control) - compare(control.focusReason, Qt.OtherFocusReason) - control.forceActiveFocus(Qt.MouseFocusReason) - compare(control.activeFocus, true) - compare(control.focusReason, Qt.MouseFocusReason) + compare(control.hovered, false) + compare(control.hoverEnabled, false) + + mouseMove(control, control.width / 2, control.height / 2) + compare(control.hovered, false) + + control.hoverEnabled = true + + mouseMove(control, control.width / 2, control.height / 2) + compare(control.hovered, true) + + if (data.pressed) { + mousePress(control, control.width / 2, control.height / 2) + compare(control.hovered, true) + } + + mouseMove(control, -10, -10) + compare(control.hovered, false) + + if (data.pressed) { + mouseRelease(control, -10, control.height / 2) + compare(control.hovered, false) + } + + mouseMove(control, control.width / 2, control.height / 2) + compare(control.hovered, true) + + control.visible = false + compare(control.hovered, false) + + control.destroy() + } + + function test_implicitSize() { + var control = component.createObject(testCase) + verify(control) + + compare(control.implicitWidth, 0) + compare(control.implicitHeight, 0) + + control.contentItem = rectangle.createObject(control, {implicitWidth: 10, implicitHeight: 20}) + compare(control.implicitWidth, 10) + compare(control.implicitHeight, 20) + + control.background = rectangle.createObject(control, {implicitWidth: 20, implicitHeight: 30}) + compare(control.implicitWidth, 20) + compare(control.implicitHeight, 30) - testCase.forceActiveFocus(Qt.TabFocusReason) - compare(control.activeFocus, false) - compare(control.focusReason, Qt.TabFocusReason) + control.padding = 100 + compare(control.implicitWidth, 210) + compare(control.implicitHeight, 220) control.destroy() } diff --git a/tests/auto/controls/data/tst_dial.qml b/tests/auto/controls/data/tst_dial.qml index e0eba27e..a2ebf192 100644 --- a/tests/auto/controls/data/tst_dial.qml +++ b/tests/auto/controls/data/tst_dial.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase @@ -179,6 +179,8 @@ TestCase { } function test_dragging(data) { + dial.wrap = true; + verify(dial.wrap); dial.from = data.from; dial.to = data.to; @@ -210,6 +212,43 @@ TestCase { valueSpy.clear(); } + function test_nonWrapping() { + compare(dial.wrap, false); + dial.value = 0; + + // Ensure that dragging from bottom left to bottom right doesn't work. + var yPos = dial.height * 0.75; + mousePress(dial, dial.width * 0.25, yPos, Qt.LeftButton); + var positionAtPress = dial.position; + mouseMove(dial, dial.width * 0.5, yPos, Qt.LeftButton); + compare(dial.position, positionAtPress); + mouseMove(dial, dial.width * 0.75, yPos, Qt.LeftButton); + compare(dial.position, positionAtPress); + mouseRelease(dial, dial.width * 0.75, yPos, Qt.LeftButton); + compare(dial.position, positionAtPress); + + // Try the same thing, but a bit higher. + yPos = dial.height * 0.6; + mousePress(dial, dial.width * 0.25, yPos, Qt.LeftButton); + positionAtPress = dial.position; + mouseMove(dial, dial.width * 0.5, yPos, Qt.LeftButton); + compare(dial.position, positionAtPress); + mouseMove(dial, dial.width * 0.75, yPos, Qt.LeftButton); + compare(dial.position, positionAtPress); + mouseRelease(dial, dial.width * 0.75, yPos, Qt.LeftButton); + compare(dial.position, positionAtPress); + + // Going from below the center of the dial to above it should work (once it gets above the center). + mousePress(dial, dial.width * 0.25, dial.height * 0.75, Qt.LeftButton); + positionAtPress = dial.position; + mouseMove(dial, dial.width * 0.5, dial.height * 0.6, Qt.LeftButton); + compare(dial.position, positionAtPress); + mouseMove(dial, dial.width * 0.75, dial.height * 0.4, Qt.LeftButton); + verify(dial.position > positionAtPress); + mouseRelease(dial, dial.width * 0.75, dial.height * 0.3, Qt.LeftButton); + verify(dial.position > positionAtPress); + } + property Component focusTest: Component { FocusScope { signal receivedKeyPress @@ -282,4 +321,39 @@ TestCase { focusScope.destroy(); } + + function test_snapMode_data() { + return [ + { tag: "NoSnap", snapMode: Slider.NoSnap, from: 0, to: 2, values: [0, 0, 1], positions: [0, 0.5, 0.5] }, + { tag: "SnapAlways (0..2)", snapMode: Slider.SnapAlways, from: 0, to: 2, values: [0.0, 0.0, 1.0], positions: [0.0, 0.5, 0.5] }, + { tag: "SnapAlways (1..3)", snapMode: Slider.SnapAlways, from: 1, to: 3, values: [1.0, 1.0, 2.0], positions: [0.0, 0.5, 0.5] }, + { tag: "SnapAlways (-1..1)", snapMode: Slider.SnapAlways, from: -1, to: 1, values: [0.0, 0.0, 0.0], positions: [0.5, 0.5, 0.5] }, + { tag: "SnapAlways (1..-1)", snapMode: Slider.SnapAlways, from: 1, to: -1, values: [1.0, 1.0, 0.0], positions: [0.0, 0.5, 0.5] }, + { tag: "SnapOnRelease (0..2)", snapMode: Slider.SnapOnRelease, from: 0, to: 2, values: [0.0, 0.0, 1.0], positions: [0.0, 0.5, 0.5] }, + { tag: "SnapOnRelease (1..3)", snapMode: Slider.SnapOnRelease, from: 1, to: 3, values: [1.0, 1.0, 2.0], positions: [0.0, 0.5, 0.5] }, + { tag: "SnapOnRelease (-1..1)", snapMode: Slider.SnapOnRelease, from: -1, to: 1, values: [0.0, 0.0, 0.0], positions: [0.5, 0.5, 0.5] }, + { tag: "SnapOnRelease (1..-1)", snapMode: Slider.SnapOnRelease, from: 1, to: -1, values: [1.0, 1.0, 0.0], positions: [0.0, 0.5, 0.5] } + ] + } + + function test_snapMode(data) { + dial.snapMode = data.snapMode; + dial.from = data.from; + dial.to = data.to; + dial.stepSize = 0.2; + + var fuzz = 0.05; + + mousePress(dial, dial.width * 0.25, dial.height * 0.75); + compare(dial.value, data.values[0]); + compare(dial.position, data.positions[0]); + + mouseMove(dial, dial.width * 0.5, dial.height * 0.25); + fuzzyCompare(dial.value, data.values[1], fuzz); + fuzzyCompare(dial.position, data.positions[1], fuzz); + + mouseRelease(dial, dial.width * 0.5, dial.height * 0.25); + fuzzyCompare(dial.value, data.values[2], fuzz); + fuzzyCompare(dial.position, data.positions[2], fuzz); + } } diff --git a/tests/auto/controls/data/tst_drawer.qml b/tests/auto/controls/data/tst_drawer.qml index 28db11c8..021afdb2 100644 --- a/tests/auto/controls/data/tst_drawer.qml +++ b/tests/auto/controls/data/tst_drawer.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase @@ -57,10 +57,45 @@ TestCase { function test_defaults() { var control = drawer.createObject(testCase) - verify(!control.contentItem) compare(control.edge, Qt.LeftEdge) compare(control.position, 0.0) - verify(control.animation) + compare(control.dragMargin, Qt.styleHints.startDragDistance) + compare(control.parent, ApplicationWindow.overlay) + control.destroy() + } + + Component { + id: rectDrawer + + Drawer { + Rectangle { + width: 200 + height: 400 + color: "steelblue" + } + } + } + + function test_swipeVelocity() { + skip("QTBUG-52003"); + + var control = rectDrawer.createObject(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, Qt.LeftButton) + verify(control.position > 0) + tryCompare(control, "position", distance / control.contentItem.width) + mouseRelease(control, distance, 0, Qt.LeftButton) + tryCompare(control, "position", 1.0) + control.destroy() } } diff --git a/tests/auto/controls/data/tst_frame.qml b/tests/auto/controls/data/tst_frame.qml index d50a0dfc..a96397de 100644 --- a/tests/auto/controls/data/tst_frame.qml +++ b/tests/auto/controls/data/tst_frame.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_groupbox.qml b/tests/auto/controls/data/tst_groupbox.qml index 0f0e33fb..0181ea6b 100644 --- a/tests/auto/controls/data/tst_groupbox.qml +++ b/tests/auto/controls/data/tst_groupbox.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_itemdelegate.qml b/tests/auto/controls/data/tst_itemdelegate.qml index e2f78ac5..37b0db2a 100644 --- a/tests/auto/controls/data/tst_itemdelegate.qml +++ b/tests/auto/controls/data/tst_itemdelegate.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase @@ -58,7 +58,18 @@ TestCase { function test_baseline() { var control = itemDelegate.createObject(testCase) verify(control) - compare(control.baselineOffset, control.label.y + control.label.baselineOffset) + compare(control.baselineOffset, control.contentItem.y + control.contentItem.baselineOffset) + control.destroy() + } + + function test_highlighted() { + var control = itemDelegate.createObject(testCase) + verify(control) + verify(!control.highlighted) + + control.highlighted = true + verify(control.highlighted) + control.destroy() } } diff --git a/tests/auto/controls/data/tst_label.qml b/tests/auto/controls/data/tst_label.qml index b93ca3c7..6dae0992 100644 --- a/tests/auto/controls/data/tst_label.qml +++ b/tests/auto/controls/data/tst_label.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_menuitem.qml b/tests/auto/controls/data/tst_menuitem.qml index 8581a43f..be0c0652 100644 --- a/tests/auto/controls/data/tst_menuitem.qml +++ b/tests/auto/controls/data/tst_menuitem.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase @@ -58,7 +58,37 @@ TestCase { function test_baseline() { var control = menuItem.createObject(testCase) verify(control) - compare(control.baselineOffset, control.label.y + control.label.baselineOffset) + compare(control.baselineOffset, control.contentItem.y + control.contentItem.baselineOffset) + control.destroy() + } + + function test_checkable() { + var control = menuItem.createObject(testCase) + verify(control) + verify(control.hasOwnProperty("checkable")) + verify(!control.checkable) + + mouseClick(control) + verify(!control.checked) + + control.checkable = true + mouseClick(control) + verify(control.checked) + + mouseClick(control) + verify(!control.checked) + + control.destroy() + } + + function test_highlighted() { + var control = menuItem.createObject(testCase) + verify(control) + verify(!control.highlighted) + + control.highlighted = true + verify(control.highlighted) + control.destroy() } } diff --git a/tests/auto/controls/data/tst_page.qml b/tests/auto/controls/data/tst_page.qml index 60a1b2ef..bc7afa50 100644 --- a/tests/auto/controls/data/tst_page.qml +++ b/tests/auto/controls/data/tst_page.qml @@ -40,8 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 -import Qt.labs.templates 1.0 as T +import QtQuick.Controls 2.0 TestCase { id: testCase @@ -113,6 +112,18 @@ TestCase { compare(control.contentItem.width, control.availableWidth) compare(control.contentItem.height, control.availableHeight - control.header.height - control.footer.height) + control.header.visible = false + compare(control.contentItem.x, control.leftPadding) + compare(control.contentItem.y, control.topPadding) + compare(control.contentItem.width, control.availableWidth) + compare(control.contentItem.height, control.availableHeight - control.footer.height) + + control.footer.visible = false + compare(control.contentItem.x, control.leftPadding) + compare(control.contentItem.y, control.topPadding) + compare(control.contentItem.width, control.availableWidth) + compare(control.contentItem.height, control.availableHeight) + control.destroy() } } diff --git a/tests/auto/controls/data/tst_pageindicator.qml b/tests/auto/controls/data/tst_pageindicator.qml index 11b2ec31..d1f1223a 100644 --- a/tests/auto/controls/data/tst_pageindicator.qml +++ b/tests/auto/controls/data/tst_pageindicator.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_pane.qml b/tests/auto/controls/data/tst_pane.qml index 1fdec049..a0b8a5c8 100644 --- a/tests/auto/controls/data/tst_pane.qml +++ b/tests/auto/controls/data/tst_pane.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_popup.qml b/tests/auto/controls/data/tst_popup.qml index 02635c9a..0ca8ce57 100644 --- a/tests/auto/controls/data/tst_popup.qml +++ b/tests/auto/controls/data/tst_popup.qml @@ -40,8 +40,8 @@ import QtQuick 2.4 import QtTest 1.0 -import Qt.labs.controls 1.0 -import Qt.labs.templates 1.0 as T +import QtQuick.Controls 2.0 +import QtQuick.Templates 2.0 as T TestCase { id: testCase @@ -72,55 +72,28 @@ TestCase { Rectangle { } } - SignalSpy { - id: availableWidthSpy - signalName: "availableWidthChanged" - } - - SignalSpy { - id: availableHeightSpy - signalName: "availableHeightChanged" - } - - SignalSpy { - id: paddingSpy - signalName: "paddingChanged" - } - - SignalSpy { - id: topPaddingSpy - signalName: "topPaddingChanged" - } - - SignalSpy { - id: leftPaddingSpy - signalName: "leftPaddingChanged" - } - - SignalSpy { - id: rightPaddingSpy - signalName: "rightPaddingChanged" - } - - SignalSpy { - id: bottomPaddingSpy - signalName: "bottomPaddingChanged" + Component { + id: signalSpy + SignalSpy { } } function test_padding() { var control = popupTemplate.createObject(testCase) verify(control) - paddingSpy.target = control - topPaddingSpy.target = control - leftPaddingSpy.target = control - rightPaddingSpy.target = control - bottomPaddingSpy.target = control - + var paddingSpy = signalSpy.createObject(testCase, {target: control, signalName: "paddingChanged"}) verify(paddingSpy.valid) + + var topPaddingSpy = signalSpy.createObject(testCase, {target: control, signalName: "topPaddingChanged"}) verify(topPaddingSpy.valid) + + var leftPaddingSpy = signalSpy.createObject(testCase, {target: control, signalName: "leftPaddingChanged"}) verify(leftPaddingSpy.valid) + + var rightPaddingSpy = signalSpy.createObject(testCase, {target: control, signalName: "rightPaddingChanged"}) verify(rightPaddingSpy.valid) + + var bottomPaddingSpy = signalSpy.createObject(testCase, {target: control, signalName: "bottomPaddingChanged"}) verify(bottomPaddingSpy.valid) var paddingChanges = 0 @@ -219,10 +192,10 @@ TestCase { var control = popupTemplate.createObject(testCase) verify(control) - availableWidthSpy.target = control - availableHeightSpy.target = control - + var availableWidthSpy = signalSpy.createObject(testCase, {target: control, signalName: "availableWidthChanged"}) verify(availableWidthSpy.valid) + + var availableHeightSpy = signalSpy.createObject(testCase, {target: control, signalName: "availableHeightChanged"}) verify(availableHeightSpy.valid) var availableWidthChanges = 0 @@ -287,6 +260,106 @@ TestCase { control.destroy() } + function test_position() { + var control = popupControl.createObject(testCase, {visible: true, leftMargin: 10, topMargin: 20, width: 100, height: 100}) + verify(control) + verify(control.visible) + + var xSpy = signalSpy.createObject(testCase, {target: control, signalName: "xChanged"}) + verify(xSpy.valid) + + var ySpy = signalSpy.createObject(testCase, {target: control, signalName: "yChanged"}) + verify(ySpy.valid) + + // moving outside margins does not trigger change notifiers + control.x = -100 + compare(control.x, 10) + compare(control.y, 20) + compare(xSpy.count, 0) + compare(ySpy.count, 0) + + control.y = -200 + compare(control.x, 10) + compare(control.y, 20) + compare(xSpy.count, 0) + compare(ySpy.count, 0) + + // moving within margins triggers change notifiers + control.x = 30 + compare(control.x, 30) + compare(control.y, 20) + compare(xSpy.count, 1) + compare(ySpy.count, 0) + + control.y = 40 + compare(control.x, 30) + compare(control.y, 40) + compare(xSpy.count, 1) + compare(ySpy.count, 1) + + // re-parent and reset the position + control.parent = rect.createObject(testCase, {color: "red", width: 100, height: 100}) + control.x = 0 + control.y = 0 + compare(xSpy.count, 2) + compare(ySpy.count, 2) + + // moving parent outside margins triggers change notifiers + control.parent.x = -50 + compare(control.x, 50 + control.leftMargin) + compare(xSpy.count, 3) + compare(ySpy.count, 2) + + control.parent.y = -60 + compare(control.y, 60 + control.topMargin) + compare(xSpy.count, 3) + compare(ySpy.count, 3) + + control.destroy() + } + + function test_resetSize() { + var control = popupControl.createObject(testCase, {visible: true, margins: 0}) + verify(control) + + control.width = control.implicitWidth = testCase.width + 10 + control.height = control.implicitHeight = testCase.height + 10 + + compare(control.width, testCase.width + 10) + compare(control.height, testCase.height + 10) + + control.width = undefined + control.height = undefined + compare(control.width, testCase.width) + compare(control.height, testCase.height) + + control.destroy() + } + + function test_negativeMargins() { + var control = popupControl.createObject(testCase, {implicitWidth: testCase.width, implicitHeight: testCase.height}) + verify(control) + + control.open() + verify(control.visible) + + compare(control.x, 0) + compare(control.y, 0) + + compare(control.margins, -1) + compare(control.topMargin, -1) + compare(control.leftMargin, -1) + compare(control.rightMargin, -1) + compare(control.bottomMargin, -1) + + control.x = -10 + control.y = -10 + compare(control.x, 0) + compare(control.y, 0) + + control.destroy() + } + function test_margins() { var control = popupControl.createObject(testCase, {width: 100, height: 100}) verify(control) @@ -344,6 +417,34 @@ TestCase { compare(control.contentItem.parent.x, testCase.width - control.width - 20) compare(control.contentItem.parent.y, testCase.height - control.height - 20) + control.margins = undefined + compare(control.margins, -1) + + control.bottomMargin = undefined + compare(control.bottomMargin, -1) + compare(control.contentItem.parent.x, testCase.width - control.width - 20) + compare(control.contentItem.parent.y, testCase.height) + + control.rightMargin = undefined + compare(control.rightMargin, -1) + compare(control.contentItem.parent.x, testCase.width) + compare(control.contentItem.parent.y, testCase.height) + + control.x = -testCase.width + control.y = -testCase.height + compare(control.contentItem.parent.x, 20) + compare(control.contentItem.parent.y, 20) + + control.topMargin = undefined + compare(control.topMargin, -1) + compare(control.contentItem.parent.x, 20) + compare(control.contentItem.parent.y, -testCase.height) + + control.leftMargin = undefined + compare(control.leftMargin, -1) + compare(control.contentItem.parent.x, -testCase.width) + compare(control.contentItem.parent.y, -testCase.height) + control.destroy() } @@ -409,38 +510,52 @@ TestCase { Component { id: component ApplicationWindow { + id: _window width: 400 height: 400 visible: true font.pixelSize: 40 property alias pane: _pane + property alias popup: _popup + property SignalSpy fontspy: SignalSpy { target: _window; signalName: "fontChanged" } Pane { id: _pane - property alias button: _button; - property alias popup: _popup; - property alias listview: _listview + property alias button: _button font.pixelSize: 30 + property SignalSpy fontspy: SignalSpy { target: _pane; signalName: "fontChanged" } Column { Button { id: _button text: "Button" font.pixelSize: 20 - + property SignalSpy fontspy: SignalSpy { target: _button; signalName: "fontChanged" } Popup { id: _popup + property alias button: _button2 + property alias listview: _listview y: _button.height implicitHeight: Math.min(396, _listview.contentHeight) - contentItem: ListView { - id: _listview - height: _button.height * 20 - model: 2 - delegate: Button { - objectName: "delegate" - width: _button.width - height: _button.height - text: "N: " + index - checkable: true - autoExclusive: true + property SignalSpy fontspy: SignalSpy { target: _popup; signalName: "fontChanged" } + contentItem: Column { + Button { + id: _button2 + text: "Button" + property SignalSpy fontspy: SignalSpy { target: _button2; signalName: "fontChanged" } + } + ListView { + id: _listview + height: _button.height * 20 + model: 2 + delegate: Button { + id: _button3 + objectName: "delegate" + width: _button.width + height: _button.height + text: "N: " + index + checkable: true + autoExclusive: true + property SignalSpy fontspy: SignalSpy { target: _button3; signalName: "fontChanged" } + } } } } @@ -454,43 +569,80 @@ TestCase { var window = component.createObject(testCase) verify(window) - window.requestActivate() - tryCompare(window, "active", true) - - var control = window.pane - waitForRendering(control) - - control.forceActiveFocus() - verify(control.activeFocus) - compare(window.font.pixelSize, 40) - compare(control.font.pixelSize, 30) - compare(control.button.font.pixelSize, 20) - - var popup = control.popup - popup.open() + compare(window.pane.font.pixelSize, 30) + compare(window.pane.button.font.pixelSize, 20) + compare(window.popup.font.pixelSize, 40) + compare(window.popup.button.font.pixelSize, 40) - verify(popup.contentItem) + var idx1 = getChild(window.popup.listview.contentItem, "delegate", -1) + compare(window.popup.listview.contentItem.children[idx1].font.pixelSize, 40) + var idx2 = getChild(window.popup.listview.contentItem, "delegate", idx1) + compare(window.popup.listview.contentItem.children[idx2].font.pixelSize, 40) - var listview = popup.contentItem - verify(listview.contentItem) - waitForRendering(listview) - - var idx1 = getChild(listview.contentItem, "delegate", -1) - compare(listview.contentItem.children[idx1].font.pixelSize, 40) - var idx2 = getChild(listview.contentItem, "delegate", idx1) - compare(listview.contentItem.children[idx2].font.pixelSize, 40) - - control.button.font.pixelSize = 30 - compare(control.button.font.pixelSize, 30) - waitForRendering(listview) - compare(listview.contentItem.children[idx1].font.pixelSize, 40) - compare(listview.contentItem.children[idx2].font.pixelSize, 40) + window.pane.button.font.pixelSize = 30 + compare(window.font.pixelSize, 40) + compare(window.fontspy.count, 0) + compare(window.pane.font.pixelSize, 30) + compare(window.pane.fontspy.count, 0) + compare(window.pane.button.font.pixelSize, 30) + compare(window.pane.button.fontspy.count, 1) + compare(window.popup.font.pixelSize, 40) + compare(window.popup.fontspy.count, 0) + compare(window.popup.button.font.pixelSize, 40) + compare(window.popup.button.fontspy.count, 0) + compare(window.popup.listview.contentItem.children[idx1].font.pixelSize, 40) + compare(window.popup.listview.contentItem.children[idx1].fontspy.count, 0) + compare(window.popup.listview.contentItem.children[idx2].font.pixelSize, 40) + compare(window.popup.listview.contentItem.children[idx2].fontspy.count, 0) window.font.pixelSize = 50 - waitForRendering(listview) - compare(listview.contentItem.children[idx1].font.pixelSize, 50) - compare(listview.contentItem.children[idx2].font.pixelSize, 50) + compare(window.font.pixelSize, 50) + compare(window.fontspy.count, 1) + compare(window.pane.font.pixelSize, 30) + compare(window.pane.fontspy.count, 0) + compare(window.pane.button.font.pixelSize, 30) + compare(window.pane.button.fontspy.count, 1) + compare(window.popup.font.pixelSize, 50) + compare(window.popup.fontspy.count, 1) + compare(window.popup.button.font.pixelSize, 50) + compare(window.popup.button.fontspy.count, 1) + compare(window.popup.listview.contentItem.children[idx1].font.pixelSize, 50) + compare(window.popup.listview.contentItem.children[idx1].fontspy.count, 1) + compare(window.popup.listview.contentItem.children[idx2].font.pixelSize, 50) + compare(window.popup.listview.contentItem.children[idx2].fontspy.count, 1) + + window.popup.button.font.pixelSize = 10 + compare(window.font.pixelSize, 50) + compare(window.fontspy.count, 1) + compare(window.pane.font.pixelSize, 30) + compare(window.pane.fontspy.count, 0) + compare(window.pane.button.font.pixelSize, 30) + compare(window.pane.button.fontspy.count, 1) + compare(window.popup.font.pixelSize, 50) + compare(window.popup.fontspy.count, 1) + compare(window.popup.button.font.pixelSize, 10) + compare(window.popup.button.fontspy.count, 2) + compare(window.popup.listview.contentItem.children[idx1].font.pixelSize, 50) + compare(window.popup.listview.contentItem.children[idx1].fontspy.count, 1) + compare(window.popup.listview.contentItem.children[idx2].font.pixelSize, 50) + compare(window.popup.listview.contentItem.children[idx2].fontspy.count, 1) + + window.popup.font.pixelSize = 60 + compare(window.font.pixelSize, 50) + compare(window.fontspy.count, 1) + compare(window.pane.font.pixelSize, 30) + compare(window.pane.fontspy.count, 0) + compare(window.pane.button.font.pixelSize, 30) + compare(window.pane.button.fontspy.count, 1) + compare(window.popup.font.pixelSize, 60) + compare(window.popup.fontspy.count, 2) + compare(window.popup.button.font.pixelSize, 10) + compare(window.popup.button.fontspy.count, 2) + compare(window.popup.listview.contentItem.children[idx1].font.pixelSize, 60) + compare(window.popup.listview.contentItem.children[idx1].fontspy.count, 2) + compare(window.popup.listview.contentItem.children[idx2].font.pixelSize, 60) + compare(window.popup.listview.contentItem.children[idx2].fontspy.count, 2) window.destroy() } @@ -511,16 +663,20 @@ TestCase { property alias button1: _button1 property alias button2: _button2 y: _button.height + locale: Qt.locale("fi_FI") implicitHeight: Math.min(396, _column.contentHeight) contentItem: Column { id: _column Button { id: _button1 text: "Button 1" + objectName: "1" } Button { id: _button2 text: "Button 2" + locale: Qt.locale("nb_NO") + objectName: "2" } } } @@ -533,26 +689,14 @@ TestCase { // test looking up natural locale from ancestors var control = localeComponent.createObject(applicationWindow.contentItem) verify(control) - verify(control.button) - verify(control.popup) - verify(control.popup.button1) - verify(control.popup.button2) - - applicationWindow.visible = true - waitForRendering(control) - - control.popup.open() - verify(control.popup.visible) - control.ApplicationWindow.window.locale = Qt.locale("fi_FI") - compare(control.ApplicationWindow.window.locale.name, "fi_FI") compare(control.locale.name, "en_US") compare(control.button.locale.name, "nb_NO") + compare(control.popup.locale.name, "fi_FI") compare(control.popup.button1.locale.name, "fi_FI") - compare(control.popup.button2.locale.name, "fi_FI") + compare(control.popup.button2.locale.name, "nb_NO") control.ApplicationWindow.window.locale = undefined - applicationWindow.visible = false control.destroy() } @@ -588,6 +732,10 @@ TestCase { property alias button2: _button2 y: _button.height implicitHeight: Math.min(396, _column.contentHeight) + property SignalSpy localespy: SignalSpy { + target: _popup + signalName: "localeChanged" + } contentItem: Column { id: _column Button { @@ -625,21 +773,12 @@ TestCase { // test default locale and locale inheritance var control = localeChangeComponent.createObject(applicationWindow.contentItem) verify(control) - verify(control.button) - verify(control.popup) - verify(control.popup.button1) - verify(control.popup.button2) - - applicationWindow.visible = true - waitForRendering(control) - - control.popup.open() - verify(control.popup.visible) var defaultLocale = Qt.locale() compare(control.ApplicationWindow.window.locale.name, defaultLocale.name) compare(control.locale.name, defaultLocale.name) compare(control.button.locale.name, defaultLocale.name) + compare(control.popup.locale.name, defaultLocale.name) compare(control.popup.button1.locale.name, defaultLocale.name) compare(control.popup.button2.locale.name, defaultLocale.name) @@ -647,10 +786,12 @@ TestCase { compare(control.ApplicationWindow.window.locale.name, "nb_NO") compare(control.locale.name, "nb_NO") compare(control.button.locale.name, "nb_NO") + compare(control.popup.locale.name, "nb_NO") compare(control.popup.button1.locale.name, "nb_NO") compare(control.popup.button2.locale.name, "nb_NO") compare(control.localespy.count, 1) compare(control.button.localespy.count, 1) + compare(control.popup.localespy.count, 1) compare(control.popup.button1.localespy.count, 1) compare(control.popup.button2.localespy.count, 1) @@ -658,10 +799,12 @@ TestCase { compare(control.ApplicationWindow.window.locale.name, defaultLocale.name) compare(control.locale.name, defaultLocale.name) compare(control.button.locale.name, defaultLocale.name) + compare(control.popup.locale.name, defaultLocale.name) compare(control.popup.button1.locale.name, defaultLocale.name) compare(control.popup.button2.locale.name, defaultLocale.name) compare(control.localespy.count, 2) compare(control.button.localespy.count, 2) + compare(control.popup.localespy.count, 2) compare(control.popup.button1.localespy.count, 2) compare(control.popup.button2.localespy.count, 2) @@ -669,12 +812,14 @@ TestCase { compare(control.ApplicationWindow.window.locale.name, defaultLocale.name) compare(control.locale.name, "ar_EG") compare(control.button.locale.name, "ar_EG") + compare(control.popup.locale.name, defaultLocale.name) compare(control.popup.button1.locale.name, defaultLocale.name) compare(control.popup.button2.locale.name, defaultLocale.name) compare(control.localespy.count, 3) compare(control.mirrorspy.count, 1) compare(control.button.localespy.count, 3) compare(control.button.mirrorspy.count, 1) + compare(control.popup.localespy.count, 2) compare(control.popup.button1.localespy.count, 2) compare(control.popup.button2.localespy.count, 2) @@ -682,12 +827,14 @@ TestCase { compare(control.ApplicationWindow.window.locale.name, "ar_EG") compare(control.locale.name, "ar_EG") compare(control.button.locale.name, "ar_EG") + compare(control.popup.locale.name, "ar_EG") compare(control.popup.button1.locale.name, "ar_EG") compare(control.popup.button2.locale.name, "ar_EG") compare(control.localespy.count, 3) compare(control.mirrorspy.count, 1) compare(control.button.localespy.count, 3) compare(control.button.mirrorspy.count, 1) + compare(control.popup.localespy.count, 3) compare(control.popup.button1.localespy.count, 3) compare(control.popup.button1.mirrorspy.count, 1) compare(control.popup.button2.localespy.count, 3) @@ -697,12 +844,14 @@ TestCase { compare(control.ApplicationWindow.window.locale.name, "ar_EG") compare(control.locale.name, "ar_EG") compare(control.button.locale.name, "nb_NO") + compare(control.popup.locale.name, "ar_EG") compare(control.popup.button1.locale.name, "ar_EG") compare(control.popup.button2.locale.name, "ar_EG") compare(control.localespy.count, 3) compare(control.mirrorspy.count, 1) compare(control.button.localespy.count, 4) compare(control.button.mirrorspy.count, 2) + compare(control.popup.localespy.count, 3) compare(control.popup.button1.localespy.count, 3) compare(control.popup.button2.localespy.count, 3) @@ -710,12 +859,14 @@ TestCase { compare(control.ApplicationWindow.window.locale.name, "ar_EG") compare(control.locale.name, "ar_EG") compare(control.button.locale.name, "nb_NO") + compare(control.popup.locale.name, "ar_EG") compare(control.popup.button1.locale.name, "ar_EG") compare(control.popup.button2.locale.name, "ar_EG") compare(control.localespy.count, 3) compare(control.mirrorspy.count, 1) compare(control.button.localespy.count, 4) compare(control.button.mirrorspy.count, 2) + compare(control.popup.localespy.count, 3) compare(control.popup.button1.localespy.count, 3) compare(control.popup.button2.localespy.count, 3) @@ -723,33 +874,70 @@ TestCase { compare(control.ApplicationWindow.window.locale.name, "ar_EG") compare(control.locale.name, "ar_EG") compare(control.button.locale.name, "nb_NO") + compare(control.popup.locale.name, "ar_EG") compare(control.popup.button1.locale.name, "nb_NO") compare(control.popup.button2.locale.name, "ar_EG") compare(control.localespy.count, 3) compare(control.mirrorspy.count, 1) compare(control.button.localespy.count, 4) compare(control.button.mirrorspy.count, 2) + compare(control.popup.localespy.count, 3) compare(control.popup.button1.localespy.count, 4) compare(control.popup.button1.mirrorspy.count, 2) compare(control.popup.button2.localespy.count, 3) compare(control.popup.button2.mirrorspy.count, 1) + control.popup.locale = Qt.locale("fi_FI") + compare(control.ApplicationWindow.window.locale.name, "ar_EG") + compare(control.locale.name, "ar_EG") + compare(control.button.locale.name, "nb_NO") + compare(control.popup.locale.name, "fi_FI") + compare(control.popup.button1.locale.name, "nb_NO") + compare(control.popup.button2.locale.name, "fi_FI") + compare(control.localespy.count, 3) + compare(control.mirrorspy.count, 1) + compare(control.button.localespy.count, 4) + compare(control.button.mirrorspy.count, 2) + compare(control.popup.localespy.count, 4) + compare(control.popup.button1.localespy.count, 4) + compare(control.popup.button1.mirrorspy.count, 2) + compare(control.popup.button2.localespy.count, 4) + compare(control.popup.button2.mirrorspy.count, 2) + control.ApplicationWindow.window.locale = undefined compare(control.ApplicationWindow.window.locale.name, defaultLocale.name) compare(control.locale.name, defaultLocale.name) compare(control.button.locale.name, "nb_NO") + compare(control.popup.locale.name, "fi_FI") compare(control.popup.button1.locale.name, "nb_NO") - compare(control.popup.button2.locale.name, defaultLocale.name) + compare(control.popup.button2.locale.name, "fi_FI") compare(control.localespy.count, 4) compare(control.mirrorspy.count, 2) compare(control.button.localespy.count, 4) compare(control.button.mirrorspy.count, 2) + compare(control.popup.localespy.count, 4) compare(control.popup.button1.localespy.count, 4) compare(control.popup.button1.mirrorspy.count, 2) compare(control.popup.button2.localespy.count, 4) compare(control.popup.button2.mirrorspy.count, 2) - applicationWindow.visible = false + control.popup.locale = undefined + compare(control.ApplicationWindow.window.locale.name, defaultLocale.name) + compare(control.locale.name, defaultLocale.name) + compare(control.button.locale.name, "nb_NO") + compare(control.popup.locale.name, defaultLocale.name) + compare(control.popup.button1.locale.name, "nb_NO") + compare(control.popup.button2.locale.name, defaultLocale.name) + compare(control.localespy.count, 4) + compare(control.mirrorspy.count, 2) + compare(control.button.localespy.count, 4) + compare(control.button.mirrorspy.count, 2) + compare(control.popup.localespy.count, 5) + compare(control.popup.button1.localespy.count, 4) + compare(control.popup.button1.mirrorspy.count, 2) + compare(control.popup.button2.localespy.count, 5) + compare(control.popup.button2.mirrorspy.count, 2) + control.destroy() } @@ -757,14 +945,66 @@ TestCase { var control = popupControl.createObject(testCase) verify(control) - control.width = 200 - control.height = 200 - control.open() waitForRendering(control.contentItem) - compare(control.width, 200) - compare(control.height, 200) + // implicit size of the content + control.contentItem.implicitWidth = 10 + compare(control.implicitWidth, 10 + control.leftPadding + control.rightPadding) + compare(control.width, control.implicitWidth) + compare(control.contentItem.width, control.width - control.leftPadding - control.rightPadding) + + control.contentItem.implicitHeight = 20 + compare(control.implicitHeight, 20 + control.topPadding + control.bottomPadding) + compare(control.height, control.implicitHeight) + compare(control.contentItem.height, control.height - control.topPadding - control.bottomPadding) + + // implicit size of the popup + control.implicitWidth = 30 + compare(control.implicitWidth, 30) + compare(control.width, 30) + compare(control.contentItem.width, control.width - control.leftPadding - control.rightPadding) + + control.implicitHeight = 40 + compare(control.implicitHeight, 40) + compare(control.height, 40) + compare(control.contentItem.height, control.height - control.topPadding - control.bottomPadding) + + // set explicit size + control.width = 50 + compare(control.implicitWidth, 30) + compare(control.width, 50) + compare(control.contentItem.width, control.width - control.leftPadding - control.rightPadding) + + control.height = 60 + compare(control.implicitHeight, 40) + compare(control.height, 60) + compare(control.contentItem.height, control.height - control.topPadding - control.bottomPadding) + + // reset explicit size + control.width = undefined + compare(control.implicitWidth, 30) + compare(control.width, 30) + compare(control.contentItem.width, control.width - control.leftPadding - control.rightPadding) + + control.height = undefined + compare(control.implicitHeight, 40) + compare(control.height, 40) + compare(control.contentItem.height, control.height - control.topPadding - control.bottomPadding) + + control.destroy() + } + + function test_visible() { + var control = popupTemplate.createObject(testCase, {visible: true}) + verify(control) + + // QTBUG-51989 + tryCompare(control, "visible", true) + + // QTBUG-55347 + control.parent = null + verify(!control.visible) control.destroy() } @@ -772,40 +1012,252 @@ TestCase { Component { id: overlayTest ApplicationWindow { - property alias popup1: popup1 - property alias popup2: popup2 + property alias firstDrawer: firstDrawer + property alias secondDrawer: secondDrawer + property alias modalPopup: modalPopup + property alias modelessPopup: modelessPopup + property alias plainPopup: plainPopup + property alias modalPopupWithoutDim: modalPopupWithoutDim visible: true + Drawer { + z: 0 + id: firstDrawer + } + Drawer { + z: 1 + id: secondDrawer + } Popup { - id: popup1 + id: modalPopup + z: 2 modal: true exit: Transition { PauseAnimation { duration: 200 } } } Popup { - id: popup2 + id: modelessPopup + z: 3 + dim: true + exit: Transition { PauseAnimation { duration: 200 } } + } + Popup { + id: plainPopup + z: 4 + enter: Transition { PauseAnimation { duration: 200 } } + exit: Transition { PauseAnimation { duration: 200 } } + } + Popup { + id: modalPopupWithoutDim + z: 5 + dim: false modal: true + exit: Transition { PauseAnimation { duration: 200 } } } } } + function indexOf(array, item) { + for (var idx = 0; idx < array.length; ++idx) { + if (item === array[idx]) + return idx; + } + return -1 + } + + function findOverlay(window, popup) { + var item = popup.contentItem.parent + var idx = indexOf(window.overlay.children, item) + return window.overlay.children[idx - 1] + } + function test_overlay() { var window = overlayTest.createObject(testCase) verify(window) window.requestActivate() tryCompare(window, "active", true) - compare(window.overlay.background.opacity, 0.0) - window.popup1.open() - compare(window.popup1.visible, true) - compare(window.popup2.visible, false) - tryCompare(window.overlay.background, "opacity", 1.0) + compare(window.overlay.children.length, 0) + + var firstOverlay = findOverlay(window, window.firstDrawer) + verify(!firstOverlay) + window.firstDrawer.open() + compare(window.overlay.children.length, 2) // 1 drawer + 1 overlay + firstOverlay = findOverlay(window, window.firstDrawer) + verify(firstOverlay) + compare(firstOverlay.z, window.firstDrawer.z) + compare(indexOf(window.overlay.children, firstOverlay), + indexOf(window.overlay.children, window.firstDrawer.contentItem.parent) - 1) + tryCompare(firstOverlay, "opacity", 1.0) + + var secondOverlay = findOverlay(window, window.secondDrawer) + verify(!secondOverlay) + window.secondDrawer.open() + compare(window.overlay.children.length, 4) // 2 drawers + 2 overlays + secondOverlay = findOverlay(window, window.secondDrawer) + verify(secondOverlay) + compare(secondOverlay.z, window.secondDrawer.z) + compare(indexOf(window.overlay.children, secondOverlay), + indexOf(window.overlay.children, window.secondDrawer.contentItem.parent) - 1) + tryCompare(secondOverlay, "opacity", 1.0) + + window.firstDrawer.close() + tryCompare(window.firstDrawer, "visible", false) + firstOverlay = findOverlay(window, window.firstDrawer) + verify(!firstOverlay) + compare(window.overlay.children.length, 2) // 1 drawer + 1 overlay + + window.secondDrawer.close() + tryCompare(window.secondDrawer, "visible", false) + secondOverlay = findOverlay(window, window.secondDrawer) + verify(!secondOverlay) + compare(window.overlay.children.length, 0) + + var modalOverlay = findOverlay(window, window.modalPopup) + verify(!modalOverlay) + window.modalPopup.open() + modalOverlay = findOverlay(window, window.modalPopup) + verify(modalOverlay) + compare(modalOverlay.z, window.modalPopup.z) + compare(window.modalPopup.visible, true) + tryCompare(modalOverlay, "opacity", 1.0) + compare(window.overlay.children.length, 2) // 1 popup + 1 overlay + + var modelessOverlay = findOverlay(window, window.modelessPopup) + verify(!modelessOverlay) + window.modelessPopup.open() + modelessOverlay = findOverlay(window, window.modelessPopup) + verify(modelessOverlay) + compare(modelessOverlay.z, window.modelessPopup.z) + compare(window.modelessPopup.visible, true) + tryCompare(modelessOverlay, "opacity", 1.0) + compare(window.overlay.children.length, 4) // 2 popups + 2 overlays + + window.modelessPopup.close() + tryCompare(window.modelessPopup, "visible", false) + modelessOverlay = findOverlay(window, window.modelessPopup) + verify(!modelessOverlay) + compare(window.overlay.children.length, 2) // 1 popup + 1 overlay + + compare(window.modalPopup.visible, true) + compare(modalOverlay.opacity, 1.0) + + window.modalPopup.close() + tryCompare(window.modalPopup, "visible", false) + modalOverlay = findOverlay(window, window.modalPopup) + verify(!modalOverlay) + compare(window.overlay.children.length, 0) + + window.plainPopup.open() + tryCompare(window.plainPopup, "visible", true) + compare(window.overlay.children.length, 1) // only popup added, no overlays involved + + window.plainPopup.modal = true + compare(window.overlay.children.length, 2) // overlay added + + window.plainPopup.close() + tryCompare(window.plainPopup, "visible", false) + compare(window.overlay.children.length, 0) // popup + overlay removed + + window.modalPopupWithoutDim.open() + tryCompare(window.modalPopupWithoutDim, "visible", true) + compare(window.overlay.children.length, 1) // only popup added, no overlays involved + + window.modalPopupWithoutDim.dim = true + compare(window.overlay.children.length, 2) // overlay added + + window.modalPopupWithoutDim.close() + tryCompare(window.modalPopupWithoutDim, "visible", false) + compare(window.overlay.children.length, 0) // popup + overlay removed + + window.destroy() + } + + function test_attached_applicationwindow() { + var control = popupControl.createObject(applicationWindow.contentItem) + verify(control) + + var child = rect.createObject(control.contentItem) + + compare(control.ApplicationWindow.window, applicationWindow) + compare(control.contentItem.ApplicationWindow.window, applicationWindow) + compare(child.ApplicationWindow.window, applicationWindow) + + control.parent = null + compare(control.ApplicationWindow.window, null) + compare(control.contentItem.ApplicationWindow.window, null) + compare(child.ApplicationWindow.window, null) - window.popup1.close() - window.popup2.open() - compare(window.popup2.visible, true) - tryCompare(window.popup1, "visible", false) - compare(window.overlay.background.opacity, 1.0) + control.destroy() + } + + SignalSpy { + id: openedSpy + signalName: "opened" + } + SignalSpy { + id: closedSpy + signalName: "closed" + } + + Component { + id: pausePopup + Popup { + enter: Transition { PauseAnimation { duration: 200 } } + exit: Transition { PauseAnimation { duration: 200 } } + } + } + + function test_openedClosed() { + var control = pausePopup.createObject(testCase) + verify(control) + + openedSpy.target = control + closedSpy.target = control + + control.open() + compare(control.visible, true) + compare(openedSpy.count, 0) + tryCompare(openedSpy, "count", 1) + compare(closedSpy.count, 0) + + control.close() + compare(openedSpy.count, 1) + compare(closedSpy.count, 0) + tryCompare(closedSpy, "count", 1) + compare(control.visible, false) + + control.destroy() + } + + Component { + id: xyBindingLoop + ApplicationWindow { + id: window + width: 360 + height: 360 + visible: true + property alias popup: popup + + Popup { + id: popup + visible: true + x: (parent.width - width) / 2 + y: (parent.height - height) / 2 + Label { + text: "Content" + anchors.fill: parent + } + } + } + } + + function test_xyBindingLoop() { + var window = xyBindingLoop.createObject(testCase) + var control = window.popup + waitForRendering(control.contentItem) + compare(control.x, (control.parent.width - control.width) / 2) + compare(control.y, (control.parent.height - control.height) / 2) window.destroy() } } diff --git a/tests/auto/controls/data/tst_progressbar.qml b/tests/auto/controls/data/tst_progressbar.qml index 1aea09f5..5603c280 100644 --- a/tests/auto/controls/data/tst_progressbar.qml +++ b/tests/auto/controls/data/tst_progressbar.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_radiobutton.qml b/tests/auto/controls/data/tst_radiobutton.qml index d4cdf0ad..e86b862e 100644 --- a/tests/auto/controls/data/tst_radiobutton.qml +++ b/tests/auto/controls/data/tst_radiobutton.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase @@ -52,13 +52,13 @@ TestCase { Component { id: radioButton - RadioButton { - id: control + RadioButton { } + } - property ControlSpy spy: ControlSpy { - target: control - signals: ["pressed", "released", "canceled", "clicked", "pressedChanged", "checkedChanged"] - } + Component { + id: signalSequenceSpy + SignalSequenceSpy { + signals: ["pressed", "released", "canceled", "clicked", "pressedChanged", "checkedChanged"] } } @@ -79,19 +79,21 @@ TestCase { var control = radioButton.createObject(testCase) verify(control) - control.spy.expectedSequence = [] // No change expected + var sequenceSpy = signalSequenceSpy.createObject(control, {target: control}) + + sequenceSpy.expectedSequence = [] // No change expected compare(control.checked, false) - verify(control.spy.success) + verify(sequenceSpy.success) - control.spy.expectedSequence = ["checkedChanged"] + sequenceSpy.expectedSequence = ["checkedChanged"] control.checked = true compare(control.checked, true) - verify(control.spy.success) + verify(sequenceSpy.success) - control.spy.reset() + sequenceSpy.reset() control.checked = false compare(control.checked, false) - verify(control.spy.success) + verify(sequenceSpy.success) control.destroy() } @@ -100,59 +102,61 @@ TestCase { var control = radioButton.createObject(testCase) verify(control) + var sequenceSpy = signalSequenceSpy.createObject(control, {target: control}) + // check - control.spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }], + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }], "pressed"] mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton) compare(control.pressed, true) - verify(control.spy.success) - control.spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false }], + verify(sequenceSpy.success) + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false }], + ["checkedChanged", { "pressed": false, "checked": true }], "released", - "clicked", - ["checkedChanged", { "pressed": false, "checked": true }]] + "clicked"] mouseRelease(control, control.width / 2, control.height / 2, Qt.LeftButton) compare(control.checked, true) compare(control.pressed, false) - verify(control.spy.success) + verify(sequenceSpy.success) // attempt uncheck - control.spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }], + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }], "pressed"] mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton) compare(control.pressed, true) - verify(control.spy.success) - control.spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": true }], + verify(sequenceSpy.success) + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": true }], "released", "clicked"] mouseRelease(control, control.width / 2, control.height / 2, Qt.LeftButton) compare(control.checked, true) compare(control.pressed, false) - verify(control.spy.success) + verify(sequenceSpy.success) // release outside - control.spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }], + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }], "pressed"] mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton) compare(control.pressed, true) - verify(control.spy.success) - control.spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": true }]] + verify(sequenceSpy.success) + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": true }]] mouseMove(control, control.width * 2, control.height * 2, 0, Qt.LeftButton) compare(control.pressed, false) - control.spy.expectedSequence = [["canceled", { "pressed": false, "checked": true }]] + sequenceSpy.expectedSequence = [["canceled", { "pressed": false, "checked": true }]] mouseRelease(control, control.width * 2, control.height * 2, Qt.LeftButton) compare(control.checked, true) compare(control.pressed, false) - verify(control.spy.success) + verify(sequenceSpy.success) // right button - control.spy.expectedSequence = [] + sequenceSpy.expectedSequence = [] mousePress(control, control.width / 2, control.height / 2, Qt.RightButton) compare(control.pressed, false) - verify(control.spy.success) + verify(sequenceSpy.success) mouseRelease(control, control.width / 2, control.height / 2, Qt.RightButton) compare(control.checked, true) compare(control.pressed, false) - verify(control.spy.success) + verify(sequenceSpy.success) control.destroy() } @@ -161,40 +165,42 @@ TestCase { var control = radioButton.createObject(testCase) verify(control) - control.spy.expectedSequence = [] + var sequenceSpy = signalSequenceSpy.createObject(control, {target: control}) + + sequenceSpy.expectedSequence = [] control.forceActiveFocus() verify(control.activeFocus) - verify(control.spy.success) + verify(sequenceSpy.success) // check - control.spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }], + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }], "pressed", ["pressedChanged", { "pressed": false, "checked": false }], + ["checkedChanged", { "pressed": false, "checked": true }], "released", - "clicked", - ["checkedChanged", { "pressed": false, "checked": true }]] + "clicked"] keyClick(Qt.Key_Space) compare(control.checked, true) - verify(control.spy.success) + verify(sequenceSpy.success) // attempt uncheck - control.spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }], + sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }], "pressed", ["pressedChanged", { "pressed": false, "checked": true }], "released", "clicked"] keyClick(Qt.Key_Space) compare(control.checked, true) - verify(control.spy.success) + verify(sequenceSpy.success) // no change - control.spy.expectedSequence = [] + sequenceSpy.expectedSequence = [] var keys = [Qt.Key_Enter, Qt.Key_Return, Qt.Key_Escape, Qt.Key_Tab] for (var i = 0; i < keys.length; ++i) { - control.spy.reset() + sequenceSpy.reset() keyClick(keys[i]) compare(control.checked, true) - verify(control.spy.success) + verify(sequenceSpy.success) } control.destroy() @@ -312,7 +318,7 @@ TestCase { function test_baseline() { var control = radioButton.createObject(testCase) verify(control) - compare(control.baselineOffset, control.label.y + control.label.baselineOffset) + compare(control.baselineOffset, control.contentItem.y + control.contentItem.baselineOffset) control.destroy() } } diff --git a/tests/auto/controls/data/tst_radiodelegate.qml b/tests/auto/controls/data/tst_radiodelegate.qml new file mode 100644 index 00000000..1a424a32 --- /dev/null +++ b/tests/auto/controls/data/tst_radiodelegate.qml @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtTest 1.0 +import QtQuick.Controls 2.0 + +TestCase { + id: testCase + width: 200 + height: 200 + visible: true + when: windowShown + name: "RadioDelegate" + + Component { + id: radioDelegate + RadioDelegate {} + } + + // TODO: data-fy tst_radiobutton (rename to tst_radio?) so we don't duplicate its tests here? + + function test_defaults() { + var control = radioDelegate.createObject(testCase); + verify(control); + verify(!control.checked); + control.destroy(); + } + + function test_checked() { + var control = radioDelegate.createObject(testCase); + verify(control); + + mouseClick(control); + verify(control.checked); + + mouseClick(control); + verify(control.checked); + + control.destroy(); + } + + function test_baseline() { + var control = radioDelegate.createObject(testCase); + verify(control); + compare(control.baselineOffset, control.contentItem.y + control.contentItem.baselineOffset); + control.destroy(); + } +} diff --git a/tests/auto/controls/data/tst_rangeslider.qml b/tests/auto/controls/data/tst_rangeslider.qml index cc12b851..3167be0b 100644 --- a/tests/auto/controls/data/tst_rangeslider.qml +++ b/tests/auto/controls/data/tst_rangeslider.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase @@ -50,14 +50,9 @@ TestCase { when: windowShown name: "RangeSlider" - SignalSpy { - id: firstPressedSpy - signalName: "pressedChanged" - } - - SignalSpy { - id: secondPressedSpy - signalName: "pressedChanged" + Component { + id: signalSpy + SignalSpy { } } Component { @@ -84,21 +79,6 @@ TestCase { } } - function init() { - verify(!firstPressedSpy.target) - compare(firstPressedSpy.count, 0) - - verify(!secondPressedSpy.target) - compare(secondPressedSpy.count, 0) - } - - function cleanup() { - firstPressedSpy.target = null - firstPressedSpy.clear() - secondPressedSpy.target = null - secondPressedSpy.clear() - } - function test_defaults() { var control = sliderComponent.createObject(testCase) verify(control) @@ -303,10 +283,10 @@ TestCase { var control = sliderComponent.createObject(testCase, { orientation: data.orientation }) verify(control) - firstPressedSpy.target = control.first + var firstPressedSpy = signalSpy.createObject(control, {target: control.first, signalName: "pressedChanged"}) verify(firstPressedSpy.valid) - secondPressedSpy.target = control.second + var secondPressedSpy = signalSpy.createObject(control, {target: control.second, signalName: "pressedChanged"}) verify(secondPressedSpy.valid) mousePress(control, control.width * 0.25, control.height * 0.75, Qt.LeftButton) @@ -473,7 +453,7 @@ TestCase { var pressedCount = 0 - firstPressedSpy.target = control.first + var firstPressedSpy = signalSpy.createObject(control, {target: control.first, signalName: "pressedChanged"}) verify(firstPressedSpy.valid) control.first.handle.forceActiveFocus() @@ -511,7 +491,7 @@ TestCase { control.stepSize = 0.25 pressedCount = 0; - secondPressedSpy.target = control.second + var secondPressedSpy = signalSpy.createObject(control, {target: control.second, signalName: "pressedChanged"}) verify(secondPressedSpy.valid) control.second.handle.forceActiveFocus() @@ -553,7 +533,7 @@ TestCase { var control = sliderComponent.createObject(testCase, { leftPadding: 10, rightPadding: 20 }) verify(control) - firstPressedSpy.target = control.first + var firstPressedSpy = signalSpy.createObject(control, {target: control.first, signalName: "pressedChanged"}) verify(firstPressedSpy.valid) mousePress(control, control.first.handle.x, control.first.handle.y, Qt.LeftButton) @@ -621,18 +601,24 @@ TestCase { function test_snapMode_data() { return [ - { tag: "NoSnap", snapMode: Slider.NoSnap, values: [0, 0, 0.25], positions: [0, 0.1, 0.1] }, - { tag: "SnapAlways", snapMode: Slider.SnapAlways, values: [0, 0, 0.2], positions: [0, 0.1, 0.1] }, - { tag: "SnapOnRelease", snapMode: Slider.SnapOnRelease, values: [0, 0, 0.2], positions: [0, 0.1, 0.1] } + { tag: "NoSnap", snapMode: RangeSlider.NoSnap, from: 0, to: 2, values: [0, 0, 0.25], positions: [0, 0.1, 0.1] }, + { tag: "SnapAlways (0..2)", snapMode: RangeSlider.SnapAlways, from: 0, to: 2, values: [0.0, 0.0, 0.2], positions: [0.0, 0.1, 0.1] }, + { tag: "SnapAlways (1..3)", snapMode: RangeSlider.SnapAlways, from: 1, to: 3, values: [1.0, 1.0, 1.2], positions: [0.0, 0.1, 0.1] }, + { tag: "SnapAlways (-1..1)", snapMode: RangeSlider.SnapAlways, from: -1, to: 1, values: [0.0, 0.0, -0.8], positions: [0.5, 0.1, 0.1] }, + { tag: "SnapAlways (1..-1)", snapMode: RangeSlider.SnapAlways, from: 1, to: -1, values: [0.0, 0.0, 0.8], positions: [0.5, 0.1, 0.1] }, + { tag: "SnapOnRelease (0..2)", snapMode: RangeSlider.SnapOnRelease, from: 0, to: 2, values: [0.0, 0.0, 0.2], positions: [0.0, 0.1, 0.1] }, + { tag: "SnapOnRelease (1..3)", snapMode: RangeSlider.SnapOnRelease, from: 1, to: 3, values: [1.0, 1.0, 1.2], positions: [0.0, 0.1, 0.1] }, + { tag: "SnapOnRelease (-1..1)", snapMode: RangeSlider.SnapOnRelease, from: -1, to: 1, values: [0.0, 0.0, -0.8], positions: [0.5, 0.1, 0.1] }, + { tag: "SnapOnRelease (1..-1)", snapMode: RangeSlider.SnapOnRelease, from: 1, to: -1, values: [0.0, 0.0, 0.8], positions: [0.5, 0.1, 0.1] } ] } function test_snapMode(data) { - var control = sliderComponent.createObject(testCase, {snapMode: data.snapMode, from: 0, to: 2, stepSize: 0.2}) + var control = sliderComponent.createObject(testCase, {snapMode: data.snapMode, from: data.from, to: data.to, stepSize: 0.2}) verify(control) control.first.value = 0 - control.second.value = 2 + control.second.value = data.to function sliderCompare(left, right) { return Math.abs(left - right) < 0.05 diff --git a/tests/auto/controls/data/tst_scrollbar.qml b/tests/auto/controls/data/tst_scrollbar.qml index 6e021ccf..7c83cca9 100644 --- a/tests/auto/controls/data/tst_scrollbar.qml +++ b/tests/auto/controls/data/tst_scrollbar.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase @@ -50,9 +50,9 @@ TestCase { when: windowShown name: "ScrollBar" - SignalSpy{ - id: pressedSpy - signalName: "pressedChanged" + Component { + id: signalSpy + SignalSpy { } } Component { @@ -72,16 +72,6 @@ TestCase { } } - function init() { - verify(!pressedSpy.target) - compare(pressedSpy.count, 0) - } - - function cleanup() { - pressedSpy.target = null - pressedSpy.clear() - } - function test_attach() { var container = flickable.createObject(testCase) verify(container) @@ -151,6 +141,22 @@ TestCase { compare(horizontal.size, container.visibleArea.widthRatio) compare(horizontal.position, container.visibleArea.xPosition) + var oldY = vertical.y + var oldHeight = vertical.height + vertical.parent = testCase + vertical.y -= 10 + container.height += 10 + compare(vertical.y, oldY - 10) + compare(vertical.height, oldHeight) + + var oldX = horizontal.x + var oldWidth = horizontal.width + horizontal.parent = testCase + horizontal.x -= 10 + container.width += 10 + compare(horizontal.x, oldX - 10) + compare(horizontal.width, oldWidth) + container.destroy() } @@ -165,7 +171,7 @@ TestCase { var control = scrollBar.createObject(testCase, data.properties) verify(control) - pressedSpy.target = control + var pressedSpy = signalSpy.createObject(control, {target: control, signalName: "pressedChanged"}) verify(pressedSpy.valid) mousePress(control, 0, 0, Qt.LeftButton) @@ -211,6 +217,69 @@ TestCase { control.destroy() } + function test_increase_decrease_data() { + return [ + { tag: "increase:active", increase: true, active: true }, + { tag: "decrease:active", increase: false, active: true }, + { tag: "increase:inactive", increase: true, active: false }, + { tag: "decrease:inactive", increase: false, active: false } + ] + } + + function test_increase_decrease(data) { + var control = scrollBar.createObject(testCase, {position: 0.5, active: data.active}) + verify(control) + + if (data.increase) { + control.increase() + compare(control.position, 0.6) + } else { + control.decrease() + compare(control.position, 0.4) + } + compare(control.active, data.active) + + control.destroy() + } + + function test_stepSize_data() { + return [ + { tag: "0.0", stepSize: 0.0 }, + { tag: "0.1", stepSize: 0.1 }, + { tag: "0.5", stepSize: 0.5 } + ] + } + + function test_stepSize(data) { + var control = scrollBar.createObject(testCase, {stepSize: data.stepSize}) + verify(control) + + compare(control.stepSize, data.stepSize) + compare(control.position, 0.0) + + var count = 10 + if (data.stepSize !== 0.0) + count = 1.0 / data.stepSize + + // increase until 1.0 + for (var i = 1; i <= count; ++i) { + control.increase() + compare(control.position, i / count) + } + control.increase() + compare(control.position, 1.0) + + // decrease until 0.0 + for (var d = count - 1; d >= 0; --d) { + control.decrease() + compare(control.position, d / count) + } + control.decrease() + compare(control.position, 0.0) + + control.destroy() + } + function test_padding_data() { return [ { tag: "horizontal", properties: { visible: true, orientation: Qt.Horizontal, width: testCase.width, leftPadding: testCase.width * 0.1 } }, @@ -225,5 +294,25 @@ TestCase { mouseRelease(control, control.leftPadding + control.availableWidth * 0.5, control.topPadding + control.availableHeight * 0.5, Qt.LeftButton) compare(control.position, 0.5) + + control.destroy() + } + + function test_warning() { + ignoreWarning(Qt.resolvedUrl("tst_scrollbar.qml") + ":45:1: QML TestCase: ScrollBar must be attached to a Flickable") + testCase.ScrollBar.vertical = null + } + + function test_mirrored() { + var container = flickable.createObject(testCase) + verify(container) + waitForRendering(container) + + container.ScrollBar.vertical = scrollBar.createObject(container) + compare(container.ScrollBar.vertical.x, container.width - container.ScrollBar.vertical.width) + container.ScrollBar.vertical.locale = Qt.locale("ar_EG") + compare(container.ScrollBar.vertical.x, 0) + + container.destroy() } } diff --git a/tests/auto/controls/data/tst_scrollindicator.qml b/tests/auto/controls/data/tst_scrollindicator.qml index 99eef833..f5e57e2d 100644 --- a/tests/auto/controls/data/tst_scrollindicator.qml +++ b/tests/auto/controls/data/tst_scrollindicator.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase @@ -136,6 +136,61 @@ TestCase { compare(horizontal.size, container.visibleArea.widthRatio) compare(horizontal.position, container.visibleArea.xPosition) + var oldY = vertical.y + var oldHeight = vertical.height + vertical.parent = testCase + vertical.y -= 10 + container.height += 10 + compare(vertical.y, oldY - 10) + compare(vertical.height, oldHeight) + + var oldX = horizontal.x + var oldWidth = horizontal.width + horizontal.parent = testCase + horizontal.x -= 10 + container.width += 10 + compare(horizontal.x, oldX - 10) + compare(horizontal.width, oldWidth) + + container.destroy() + } + + function test_warning() { + ignoreWarning(Qt.resolvedUrl("tst_scrollindicator.qml") + ":45:1: QML TestCase: ScrollIndicator must be attached to a Flickable") + testCase.ScrollIndicator.vertical = null + } + + function test_overshoot() { + var container = flickable.createObject(testCase) + verify(container) + waitForRendering(container) + + var vertical = scrollIndicator.createObject(container, {size: 0.5}) + container.ScrollIndicator.vertical = vertical + + var horizontal = scrollIndicator.createObject(container, {size: 0.5}) + container.ScrollIndicator.horizontal = horizontal + + // negative vertical overshoot (pos < 0) + vertical.position = -0.1 + compare(vertical.contentItem.y, vertical.topPadding) + compare(vertical.contentItem.height, 0.4 * vertical.availableHeight) + + // positive vertical overshoot (pos + size > 1) + vertical.position = 0.8 + compare(vertical.contentItem.y, vertical.topPadding + 0.8 * vertical.availableHeight) + compare(vertical.contentItem.height, 0.2 * vertical.availableHeight) + + // negative horizontal overshoot (pos < 0) + horizontal.position = -0.1 + compare(horizontal.contentItem.x, horizontal.leftPadding) + compare(horizontal.contentItem.width, 0.4 * horizontal.availableWidth) + + // positive horizontal overshoot (pos + size > 1) + horizontal.position = 0.8 + compare(horizontal.contentItem.x, horizontal.leftPadding + 0.8 * horizontal.availableWidth) + compare(horizontal.contentItem.width, 0.2 * horizontal.availableWidth) + container.destroy() } } diff --git a/tests/auto/controls/data/tst_slider.qml b/tests/auto/controls/data/tst_slider.qml index 53e2fb8f..4a698076 100644 --- a/tests/auto/controls/data/tst_slider.qml +++ b/tests/auto/controls/data/tst_slider.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase @@ -50,9 +50,9 @@ TestCase { when: windowShown name: "Slider" - SignalSpy{ - id: pressedSpy - signalName: "pressedChanged" + Component { + id: signalSpy + SignalSpy { } } Component { @@ -60,16 +60,6 @@ TestCase { Slider { } } - function init() { - verify(!pressedSpy.target) - compare(pressedSpy.count, 0) - } - - function cleanup() { - pressedSpy.target = null - pressedSpy.clear() - } - function test_defaults() { var control = slider.createObject(testCase) verify(control) @@ -232,7 +222,7 @@ TestCase { var control = slider.createObject(testCase, {orientation: data.orientation}) verify(control) - pressedSpy.target = control + var pressedSpy = signalSpy.createObject(control, {target: control, signalName: "pressedChanged"}) verify(pressedSpy.valid) mousePress(control, 0, 0, Qt.LeftButton) @@ -286,6 +276,12 @@ TestCase { verify(control.value <= 0.25 && control.value >= 0.0) verify(control.position <= 0.25 && control.position >= 0.0) + // QTBUG-53846 + mouseClick(control, control.width * 0.5, control.height * 0.5, Qt.LeftButton) + compare(pressedSpy.count, 6) + compare(control.value, 0.5) + compare(control.position, 0.5) + control.destroy() } @@ -302,7 +298,7 @@ TestCase { var pressedCount = 0 - pressedSpy.target = control + var pressedSpy = signalSpy.createObject(control, {target: control, signalName: "pressedChanged"}) verify(pressedSpy.valid) control.forceActiveFocus() @@ -374,7 +370,7 @@ TestCase { var control = slider.createObject(testCase, {leftPadding: 10, rightPadding: 20}) verify(control) - pressedSpy.target = control + var pressedSpy = signalSpy.createObject(control, {target: control, signalName: "pressedChanged"}) verify(pressedSpy.valid) mousePress(control, 0, 0, Qt.LeftButton) @@ -442,14 +438,20 @@ TestCase { function test_snapMode_data() { return [ - { tag: "NoSnap", snapMode: Slider.NoSnap, values: [0, 0, 0.25], positions: [0, 0.1, 0.1] }, - { tag: "SnapAlways", snapMode: Slider.SnapAlways, values: [0, 0, 0.2], positions: [0, 0.1, 0.1] }, - { tag: "SnapOnRelease", snapMode: Slider.SnapOnRelease, values: [0, 0, 0.2], positions: [0, 0.1, 0.1] } + { tag: "NoSnap", snapMode: Slider.NoSnap, from: 0, to: 2, values: [0, 0, 0.25], positions: [0, 0.1, 0.1] }, + { tag: "SnapAlways (0..2)", snapMode: Slider.SnapAlways, from: 0, to: 2, values: [0.0, 0.0, 0.2], positions: [0.0, 0.1, 0.1] }, + { tag: "SnapAlways (1..3)", snapMode: Slider.SnapAlways, from: 1, to: 3, values: [1.0, 1.0, 1.2], positions: [0.0, 0.1, 0.1] }, + { tag: "SnapAlways (-1..1)", snapMode: Slider.SnapAlways, from: -1, to: 1, values: [0.0, 0.0, -0.8], positions: [0.5, 0.1, 0.1] }, + { tag: "SnapAlways (1..-1)", snapMode: Slider.SnapAlways, from: 1, to: -1, values: [0.0, 0.0, 0.8], positions: [0.5, 0.1, 0.1] }, + { tag: "SnapOnRelease (0..2)", snapMode: Slider.SnapOnRelease, from: 0, to: 2, values: [0.0, 0.0, 0.2], positions: [0.0, 0.1, 0.1] }, + { tag: "SnapOnRelease (1..3)", snapMode: Slider.SnapOnRelease, from: 1, to: 3, values: [1.0, 1.0, 1.2], positions: [0.0, 0.1, 0.1] }, + { tag: "SnapOnRelease (-1..1)", snapMode: Slider.SnapOnRelease, from: -1, to: 1, values: [0.0, 0.0, -0.8], positions: [0.5, 0.1, 0.1] }, + { tag: "SnapOnRelease (1..-1)", snapMode: Slider.SnapOnRelease, from: 1, to: -1, values: [0.0, 0.0, 0.8], positions: [0.5, 0.1, 0.1] } ] } function test_snapMode(data) { - var control = slider.createObject(testCase, {snapMode: data.snapMode, from: 0, to: 2, stepSize: 0.2}) + var control = slider.createObject(testCase, {snapMode: data.snapMode, from: data.from, to: data.to, stepSize: 0.2}) verify(control) function sliderCompare(left, right) { @@ -471,4 +473,51 @@ TestCase { control.destroy() } + + function test_wheel_data() { + return [ + { tag: "horizontal", orientation: Qt.Horizontal, dx: 120, dy: 0 }, + { tag: "vertical", orientation: Qt.Vertical, dx: 0, dy: 120 } + ] + } + + function test_wheel(data) { + var control = slider.createObject(testCase, {wheelEnabled: true, orientation: data.orientation}) + verify(control) + + compare(control.value, 0.0) + + mouseWheel(control, control.width / 2, control.height / 2, data.dx, data.dy) + compare(control.value, 0.1) + compare(control.position, 0.1) + + control.stepSize = 0.2 + + mouseWheel(control, control.width / 2, control.height / 2, data.dx, data.dy) + compare(control.value, 0.3) + compare(control.position, 0.3) + + control.stepSize = 10.0 + + mouseWheel(control, control.width / 2, control.height / 2, -data.dx, -data.dy) + compare(control.value, 0.0) + compare(control.position, 0.0) + + control.to = 10.0 + control.stepSize = 5.0 + + mouseWheel(control, control.width / 2, control.height / 2, data.dx, data.dy) + compare(control.value, 5.0) + compare(control.position, 0.5) + + mouseWheel(control, control.width / 2, control.height / 2, 0.5 * data.dx, 0.5 * data.dy) + compare(control.value, 7.5) + compare(control.position, 0.75) + + mouseWheel(control, control.width / 2, control.height / 2, -data.dx, -data.dy) + compare(control.value, 2.5) + compare(control.position, 0.25) + + control.destroy() + } } diff --git a/tests/auto/controls/data/tst_spinbox.qml b/tests/auto/controls/data/tst_spinbox.qml index cdea8b66..f2d8d3ef 100644 --- a/tests/auto/controls/data/tst_spinbox.qml +++ b/tests/auto/controls/data/tst_spinbox.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase @@ -50,14 +50,9 @@ TestCase { when: windowShown name: "SpinBox" - SignalSpy{ - id: upPressedSpy - signalName: "pressedChanged" - } - - SignalSpy{ - id: downPressedSpy - signalName: "pressedChanged" + Component { + id: signalSpy + SignalSpy { } } Component { @@ -65,20 +60,6 @@ TestCase { SpinBox { } } - function init() { - verify(!upPressedSpy.target) - compare(upPressedSpy.count, 0) - verify(!downPressedSpy.target) - compare(downPressedSpy.count, 0) - } - - function cleanup() { - upPressedSpy.target = null - upPressedSpy.clear() - downPressedSpy.target = null - downPressedSpy.clear() - } - function test_defaults() { var control = spinBox.createObject(testCase) verify(control) @@ -87,8 +68,11 @@ TestCase { compare(control.to, 99) compare(control.value, 0) compare(control.stepSize, 1) + compare(control.editable, false) compare(control.up.pressed, false) + compare(control.up.indicator.enabled, true) compare(control.down.pressed, false) + compare(control.down.indicator.enabled, false) control.destroy() } @@ -117,23 +101,40 @@ TestCase { compare(control.from, 0) compare(control.to, 100) compare(control.value, 50) + compare(control.up.indicator.enabled, true) + compare(control.down.indicator.enabled, true) control.value = 1000 compare(control.value, 100) + compare(control.up.indicator.enabled, false) + compare(control.down.indicator.enabled, true) control.value = -1 compare(control.value, 0) + compare(control.up.indicator.enabled, true) + compare(control.down.indicator.enabled, false) control.from = 25 compare(control.from, 25) compare(control.value, 25) + compare(control.up.indicator.enabled, true) + compare(control.down.indicator.enabled, false) control.to = 75 compare(control.to, 75) compare(control.value, 25) + compare(control.up.indicator.enabled, true) + compare(control.down.indicator.enabled, false) control.value = 50 compare(control.value, 50) + compare(control.up.indicator.enabled, true) + compare(control.down.indicator.enabled, true) + + control.to = 40; + compare(control.value, 40) + compare(control.up.indicator.enabled, false) + compare(control.down.indicator.enabled, true) control.destroy() } @@ -145,15 +146,23 @@ TestCase { compare(control.from, 100) compare(control.to, -100) compare(control.value, 0) + compare(control.up.indicator.enabled, true) + compare(control.down.indicator.enabled, true) control.value = 200 compare(control.value, 100) + compare(control.up.indicator.enabled, true) + compare(control.down.indicator.enabled, false) control.value = -200 compare(control.value, -100) + compare(control.up.indicator.enabled, false) + compare(control.down.indicator.enabled, true) control.value = 0 compare(control.value, 0) + compare(control.up.indicator.enabled, true) + compare(control.down.indicator.enabled, true) control.destroy() } @@ -162,9 +171,12 @@ TestCase { var control = spinBox.createObject(testCase, {stepSize: 50}) verify(control) - upPressedSpy.target = control.up + var upPressedSpy = signalSpy.createObject(control, {target: control.up, signalName: "pressedChanged"}) verify(upPressedSpy.valid) + var downPressedSpy = signalSpy.createObject(control, {target: control.down, signalName: "pressedChanged"}) + verify(downPressedSpy.valid) + mousePress(control.up.indicator) compare(upPressedSpy.count, 1) compare(control.up.pressed, true) @@ -179,9 +191,25 @@ TestCase { compare(control.down.pressed, false) compare(control.value, 50) - downPressedSpy.target = control.down - verify(downPressedSpy.valid) + // Disable the up button and try again. + control.value = control.to + compare(control.up.indicator.enabled, false) + mousePress(control.up.indicator) + compare(upPressedSpy.count, 2) + compare(control.up.pressed, false) + compare(downPressedSpy.count, 0) + compare(control.down.pressed, false) + compare(control.value, control.to) + + mouseRelease(control.up.indicator) + compare(upPressedSpy.count, 2) + compare(control.up.pressed, false) + compare(downPressedSpy.count, 0) + compare(control.down.pressed, false) + compare(control.value, control.to) + + control.value = 50; mousePress(control.down.indicator) compare(downPressedSpy.count, 1) compare(control.down.pressed, true) @@ -196,6 +224,24 @@ TestCase { compare(control.up.pressed, false) compare(control.value, 0) + // Disable the down button and try again. + control.value = control.from + compare(control.down.indicator.enabled, false) + + mousePress(control.down.indicator) + compare(downPressedSpy.count, 2) + compare(control.down.pressed, false) + compare(upPressedSpy.count, 2) + compare(control.up.pressed, false) + compare(control.value, control.from) + + mouseRelease(control.down.indicator) + compare(downPressedSpy.count, 2) + compare(control.down.pressed, false) + compare(upPressedSpy.count, 2) + compare(control.up.pressed, false) + compare(control.value, control.from) + control.destroy() } @@ -206,10 +252,10 @@ TestCase { var upPressedCount = 0 var downPressedCount = 0 - upPressedSpy.target = control.up + var upPressedSpy = signalSpy.createObject(control, {target: control.up, signalName: "pressedChanged"}) verify(upPressedSpy.valid) - downPressedSpy.target = control.down + var downPressedSpy = signalSpy.createObject(control, {target: control.down, signalName: "pressedChanged"}) verify(downPressedSpy.valid) control.forceActiveFocus() @@ -252,32 +298,42 @@ TestCase { compare(control.stepSize, 25) for (var d2 = 1; d2 <= 10; ++d2) { + var wasDownEnabled = control.value > control.from keyPress(Qt.Key_Down) - compare(control.down.pressed, true) + compare(control.down.pressed, wasDownEnabled) compare(control.up.pressed, false) - compare(downPressedSpy.count, ++downPressedCount) + if (wasDownEnabled) + ++downPressedCount + compare(downPressedSpy.count, downPressedCount) compare(control.value, Math.max(0, 50 - d2 * 25)) keyRelease(Qt.Key_Down) compare(control.down.pressed, false) compare(control.up.pressed, false) - compare(downPressedSpy.count, ++downPressedCount) + if (wasDownEnabled) + ++downPressedCount + compare(downPressedSpy.count, downPressedCount) } compare(control.value, 0) for (var i2 = 1; i2 <= 10; ++i2) { + var wasUpEnabled = control.value < control.to keyPress(Qt.Key_Up) - compare(control.up.pressed, true) + compare(control.up.pressed, wasUpEnabled) compare(control.down.pressed, false) - compare(upPressedSpy.count, ++upPressedCount) + if (wasUpEnabled) + ++upPressedCount + compare(upPressedSpy.count, upPressedCount) compare(control.value, Math.min(99, i2 * 25)) keyRelease(Qt.Key_Up) compare(control.down.pressed, false) compare(control.up.pressed, false) - compare(upPressedSpy.count, ++upPressedCount) + if (wasUpEnabled) + ++upPressedCount + compare(upPressedSpy.count, upPressedCount) } compare(control.value, 99) @@ -326,4 +382,175 @@ TestCase { control.destroy() } + + function test_editable() { + var control = spinBox.createObject(testCase) + verify(control) + + control.contentItem.forceActiveFocus() + compare(control.contentItem.activeFocus, true) + + compare(control.editable, false) + control.contentItem.selectAll() + keyClick(Qt.Key_5) + keyClick(Qt.Key_Return) + compare(control.value, 0) + + control.editable = true + compare(control.editable, true) + control.contentItem.selectAll() + keyClick(Qt.Key_5) + keyClick(Qt.Key_Return) + compare(control.value, 5) + + control.destroy() + } + + function test_wheel(data) { + var control = spinBox.createObject(testCase, {wheelEnabled: true}) + verify(control) + + var delta = 120 + + compare(control.value, 0) + + mouseWheel(control, control.width / 2, control.height / 2, delta, delta) + compare(control.value, 1) + + control.stepSize = 2 + + mouseWheel(control, control.width / 2, control.height / 2, delta, delta) + compare(control.value, 3) + + control.stepSize = 10 + + mouseWheel(control, control.width / 2, control.height / 2, -delta, -delta) + compare(control.value, 0) + + control.stepSize = 5 + + mouseWheel(control, control.width / 2, control.height / 2, delta, delta) + compare(control.value, 5) + + mouseWheel(control, control.width / 2, control.height / 2, 0.5 * delta, 0.5 * delta) + compare(control.value, 8) + + mouseWheel(control, control.width / 2, control.height / 2, -delta, -delta) + compare(control.value, 3) + + control.destroy() + } + + function test_initiallyDisabledIndicators_data() { + return [ + { tag: "down disabled", from: 0, value: 0, to: 99, upEnabled: true, downEnabled: false }, + { tag: "up disabled", from: 0, value: 99, to: 99, upEnabled: false, downEnabled: true }, + { tag: "inverted, down disabled", from: 99, value: 99, to: 0, upEnabled: true, downEnabled: false }, + { tag: "inverted, up disabled", from: 99, value: 0, to: 0, upEnabled: false, downEnabled: true } + ] + } + + function test_initiallyDisabledIndicators(data) { + var control = spinBox.createObject(testCase, { from: data.from, value: data.value, to: data.to }) + verify(control) + + compare(control.up.indicator.enabled, data.upEnabled) + compare(control.down.indicator.enabled, data.downEnabled) + + control.destroy() + } + + function test_valueFromText_data() { + return [ + { tag: "editable", editable: true }, + { tag: "non-editable", editable: false } + ] + } + + function test_valueFromText(data) { + var control = spinBox.createObject(testCase, {editable: data.editable}) + verify(control) + + control.forceActiveFocus() + verify(control.activeFocus) + + var valueFromTextCalls = 0 + control.valueFromText = function(text, locale) { + ++valueFromTextCalls + return Number.fromLocaleString(locale, text); + } + + keyClick(Qt.Key_Enter) + compare(valueFromTextCalls, data.editable ? 1 : 0) + + keyClick(Qt.Key_Return) + compare(valueFromTextCalls, data.editable ? 2 : 0) + + control.focus = false + compare(valueFromTextCalls, data.editable ? 3 : 0) + + control.destroy() + } + + function test_autoRepeat() { + var control = spinBox.createObject(testCase) + verify(control) + + compare(control.value, 0) + + var valueSpy = signalSpy.createObject(control, {target: control, signalName: "valueChanged"}) + verify(valueSpy.valid) + + var countBefore = 0 + + // repeat up + mousePress(control.up.indicator) + verify(control.up.pressed) + compare(valueSpy.count, 0) + valueSpy.wait() + valueSpy.wait() + countBefore = valueSpy.count + mouseRelease(control.up.indicator) + verify(!control.up.pressed) + compare(valueSpy.count, countBefore) + + valueSpy.clear() + + // repeat down + mousePress(control.down.indicator) + verify(control.down.pressed) + compare(valueSpy.count, 0) + valueSpy.wait() + valueSpy.wait() + countBefore = valueSpy.count + mouseRelease(control.down.indicator) + verify(!control.down.pressed) + compare(valueSpy.count, countBefore) + + mousePress(control.up.indicator) + verify(control.up.pressed) + valueSpy.wait() + + // move inside during repeat -> continue repeat (QTBUG-57085) + mouseMove(control.up.indicator, control.up.indicator.width / 4, control.up.indicator.height / 4) + verify(control.up.pressed) + valueSpy.wait() + + valueSpy.clear() + + // move outside during repeat -> stop repeat + mouseMove(control.up.indicator, -1, -1) + verify(!control.up.pressed) + // NOTE: The following wait() is NOT a reliable way to test that the + // auto-repeat timer is not running, but there's no way dig into the + // private APIs from QML. If this test ever fails in the future, it + // indicates that the auto-repeat timer logic is broken. + wait(125) + compare(valueSpy.count, 0) + + mouseRelease(control.up.indicator, -1, -1) + verify(!control.up.pressed) + + control.destroy() + } } diff --git a/tests/auto/controls/data/tst_stackview.qml b/tests/auto/controls/data/tst_stackview.qml index 762be4cc..28a22306 100644 --- a/tests/auto/controls/data/tst_stackview.qml +++ b/tests/auto/controls/data/tst_stackview.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase @@ -59,6 +59,11 @@ TestCase { StackView { } } + Component { + id: signalSpy + SignalSpy { } + } + function test_initialItem() { var control1 = stackView.createObject(testCase) verify(control1) @@ -87,18 +92,13 @@ TestCase { control.destroy() } - SignalSpy { - id: busySpy - signalName: "busyChanged" - } - function test_busy() { var control = stackView.createObject(testCase) verify(control) compare(control.busy, false) var busyCount = 0 - busySpy.target = control + var busySpy = signalSpy.createObject(control, {target: control, signalName: "busyChanged"}) verify(busySpy.valid) control.push(component) @@ -243,10 +243,31 @@ TestCase { verify(container) var control = stackView.createObject(container, {width: 100, height: 100}) verify(control) + container.width += 10 container.height += 20 compare(control.width, 100) compare(control.height, 100) + + control.push(item, StackView.Immediate) + compare(item.width, control.width) + compare(item.height, control.height) + + control.width = 200 + control.height = 200 + compare(item.width, control.width) + compare(item.height, control.height) + + control.clear() + control.width += 10 + control.height += 20 + verify(item.width !== control.width) + verify(item.height !== control.height) + + control.push(item, StackView.Immediate) + compare(item.width, control.width) + compare(item.height, control.height) + container.destroy() } @@ -385,6 +406,11 @@ TestCase { compare(control.depth, 6) compare(control.currentItem, items[5]) + // pop down to the current item + compare(control.pop(control.currentItem, StackView.Immediate), null) + compare(control.depth, 6) + compare(control.currentItem, items[5]) + // pop down to (but not including) the Nth item compare(control.pop(items[3], StackView.Immediate), items[5]) compare(control.depth, 4) @@ -835,4 +861,22 @@ TestCase { control.destroy() } + + // QTBUG-56158 + function test_repeatedPop() { + var control = stackView.createObject(testCase, {initialItem: component, width: testCase.width, height: testCase.height}) + verify(control) + + for (var i = 0; i < 12; ++i) + control.push(component) + tryCompare(control, "busy", false) + + while (control.depth > 1) { + control.pop() + wait(50) + } + tryCompare(control, "busy", false) + + control.destroy() + } } diff --git a/tests/auto/controls/data/tst_swipedelegate.qml b/tests/auto/controls/data/tst_swipedelegate.qml new file mode 100644 index 00000000..0404fd86 --- /dev/null +++ b/tests/auto/controls/data/tst_swipedelegate.qml @@ -0,0 +1,1076 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtTest 1.0 +import QtQuick.Controls 2.0 + +TestCase { + id: testCase + width: 200 + height: 200 + visible: true + when: windowShown + name: "SwipeDelegate" + + readonly property int dragDistance: Math.max(20, Qt.styleHints.startDragDistance + 5) + + Component { + id: backgroundFillComponent + SwipeDelegate { + background: Item { anchors.fill: parent } + } + } + + Component { + id: backgroundCenterInComponent + SwipeDelegate { + background: Item { anchors.centerIn: parent } + } + } + + Component { + id: backgroundLeftComponent + SwipeDelegate { + background: Item { anchors.left: parent.left } + } + } + + Component { + id: backgroundRightComponent + SwipeDelegate { + background: Item { anchors.right: parent.right } + } + } + + Component { + id: contentItemFillComponent + SwipeDelegate { + contentItem: Item { anchors.fill: parent } + } + } + + Component { + id: contentItemCenterInComponent + SwipeDelegate { + contentItem: Item { anchors.centerIn: parent } + } + } + + Component { + id: contentItemLeftComponent + SwipeDelegate { + contentItem: Item { anchors.left: parent.left } + } + } + + Component { + id: contentItemRightComponent + SwipeDelegate { + contentItem: Item { anchors.right: parent.right } + } + } + + function test_horizontalAnchors_data() { + return [ + { tag: "background, fill", component: backgroundFillComponent, itemName: "background", warningLocation: ":58:25" }, + { tag: "background, centerIn", component: backgroundCenterInComponent, itemName: "background", warningLocation: ":65:25" }, + { tag: "background, left", component: backgroundLeftComponent, itemName: "background", warningLocation: ":72:25" }, + { tag: "background, right", component: backgroundRightComponent, itemName: "background", warningLocation: ":79:25" }, + { tag: "contentItem, fill", component: contentItemFillComponent, itemName: "contentItem", warningLocation: ":86:26" }, + { tag: "contentItem, centerIn", component: contentItemCenterInComponent, itemName: "contentItem", warningLocation: ":93:26" }, + { tag: "contentItem, left", component: contentItemLeftComponent, itemName: "contentItem", warningLocation: ":100:26" }, + { tag: "contentItem, right", component: contentItemRightComponent, itemName: "contentItem", warningLocation: ":107:26" } + ]; + } + + function test_horizontalAnchors(data) { + var warningMessage = Qt.resolvedUrl("tst_swipedelegate.qml") + data.warningLocation + + ": QML : SwipeDelegate: cannot use horizontal anchors with " + data.itemName + "; unable to layout the item." + + ignoreWarning(warningMessage); + + var control = data.component.createObject(testCase); + verify(control.contentItem); + + control.destroy(); + } + + Component { + id: greenLeftComponent + + Rectangle { + objectName: "leftItem" + anchors.fill: parent + color: "green" + } + } + + Component { + id: redRightComponent + + Rectangle { + objectName: "rightItem" + anchors.fill: parent + color: "red" + } + } + + Component { + id: swipeDelegateComponent + + SwipeDelegate { + id: swipeDelegate + text: "SwipeDelegate" + width: 150 + swipe.left: greenLeftComponent + swipe.right: redRightComponent + } + } + + Component { + id: itemComponent + + Item {} + } + + // Assumes that the delegate is smaller than the width of the control. + function swipe(control, from, to) { + // Sanity check. + compare(control.swipe.position, from); + + var distance = (to - from) * control.width; + + mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton); + mouseMove(control, control.width / 2 + distance, control.height / 2, Qt.LeftButton); + mouseRelease(control, control.width / 2 + distance, control.height / 2, Qt.LeftButton); + compare(control.swipe.position, to); + + if (control.swipe.position === -1.0) { + if (control.swipe.right) + verify(control.swipe.rightItem); + else if (control.swipe.behind) + verify(control.swipe.behindItem); + } else if (control.swipe.position === 1.0) { + if (control.swipe.left) + verify(control.swipe.leftItem); + else if (control.swipe.behind) + verify(control.swipe.behindItem); + } + } + + function test_settingDelegates() { + var control = swipeDelegateComponent.createObject(testCase); + verify(control); + + ignoreWarning(Qt.resolvedUrl("tst_swipedelegate.qml") + + ":159:9: QML SwipeDelegate: cannot set both behind and left/right properties") + control.swipe.behind = itemComponent; + + // Shouldn't be any warnings when unsetting delegates. + control.swipe.left = null; + compare(control.swipe.leftItem, null); + + // right is still set. + ignoreWarning(Qt.resolvedUrl("tst_swipedelegate.qml") + + ":159:9: QML SwipeDelegate: cannot set both behind and left/right properties") + control.swipe.behind = itemComponent; + + control.swipe.right = null; + compare(control.swipe.rightItem, null); + + control.swipe.behind = itemComponent; + + ignoreWarning(Qt.resolvedUrl("tst_swipedelegate.qml") + + ":159:9: QML SwipeDelegate: cannot set both behind and left/right properties") + control.swipe.left = itemComponent; + + ignoreWarning(Qt.resolvedUrl("tst_swipedelegate.qml") + + ":159:9: QML SwipeDelegate: cannot set both behind and left/right properties") + control.swipe.right = itemComponent; + + control.swipe.behind = null; + control.swipe.left = greenLeftComponent; + control.swipe.right = redRightComponent; + + // Test that the user is warned when attempting to set or unset left or + // right item while they're exposed. + // First, try the left item. + swipe(control, 0.0, 1.0); + + var oldLeft = control.swipe.left; + var oldLeftItem = control.swipe.leftItem; + ignoreWarning(Qt.resolvedUrl("tst_swipedelegate.qml") + + ":159:9: QML SwipeDelegate: left/right/behind properties may only be set when swipe.position is 0") + control.swipe.left = null; + compare(control.swipe.left, oldLeft); + compare(control.swipe.leftItem, oldLeftItem); + + // Try the same thing with the right item. + swipe(control, 1.0, -1.0); + + var oldRight = control.swipe.right; + var oldRightItem = control.swipe.rightItem; + ignoreWarning(Qt.resolvedUrl("tst_swipedelegate.qml") + + ":159:9: QML SwipeDelegate: left/right/behind properties may only be set when swipe.position is 0") + control.swipe.right = null; + compare(control.swipe.right, oldRight); + compare(control.swipe.rightItem, oldRightItem); + + // Return to the default position. + swipe(control, -1.0, 0.0); + + tryCompare(control.background, "x", 0, 1000); + + // Try the same thing with the behind item. + control.swipe.left = null; + verify(!control.swipe.left); + verify(!control.swipe.leftItem); + control.swipe.right = null; + verify(!control.swipe.right); + verify(!control.swipe.rightItem); + control.swipe.behind = greenLeftComponent; + verify(control.swipe.behind); + verify(!control.swipe.behindItem); + + swipe(control, 0.0, 1.0); + + var oldBehind = control.swipe.behind; + var oldBehindItem = control.swipe.behindItem; + ignoreWarning(Qt.resolvedUrl("tst_swipedelegate.qml") + + ":159:9: QML SwipeDelegate: left/right/behind properties may only be set when swipe.position is 0") + control.swipe.behind = null; + compare(control.swipe.behind, oldBehind); + compare(control.swipe.behindItem, oldBehindItem); + + control.destroy(); + } + + function test_defaults() { + var control = swipeDelegateComponent.createObject(testCase); + verify(control); + + compare(control.baselineOffset, control.contentItem.y + control.contentItem.baselineOffset); + compare(control.swipe.position, 0); + verify(!control.pressed); + verify(!control.swipe.complete); + + control.destroy(); + } + + SignalSequenceSpy { + id: mouseSignalSequenceSpy + signals: ["pressed", "released", "canceled", "clicked", "doubleClicked", "pressedChanged"] + } + + function test_swipe() { + var control = swipeDelegateComponent.createObject(testCase); + verify(control); + + var overDragDistance = Math.round(dragDistance * 1.1); + + mouseSignalSequenceSpy.target = control; + mouseSignalSequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true }], "pressed"]; + mousePress(control, control.width / 2, control.height / 2); + verify(control.pressed); + compare(control.swipe.position, 0.0); + verify(!control.swipe.complete); + verify(mouseSignalSequenceSpy.success); + verify(!control.swipe.leftItem); + verify(!control.swipe.rightItem); + + // Drag to the right so that leftItem is created and visible. + mouseMove(control, control.width / 2 + overDragDistance, control.height / 2); + verify(control.pressed); + compare(control.swipe.position, overDragDistance / control.width); + verify(!control.swipe.complete); + verify(control.swipe.leftItem); + verify(control.swipe.leftItem.visible); + compare(control.swipe.leftItem.parent, control); + compare(control.swipe.leftItem.objectName, "leftItem"); + verify(!control.swipe.rightItem); + + // Go back to 0. + mouseMove(control, control.width / 2, control.height / 2); + verify(control.pressed); + compare(control.swipe.position, 0.0); + verify(!control.swipe.complete); + verify(control.swipe.leftItem); + verify(control.swipe.leftItem.visible); + compare(control.swipe.leftItem.parent, control); + compare(control.swipe.leftItem.objectName, "leftItem"); + verify(!control.swipe.rightItem); + + // Try the other direction. The right item should be created and visible, + // and the left item should be hidden. + mouseMove(control, control.width / 2 - overDragDistance, control.height / 2); + verify(control.pressed); + compare(control.swipe.position, -overDragDistance / control.width); + verify(!control.swipe.complete); + verify(control.swipe.leftItem); + verify(!control.swipe.leftItem.visible); + verify(control.swipe.rightItem); + verify(control.swipe.rightItem.visible); + compare(control.swipe.rightItem.parent, control); + compare(control.swipe.rightItem.objectName, "rightItem"); + + // Now release outside the right edge of the control. + mouseMove(control, control.width * 1.1, control.height / 2); + verify(control.pressed); + compare(control.swipe.position, 0.6); + verify(!control.swipe.complete); + verify(control.swipe.leftItem); + verify(control.swipe.leftItem.visible); + verify(control.swipe.rightItem); + verify(!control.swipe.rightItem.visible); + + mouseSignalSequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false }], "canceled"]; + mouseRelease(control, control.width / 2, control.height / 2); + verify(!control.pressed); + compare(control.swipe.position, 1.0); + verify(control.swipe.complete); + verify(mouseSignalSequenceSpy.success); + verify(control.swipe.leftItem); + verify(control.swipe.leftItem.visible); + verify(control.swipe.rightItem); + verify(!control.swipe.rightItem.visible); + tryCompare(control.contentItem, "x", control.width + control.leftPadding); + + // Swiping from the right and releasing early should return position to 1.0. + mouseSignalSequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true }], "pressed"]; + mousePress(control, control.width / 2, control.height / 2); + verify(control.pressed); + compare(control.swipe.position, 1.0); + // complete should still be true, because we haven't moved yet, and hence + // haven't started grabbing behind's mouse events. + verify(control.swipe.complete); + verify(mouseSignalSequenceSpy.success); + + mouseMove(control, control.width / 2 - overDragDistance, control.height / 2); + verify(control.pressed); + verify(!control.swipe.complete); + compare(control.swipe.position, 1.0 - overDragDistance / control.width); + + // Since we went over the drag distance, we should expect canceled() to be emitted. + mouseSignalSequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false }], "canceled"]; + mouseRelease(control, control.width * 0.4, control.height / 2); + verify(!control.pressed); + compare(control.swipe.position, 1.0); + verify(control.swipe.complete); + verify(mouseSignalSequenceSpy.success); + tryCompare(control.contentItem, "x", control.width + control.leftPadding); + + // Swiping from the right and releasing should return contents to default position. + mouseSignalSequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true }], "pressed"]; + mousePress(control, control.width / 2, control.height / 2); + verify(control.pressed); + compare(control.swipe.position, 1.0); + verify(control.swipe.complete); + verify(mouseSignalSequenceSpy.success); + + mouseMove(control, control.width * -0.1, control.height / 2); + verify(control.pressed); + verify(!control.swipe.complete); + compare(control.swipe.position, 0.4); + + mouseSignalSequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false }], "canceled"]; + mouseRelease(control, control.width * -0.1, control.height / 2); + verify(!control.pressed); + compare(control.swipe.position, 0.0); + verify(!control.swipe.complete); + verify(mouseSignalSequenceSpy.success); + tryCompare(control.contentItem, "x", control.leftPadding); + + control.destroy(); + } + + function test_swipeVelocity_data() { + return [ + { tag: "positive velocity", direction: 1 }, + { tag: "negative velocity", direction: -1 } + ]; + } + + function test_swipeVelocity(data) { + skip("QTBUG-52003"); + + var control = swipeDelegateComponent.createObject(testCase); + verify(control); + + var distance = Math.round(dragDistance * 1.1); + if (distance >= control.width / 2) + skip("This test requires a startDragDistance that is less than half the width of the control"); + + distance *= data.direction; + + mouseSignalSequenceSpy.target = control; + mouseSignalSequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true }], "pressed"]; + mousePress(control, control.width / 2, control.height / 2); + verify(control.pressed); + compare(control.swipe.position, 0.0); + verify(!control.swipe.complete); + verify(mouseSignalSequenceSpy.success); + verify(!control.swipe.leftItem); + verify(!control.swipe.rightItem); + + // Swipe quickly to the side over a distance that is longer than the drag threshold, + // quicker than the expose velocity threshold, but shorter than the halfway mark. + mouseMove(control, control.width / 2 + distance, control.height / 2); + verify(control.pressed); + compare(control.swipe.position, distance / control.width); + verify(control.swipe.position < 0.5); + verify(!control.swipe.complete); + + var expectedVisibleItem; + var expectedVisibleObjectName; + var expectedHiddenItem; + var expectedContentItemX; + if (distance > 0) { + expectedVisibleObjectName = "leftItem"; + expectedVisibleItem = control.swipe.leftItem; + expectedHiddenItem = control.swipe.rightItem; + expectedContentItemX = control.width + control.leftPadding; + } else { + expectedVisibleObjectName = "rightItem"; + expectedVisibleItem = control.swipe.rightItem; + expectedHiddenItem = control.swipe.leftItem; + expectedContentItemX = -control.width + control.leftPadding; + } + verify(expectedVisibleItem); + verify(expectedVisibleItem.visible); + compare(expectedVisibleItem.parent, control); + compare(expectedVisibleItem.objectName, expectedVisibleObjectName); + verify(!expectedHiddenItem); + + mouseSignalSequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false }], "released", "clicked"]; + // Add a delay to ensure that the release event doesn't happen too quickly, + // and hence that the second timestamp isn't zero (can happen with e.g. release builds). + mouseRelease(control, control.width / 2 + distance, control.height / 2, Qt.LeftButton, Qt.NoModifier, 30); + verify(!control.pressed); + compare(control.swipe.position, data.direction); + verify(control.swipe.complete); + verify(mouseSignalSequenceSpy.success); + verify(expectedVisibleItem); + verify(expectedVisibleItem.visible); + verify(!expectedHiddenItem); + tryCompare(control.contentItem, "x", expectedContentItemX); + + control.destroy(); + } + + Component { + id: swipeDelegateWithButtonComponent + SwipeDelegate { + text: "SwipeDelegate" + width: 150 + swipe.right: Button { + width: parent.width + height: parent.height + text: "Boo!" + } + } + } + + Component { + id: signalSpyComponent + + SignalSpy {} + } + + function test_eventsToLeftAndRight() { + var control = swipeDelegateWithButtonComponent.createObject(testCase); + verify(control); + + // The button should be pressed instead of the SwipeDelegate. + mouseDrag(control, control.width / 2, control.height / 2, -control.width, 0); + // Mouse has been released by this stage. + verify(!control.pressed); + compare(control.swipe.position, -1.0); + verify(control.swipe.rightItem); + verify(control.swipe.rightItem.visible); + compare(control.swipe.rightItem.parent, control); + + var buttonPressedSpy = signalSpyComponent.createObject(control, { target: control.swipe.rightItem, signalName: "pressed" }); + verify(buttonPressedSpy); + verify(buttonPressedSpy.valid); + var buttonReleasedSpy = signalSpyComponent.createObject(control, { target: control.swipe.rightItem, signalName: "released" }); + verify(buttonReleasedSpy); + verify(buttonReleasedSpy.valid); + var buttonClickedSpy = signalSpyComponent.createObject(control, { target: control.swipe.rightItem, signalName: "clicked" }); + verify(buttonClickedSpy); + verify(buttonClickedSpy.valid); + + // Now press the button. + mousePress(control, control.width / 2, control.height / 2); + verify(!control.pressed); + var button = control.swipe.rightItem; + verify(button.pressed); + compare(buttonPressedSpy.count, 1); + compare(buttonReleasedSpy.count, 0); + compare(buttonClickedSpy.count, 0); + + mouseRelease(control, control.width / 2, control.height / 2); + verify(!button.pressed); + compare(buttonPressedSpy.count, 1); + compare(buttonReleasedSpy.count, 1); + compare(buttonClickedSpy.count, 1); + + // Returning back to a position of 0 and pressing on the control should + // result in the control being pressed. + mouseDrag(control, control.width / 2, control.height / 2, control.width * 0.6, 0); + compare(control.swipe.position, 0); + mousePress(control, control.width / 2, control.height / 2); + verify(control.pressed); + verify(!button.pressed); + mouseRelease(control, control.width / 2, control.height / 2); + verify(!control.pressed); + + control.destroy(); + } + + function test_mouseButtons() { + var control = swipeDelegateComponent.createObject(testCase); + verify(control); + + // click + mouseSignalSequenceSpy.target = control; + mouseSignalSequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true }], "pressed"]; + mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton); + compare(control.pressed, true); + + verify(mouseSignalSequenceSpy.success); + + mouseSignalSequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false }], "released", "clicked"]; + mouseRelease(control, control.width / 2, control.height / 2, Qt.LeftButton); + compare(control.pressed, false); + verify(mouseSignalSequenceSpy.success); + + // right button + mouseSignalSequenceSpy.expectedSequence = []; + mousePress(control, control.width / 2, control.height / 2, Qt.RightButton); + compare(control.pressed, false); + + mouseRelease(control, control.width / 2, control.height / 2, Qt.RightButton); + compare(control.pressed, false); + verify(mouseSignalSequenceSpy.success); + + // double click + mouseSignalSequenceSpy.expectedSequence = [ + ["pressedChanged", { "pressed": true }], + "pressed", + ["pressedChanged", { "pressed": false }], + "released", + "clicked", + ["pressedChanged", { "pressed": true }], + "pressed", + "doubleClicked", + ["pressedChanged", { "pressed": false }], + "released", + "clicked" + ]; + mouseDoubleClickSequence(control, control.width / 2, control.height / 2, Qt.LeftButton); + verify(mouseSignalSequenceSpy.success); + + control.destroy(); + } + + Component { + id: removableDelegatesComponent + + ListView { + id: listView + width: 100 + height: 120 + + model: ListModel { + ListElement { name: "Apple" } + ListElement { name: "Orange" } + ListElement { name: "Pear" } + } + + delegate: SwipeDelegate { + id: rootDelegate + text: modelData + width: listView.width + + onClicked: if (swipe.complete) ListView.view.model.remove(index) + + property alias removeAnimation: onRemoveAnimation + + ListView.onRemove: SequentialAnimation { + id: onRemoveAnimation + + PropertyAction { + target: rootDelegate + property: "ListView.delayRemove" + value: true + } + NumberAnimation { + target: rootDelegate + property: "height" + to: 0 + easing.type: Easing.InOutQuad + } + PropertyAction { + target: rootDelegate; + property: "ListView.delayRemove"; + value: false + } + } + + swipe.left: Rectangle { + color: rootDelegate.swipe.complete && rootDelegate.pressed ? "#333" : "#444" + anchors.fill: parent + + Label { + objectName: "label" + text: "Remove" + color: "white" + anchors.centerIn: parent + } + } + } + } + } + + function test_removableDelegates() { + var listView = removableDelegatesComponent.createObject(testCase); + verify(listView); + compare(listView.count, 3); + + // Expose the remove button. + var firstItem = listView.itemAt(0, 0); + mousePress(listView, firstItem.width / 2, firstItem.height / 2); + verify(firstItem.pressed); + compare(firstItem.swipe.position, 0.0); + verify(!firstItem.swipe.complete); + + mouseMove(listView, firstItem.width * 1.1, firstItem.height / 2); + verify(firstItem.pressed); + compare(firstItem.swipe.position, 0.6); + verify(!firstItem.swipe.complete); + + mouseRelease(listView, firstItem.width / 2, firstItem.height / 2); + verify(!firstItem.pressed); + compare(firstItem.swipe.position, 1.0); + verify(firstItem.swipe.complete); + compare(listView.count, 3); + + // Wait for it to settle down. + tryCompare(firstItem.contentItem, "x", firstItem.leftPadding + firstItem.width); + + // Click the button to remove the item. + var contentItemX = firstItem.contentItem.x; + mouseClick(listView, firstItem.width / 2, firstItem.height / 2); + tryCompare(firstItem.removeAnimation, "running", true); + // There was a bug where the resizeContent() would be called because the height + // of the control was changing due to the animation. contentItem would then + // change x position and hence be visible when it shouldn't be. + verify(firstItem.removeAnimation.running); + while (1) { + wait(10) + if (firstItem && firstItem.removeAnimation && firstItem.removeAnimation.running) + compare(firstItem.contentItem.x, contentItemX); + else + break; + } + compare(listView.count, 2); + + listView.destroy(); + } + + Component { + id: leadingTrailingXComponent + SwipeDelegate { + id: delegate + width: 150 + text: "SwipeDelegate" + + swipe.left: Rectangle { + x: delegate.background.x - width + width: delegate.width + height: delegate.height + color: "green" + } + + swipe.right: Rectangle { + x: delegate.background.x + delegate.background.width + width: delegate.width + height: delegate.height + color: "red" + } + } + } + + Component { + id: leadingTrailingAnchorsComponent + SwipeDelegate { + id: delegate + width: 150 + text: "SwipeDelegate" + + swipe.left: Rectangle { + anchors.right: delegate.background.left + width: delegate.width + height: delegate.height + color: "green" + } + + swipe.right: Rectangle { + anchors.left: delegate.background.right + width: delegate.width + height: delegate.height + color: "red" + } + } + } + + function test_leadingTrailing_data() { + return [ + { tag: "x", component: leadingTrailingXComponent }, + { tag: "anchors", component: leadingTrailingAnchorsComponent }, + ]; + } + + function test_leadingTrailing(data) { + var control = data.component.createObject(testCase); + verify(control); + + mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton); + mouseMove(control, control.width, control.height / 2, Qt.LeftButton); + verify(control.swipe.leftItem); + compare(control.swipe.leftItem.x, -control.width / 2); + mouseRelease(control, control.width / 2, control.height / 2, Qt.LeftButton); + + control.destroy(); + } + + function test_minMaxPosition() { + var control = leadingTrailingXComponent.createObject(testCase); + verify(control); + + // Should be limited within the range -1.0 to 1.0. + mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton); + mouseMove(control, control.width * 1.5, control.height / 2, Qt.LeftButton); + compare(control.swipe.position, 1.0); + mouseMove(control, control.width * 1.6, control.height / 2, Qt.LeftButton); + compare(control.swipe.position, 1.0); + mouseMove(control, control.width * -1.6, control.height / 2, Qt.LeftButton); + compare(control.swipe.position, -1.0); + mouseRelease(control, control.width / 2, control.height / 2, Qt.LeftButton); + + control.destroy(); + } + + Component { + id: emptySwipeDelegateComponent + + SwipeDelegate { + text: "SwipeDelegate" + width: 150 + } + } + + Component { + id: smallLeftComponent + + Rectangle { + width: 80 + height: 40 + color: "green" + } + } + + // swipe.position should be scaled to the width of the relevant delegate, + // and it shouldn't be possible to drag past the delegate (so that content behind the control is visible). + function test_delegateWidth() { + var control = emptySwipeDelegateComponent.createObject(testCase); + verify(control); + + control.swipe.left = smallLeftComponent; + + // Ensure that the position is scaled to the width of the currently visible delegate. + var overDragDistance = Math.round(dragDistance * 1.1); + mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton); + mouseMove(control, control.width / 2 + overDragDistance, control.height / 2, Qt.LeftButton); + verify(control.swipe.leftItem); + compare(control.swipe.position, overDragDistance / control.swipe.leftItem.width); + + mouseMove(control, control.width / 2 + control.swipe.leftItem.width, control.height / 2, Qt.LeftButton); + compare(control.swipe.position, 1.0); + + // Ensure that it's not possible to drag past the (left) delegate. + mouseMove(control, control.width / 2 + control.swipe.leftItem.width + 1, control.height / 2, Qt.LeftButton); + compare(control.swipe.position, 1.0); + + // Now release over the right side; the position should be 1.0 and the background + // should be "anchored" to the right side of the left delegate item. + mouseMove(control, control.width / 2 + control.swipe.leftItem.width, control.height / 2, Qt.LeftButton); + mouseRelease(control, control.width / 2 + control.swipe.leftItem.width, control.height / 2, Qt.LeftButton); + compare(control.swipe.position, 1.0); + tryCompare(control.background, "x", control.swipe.leftItem.width, 1000); + + control.destroy(); + } + + SignalSpy { + id: leftVisibleSpy + signalName: "visibleChanged" + } + + SignalSpy { + id: rightVisibleSpy + signalName: "visibleChanged" + } + + function test_positionAfterSwipeCompleted() { + var control = swipeDelegateComponent.createObject(testCase); + verify(control); + + // Ensure that both delegates are constructed. + mousePress(control, 0, control.height / 2, Qt.LeftButton); + mouseMove(control, control.width * 1.1, control.height / 2, Qt.LeftButton); + verify(control.swipe.leftItem); + mouseMove(control, control.width * -0.1, control.height / 2, Qt.LeftButton); + verify(control.swipe.rightItem); + + // Expose the left delegate. + mouseMove(control, control.swipe.leftItem.width, control.height / 2, Qt.LeftButton); + mouseRelease(control, control.swipe.leftItem.width, control.height / 2); + verify(control.swipe.complete); + compare(control.swipe.position, 1.0); + + leftVisibleSpy.target = control.swipe.leftItem; + rightVisibleSpy.target = control.swipe.rightItem; + + // Swipe from right to left without exposing the right item, + // and make sure that the right item never becomes visible + // (and hence that the left item never loses visibility). + mousePress(control, control.swipe.leftItem.width, control.height / 2, Qt.LeftButton); + compare(leftVisibleSpy.count, 0); + compare(rightVisibleSpy.count, 0); + var newX = control.swipe.leftItem.width - Math.round(dragDistance * 1.1); + mouseMove(control, newX, control.height / 2, Qt.LeftButton, Qt.LeftButton); + compare(leftVisibleSpy.count, 0); + compare(rightVisibleSpy.count, 0); + compare(control.swipe.position, newX / control.swipe.leftItem.width); + + mouseMove(control, 0, control.height / 2, Qt.LeftButton); + compare(control.swipe.position, 0); + + // Test swiping over a distance that is greater than the width of the left item. + mouseMove(control, -1, control.height / 2, Qt.LeftButton); + verify(control.swipe.rightItem); + compare(control.swipe.position, -1 / control.swipe.rightItem.width); + + // Now go back to 1.0. + mouseMove(control, control.swipe.leftItem.width, control.height / 2, Qt.LeftButton); + compare(control.swipe.position, 1.0); + tryCompare(control.background, "x", control.swipe.leftItem.width, 1000); + mouseRelease(control, control.swipe.leftItem.width, control.height / 2, Qt.LeftButton); + + control.destroy(); + } + + // TODO: this somehow results in the behind item having a negative width +// Component { +// id: behindSwipeDelegateComponent +// SwipeDelegate { +// anchors.centerIn: parent +// swipe.behind: Rectangle { +// onXChanged: print("x changed", x) +// anchors.left: { +// print("anchors.left expression", swipe.position) +// swipe.position < 0 ? parent.background.right : undefined +// } +// anchors.right: { +// print("anchors.right expression", swipe.position) +// swipe.position > 0 ? parent.background.left : undefined +// } +// width: parent.width +// height: parent.height +// color: "green" +// } +// swipe.left: null +// swipe.right: null +// Rectangle { +// anchors.fill: parent +// color: "transparent" +// border.color: "darkorange" +// } +// } +// } + + Component { + id: behindSwipeDelegateComponent + SwipeDelegate { + text: "SwipeDelegate" + width: 150 + anchors.centerIn: parent + swipe.behind: Rectangle { + x: swipe.position < 0 ? parent.background.x + parent.background.width + : (swipe.position > 0 ? parent.background.x - width : 0) + width: parent.width + height: parent.height + color: "green" + } + swipe.left: null + swipe.right: null + } + } + + function test_leadingTrailingBehindItem() { + var control = behindSwipeDelegateComponent.createObject(testCase); + verify(control); + + swipe(control, 0.0, 1.0); + verify(control.swipe.behindItem.visible); + compare(control.swipe.behindItem.x, control.background.x - control.background.width); + + swipe(control, 1.0, -1.0); + verify(control.swipe.behindItem.visible); + compare(control.swipe.behindItem.x, control.background.x + control.background.width); + + swipe(control, -1.0, 1.0); + verify(control.swipe.behindItem.visible); + compare(control.swipe.behindItem.x, control.background.x - control.background.width); + + // Should be possible to "wrap" with a behind delegate specified. + mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton); + mouseMove(control, control.width / 2 + control.swipe.behindItem.width * 0.8, control.height / 2, Qt.LeftButton); + compare(control.swipe.position, -0.2); + mouseRelease(control, control.width / 2 + control.swipe.behindItem.width * 0.8, control.height / 2, Qt.LeftButton); + compare(control.swipe.position, 0.0); + + // Try wrapping the other way. + swipe(control, 0.0, -1.0); + verify(control.swipe.behindItem.visible); + compare(control.swipe.behindItem.x, control.background.x + control.background.width); + + mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton); + mouseMove(control, control.width / 2 - control.swipe.behindItem.width * 0.8, control.height / 2, Qt.LeftButton); + compare(control.swipe.position, 0.2); + mouseRelease(control, control.width / 2 - control.swipe.behindItem.width * 0.8, control.height / 2, Qt.LeftButton); + compare(control.swipe.position, 0.0); + + control.destroy(); + } + + // When the width of a SwipeDelegate changes (as it does upon portrait => landscape + // rotation, for example), the positions of the contentItem and background items + // should be updated accordingly. + function test_contentItemPosOnWidthChanged() { + var control = swipeDelegateComponent.createObject(testCase); + verify(control); + + swipe(control, 0.0, 1.0); + + var oldContentItemX = control.contentItem.x; + var oldBackgroundX = control.background.x; + control.width += 100; + compare(control.contentItem.x, oldContentItemX + 100); + compare(control.background.x, oldBackgroundX + 100); + + control.destroy(); + } + + function test_contentItemHeightOnHeightChanged() { + var control = swipeDelegateComponent.createObject(testCase); + verify(control); + + // Try when swipe.complete is false. + var originalHeight = control.height; + var originalContentItemHeight = control.contentItem.height; + verify(control.height !== 10); + control.height = 10; + compare(control.contentItem.height, control.availableHeight); + verify(control.contentItem.height < originalContentItemHeight); + compare(control.contentItem.y, control.topPadding); + + // Try when swipe.complete is true. + control.height = originalHeight; + swipe(control, 0.0, 1.0); + control.height = 10; + compare(control.contentItem.height, control.availableHeight); + verify(control.contentItem.height < originalContentItemHeight); + compare(control.contentItem.y, control.topPadding); + + control.destroy(); + } + + function test_releaseOutside_data() { + return [ + { tag: "no delegates", component: emptySwipeDelegateComponent }, + { tag: "delegates", component: swipeDelegateComponent }, + ]; + } + + function test_releaseOutside(data) { + var control = data.component.createObject(testCase); + verify(control); + + // Press and then release below the control. + mouseSignalSequenceSpy.target = control; + mouseSignalSequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true }], "pressed", ["pressedChanged", { "pressed": false }]]; + mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton); + mouseMove(control, control.width / 2, control.height + 10, Qt.LeftButton); + verify(mouseSignalSequenceSpy.success); + + mouseSignalSequenceSpy.expectedSequence = ["canceled"]; + mouseRelease(control, control.width / 2, control.height + 10, Qt.LeftButton); + verify(mouseSignalSequenceSpy.success); + + // Press and then release to the right of the control. + var hasDelegates = control.swipe.left || control.swipe.right || control.swipe.behind; + mouseSignalSequenceSpy.target = control; + mouseSignalSequenceSpy.expectedSequence = hasDelegates + ? [["pressedChanged", { "pressed": true }], "pressed"] + : [["pressedChanged", { "pressed": true }], "pressed", ["pressedChanged", { "pressed": false }]]; + mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton); + mouseMove(control, control.width + 10, control.height / 2, Qt.LeftButton); + if (hasDelegates) + verify(control.swipe.position > 0); + verify(mouseSignalSequenceSpy.success); + + mouseSignalSequenceSpy.expectedSequence = hasDelegates ? [["pressedChanged", { "pressed": false }], "canceled"] : ["canceled"]; + mouseRelease(control, control.width + 10, control.height / 2, Qt.LeftButton); + verify(mouseSignalSequenceSpy.success); + } +} diff --git a/tests/auto/controls/data/tst_swipeview.qml b/tests/auto/controls/data/tst_swipeview.qml index a17b9fc0..3afcdf16 100644 --- a/tests/auto/controls/data/tst_swipeview.qml +++ b/tests/auto/controls/data/tst_swipeview.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase @@ -60,20 +60,16 @@ TestCase { Text { } } - SignalSpy { - id: currentItemChangedSpy - signalName: "currentItemChanged" - } - - function cleanup() { - currentItemChangedSpy.clear() - currentItemChangedSpy.target = null + Component { + id: signalSpy + SignalSpy { } } function test_current() { var control = swipeView.createObject(testCase) - currentItemChangedSpy.target = control + var currentItemChangedSpy = signalSpy.createObject(testCase, {target: control, signalName: "currentItemChanged"}) + verify(currentItemChangedSpy.valid) compare(control.count, 0) compare(control.currentIndex, -1) @@ -146,7 +142,8 @@ TestCase { control.currentIndexChanged.connect(verifyCurrentIndexCountDiff) control.countChanged.connect(verifyCurrentIndexCountDiff) - currentItemChangedSpy.target = control; + var currentItemChangedSpy = signalSpy.createObject(testCase, {target: control, signalName: "currentItemChanged"}) + verify(currentItemChangedSpy.valid) compare(control.count, 0) compare(control.currentIndex, -1) diff --git a/tests/auto/controls/data/tst_switch.qml b/tests/auto/controls/data/tst_switch.qml index 13924ed0..93773e0d 100644 --- a/tests/auto/controls/data/tst_switch.qml +++ b/tests/auto/controls/data/tst_switch.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase @@ -50,42 +50,16 @@ TestCase { when: windowShown name: "Switch" - SignalSpy { - id: checkedSpy - signalName: "checkedChanged" - } - - SignalSpy { - id: pressedSpy - signalName: "pressedChanged" - } - - SignalSpy { - id: clickedSpy - signalName: "clicked" - } - Component { id: swtch Switch { } } - function init() { - verify(!checkedSpy.target) - verify(!pressedSpy.target) - verify(!clickedSpy.target) - compare(checkedSpy.count, 0) - compare(pressedSpy.count, 0) - compare(clickedSpy.count, 0) - } - - function cleanup() { - checkedSpy.target = null - pressedSpy.target = null - clickedSpy.target = null - checkedSpy.clear() - pressedSpy.clear() - clickedSpy.clear() + Component { + id: signalSequenceSpy + SignalSequenceSpy { + signals: ["pressed", "released", "canceled", "clicked", "pressedChanged", "checkedChanged"] + } } function test_text() { @@ -105,19 +79,41 @@ TestCase { var control = swtch.createObject(testCase) verify(control) - checkedSpy.target = control - verify(checkedSpy.valid) - compare(control.checked, false) - compare(checkedSpy.count, 0) + var spy = signalSequenceSpy.createObject(control, {target: control}) + spy.expectedSequence = [["checkedChanged", { "checked": true }]] control.checked = true compare(control.checked, true) - compare(checkedSpy.count, 1) + verify(spy.success) + spy.expectedSequence = [["checkedChanged", { "checked": false }]] control.checked = false compare(control.checked, false) - compare(checkedSpy.count, 2) + verify(spy.success) + + control.destroy() + } + + function test_pressed_data() { + return [ + { tag: "indicator", x: 15 }, + { tag: "background", x: 5 } + ] + } + + function test_pressed(data) { + var control = swtch.createObject(testCase, {padding: 10}) + verify(control) + + // stays pressed when dragged outside + compare(control.pressed, false) + mousePress(control, data.x, control.height / 2, Qt.LeftButton) + compare(control.pressed, true) + mouseMove(control, -1, control.height / 2) + compare(control.pressed, true) + mouseRelease(control, -1, control.height / 2, Qt.LeftButton) + compare(control.pressed, false) control.destroy() } @@ -126,71 +122,184 @@ TestCase { var control = swtch.createObject(testCase) verify(control) - checkedSpy.target = control - pressedSpy.target = control - clickedSpy.target = control - verify(checkedSpy.valid) - verify(pressedSpy.valid) - verify(clickedSpy.valid) - // check + var spy = signalSequenceSpy.createObject(control, {target: control}) + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }], + "pressed"] mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton) - compare(pressedSpy.count, 1) compare(control.pressed, true) + verify(spy.success) + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false }], + ["checkedChanged", { "pressed": false, "checked": true }], + "released", + "clicked"] mouseRelease(control, control.width / 2, control.height / 2, Qt.LeftButton) - compare(clickedSpy.count, 1) - compare(checkedSpy.count, 1) - compare(pressedSpy.count, 2) compare(control.checked, true) compare(control.pressed, false) + verify(spy.success) // uncheck + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }], + "pressed"] mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton) - compare(pressedSpy.count, 3) compare(control.pressed, true) + verify(spy.success) + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": true }], + ["checkedChanged", { "pressed": false, "checked": false }], + "released", + "clicked"] mouseRelease(control, control.width / 2, control.height / 2, Qt.LeftButton) - compare(clickedSpy.count, 2) - compare(checkedSpy.count, 2) - compare(pressedSpy.count, 4) compare(control.checked, false) compare(control.pressed, false) + verify(spy.success) // release on the right + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }], + "pressed"] mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton) - compare(pressedSpy.count, 5) compare(control.pressed, true) + verify(spy.success) mouseMove(control, control.width * 2, control.height / 2, 0, Qt.LeftButton) compare(control.pressed, true) + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false }], + ["checkedChanged", { "pressed": false, "checked": true }], + "released", + "clicked"] mouseRelease(control, control.width * 2, control.height / 2, Qt.LeftButton) - compare(clickedSpy.count, 2) - compare(checkedSpy.count, 3) - compare(pressedSpy.count, 6) compare(control.checked, true) compare(control.pressed, false) + verify(spy.success) // release on the left + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }], + "pressed"] mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton) - compare(pressedSpy.count, 7) compare(control.pressed, true) + verify(spy.success) mouseMove(control, -control.width, control.height / 2, 0, Qt.LeftButton) compare(control.pressed, true) + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": true }], + ["checkedChanged", { "pressed": false, "checked": false }], + "released", + "clicked"] mouseRelease(control, -control.width, control.height / 2, Qt.LeftButton) - compare(clickedSpy.count, 2) - compare(checkedSpy.count, 4) - compare(pressedSpy.count, 8) compare(control.checked, false) compare(control.pressed, false) + verify(spy.success) // right button + spy.expectedSequence = [] mousePress(control, control.width / 2, control.height / 2, Qt.RightButton) - compare(pressedSpy.count, 8) compare(control.pressed, false) + verify(spy.success) mouseRelease(control, control.width / 2, control.height / 2, Qt.RightButton) - compare(clickedSpy.count, 2) - compare(checkedSpy.count, 4) - compare(pressedSpy.count, 8) compare(control.checked, false) compare(control.pressed, false) + verify(spy.success) + + control.destroy() + } + + function test_drag() { + var control = swtch.createObject(testCase, {leftPadding: 100, rightPadding: 100}) + verify(control) + + var spy = signalSequenceSpy.createObject(control, {target: control}) + compare(control.position, 0.0) + compare(control.checked, false) + compare(control.pressed, false) + + // press-drag-release inside the indicator + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }], + "pressed"] + mousePress(control.indicator, 0) + compare(control.position, 0.0) + compare(control.checked, false) + compare(control.pressed, true) + verify(spy.success) + + mouseMove(control.indicator, control.width) + compare(control.position, 1.0) + compare(control.checked, false) + compare(control.pressed, true) + + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false }], + ["checkedChanged", { "pressed": false, "checked": true }], + "released", + "clicked"] + mouseRelease(control.indicator, control.indicator.width) + compare(control.position, 1.0) + compare(control.checked, true) + compare(control.pressed, false) + verify(spy.success) + + // press-drag-release outside the indicator + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }], + "pressed"] + mousePress(control, 0) + compare(control.position, 1.0) + compare(control.checked, true) + compare(control.pressed, true) + verify(spy.success) + + mouseMove(control, control.width - control.rightPadding) + compare(control.position, 1.0) + compare(control.checked, true) + compare(control.pressed, true) + + mouseMove(control, control.width / 2) + compare(control.position, 0.5) + compare(control.checked, true) + compare(control.pressed, true) + + mouseMove(control, control.leftPadding) + compare(control.position, 0.0) + compare(control.checked, true) + compare(control.pressed, true) + + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": true }], + ["checkedChanged", { "pressed": false, "checked": false }], + "released", + "clicked"] + mouseRelease(control, control.width) + compare(control.position, 0.0) + compare(control.checked, false) + compare(control.pressed, false) + verify(spy.success) + + // press-drag-release from and to outside the indicator + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }], + "pressed"] + mousePress(control, control.width) + compare(control.position, 0.0) + compare(control.checked, false) + compare(control.pressed, true) + verify(spy.success) + + mouseMove(control, control.width - control.rightPadding) + compare(control.position, 0.0) + compare(control.checked, false) + compare(control.pressed, true) + + mouseMove(control, control.width / 2) + compare(control.position, 0.5) + compare(control.checked, false) + compare(control.pressed, true) + + mouseMove(control, control.width - control.rightPadding) + compare(control.position, 1.0) + compare(control.checked, false) + compare(control.pressed, true) + + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false }], + ["checkedChanged", { "pressed": false, "checked": true }], + "released", + "clicked"] + mouseRelease(control, control.width) + compare(control.position, 1.0) + compare(control.checked, true) + compare(control.pressed, false) + verify(spy.success) control.destroy() } @@ -199,33 +308,39 @@ TestCase { var control = swtch.createObject(testCase) verify(control) - checkedSpy.target = control - clickedSpy.target = control - verify(checkedSpy.valid) - verify(clickedSpy.valid) - control.forceActiveFocus() verify(control.activeFocus) // check + var spy = signalSequenceSpy.createObject(control, {target: control}) + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }], + "pressed", + ["pressedChanged", { "pressed": false, "checked": false }], + ["checkedChanged", { "pressed": false, "checked": true }], + "released", + "clicked"] keyClick(Qt.Key_Space) - compare(clickedSpy.count, 1) - compare(checkedSpy.count, 1) compare(control.checked, true) + verify(spy.success) // uncheck + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }], + "pressed", + ["pressedChanged", { "pressed": false, "checked": true }], + ["checkedChanged", { "pressed": false, "checked": false }], + "released", + "clicked"] keyClick(Qt.Key_Space) - compare(clickedSpy.count, 2) - compare(checkedSpy.count, 2) compare(control.checked, false) + verify(spy.success) // no change + spy.expectedSequence = [] var keys = [Qt.Key_Enter, Qt.Key_Return, Qt.Key_Escape, Qt.Key_Tab] for (var i = 0; i < keys.length; ++i) { keyClick(keys[i]) - compare(clickedSpy.count, 2) - compare(checkedSpy.count, 2) compare(control.checked, false) + verify(spy.success) } control.destroy() @@ -260,7 +375,18 @@ TestCase { function test_baseline() { var control = swtch.createObject(testCase) verify(control) - compare(control.baselineOffset, control.label.y + control.label.baselineOffset) + compare(control.baselineOffset, control.contentItem.y + control.contentItem.baselineOffset) + control.destroy() + } + + function test_focus() { + var control = swtch.createObject(testCase) + verify(control) + + verify(!control.activeFocus) + mouseClick(control.indicator) + verify(control.activeFocus) + control.destroy() } } diff --git a/tests/auto/controls/data/tst_switchdelegate.qml b/tests/auto/controls/data/tst_switchdelegate.qml new file mode 100644 index 00000000..8bc0e4c3 --- /dev/null +++ b/tests/auto/controls/data/tst_switchdelegate.qml @@ -0,0 +1,302 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtTest 1.0 +import QtQuick.Controls 2.0 + +TestCase { + id: testCase + width: 200 + height: 200 + visible: true + when: windowShown + name: "SwitchDelegate" + + Component { + id: switchDelegate + SwitchDelegate {} + } + + Component { + id: signalSequenceSpy + SignalSequenceSpy { + signals: ["pressed", "released", "canceled", "clicked", "pressedChanged", "checkedChanged"] + } + } + + // TODO: data-fy tst_checkbox (rename to tst_check?) so we don't duplicate its tests here? + + function test_defaults() { + var control = switchDelegate.createObject(testCase); + verify(control); + verify(!control.checked); + control.destroy(); + } + + function test_checked() { + var control = switchDelegate.createObject(testCase); + verify(control); + + mouseClick(control); + verify(control.checked); + + mouseClick(control); + verify(!control.checked); + + control.destroy(); + } + + function test_baseline() { + var control = switchDelegate.createObject(testCase); + verify(control); + compare(control.baselineOffset, control.contentItem.y + control.contentItem.baselineOffset); + control.destroy(); + } + + function test_pressed_data() { + return [ + { tag: "indicator", x: 15 }, + { tag: "background", x: 5 } + ] + } + + function test_pressed(data) { + var control = switchDelegate.createObject(testCase, {padding: 10}) + verify(control) + + // stays pressed when dragged outside + compare(control.pressed, false) + mousePress(control, data.x, control.height / 2, Qt.LeftButton) + compare(control.pressed, true) + mouseMove(control, -1, control.height / 2) + compare(control.pressed, true) + mouseRelease(control, -1, control.height / 2, Qt.LeftButton) + compare(control.pressed, false) + + control.destroy() + } + + function test_mouse() { + var control = switchDelegate.createObject(testCase) + verify(control) + + // check + var spy = signalSequenceSpy.createObject(control, {target: control}) + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }], + "pressed"] + mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton) + compare(control.pressed, true) + verify(spy.success) + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false }], + ["checkedChanged", { "pressed": false, "checked": true }], + "released", + "clicked"] + mouseRelease(control, control.width / 2, control.height / 2, Qt.LeftButton) + compare(control.checked, true) + compare(control.pressed, false) + verify(spy.success) + + // uncheck + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }], + "pressed"] + mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton) + compare(control.pressed, true) + verify(spy.success) + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": true }], + ["checkedChanged", { "pressed": false, "checked": false }], + "released", + "clicked"] + mouseRelease(control, control.width / 2, control.height / 2, Qt.LeftButton) + compare(control.checked, false) + compare(control.pressed, false) + verify(spy.success) + + // release on the right + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }], + "pressed"] + mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton) + compare(control.pressed, true) + verify(spy.success) + mouseMove(control, control.width * 2, control.height / 2, 0, Qt.LeftButton) + compare(control.pressed, true) + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false }], + ["checkedChanged", { "pressed": false, "checked": true }], + "released", + "clicked"] + mouseRelease(control, control.width * 2, control.height / 2, Qt.LeftButton) + compare(control.checked, true) + compare(control.pressed, false) + verify(spy.success) + + // release on the left + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }], + "pressed"] + mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton) + compare(control.pressed, true) + verify(spy.success) + mouseMove(control, -control.width, control.height / 2, 0, Qt.LeftButton) + compare(control.pressed, true) + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": true }], + ["checkedChanged", { "pressed": false, "checked": false }], + "released", + "clicked"] + mouseRelease(control, -control.width, control.height / 2, Qt.LeftButton) + compare(control.checked, false) + compare(control.pressed, false) + verify(spy.success) + + // right button + spy.expectedSequence = [] + mousePress(control, control.width / 2, control.height / 2, Qt.RightButton) + compare(control.pressed, false) + verify(spy.success) + mouseRelease(control, control.width / 2, control.height / 2, Qt.RightButton) + compare(control.checked, false) + compare(control.pressed, false) + verify(spy.success) + + control.destroy() + } + + function test_drag() { + var control = switchDelegate.createObject(testCase, {leftPadding: 100, rightPadding: 100}) + verify(control) + + var spy = signalSequenceSpy.createObject(control, {target: control}) + compare(control.position, 0.0) + compare(control.checked, false) + compare(control.pressed, false) + + // press-drag-release inside the indicator + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }], + "pressed"] + mousePress(control.indicator, 0) + compare(control.position, 0.0) + compare(control.checked, false) + compare(control.pressed, true) + verify(spy.success) + + mouseMove(control.indicator, control.width) + compare(control.position, 1.0) + compare(control.checked, false) + compare(control.pressed, true) + + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false }], + ["checkedChanged", { "pressed": false, "checked": true }], + "released", + "clicked"] + mouseRelease(control.indicator, control.indicator.width) + compare(control.position, 1.0) + compare(control.checked, true) + compare(control.pressed, false) + verify(spy.success) + + // press-drag-release outside the indicator + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }], + "pressed"] + mousePress(control, 0) + compare(control.position, 1.0) + compare(control.checked, true) + compare(control.pressed, true) + verify(spy.success) + + mouseMove(control, control.width - control.rightPadding) + compare(control.position, 1.0) + compare(control.checked, true) + compare(control.pressed, true) + + mouseMove(control, control.width / 2) + compare(control.position, 0.5) + compare(control.checked, true) + compare(control.pressed, true) + + mouseMove(control, control.leftPadding) + compare(control.position, 0.0) + compare(control.checked, true) + compare(control.pressed, true) + + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": true }], + ["checkedChanged", { "pressed": false, "checked": false }], + "released", + "clicked"] + mouseRelease(control, control.width) + compare(control.position, 0.0) + compare(control.checked, false) + compare(control.pressed, false) + verify(spy.success) + + // press-drag-release from and to outside the indicator + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }], + "pressed"] + mousePress(control, control.width) + compare(control.position, 0.0) + compare(control.checked, false) + compare(control.pressed, true) + verify(spy.success) + + mouseMove(control, control.width - control.rightPadding) + compare(control.position, 0.0) + compare(control.checked, false) + compare(control.pressed, true) + + mouseMove(control, control.width / 2) + compare(control.position, 0.5) + compare(control.checked, false) + compare(control.pressed, true) + + mouseMove(control, control.width - control.rightPadding) + compare(control.position, 1.0) + compare(control.checked, false) + compare(control.pressed, true) + + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false }], + ["checkedChanged", { "pressed": false, "checked": true }], + "released", + "clicked"] + mouseRelease(control, control.width) + compare(control.position, 1.0) + compare(control.checked, true) + compare(control.pressed, false) + verify(spy.success) + + control.destroy() + } +} diff --git a/tests/auto/controls/data/tst_tabbar.qml b/tests/auto/controls/data/tst_tabbar.qml index d40d5c0b..9268f765 100644 --- a/tests/auto/controls/data/tst_tabbar.qml +++ b/tests/auto/controls/data/tst_tabbar.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase @@ -85,19 +85,9 @@ TestCase { } } - SignalSpy { - id: contentChildrenSpy - signalName: "contentChildrenChanged" - } - - function init() { - verify(!contentChildrenSpy.target) - compare(contentChildrenSpy.count, 0) - } - - function cleanup() { - contentChildrenSpy.target = null - contentChildrenSpy.clear() + Component { + id: signalSpy + SignalSpy { } } function test_defaults() { @@ -176,7 +166,7 @@ TestCase { control.currentIndexChanged.connect(verifyCurrentIndexCountDiff) control.countChanged.connect(verifyCurrentIndexCountDiff) - contentChildrenSpy.target = control + var contentChildrenSpy = signalSpy.createObject(testCase, {target: control, signalName: "contentChildrenChanged"}) verify(contentChildrenSpy.valid) compare(control.count, 0) @@ -293,7 +283,7 @@ TestCase { return true } - contentChildrenSpy.target = control + var contentChildrenSpy = signalSpy.createObject(testCase, {target: control, signalName: "contentChildrenChanged"}) verify(contentChildrenSpy.valid) verify(compareObjectNames(control.contentData, ["object", "button1", "timer", "button2", ""])) @@ -504,17 +494,37 @@ TestCase { control.destroy() } - function test_layout() { - var control = tabBar.createObject(testCase, {spacing: 0, width: 200}) + function test_layout_data() { + return [ + { tag: "spacing:0", spacing: 0 }, + { tag: "spacing:1", spacing: 1 }, + { tag: "spacing:10", spacing: 10 }, + ] + } + + function test_layout(data) { + var control = tabBar.createObject(testCase, {spacing: data.spacing, width: 200}) - var tab1 = tabButton.createObject(control) + var tab1 = tabButton.createObject(control, {text: "First"}) control.addItem(tab1) tryCompare(tab1, "width", control.width) - var tab2 = tabButton.createObject(control) + var tab2 = tabButton.createObject(control, {text: "Second"}) control.addItem(tab2) - tryCompare(tab1, "width", control.width / 2) - tryCompare(tab2, "width", control.width / 2) + tryCompare(tab1, "width", (control.width - data.spacing) / 2) + compare(tab2.width, (control.width - data.spacing) / 2) + + var tab3 = tabButton.createObject(control, {width: 50, text: "Third"}) + control.addItem(tab3) + tryCompare(tab1, "width", (control.width - 2 * data.spacing - 50) / 2) + compare(tab2.width, (control.width - 2 * data.spacing - 50) / 2) + compare(tab3.width, 50) + + var expectedWidth = tab3.contentItem.implicitWidth + tab3.leftPadding + tab3.rightPadding + tab3.width = tab3.implicitWidth + tryCompare(tab1, "width", (control.width - 2 * data.spacing - expectedWidth) / 2) + tryCompare(tab2, "width", (control.width - 2 * data.spacing - expectedWidth) / 2) + compare(tab3.width, expectedWidth) control.destroy() } diff --git a/tests/auto/controls/data/tst_tabbutton.qml b/tests/auto/controls/data/tst_tabbutton.qml index 3a817cfd..4ab9d955 100644 --- a/tests/auto/controls/data/tst_tabbutton.qml +++ b/tests/auto/controls/data/tst_tabbutton.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase @@ -85,7 +85,7 @@ TestCase { function test_baseline() { var control = tabButton.createObject(testCase) verify(control) - compare(control.baselineOffset, control.label.y + control.label.baselineOffset) + compare(control.baselineOffset, control.contentItem.y + control.contentItem.baselineOffset) control.destroy() } } diff --git a/tests/auto/controls/data/tst_textarea.qml b/tests/auto/controls/data/tst_textarea.qml index 269e11ec..bda0b3e3 100644 --- a/tests/auto/controls/data/tst_textarea.qml +++ b/tests/auto/controls/data/tst_textarea.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase @@ -56,6 +56,15 @@ TestCase { } Component { + id: flickable + Flickable { + width: 200 + height: 200 + TextArea.flickable: TextArea { } + } + } + + Component { id: signalSpy SignalSpy { } } @@ -68,10 +77,16 @@ TestCase { function test_implicitSize() { var control = textArea.createObject(testCase) + + var implicitWidthSpy = signalSpy.createObject(control, { target: control, signalName: "implicitWidthChanged"} ) + var implicitHeightSpy = signalSpy.createObject(control, { target: control, signalName: "implicitHeightChanged"} ) control.background.implicitWidth = 400 control.background.implicitHeight = 200 compare(control.implicitWidth, 400) compare(control.implicitHeight, 200) + compare(implicitWidthSpy.count, 1) + compare(implicitHeightSpy.count, 1) + control.destroy() } @@ -137,4 +152,69 @@ TestCase { control.destroy() } + + function test_flickable() { + var control = flickable.createObject(testCase, {text:"line0", selectByMouse: true}) + verify(control) + + var textArea = control.TextArea.flickable + verify(textArea) + + for (var i = 1; i <= 100; ++i) + textArea.text += "line\n" + i + + verify(textArea.contentWidth > 0) + verify(textArea.contentHeight > 200) + + compare(control.contentWidth, textArea.contentWidth + textArea.leftPadding + textArea.rightPadding) + compare(control.contentHeight, textArea.contentHeight + textArea.topPadding + textArea.bottomPadding) + + compare(textArea.cursorPosition, 0) + + var center = textArea.positionAt(control.width / 2, control.height / 2) + verify(center > 0) + mouseClick(textArea, control.width / 2, control.height / 2) + compare(textArea.cursorPosition, center) + + // click inside text area, but below flickable + var below = textArea.positionAt(control.width / 2, control.height + 1) + verify(below > center) + mouseClick(textArea, control.width / 2, control.height + 1) + compare(textArea.cursorPosition, center) // no change + + // scroll down + control.contentY = -(control.contentHeight - control.height) / 2 + + // click inside textarea, but above flickable + var above = textArea.positionAt(control.width / 2, textArea.topPadding) + verify(above > 0 && above < center) + mouseClick(textArea, control.width / 2, 0) + compare(textArea.cursorPosition, center) // no change + + control.destroy() + } + + function test_warning() { + ignoreWarning(Qt.resolvedUrl("tst_textarea.qml") + ":45:1: QML TestCase: TextArea must be attached to a Flickable") + testCase.TextArea.flickable = null + } + + function test_multiClick() { + var control = textArea.createObject(testCase, {text: "Qt Quick Controls 2 TextArea", selectByMouse: true}) + verify(control) + + waitForRendering(control) + control.width = control.contentWidth + var rect = control.positionToRectangle(12) + + // double click -> select word + mouseDoubleClickSequence(control, rect.x + rect.width / 2, rect.y + rect.height / 2) + compare(control.selectedText, "Controls") + + // tripple click -> select whole line + mouseClick(control, rect.x + rect.width / 2, rect.y + rect.height / 2) + compare(control.selectedText, "Qt Quick Controls 2 TextArea") + + control.destroy() + } } diff --git a/tests/auto/controls/data/tst_textfield.qml b/tests/auto/controls/data/tst_textfield.qml index a7e2f6ec..959662ee 100644 --- a/tests/auto/controls/data/tst_textfield.qml +++ b/tests/auto/controls/data/tst_textfield.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase @@ -69,10 +69,35 @@ TestCase { function test_implicitSize() { var control = textField.createObject(testCase) verify(control.implicitWidth > control.leftPadding + control.rightPadding) + + var implicitWidthSpy = signalSpy.createObject(control, { target: control, signalName: "implicitWidthChanged"} ) + var implicitHeightSpy = signalSpy.createObject(control, { target: control, signalName: "implicitHeightChanged"} ) + control.background.implicitWidth = 400 control.background.implicitHeight = 200 compare(control.implicitWidth, 400) compare(control.implicitHeight, 200) + compare(implicitWidthSpy.count, 1) + compare(implicitHeightSpy.count, 1) + + control.background = null + compare(control.implicitWidth, control.leftPadding + control.rightPadding) + compare(control.implicitHeight, control.contentHeight + control.topPadding + control.bottomPadding) + compare(implicitWidthSpy.count, 2) + compare(implicitHeightSpy.count, 2) + + control.text = "TextField" + compare(control.implicitWidth, control.contentWidth + control.leftPadding + control.rightPadding) + compare(control.implicitHeight, control.contentHeight + control.topPadding + control.bottomPadding) + compare(implicitWidthSpy.count, 3) + compare(implicitHeightSpy.count, 2) + + control.placeholderText = "..." + verify(control.implicitWidth < control.contentWidth + control.leftPadding + control.rightPadding) + compare(control.implicitHeight, control.contentHeight + control.topPadding + control.bottomPadding) + compare(implicitWidthSpy.count, 4) + compare(implicitHeightSpy.count, 2) + control.destroy() } @@ -138,4 +163,23 @@ TestCase { control.destroy() } + + function test_multiClick() { + var control = textField.createObject(testCase, {text: "Qt Quick Controls 2 TextArea", selectByMouse: true}) + verify(control) + + waitForRendering(control) + control.width = control.contentWidth + var rect = control.positionToRectangle(12) + + // double click -> select word + mouseDoubleClickSequence(control, rect.x + rect.width / 2, rect.y + rect.height / 2) + compare(control.selectedText, "Controls") + + // tripple click -> select whole line + mouseClick(control, rect.x + rect.width / 2, rect.y + rect.height / 2) + compare(control.selectedText, "Qt Quick Controls 2 TextArea") + + control.destroy() + } } diff --git a/tests/auto/controls/data/tst_toolbar.qml b/tests/auto/controls/data/tst_toolbar.qml index 128aa403..b68f26e6 100644 --- a/tests/auto/controls/data/tst_toolbar.qml +++ b/tests/auto/controls/data/tst_toolbar.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_toolbutton.qml b/tests/auto/controls/data/tst_toolbutton.qml index 63a87ec2..73431ca6 100644 --- a/tests/auto/controls/data/tst_toolbutton.qml +++ b/tests/auto/controls/data/tst_toolbutton.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase @@ -50,14 +50,9 @@ TestCase { when: windowShown name: "ToolButton" - SignalSpy { - id: pressedSpy - signalName: "pressedChanged" - } - - SignalSpy { - id: clickedSpy - signalName: "clicked" + Component { + id: signalSpy + SignalSpy { } } Component { @@ -65,20 +60,6 @@ TestCase { ToolButton { } } - function init() { - verify(!pressedSpy.target) - verify(!clickedSpy.target) - compare(pressedSpy.count, 0) - compare(clickedSpy.count, 0) - } - - function cleanup() { - pressedSpy.target = null - clickedSpy.target = null - pressedSpy.clear() - clickedSpy.clear() - } - function test_text() { var control = toolButton.createObject(testCase) verify(control) @@ -96,48 +77,69 @@ TestCase { var control = toolButton.createObject(testCase) verify(control) - pressedSpy.target = control - clickedSpy.target = control + var pressedSpy = signalSpy.createObject(control, {target: control, signalName: "pressedChanged"}) verify(pressedSpy.valid) + + var downSpy = signalSpy.createObject(control, {target: control, signalName: "downChanged"}) + verify(downSpy.valid) + + var clickedSpy = signalSpy.createObject(control, {target: control, signalName: "clicked"}) verify(clickedSpy.valid) // check mousePress(control, control.width / 2, control.height / 2, Qt.LeftToolButton) compare(pressedSpy.count, 1) + compare(downSpy.count, 1) compare(control.pressed, true) + compare(control.down, true) mouseRelease(control, control.width / 2, control.height / 2, Qt.LeftToolButton) compare(clickedSpy.count, 1) compare(pressedSpy.count, 2) + compare(downSpy.count, 2) compare(control.pressed, false) + compare(control.down, false) // uncheck mousePress(control, control.width / 2, control.height / 2, Qt.LeftToolButton) compare(pressedSpy.count, 3) + compare(downSpy.count, 3) compare(control.pressed, true) + compare(control.down, true) mouseRelease(control, control.width / 2, control.height / 2, Qt.LeftToolButton) compare(clickedSpy.count, 2) compare(pressedSpy.count, 4) + compare(downSpy.count, 4) compare(control.pressed, false) + compare(control.down, false) // release outside mousePress(control, control.width / 2, control.height / 2, Qt.LeftToolButton) compare(pressedSpy.count, 5) + compare(downSpy.count, 5) compare(control.pressed, true) + compare(control.down, true) mouseMove(control, control.width * 2, control.height * 2, 0, Qt.LeftToolButton) compare(control.pressed, false) + compare(control.down, false) mouseRelease(control, control.width * 2, control.height * 2, Qt.LeftToolButton) compare(clickedSpy.count, 2) compare(pressedSpy.count, 6) + compare(downSpy.count, 6) compare(control.pressed, false) + compare(control.down, false) // right button mousePress(control, control.width / 2, control.height / 2, Qt.RightButton) compare(pressedSpy.count, 6) + compare(downSpy.count, 6) compare(control.pressed, false) + compare(control.down, false) mouseRelease(control, control.width / 2, control.height / 2, Qt.RightButton) compare(clickedSpy.count, 2) compare(pressedSpy.count, 6) + compare(downSpy.count, 6) compare(control.pressed, false) + compare(control.down, false) control.destroy() } @@ -146,7 +148,7 @@ TestCase { var control = toolButton.createObject(testCase) verify(control) - clickedSpy.target = control + var clickedSpy = signalSpy.createObject(control, {target: control, signalName: "clicked"}) verify(clickedSpy.valid) control.forceActiveFocus() @@ -173,7 +175,7 @@ TestCase { function test_baseline() { var control = toolButton.createObject(testCase) verify(control) - compare(control.baselineOffset, control.label.y + control.label.baselineOffset) + compare(control.baselineOffset, control.contentItem.y + control.contentItem.baselineOffset) control.destroy() } } diff --git a/tests/auto/controls/data/tst_tooltip.qml b/tests/auto/controls/data/tst_tooltip.qml new file mode 100644 index 00000000..c78a7770 --- /dev/null +++ b/tests/auto/controls/data/tst_tooltip.qml @@ -0,0 +1,254 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 +import QtTest 1.0 +import QtQuick.Controls 2.0 + +TestCase { + id: testCase + width: 400 + height: 400 + visible: true + when: windowShown + name: "ToolTip" + + Component { + id: toolTip + ToolTip { } + } + + Component { + id: mouseArea + MouseArea { } + } + + Component { + id: signalSpy + SignalSpy { } + } + + QtObject { + id: object + } + + function test_properties_data() { + return [ + {tag: "text", property: "text", defaultValue: "", setValue: "Hello", signalName: "textChanged"}, + {tag: "delay", property: "delay", defaultValue: 0, setValue: 1000, signalName: "delayChanged"}, + {tag: "timeout", property: "timeout", defaultValue: -1, setValue: 2000, signalName: "timeoutChanged"} + ] + } + + function test_properties(data) { + var control = toolTip.createObject(testCase) + verify(control) + + compare(control[data.property], data.defaultValue) + + var spy = signalSpy.createObject(testCase, {target: control, signalName: data.signalName}) + verify(spy.valid) + + control[data.property] = data.setValue + compare(control[data.property], data.setValue) + compare(spy.count, 1) + + spy.destroy() + control.destroy() + } + + function test_attached_data() { + return [ + {tag: "text", property: "text", defaultValue: "", setValue: "Hello", signalName: "textChanged"}, + {tag: "delay", property: "delay", defaultValue: 0, setValue: 1000, signalName: "delayChanged"}, + {tag: "timeout", property: "timeout", defaultValue: -1, setValue: 2000, signalName: "timeoutChanged"} + ] + } + + function test_attached(data) { + var item1 = mouseArea.createObject(testCase) + verify(item1) + + var item2 = mouseArea.createObject(testCase) + verify(item2) + + compare(item1.ToolTip[data.property], data.defaultValue) + compare(item2.ToolTip[data.property], data.defaultValue) + + var spy1 = signalSpy.createObject(item1, {target: item1.ToolTip, signalName: data.signalName}) + verify(spy1.valid) + + var spy2 = signalSpy.createObject(item2, {target: item2.ToolTip, signalName: data.signalName}) + verify(spy2.valid) + + var sharedTip = ToolTip.toolTip + var sharedSpy = signalSpy.createObject(testCase, {target: sharedTip, signalName: data.signalName}) + verify(sharedSpy.valid) + + // change attached properties while the shared tooltip is not visible + item1.ToolTip[data.property] = data.setValue + compare(item1.ToolTip[data.property], data.setValue) + compare(spy1.count, 1) + + compare(spy2.count, 0) + compare(item2.ToolTip[data.property], data.defaultValue) + + // the shared tooltip is not visible for item1, so the attached + // property change should therefore not apply to the shared instance + compare(sharedSpy.count, 0) + compare(sharedTip[data.property], data.defaultValue) + + // show the shared tooltip for item2 + item2.ToolTip.visible = true + verify(item2.ToolTip.visible) + verify(sharedTip.visible) + + // change attached properties while the shared tooltip is visible + item2.ToolTip[data.property] = data.setValue + compare(item2.ToolTip[data.property], data.setValue) + compare(spy2.count, 1) + + // the shared tooltip is visible for item2, so the attached + // property change should apply to the shared instance + compare(sharedSpy.count, 1) + compare(sharedTip[data.property], data.setValue) + + item1.destroy() + item2.destroy() + } + + function test_delay_data() { + return [ + {tag: "imperative:0", delay: 0, imperative: true}, + {tag: "imperative:100", delay: 100, imperative: true}, + {tag: "declarative:0", delay: 0, imperative: false}, + {tag: "declarative:100", delay: 100, imperative: false} + ] + } + + function test_delay(data) { + var control = toolTip.createObject(testCase, {delay: data.delay}) + + compare(control.visible, false) + if (data.imperative) + control.open() + else + control.visible = true + compare(control.visible, data.delay <= 0) + tryCompare(control, "visible", true) + + control.destroy() + } + + function test_timeout_data() { + return [ + {tag: "imperative", imperative: true}, + {tag: "declarative", imperative: false} + ] + } + + function test_timeout(data) { + var control = toolTip.createObject(testCase, {timeout: 100}) + + compare(control.visible, false) + if (data.imperative) + control.open() + else + control.visible = true + compare(control.visible, true) + tryCompare(control, "visible", false) + + control.destroy() + } + + function test_warning() { + ignoreWarning(Qt.resolvedUrl("tst_tooltip.qml") + ":68:5: QML QtObject: ToolTip must be attached to an Item") + ignoreWarning("<Unknown File>:1:30: QML ToolTip: cannot find any window to open popup in.") + object.ToolTip.show("") // don't crash (QTBUG-56243) + } + + Component { + id: toolTipWithExitTransition + + ToolTip { + enter: Transition { + NumberAnimation { property: "opacity"; from: 0.0; to: 1.0; duration: 100 } + } + exit: Transition { + NumberAnimation { property: "opacity"; from: 1.0; to: 0.0; duration: 1000 } + } + } + } + + function test_makeVisibleWhileExitTransitionRunning_data() { + return [ + { tag: "imperative", imperative: true }, + { tag: "declarative", imperative: false } + ] + } + + function test_makeVisibleWhileExitTransitionRunning(data) { + var control = toolTipWithExitTransition.createObject(testCase) + + // Show, hide, and show the tooltip again. Its exit transition should + // start and get cancelled, and then its enter transition should run. + if (data.imperative) + control.open() + else + control.visible = true + tryCompare(control, "opacity", 1) + + if (data.imperative) + control.close() + else + control.visible = false + verify(control.exit.running) + wait(100) // TODO: replace with tryVerify() in 5.8 + verify(control.opacity < 1) + + if (data.imperative) + control.open() + else + control.visible = true + tryCompare(control, "opacity", 1) + + control.destroy() + } +} diff --git a/tests/auto/controls/data/tst_tumbler.qml b/tests/auto/controls/data/tst_tumbler.qml index 58d74c40..2e0e3295 100644 --- a/tests/auto/controls/data/tst_tumbler.qml +++ b/tests/auto/controls/data/tst_tumbler.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. +** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 TestCase { id: testCase @@ -51,19 +51,38 @@ TestCase { name: "Tumbler" property var tumbler: null + // With the help of cleanup(), ensures that all items created during a test function + // are destroyed if that test fails. + property Item cleanupItem readonly property real implicitTumblerWidth: 60 readonly property real implicitTumblerHeight: 200 readonly property real defaultImplicitDelegateHeight: implicitTumblerHeight / 3 readonly property real defaultListViewTumblerOffset: -defaultImplicitDelegateHeight + Component { + id: itemComponent + + Item { + anchors.fill: parent + } + } + function init() { - tumbler = Qt.createQmlObject("import Qt.labs.controls 1.0; Tumbler { }", testCase, ""); - verify(tumbler, "Tumbler: failed to create an instance"); - compare(tumbler.contentItem.parent, tumbler); + cleanupItem = itemComponent.createObject(testCase); + verify(cleanupItem); } function cleanup() { - tumbler.destroy(); + var destroyed = false; + cleanupItem.Component.destruction.connect(function() { destroyed = true; }); + + cleanupItem.destroy(); + + // Waiting until it's deleted before continuing makes debugging + // test failures much easier, because there aren't unrelated items hanging around. + // TODO: Replace with tryVerify(!tumbler) in 5.8. + while (!destroyed) + wait(0) } function tumblerXCenter() { @@ -92,11 +111,21 @@ TestCase { } } - function tst_dynamicContentItemChange() { - // test that currentIndex is maintained between contentItem changes... + Component { + id: tumblerComponent + + Tumbler {} } + // TODO: test that currentIndex is maintained between contentItem changes... +// function tst_dynamicContentItemChange() { +// } + function test_currentIndex() { + tumbler = tumblerComponent.createObject(cleanupItem); + verify(tumbler); + compare(tumbler.contentItem.parent, tumbler); + tumbler.model = 5; compare(tumbler.currentIndex, 0); @@ -122,6 +151,9 @@ TestCase { } function test_keyboardNavigation() { + tumbler = tumblerComponent.createObject(cleanupItem); + verify(tumbler); + tumbler.model = 5; tumbler.forceActiveFocus(); tumbler.contentItem.highlightMoveDuration = 0; @@ -150,6 +182,9 @@ TestCase { } function test_itemsCorrectlyPositioned() { + tumbler = tumblerComponent.createObject(cleanupItem); + verify(tumbler); + tumbler.model = 4; tumbler.height = 120; compare(tumbler.contentItem.delegateHeight, 40); @@ -158,7 +193,7 @@ TestCase { wait(tumbler.contentItem.highlightMoveDuration); var firstItemCenterPos = itemCenterPos(1); var firstItem = tumbler.contentItem.itemAt(firstItemCenterPos.x, firstItemCenterPos.y); - var actualPos = testCase.mapFromItem(firstItem, 0, 0); + var actualPos = cleanupItem.mapFromItem(firstItem, 0, 0); compare(actualPos.x, tumbler.leftPadding); compare(actualPos.y, tumbler.topPadding + 40); @@ -169,7 +204,7 @@ TestCase { firstItem = tumbler.contentItem.itemAt(firstItemCenterPos.x, firstItemCenterPos.y); verify(firstItem); // Test QTBUG-40298. - actualPos = testCase.mapFromItem(firstItem, 0, 0); + actualPos = cleanupItem.mapFromItem(firstItem, 0, 0); compare(actualPos.x, tumbler.leftPadding); compare(actualPos.y, tumbler.topPadding); @@ -186,8 +221,11 @@ TestCase { } function test_focusPastTumbler() { + tumbler = tumblerComponent.createObject(cleanupItem); + verify(tumbler); + var mouseArea = Qt.createQmlObject( - "import QtQuick 2.2; TextInput { activeFocusOnTab: true; width: 50; height: 50 }", testCase, ""); + "import QtQuick 2.2; TextInput { activeFocusOnTab: true; width: 50; height: 50 }", cleanupItem, ""); tumbler.forceActiveFocus(); verify(tumbler.activeFocus); @@ -195,16 +233,12 @@ TestCase { keyClick(Qt.Key_Tab); verify(!tumbler.activeFocus); verify(mouseArea.activeFocus); - - mouseArea.destroy(); } function test_datePicker() { - tumbler.destroy(); - var component = Qt.createComponent("TumblerDatePicker.qml"); compare(component.status, Component.Ready, component.errorString()); - tumbler = component.createObject(testCase); + tumbler = component.createObject(cleanupItem); // Should not be any warnings. compare(tumbler.dayTumbler.currentIndex, 0); @@ -234,28 +268,75 @@ TestCase { tryCompare(tumbler.dayTumbler, "currentIndex", 27); } + Component { + id: timePickerComponent + + Row { + property alias minuteTumbler: minuteTumbler + property alias amPmTumbler: amPmTumbler + + Tumbler { + id: minuteTumbler + currentIndex: 6 + model: 60 + width: 50 + height: 150 + } + + Tumbler { + id: amPmTumbler + model: ["AM", "PM"] + width: 50 + height: 150 + contentItem: ListView { + anchors.fill: parent + model: amPmTumbler.model + delegate: amPmTumbler.delegate + } + } + } + } + + function test_listViewTimePicker() { + var root = timePickerComponent.createObject(cleanupItem); + verify(root); + + mouseDrag(root.minuteTumbler, root.minuteTumbler.width / 2, root.minuteTumbler.height / 2, 0, 50); + // Shouldn't crash. + mouseDrag(root.amPmTumbler, root.amPmTumbler.width / 2, root.amPmTumbler.height / 2, 0, 50); + } + function test_displacement_data() { var data = [ // At 0 offset, the first item is current. - { index: 0, offset: 0, expectedDisplacement: 0 }, - { index: 1, offset: 0, expectedDisplacement: -1 }, - { index: 5, offset: 0, expectedDisplacement: 1 }, + { count: 6, index: 0, offset: 0, expectedDisplacement: 0 }, + { count: 6, index: 1, offset: 0, expectedDisplacement: -1 }, + { count: 6, index: 5, offset: 0, expectedDisplacement: 1 }, // When we start to move the first item down, the second item above it starts to become current. - { index: 0, offset: 0.25, expectedDisplacement: -0.25 }, - { index: 1, offset: 0.25, expectedDisplacement: -1.25 }, - { index: 5, offset: 0.25, expectedDisplacement: 0.75 }, - { index: 0, offset: 0.5, expectedDisplacement: -0.5 }, - { index: 1, offset: 0.5, expectedDisplacement: -1.5 }, - { index: 5, offset: 0.5, expectedDisplacement: 0.5 }, + { count: 6, index: 0, offset: 0.25, expectedDisplacement: -0.25 }, + { count: 6, index: 1, offset: 0.25, expectedDisplacement: -1.25 }, + { count: 6, index: 5, offset: 0.25, expectedDisplacement: 0.75 }, + { count: 6, index: 0, offset: 0.5, expectedDisplacement: -0.5 }, + { count: 6, index: 1, offset: 0.5, expectedDisplacement: -1.5 }, + { count: 6, index: 5, offset: 0.5, expectedDisplacement: 0.5 }, // By this stage, the delegate at index 1 is destroyed, so we can't test its displacement. - { index: 0, offset: 0.75, expectedDisplacement: -0.75 }, - { index: 5, offset: 0.75, expectedDisplacement: 0.25 }, - { index: 0, offset: 4.75, expectedDisplacement: 1.25 }, - { index: 1, offset: 4.75, expectedDisplacement: 0.25 }, - { index: 0, offset: 4.5, expectedDisplacement: 1.5 }, - { index: 1, offset: 4.5, expectedDisplacement: 0.5 }, - { index: 0, offset: 4.25, expectedDisplacement: 1.75 }, - { index: 1, offset: 4.25, expectedDisplacement: 0.75 } + { count: 6, index: 0, offset: 0.75, expectedDisplacement: -0.75 }, + { count: 6, index: 5, offset: 0.75, expectedDisplacement: 0.25 }, + { count: 6, index: 0, offset: 4.75, expectedDisplacement: 1.25 }, + { count: 6, index: 1, offset: 4.75, expectedDisplacement: 0.25 }, + { count: 6, index: 0, offset: 4.5, expectedDisplacement: 1.5 }, + { count: 6, index: 1, offset: 4.5, expectedDisplacement: 0.5 }, + { count: 6, index: 0, offset: 4.25, expectedDisplacement: 1.75 }, + { count: 6, index: 1, offset: 4.25, expectedDisplacement: 0.75 }, + // count == visibleItemCount + { count: 3, index: 0, offset: 0, expectedDisplacement: 0 }, + { count: 3, index: 1, offset: 0, expectedDisplacement: -1 }, + { count: 3, index: 2, offset: 0, expectedDisplacement: 1 }, + // count < visibleItemCount + { count: 2, index: 0, offset: 0, expectedDisplacement: 0 }, + { count: 2, index: 1, offset: 0, expectedDisplacement: 1 }, + // count == 1 + { count: 1, index: 0, offset: 0, expectedDisplacement: 0 } ]; for (var i = 0; i < data.length; ++i) { var row = data[i]; @@ -280,11 +361,14 @@ TestCase { } function test_displacement(data) { + tumbler = tumblerComponent.createObject(cleanupItem); + verify(tumbler); + // TODO: test setting these in the opposite order (delegate after model // doesn't seem to cause a change in delegates in PathView) tumbler.delegate = displacementDelegate; - tumbler.model = 6; - compare(tumbler.count, 6); + tumbler.model = data.count; + compare(tumbler.count, data.count); var delegate = findChild(tumbler.contentItem, "delegate" + data.index); verify(delegate); @@ -354,11 +438,10 @@ TestCase { } function test_displacementListView(data) { - tumbler.destroy(); // Sanity check that they're aren't any children at this stage. - tryCompare(testCase.children, "length", 0); + tryCompare(cleanupItem.children, "length", 0); - tumbler = listViewTumblerComponent.createObject(testCase); + tumbler = listViewTumblerComponent.createObject(cleanupItem); verify(tumbler); tumbler.delegate = displacementDelegate; @@ -428,9 +511,7 @@ TestCase { } function test_listViewFlickAboveBounds(data) { - tumbler.destroy(); - - tumbler = listViewTumblerComponent.createObject(testCase); + tumbler = listViewTumblerComponent.createObject(cleanupItem); verify(tumbler); tumbler.delegate = displacementDelegate; @@ -496,6 +577,9 @@ TestCase { } function test_visibleItemCount(data) { + tumbler = tumblerComponent.createObject(cleanupItem); + verify(tumbler); + tumbler.delegate = objectNameDelegate; tumbler.visibleItemCount = data.visibleItemCount; @@ -527,6 +611,9 @@ TestCase { } function test_attachedProperties() { + tumbler = tumblerComponent.createObject(cleanupItem); + verify(tumbler); + // TODO: crashes somewhere in QML's guts // tumbler.model = 5; // tumbler.delegate = wrongDelegateTypeComponent; @@ -538,14 +625,15 @@ TestCase { noParentDelegateComponent.createObject(null); ignoreWarning("Tumbler: attempting to access attached property on item without an \"index\" property"); - var object = noParentDelegateComponent.createObject(testCase); + var object = noParentDelegateComponent.createObject(cleanupItem); + verify(object); object.destroy(); // Should not be any warnings from this, as ListView, for example, doesn't produce warnings for the same code. - var gridView = gridViewComponent.createObject(testCase); + var gridView = gridViewComponent.createObject(cleanupItem); object = simpleDisplacementDelegate.createObject(gridView); + verify(object); object.destroy(); - gridView.destroy(); } property Component paddingDelegate: Text { @@ -592,6 +680,9 @@ TestCase { } function test_padding(data) { + tumbler = tumblerComponent.createObject(cleanupItem); + verify(tumbler); + tumbler.delegate = paddingDelegate; tumbler.model = 5; compare(tumbler.padding, 0); diff --git a/tests/auto/styles/styles.pro b/tests/auto/controls/default/default.pro index 3460900c..6ab5b5ff 100644 --- a/tests/auto/styles/styles.pro +++ b/tests/auto/controls/default/default.pro @@ -1,8 +1,14 @@ TEMPLATE = app -TARGET = tst_styles +TARGET = tst_default CONFIG += qmltestcase DEFINES += TST_CONTROLS_DATA=\\\"$$QQC2_SOURCE_TREE/tests/auto/controls/data\\\" SOURCES += \ - $$PWD/tst_styles.cpp + $$PWD/tst_default.cpp + +OTHER_FILES += \ + $$PWD/../data/* + +TESTDATA += \ + $$PWD/../data/tst_* diff --git a/tests/auto/universal/tst_universal.cpp b/tests/auto/controls/default/tst_default.cpp index ea42cc5e..68c3ab8f 100644 --- a/tests/auto/universal/tst_universal.cpp +++ b/tests/auto/controls/default/tst_default.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. +** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. @@ -35,4 +35,10 @@ ****************************************************************************/ #include <QtQuickTest/quicktest.h> -QUICK_TEST_MAIN(tst_universal) + +int main(int argc, char *argv[]) +{ + QTEST_ADD_GPU_BLACKLIST_SUPPORT + QTEST_SET_MAIN_SOURCE_PATH + return quick_test_main(argc, argv, "tst_controls::Default", TST_CONTROLS_DATA); +} diff --git a/tests/auto/controls/material/material.pro b/tests/auto/controls/material/material.pro new file mode 100644 index 00000000..1a8260f3 --- /dev/null +++ b/tests/auto/controls/material/material.pro @@ -0,0 +1,15 @@ +TEMPLATE = app +TARGET = tst_material +CONFIG += qmltestcase +QT += quickcontrols2 + +DEFINES += TST_CONTROLS_DATA=\\\"$$QQC2_SOURCE_TREE/tests/auto/controls/data\\\" + +SOURCES += \ + $$PWD/tst_material.cpp + +OTHER_FILES += \ + $$PWD/../data/* + +TESTDATA += \ + $$PWD/../data/tst_* diff --git a/tests/auto/styles/tst_styles.cpp b/tests/auto/controls/material/tst_material.cpp index 99c48126..2825b127 100644 --- a/tests/auto/styles/tst_styles.cpp +++ b/tests/auto/controls/material/tst_material.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. +** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. @@ -34,41 +34,13 @@ ** ****************************************************************************/ -#include <QtCore/qcoreapplication.h> -#include <QtCore/qprocess.h> #include <QtQuickTest/quicktest.h> - -static const char* styles[] = { "material", "universal" }; +#include <QtQuickControls2/qquickstyle.h> int main(int argc, char *argv[]) { - QByteArray style = qgetenv("QT_LABS_CONTROLS_STYLE"); - if (!style.isEmpty()) - return quick_test_main(argc, argv, "tst_styles(" + style + ")", TST_CONTROLS_DATA); - - QCoreApplication app(argc, argv); - -#ifndef QT_NO_PROCESS - int failures = 0; - int count = sizeof(styles) / sizeof(styles[0]); - - for (int i = 0; i < count; ++i) { - QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); - env.insert("QT_LABS_CONTROLS_STYLE", styles[i]); - - QProcess process; - process.setProcessEnvironment(env); - process.setWorkingDirectory(QDir::currentPath()); - process.setProcessChannelMode(QProcess::ForwardedChannels); - - process.start(argv[0], app.arguments().mid(1)); - process.waitForFinished(); - - failures += process.exitCode(); - } - - return failures; -#else // QT_NO_PROCESS - return 0; -#endif // QT_NO_PROCESS + QTEST_ADD_GPU_BLACKLIST_SUPPORT + QTEST_SET_MAIN_SOURCE_PATH + QQuickStyle::setStyle("Material"); + return quick_test_main(argc, argv, "tst_controls::Material", TST_CONTROLS_DATA); } diff --git a/tests/auto/controls/universal/tst_universal.cpp b/tests/auto/controls/universal/tst_universal.cpp new file mode 100644 index 00000000..de4ca85c --- /dev/null +++ b/tests/auto/controls/universal/tst_universal.cpp @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtQuickTest/quicktest.h> +#include <QtQuickControls2/qquickstyle.h> + +int main(int argc, char *argv[]) +{ + QTEST_ADD_GPU_BLACKLIST_SUPPORT + QTEST_SET_MAIN_SOURCE_PATH + QQuickStyle::setStyle("Universal"); + return quick_test_main(argc, argv, "tst_controls::Universal", TST_CONTROLS_DATA); +} diff --git a/tests/auto/controls/universal/universal.pro b/tests/auto/controls/universal/universal.pro new file mode 100644 index 00000000..7a16cc64 --- /dev/null +++ b/tests/auto/controls/universal/universal.pro @@ -0,0 +1,15 @@ +TEMPLATE = app +TARGET = tst_universal +CONFIG += qmltestcase +QT += quickcontrols2 + +DEFINES += TST_CONTROLS_DATA=\\\"$$QQC2_SOURCE_TREE/tests/auto/controls/data\\\" + +SOURCES += \ + $$PWD/tst_universal.cpp + +OTHER_FILES += \ + $$PWD/../data/* + +TESTDATA += \ + $$PWD/../data/tst_* diff --git a/tests/auto/drawer/data/applicationwindow-hover.qml b/tests/auto/drawer/data/applicationwindow-hover.qml new file mode 100644 index 00000000..5ac41457 --- /dev/null +++ b/tests/auto/drawer/data/applicationwindow-hover.qml @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 2.0 + +ApplicationWindow { + width: 400 + height: 400 + + property alias drawer: drawer + property alias backgroundButton: backgroundButton + property alias drawerButton: drawerButton + + Button { + id: backgroundButton + text: "Background" + anchors.fill: parent + } + + Drawer { + id: drawer + width: 100 + height: 400 + topPadding: 2 + leftPadding: 2 + rightPadding: 2 + bottomPadding: 2 + + contentItem: Button { + id: drawerButton + text: "Drawer" + } + } +} diff --git a/tests/auto/drawer/data/applicationwindow-wheel.qml b/tests/auto/drawer/data/applicationwindow-wheel.qml new file mode 100644 index 00000000..9c8b4a83 --- /dev/null +++ b/tests/auto/drawer/data/applicationwindow-wheel.qml @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 2.0 + +ApplicationWindow { + id: window + width: 400 + height: 400 + + property alias drawer: drawer + property alias drawerSlider: drawerSlider + property alias contentSlider: contentSlider + + Slider { + id: contentSlider + anchors.fill: parent + wheelEnabled: true + } + + Drawer { + id: drawer + edge: Qt.RightEdge + width: window.width * 0.8 + height: window.height + clip: true + contentItem: Slider { + id: drawerSlider + wheelEnabled: true + } + } +} diff --git a/tests/auto/drawer/data/applicationwindow.qml b/tests/auto/drawer/data/applicationwindow.qml new file mode 100644 index 00000000..9032ea0d --- /dev/null +++ b/tests/auto/drawer/data/applicationwindow.qml @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 2.0 + +ApplicationWindow { + width: 400 + height: 400 + + property alias drawer: drawer + + Drawer { + id: drawer + width: 200 + height: 200 + } +} diff --git a/tests/auto/drawer/data/grabber.qml b/tests/auto/drawer/data/grabber.qml new file mode 100644 index 00000000..8b85f71a --- /dev/null +++ b/tests/auto/drawer/data/grabber.qml @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 2.0 + +ApplicationWindow { + width: 400 + height: 400 + + property alias drawer: drawer + property alias popup: popup + + Drawer { + id: drawer + width: 200 + height: parent.height + } + + Popup { + id: popup + x: 200 + width: 200 + height: parent.height + } +} diff --git a/tests/auto/drawer/data/header.qml b/tests/auto/drawer/data/header.qml new file mode 100644 index 00000000..c74cc0c0 --- /dev/null +++ b/tests/auto/drawer/data/header.qml @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 2.0 + +ApplicationWindow { + width: 400 + height: 400 + + property alias drawer: drawer + property alias button: button + + header: ToolBar { + ToolButton { + id: button + text: "=" + } + } + + Drawer { + id: drawer + width: 200 + height: parent.height + } +} diff --git a/tests/auto/drawer/data/multiple.qml b/tests/auto/drawer/data/multiple.qml new file mode 100644 index 00000000..b2ef9781 --- /dev/null +++ b/tests/auto/drawer/data/multiple.qml @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 2.0 + +ApplicationWindow { + width: 400 + height: 400 + + property alias leftDrawer: leftDrawer + property alias leftButton: leftButton + + property alias rightDrawer: rightDrawer + property alias rightButton: rightButton + + property alias contentButton: contentButton + + Drawer { + id: leftDrawer + width: 300 + height: 400 + z: 1 + + contentItem: Button { + id: leftButton + text: "Left" + } + } + + Button { + id: contentButton + text: "Content" + anchors.fill: parent + } + + Drawer { + id: rightDrawer + width: 300 + height: 400 + edge: Qt.RightEdge + + contentItem: Button { + id: rightButton + text: "Right" + } + } +} diff --git a/tests/auto/drawer/data/reposition.qml b/tests/auto/drawer/data/reposition.qml new file mode 100644 index 00000000..abaec5ae --- /dev/null +++ b/tests/auto/drawer/data/reposition.qml @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 2.0 + +ApplicationWindow { + width: 400 + height: 400 + + property alias drawer: drawer + + header: Item { implicitHeight: 50 } + footer: Item { implicitHeight: 50 } + + Drawer { + id: drawer + width: parent.width / 2 + implicitHeight: parent.height + } +} diff --git a/tests/auto/drawer/data/window-hover.qml b/tests/auto/drawer/data/window-hover.qml new file mode 100644 index 00000000..872b934e --- /dev/null +++ b/tests/auto/drawer/data/window-hover.qml @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Window 2.2 +import QtQuick.Controls 2.0 + +Window { + width: 400 + height: 400 + + property alias drawer: drawer + property alias backgroundButton: backgroundButton + property alias drawerButton: drawerButton + + Button { + id: backgroundButton + text: "Background" + anchors.fill: parent + } + + Drawer { + id: drawer + width: 100 + height: 400 + topPadding: 2 + leftPadding: 2 + rightPadding: 2 + bottomPadding: 2 + + contentItem: Button { + id: drawerButton + text: "Drawer" + } + } +} diff --git a/tests/auto/drawer/data/window-wheel.qml b/tests/auto/drawer/data/window-wheel.qml new file mode 100644 index 00000000..18ca2ace --- /dev/null +++ b/tests/auto/drawer/data/window-wheel.qml @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Window 2.2 +import QtQuick.Controls 2.0 + +Window { + id: window + width: 400 + height: 400 + + property alias drawer: drawer + property alias drawerSlider: drawerSlider + property alias contentSlider: contentSlider + + Slider { + id: contentSlider + anchors.fill: parent + wheelEnabled: true + } + + Drawer { + id: drawer + edge: Qt.RightEdge + width: window.width * 0.8 + height: window.height + clip: true + contentItem: Slider { + id: drawerSlider + wheelEnabled: true + } + } +} diff --git a/tests/auto/drawer/data/window.qml b/tests/auto/drawer/data/window.qml new file mode 100644 index 00000000..47ef5cb0 --- /dev/null +++ b/tests/auto/drawer/data/window.qml @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Window 2.2 +import QtQuick.Controls 2.0 + +Window { + width: 400 + height: 400 + + property alias drawer: drawer + + Drawer { + id: drawer + width: 200 + height: 200 + } +} diff --git a/tests/auto/activeFocusOnTab/activeFocusOnTab.pro b/tests/auto/drawer/drawer.pro index cac27bcc..95ed44e9 100644 --- a/tests/auto/activeFocusOnTab/activeFocusOnTab.pro +++ b/tests/auto/drawer/drawer.pro @@ -1,11 +1,14 @@ CONFIG += testcase -TARGET = tst_activeFocusOnTab +TARGET = tst_drawer +SOURCES += tst_drawer.cpp + osx:CONFIG -= app_bundle -SOURCES += tst_activeFocusOnTab.cpp +QT += core-private gui-private qml-private quick-private testlib quicktemplates2-private include (../shared/util.pri) TESTDATA = data/* -QT += core-private gui-private qml-private quick-private testlib +OTHER_FILES += \ + data/* diff --git a/tests/auto/drawer/tst_drawer.cpp b/tests/auto/drawer/tst_drawer.cpp new file mode 100644 index 00000000..ab652466 --- /dev/null +++ b/tests/auto/drawer/tst_drawer.cpp @@ -0,0 +1,795 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/qtest.h> +#include <QtTest/qsignalspy.h> +#include "../shared/util.h" +#include "../shared/visualtestutil.h" + +#include <QtGui/qstylehints.h> +#include <QtGui/qtouchdevice.h> +#include <QtGui/qguiapplication.h> +#include <QtGui/qpa/qwindowsysteminterface.h> +#include <QtQuick/private/qquickwindow_p.h> +#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h> +#include <QtQuickTemplates2/private/qquickoverlay_p.h> +#include <QtQuickTemplates2/private/qquickpopup_p_p.h> +#include <QtQuickTemplates2/private/qquickdrawer_p.h> +#include <QtQuickTemplates2/private/qquickbutton_p.h> +#include <QtQuickTemplates2/private/qquickslider_p.h> + +using namespace QQuickVisualTestUtil; + +class tst_Drawer : public QQmlDataTest +{ + Q_OBJECT + +private slots: + void visible_data(); + void visible(); + + void state(); + + void position_data(); + void position(); + + void dragMargin_data(); + void dragMargin(); + + void reposition(); + void header(); + + void hover_data(); + void hover(); + + void wheel_data(); + void wheel(); + + void multiple(); + + void touch_data(); + void touch(); + + void grabber(); +}; + +void tst_Drawer::visible_data() +{ + QTest::addColumn<QString>("source"); + QTest::newRow("Window") << "window.qml"; + QTest::newRow("ApplicationWindow") << "applicationwindow.qml"; +} + +void tst_Drawer::visible() +{ + QFETCH(QString, source); + QQuickApplicationHelper helper(this, source); + + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + QQuickDrawer *drawer = window->property("drawer").value<QQuickDrawer*>(); + QVERIFY(drawer); + QQuickItem *popupItem = drawer->popupItem(); + + QCOMPARE(drawer->isVisible(), false); + QCOMPARE(drawer->position(), qreal(0.0)); + + QQuickOverlay *overlay = QQuickOverlay::overlay(window); + QVERIFY(overlay); + QVERIFY(!overlay->childItems().contains(popupItem)); + + drawer->open(); + QVERIFY(drawer->isVisible()); + QVERIFY(overlay->childItems().contains(popupItem)); + QTRY_COMPARE(drawer->position(), qreal(1.0)); + + drawer->close(); + QTRY_VERIFY(!drawer->isVisible()); + QTRY_COMPARE(drawer->position(), qreal(0.0)); + QVERIFY(!overlay->childItems().contains(popupItem)); + + drawer->setVisible(true); + QVERIFY(drawer->isVisible()); + QVERIFY(overlay->childItems().contains(popupItem)); + QTRY_COMPARE(drawer->position(), qreal(1.0)); + + drawer->setVisible(false); + QTRY_VERIFY(!drawer->isVisible()); + QTRY_COMPARE(drawer->position(), qreal(0.0)); + QTRY_VERIFY(!overlay->childItems().contains(popupItem)); +} + +void tst_Drawer::state() +{ + QQuickApplicationHelper helper(this, "applicationwindow.qml"); + + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + QQuickDrawer *drawer = window->property("drawer").value<QQuickDrawer*>(); + QVERIFY(drawer); + + QCOMPARE(drawer->isVisible(), false); + + QSignalSpy visibleChangedSpy(drawer, SIGNAL(visibleChanged())); + QSignalSpy aboutToShowSpy(drawer, SIGNAL(aboutToShow())); + QSignalSpy aboutToHideSpy(drawer, SIGNAL(aboutToHide())); + QSignalSpy openedSpy(drawer, SIGNAL(opened())); + QSignalSpy closedSpy(drawer, SIGNAL(closed())); + + QVERIFY(visibleChangedSpy.isValid()); + QVERIFY(aboutToShowSpy.isValid()); + QVERIFY(aboutToHideSpy.isValid()); + QVERIFY(openedSpy.isValid()); + QVERIFY(closedSpy.isValid()); + + int visibleChangedCount = 0; + int aboutToShowCount = 0; + int aboutToHideCount = 0; + int openedCount = 0; + int closedCount = 0; + + // open programmatically... + drawer->open(); + QCOMPARE(visibleChangedSpy.count(), ++visibleChangedCount); + QCOMPARE(aboutToShowSpy.count(), ++aboutToShowCount); + QCOMPARE(aboutToHideSpy.count(), aboutToHideCount); + QCOMPARE(openedSpy.count(), openedCount); + QCOMPARE(closedSpy.count(), closedCount); + + // ...and wait until fully open + QVERIFY(openedSpy.wait()); + QCOMPARE(visibleChangedSpy.count(), visibleChangedCount); + QCOMPARE(aboutToShowSpy.count(), aboutToShowCount); + QCOMPARE(aboutToHideSpy.count(), aboutToHideCount); + QCOMPARE(openedSpy.count(), ++openedCount); + QCOMPARE(closedSpy.count(), closedCount); + + // close programmatically... + drawer->close(); + QCOMPARE(visibleChangedSpy.count(), visibleChangedCount); + QCOMPARE(aboutToShowSpy.count(), aboutToShowCount); + QCOMPARE(aboutToHideSpy.count(), ++aboutToHideCount); + QCOMPARE(openedSpy.count(), openedCount); + QCOMPARE(closedSpy.count(), closedCount); + + // ...and wait until fully closed + QVERIFY(closedSpy.wait()); + QCOMPARE(visibleChangedSpy.count(), ++visibleChangedCount); + QCOMPARE(aboutToShowSpy.count(), aboutToShowCount); + QCOMPARE(aboutToHideSpy.count(), aboutToHideCount); + QCOMPARE(openedSpy.count(), openedCount); + QCOMPARE(closedSpy.count(), ++closedCount); + + // open interactively... + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(0, drawer->height() / 2)); + QTest::mouseMove(window, QPoint(drawer->width() * 0.2, drawer->height() / 2), 16); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(drawer->width() * 0.8, drawer->height() / 2), 16); + QCOMPARE(visibleChangedSpy.count(), ++visibleChangedCount); + QCOMPARE(aboutToShowSpy.count(), ++aboutToShowCount); + QCOMPARE(aboutToHideSpy.count(), aboutToHideCount); + QCOMPARE(openedSpy.count(), openedCount); + QCOMPARE(closedSpy.count(), closedCount); + + // ...and wait until fully open + QVERIFY(openedSpy.wait()); + QCOMPARE(visibleChangedSpy.count(), visibleChangedCount); + QCOMPARE(aboutToShowSpy.count(), aboutToShowCount); + QCOMPARE(aboutToHideSpy.count(), aboutToHideCount); + QCOMPARE(openedSpy.count(), ++openedCount); + QCOMPARE(closedSpy.count(), closedCount); + + // close interactively... + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(drawer->width(), drawer->height() / 2)); + QTest::mouseMove(window, QPoint(drawer->width() * 0.8, drawer->height() / 2), 16); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(drawer->width() * 0.2, drawer->height() / 2), 16); + QCOMPARE(visibleChangedSpy.count(), visibleChangedCount); + QCOMPARE(aboutToShowSpy.count(), aboutToShowCount); + QCOMPARE(aboutToHideSpy.count(), ++aboutToHideCount); + QCOMPARE(openedSpy.count(), openedCount); + QCOMPARE(closedSpy.count(), closedCount); + + // ...and wait until fully closed + QVERIFY(closedSpy.wait()); + QCOMPARE(visibleChangedSpy.count(), ++visibleChangedCount); + QCOMPARE(aboutToShowSpy.count(), aboutToShowCount); + QCOMPARE(aboutToHideSpy.count(), aboutToHideCount); + QCOMPARE(openedSpy.count(), openedCount); + QCOMPARE(closedSpy.count(), ++closedCount); +} + +void tst_Drawer::position_data() +{ + QTest::addColumn<Qt::Edge>("edge"); + QTest::addColumn<QPoint>("from"); + QTest::addColumn<QPoint>("to"); + QTest::addColumn<qreal>("position"); + + QTest::newRow("top") << Qt::TopEdge << QPoint(100, 0) << QPoint(100, 100) << qreal(0.5); + QTest::newRow("left") << Qt::LeftEdge << QPoint(0, 100) << QPoint(100, 100) << qreal(0.5); + QTest::newRow("right") << Qt::RightEdge << QPoint(399, 100) << QPoint(300, 100) << qreal(0.5); + QTest::newRow("bottom") << Qt::BottomEdge << QPoint(100, 399) << QPoint(100, 300) << qreal(0.5); +} + +void tst_Drawer::position() +{ + QFETCH(Qt::Edge, edge); + QFETCH(QPoint, from); + QFETCH(QPoint, to); + QFETCH(qreal, position); + + QQuickApplicationHelper helper(this, QStringLiteral("applicationwindow.qml")); + + QQuickApplicationWindow *window = helper.appWindow; + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + QQuickDrawer *drawer = helper.appWindow->property("drawer").value<QQuickDrawer*>(); + QVERIFY(drawer); + drawer->setEdge(edge); + + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, from); + QTest::mouseMove(window, to); + QCOMPARE(drawer->position(), position); + + // moved half-way open at almost infinite speed => snap to open + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, to); + QTRY_COMPARE(drawer->position(), 1.0); +} + +void tst_Drawer::dragMargin_data() +{ + QTest::addColumn<Qt::Edge>("edge"); + QTest::addColumn<qreal>("dragMargin"); + QTest::addColumn<qreal>("dragFromLeft"); + QTest::addColumn<qreal>("dragFromRight"); + + QTest::newRow("left:0") << Qt::LeftEdge << qreal(0) << qreal(0) << qreal(0); + QTest::newRow("left:-1") << Qt::LeftEdge << qreal(-1) << qreal(0) << qreal(0); + QTest::newRow("left:startDragDistance") << Qt::LeftEdge << qreal(QGuiApplication::styleHints()->startDragDistance()) << qreal(0.45) << qreal(0); + QTest::newRow("left:startDragDistance*2") << Qt::LeftEdge << qreal(QGuiApplication::styleHints()->startDragDistance() * 2) << qreal(0.45) << qreal(0); + + QTest::newRow("right:0") << Qt::RightEdge << qreal(0) << qreal(0) << qreal(0); + QTest::newRow("right:-1") << Qt::RightEdge << qreal(-1) << qreal(0) << qreal(0); + QTest::newRow("right:startDragDistance") << Qt::RightEdge << qreal(QGuiApplication::styleHints()->startDragDistance()) << qreal(0) << qreal(0.75); + QTest::newRow("right:startDragDistance*2") << Qt::RightEdge << qreal(QGuiApplication::styleHints()->startDragDistance() * 2) << qreal(0) << qreal(0.75); +} + +void tst_Drawer::dragMargin() +{ + QFETCH(Qt::Edge, edge); + QFETCH(qreal, dragMargin); + QFETCH(qreal, dragFromLeft); + QFETCH(qreal, dragFromRight); + + QQuickApplicationHelper helper(this, QStringLiteral("applicationwindow.qml")); + + QQuickApplicationWindow *window = helper.appWindow; + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + QQuickDrawer *drawer = helper.appWindow->property("drawer").value<QQuickDrawer*>(); + QVERIFY(drawer); + drawer->setEdge(edge); + drawer->setDragMargin(dragMargin); + + // drag from the left + int leftX = qMax<int>(0, dragMargin); + int leftDistance = drawer->width() * 0.45; + QVERIFY(leftDistance > QGuiApplication::styleHints()->startDragDistance()); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(leftX, drawer->height() / 2)); + QTest::mouseMove(window, QPoint(leftDistance, drawer->height() / 2)); + QCOMPARE(drawer->position(), dragFromLeft); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(leftDistance, drawer->height() / 2)); + + drawer->close(); + QTRY_COMPARE(drawer->position(), qreal(0.0)); + + // drag from the right + int rightX = qMin<int>(window->width() - 1, window->width() - dragMargin); + int rightDistance = drawer->width() * 0.75; + QVERIFY(rightDistance > QGuiApplication::styleHints()->startDragDistance()); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(rightX, drawer->height() / 2)); + QTest::mouseMove(window, QPoint(window->width() - rightDistance, drawer->height() / 2)); + QCOMPARE(drawer->position(), dragFromRight); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(window->width() - rightDistance, drawer->height() / 2)); +} + +static QRectF geometry(const QQuickItem *item) +{ + return QRectF(item->x(), item->y(), item->width(), item->height()); +} + +void tst_Drawer::reposition() +{ + QQuickApplicationHelper helper(this, QStringLiteral("reposition.qml")); + + QQuickApplicationWindow *window = helper.appWindow; + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + QQuickDrawer *drawer = window->property("drawer").value<QQuickDrawer*>(); + QVERIFY(drawer); + QQuickItem *popupItem = drawer->popupItem(); + QVERIFY(popupItem); + + drawer->open(); + QQuickItem *dimmer = QQuickPopupPrivate::get(drawer)->dimmer; + QVERIFY(dimmer); + + QCOMPARE(geometry(dimmer), QRectF(0, 0, window->width(), window->height())); + QTRY_COMPARE(geometry(popupItem), QRectF(0, 0, window->width() / 2, window->height())); + + drawer->setY(100); + QCOMPARE(geometry(dimmer), QRectF(0, 100, window->width(), window->height() - 100)); + QCOMPARE(geometry(popupItem), QRectF(0, 100, window->width() / 2, window->height() - 100)); + + drawer->setHeight(window->height()); + QCOMPARE(geometry(dimmer), QRectF(0, 100, window->width(), window->height())); + QCOMPARE(geometry(popupItem), QRectF(0, 100, window->width() / 2, window->height())); + + drawer->resetHeight(); + QCOMPARE(geometry(dimmer), QRectF(0, 100, window->width(), window->height() - 100)); + QCOMPARE(geometry(popupItem), QRectF(0, 100, window->width() / 2, window->height() - 100)); + + drawer->setParentItem(window->contentItem()); + QCOMPARE(geometry(dimmer), QRectF(0, 150, window->width(), window->height() - 150)); + QCOMPARE(geometry(popupItem), QRectF(0, 150, window->width() / 2, window->height() - 150)); + + drawer->setEdge(Qt::RightEdge); + QCOMPARE(geometry(dimmer), QRectF(0, 150, window->width(), window->height() - 150)); + QTRY_COMPARE(geometry(popupItem), QRectF(window->width() - drawer->width(), 150, window->width() / 2, window->height() - 150)); + + window->setWidth(window->width() + 100); + QTRY_COMPARE(geometry(dimmer), QRectF(0, 150, window->width(), window->height() - 150)); + QTRY_COMPARE(geometry(popupItem), QRectF(window->width() - drawer->width(), 150, window->width() / 2, window->height() - 150)); + + drawer->close(); + QTRY_COMPARE(geometry(popupItem), QRectF(window->width(), 150, window->width() / 2, window->height() - 150)); +} + +void tst_Drawer::header() +{ + QQuickApplicationHelper helper(this, QStringLiteral("header.qml")); + + QQuickApplicationWindow *window = helper.appWindow; + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + QQuickItem *content = window->contentItem(); + QVERIFY(content); + + QQuickOverlay *overlay = QQuickOverlay::overlay(window); + QVERIFY(overlay); + + QQuickDrawer *drawer = window->property("drawer").value<QQuickDrawer*>(); + QVERIFY(drawer); + QQuickItem *popupItem = drawer->popupItem(); + + QQuickButton *button = window->property("button").value<QQuickButton*>(); + QVERIFY(button); + + drawer->open(); + QVERIFY(drawer->isVisible()); + + QCOMPARE(drawer->parentItem(), overlay); + QCOMPARE(drawer->height(), overlay->height()); + QCOMPARE(popupItem->height(), overlay->height()); + + drawer->setParentItem(content); + QCOMPARE(drawer->parentItem(), content); + QCOMPARE(drawer->height(), content->height()); + QCOMPARE(popupItem->height(), content->height()); + + // must be possible to interact with the header when the drawer is below the header + QSignalSpy clickSpy(button, SIGNAL(clicked())); + QVERIFY(clickSpy.isValid()); + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, QPoint(button->x() + button->width() / 2, button->y() + button->height() / 2)); + QCOMPARE(clickSpy.count(), 1); +} + +void tst_Drawer::hover_data() +{ + QTest::addColumn<QString>("source"); + QTest::addColumn<bool>("modal"); + + QTest::newRow("Window:modal") << "window-hover.qml" << true; + QTest::newRow("Window:modeless") << "window-hover.qml" << false; + QTest::newRow("ApplicationWindow:modal") << "applicationwindow-hover.qml" << true; + QTest::newRow("ApplicationWindow:modeless") << "applicationwindow-hover.qml" << false; +} + +void tst_Drawer::hover() +{ + QFETCH(QString, source); + QFETCH(bool, modal); + + QQuickApplicationHelper helper(this, source); + QQuickWindow *window = helper.window; + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + QQuickDrawer *drawer = window->property("drawer").value<QQuickDrawer*>(); + QVERIFY(drawer); + drawer->setModal(modal); + + QQuickButton *backgroundButton = window->property("backgroundButton").value<QQuickButton*>(); + QVERIFY(backgroundButton); + backgroundButton->setHoverEnabled(true); + + QQuickButton *drawerButton = window->property("drawerButton").value<QQuickButton*>(); + QVERIFY(drawerButton); + drawerButton->setHoverEnabled(true); + + QSignalSpy openedSpy(drawer, SIGNAL(opened())); + QVERIFY(openedSpy.isValid()); + drawer->open(); + QVERIFY(openedSpy.count() == 1 || openedSpy.wait()); + + // hover the background button outside the drawer + QTest::mouseMove(window, QPoint(window->width() - 1, window->height() - 1)); + QCOMPARE(backgroundButton->isHovered(), !modal); + QVERIFY(!drawerButton->isHovered()); + + // hover the drawer background + QTest::mouseMove(window, QPoint(1, 1)); + QVERIFY(!backgroundButton->isHovered()); + QVERIFY(!drawerButton->isHovered()); + + // hover the button in a drawer + QTest::mouseMove(window, QPoint(2, 2)); + QVERIFY(!backgroundButton->isHovered()); + QVERIFY(drawerButton->isHovered()); + + QSignalSpy closedSpy(drawer, SIGNAL(closed())); + QVERIFY(closedSpy.isValid()); + drawer->close(); + QVERIFY(closedSpy.count() == 1 || closedSpy.wait()); + + // hover the background button after closing the drawer + QTest::mouseMove(window, QPoint(window->width() / 2, window->height() / 2)); + QVERIFY(backgroundButton->isHovered()); +} + +void tst_Drawer::wheel_data() +{ + QTest::addColumn<QString>("source"); + QTest::addColumn<bool>("modal"); + + QTest::newRow("Window:modal") << "window-wheel.qml" << true; + QTest::newRow("Window:modeless") << "window-wheel.qml" << false; + QTest::newRow("ApplicationWindow:modal") << "applicationwindow-wheel.qml" << true; + QTest::newRow("ApplicationWindow:modeless") << "applicationwindow-wheel.qml" << false; +} + +static bool sendWheelEvent(QQuickItem *item, const QPoint &localPos, int degrees) +{ + QQuickWindow *window = item->window(); + QWheelEvent wheelEvent(localPos, item->window()->mapToGlobal(localPos), QPoint(0, 0), QPoint(0, 8 * degrees), 0, Qt::Vertical, Qt::NoButton, 0); + QSpontaneKeyEvent::setSpontaneous(&wheelEvent); + return qGuiApp->notify(window, &wheelEvent); +} + +void tst_Drawer::wheel() +{ + QFETCH(QString, source); + QFETCH(bool, modal); + + QQuickApplicationHelper helper(this, source); + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + QQuickSlider *contentSlider = window->property("contentSlider").value<QQuickSlider*>(); + QVERIFY(contentSlider); + + QQuickDrawer *drawer = window->property("drawer").value<QQuickDrawer*>(); + QVERIFY(drawer && drawer->contentItem()); + drawer->setModal(modal); + + QQuickSlider *drawerSlider = window->property("drawerSlider").value<QQuickSlider*>(); + QVERIFY(drawerSlider); + + { + // wheel over the content + qreal oldContentValue = contentSlider->value(); + qreal oldDrawerValue = drawerSlider->value(); + + QVERIFY(sendWheelEvent(contentSlider, QPoint(contentSlider->width() / 2, contentSlider->height() / 2), 15)); + + QVERIFY(!qFuzzyCompare(contentSlider->value(), oldContentValue)); // must have moved + QVERIFY(qFuzzyCompare(drawerSlider->value(), oldDrawerValue)); // must not have moved + } + + QSignalSpy openedSpy(drawer, SIGNAL(opened())); + QVERIFY(openedSpy.isValid()); + drawer->open(); + QVERIFY(openedSpy.count() == 1 || openedSpy.wait()); + + { + // wheel over the drawer content + qreal oldContentValue = contentSlider->value(); + qreal oldDrawerValue = drawerSlider->value(); + + QVERIFY(sendWheelEvent(drawerSlider, QPoint(drawerSlider->width() / 2, drawerSlider->height() / 2), 15)); + + QVERIFY(qFuzzyCompare(contentSlider->value(), oldContentValue)); // must not have moved + QVERIFY(!qFuzzyCompare(drawerSlider->value(), oldDrawerValue)); // must have moved + } + + { + // wheel over the overlay + qreal oldContentValue = contentSlider->value(); + qreal oldDrawerValue = drawerSlider->value(); + + QVERIFY(sendWheelEvent(QQuickOverlay::overlay(window), QPoint(0, 0), 15)); + + if (modal) { + // the content below a modal overlay must not move + QVERIFY(qFuzzyCompare(contentSlider->value(), oldContentValue)); + } else { + // the content below a modeless overlay must move + QVERIFY(!qFuzzyCompare(contentSlider->value(), oldContentValue)); + } + QVERIFY(qFuzzyCompare(drawerSlider->value(), oldDrawerValue)); // must not have moved + } +} + +void tst_Drawer::multiple() +{ + QQuickApplicationHelper helper(this, QStringLiteral("multiple.qml")); + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + QQuickDrawer *leftDrawer = window->property("leftDrawer").value<QQuickDrawer*>(); + QVERIFY(leftDrawer); + QQuickButton *leftButton = window->property("leftButton").value<QQuickButton*>(); + QVERIFY(leftButton); + QSignalSpy leftClickSpy(leftButton, SIGNAL(clicked())); + QVERIFY(leftClickSpy.isValid()); + + QQuickDrawer *rightDrawer = window->property("rightDrawer").value<QQuickDrawer*>(); + QVERIFY(rightDrawer); + QQuickButton *rightButton = window->property("rightButton").value<QQuickButton*>(); + QVERIFY(rightButton); + QSignalSpy rightClickSpy(rightButton, SIGNAL(clicked())); + QVERIFY(rightClickSpy.isValid()); + + QQuickButton *contentButton = window->property("contentButton").value<QQuickButton*>(); + QVERIFY(contentButton); + QSignalSpy contentClickSpy(contentButton, SIGNAL(clicked())); + QVERIFY(contentClickSpy.isValid()); + + // no drawers open, click the content + QTest::mouseClick(window, Qt::LeftButton); + QCOMPARE(contentClickSpy.count(), 1); + QCOMPARE(leftClickSpy.count(), 0); + QCOMPARE(rightClickSpy.count(), 0); + + // drag the left drawer open + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(0, window->height() / 2)); + QTest::mouseMove(window, QPoint(leftDrawer->width() / 2, window->height() / 2)); + QCOMPARE(leftDrawer->position(), 0.5); + QCOMPARE(rightDrawer->position(), 0.0); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(leftDrawer->width() / 2, window->height() / 2)); + QTRY_COMPARE(leftDrawer->position(), 1.0); + QCOMPARE(rightDrawer->position(), 0.0); + + // cannot drag the right drawer while the left drawer is open + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(window->width() - 1, window->height() / 2)); + QTest::mouseMove(window, QPoint(window->width() - leftDrawer->width() / 2, window->height() / 2)); + QCOMPARE(leftDrawer->position(), 1.0); + QCOMPARE(rightDrawer->position(), 0.0); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(window->width() - leftDrawer->width() / 2, window->height() / 2)); + QCOMPARE(rightDrawer->position(), 0.0); + QCOMPARE(leftDrawer->position(), 1.0); + + // open the right drawer below the left drawer + rightDrawer->open(); + QTRY_COMPARE(rightDrawer->position(), 1.0); + + // click the left drawer's button + QTest::mouseClick(window, Qt::LeftButton); + QCOMPARE(contentClickSpy.count(), 1); + QCOMPARE(leftClickSpy.count(), 1); + QCOMPARE(rightClickSpy.count(), 0); + + // click the left drawer's background (button disabled, don't leak through to the right drawer below) + leftButton->setEnabled(false); + QTest::mouseClick(window, Qt::LeftButton); + QCOMPARE(contentClickSpy.count(), 1); + QCOMPARE(leftClickSpy.count(), 1); + QCOMPARE(rightClickSpy.count(), 0); + leftButton->setEnabled(true); + + // click the overlay of the left drawer (don't leak through to right drawer below) + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, QPoint(window->width() - (window->width() - leftDrawer->width()) / 2, window->height() / 2)); + QCOMPARE(contentClickSpy.count(), 1); + QCOMPARE(leftClickSpy.count(), 1); + QCOMPARE(rightClickSpy.count(), 0); + QTRY_VERIFY(!leftDrawer->isVisible()); + + // click the right drawer's button + QTest::mouseClick(window, Qt::LeftButton); + QCOMPARE(contentClickSpy.count(), 1); + QCOMPARE(leftClickSpy.count(), 1); + QCOMPARE(rightClickSpy.count(), 1); + + // cannot drag the left drawer while the right drawer is open + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(0, window->height() / 2)); + QTest::mouseMove(window, QPoint(leftDrawer->width() / 2, window->height() / 2)); + QCOMPARE(leftDrawer->position(), 0.0); + QCOMPARE(rightDrawer->position(), 1.0); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(leftDrawer->width() / 2, window->height() / 2)); + QCOMPARE(leftDrawer->position(), 0.0); + QCOMPARE(rightDrawer->position(), 1.0); + + // click the right drawer's background (button disabled, don't leak through to the content below) + rightButton->setEnabled(false); + QTest::mouseClick(window, Qt::LeftButton); + QCOMPARE(contentClickSpy.count(), 1); + QCOMPARE(leftClickSpy.count(), 1); + QCOMPARE(rightClickSpy.count(), 1); + rightButton->setEnabled(true); + + // click the overlay of the right drawer (don't leak through to the content below) + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, QPoint((window->width() - rightDrawer->width()) / 2, window->height() / 2)); + QCOMPARE(contentClickSpy.count(), 1); + QCOMPARE(leftClickSpy.count(), 1); + QCOMPARE(rightClickSpy.count(), 1); + QTRY_VERIFY(!rightDrawer->isVisible()); + + // no drawers open, click the content + QTest::mouseClick(window, Qt::LeftButton); + QCOMPARE(contentClickSpy.count(), 2); + QCOMPARE(leftClickSpy.count(), 1); + QCOMPARE(rightClickSpy.count(), 1); + + // drag the right drawer open + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(window->width() - 1, window->height() / 2)); + QTest::mouseMove(window, QPoint(window->width() - rightDrawer->width() / 2, window->height() / 2)); + QCOMPARE(rightDrawer->position(), 0.5); + QCOMPARE(leftDrawer->position(), 0.0); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(window->width() - rightDrawer->width() / 2, window->height() / 2)); + QTRY_COMPARE(rightDrawer->position(), 1.0); + QCOMPARE(leftDrawer->position(), 0.0); +} + +void tst_Drawer::touch_data() +{ + QTest::addColumn<QString>("source"); + QTest::newRow("Window") << "window.qml"; + QTest::newRow("ApplicationWindow") << "applicationwindow.qml"; +} + +void tst_Drawer::touch() +{ + QFETCH(QString, source); + QQuickApplicationHelper helper(this, source); + + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + QQuickDrawer *drawer = window->property("drawer").value<QQuickDrawer*>(); + QVERIFY(drawer); + + QSignalSpy drawerOpenedSpy(drawer, SIGNAL(opened())); + QSignalSpy drawerClosedSpy(drawer, SIGNAL(closed())); + QVERIFY(drawerOpenedSpy.isValid()); + QVERIFY(drawerClosedSpy.isValid()); + + 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()); + + // drag to open + QTest::touchEvent(window, device.data()).press(0, QPoint(0, 100)); + QTest::touchEvent(window, device.data()).move(0, QPoint(100, 100)); + QTRY_COMPARE(drawer->position(), 0.5); + QTest::touchEvent(window, device.data()).release(0, QPoint(100, 100)); + QVERIFY(drawerOpenedSpy.wait()); + QCOMPARE(drawer->position(), 1.0); + + // drag to close + QTest::touchEvent(window, device.data()).press(0, QPoint(300, 100)); + QTest::touchEvent(window, device.data()).move(0, QPoint(300 - drawer->dragMargin(), 100)); + for (int x = 300; x > 100; x -= 10) { + QTest::touchEvent(window, device.data()).move(0, QPoint(x, 100)); + QQuickWindowPrivate::get(window)->flushDelayedTouchEvent(); + } + QTest::touchEvent(window, device.data()).move(0, QPoint(100, 100)); + QTRY_COMPARE(drawer->position(), 0.5); + QTest::touchEvent(window, device.data()).release(0, QPoint(100, 100)); + QVERIFY(drawerClosedSpy.wait()); + QCOMPARE(drawer->position(), 0.0); +} + +void tst_Drawer::grabber() +{ + QQuickApplicationHelper helper(this, QStringLiteral("grabber.qml")); + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + QQuickDrawer *drawer = window->property("drawer").value<QQuickDrawer *>(); + QVERIFY(drawer); + + QSignalSpy drawerOpenedSpy(drawer, SIGNAL(opened())); + QSignalSpy drawerClosedSpy(drawer, SIGNAL(closed())); + QVERIFY(drawerOpenedSpy.isValid()); + QVERIFY(drawerClosedSpy.isValid()); + + drawer->open(); + QVERIFY(drawerOpenedSpy.wait()); + + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, QPoint(300, 100)); + QVERIFY(drawerClosedSpy.wait()); + + QQuickPopup *popup = window->property("popup").value<QQuickPopup *>(); + QVERIFY(popup); + + QSignalSpy popupOpenedSpy(popup, SIGNAL(opened())); + QSignalSpy popupClosedSpy(popup, SIGNAL(closed())); + QVERIFY(popupOpenedSpy.isValid()); + QVERIFY(popupClosedSpy.isValid()); + + popup->open(); + QTRY_COMPARE(popupOpenedSpy.count(), 1); + + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, QPoint(100, 300)); + QTRY_COMPARE(popupClosedSpy.count(), 1); +} + +QTEST_MAIN(tst_Drawer) + +#include "tst_drawer.moc" diff --git a/tests/auto/activeFocusOnTab/data/activeFocusOnTab.qml b/tests/auto/focus/data/activeFocusOnTab.qml index 08ecdda2..249cdba9 100644 --- a/tests/auto/activeFocusOnTab/data/activeFocusOnTab.qml +++ b/tests/auto/focus/data/activeFocusOnTab.qml @@ -39,7 +39,7 @@ ****************************************************************************/ import QtQuick 2.5 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 Item { id: main @@ -129,6 +129,8 @@ Item { RangeSlider { id: rangeslider objectName: "rangeslider" + first.handle.objectName: "rangeslider.first" + second.handle.objectName: "rangeslider.second" } // ScrollBar ScrollIndicator { @@ -143,6 +145,7 @@ Item { SpinBox { id: spinbox objectName: "spinbox" + editable: true value: 50 } // StackView diff --git a/tests/auto/focus/data/keyNavigation.qml b/tests/auto/focus/data/keyNavigation.qml new file mode 100644 index 00000000..3be791b5 --- /dev/null +++ b/tests/auto/focus/data/keyNavigation.qml @@ -0,0 +1,251 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.5 +import QtQuick.Controls 2.0 + +Item { + id: main + objectName: "main" + width: 400 + height: 800 + focus: true + Component.onCompleted: button1.focus = true + Column { + anchors.fill: parent + id: column + objectName: "column" + BusyIndicator { + id: busyindicator + objectName: "busyindicator" + } + Button { + id: button1 + objectName: "button1" + text: "button1" + KeyNavigation.up: textarea + KeyNavigation.down: button2 + KeyNavigation.left: toolbutton + KeyNavigation.right: button2 + } + Button { + id: button2 + objectName: "button2" + text: "button2" + KeyNavigation.up: button1 + KeyNavigation.down: checkbox + KeyNavigation.left: button1 + KeyNavigation.right: checkbox + } + CheckBox { + id: checkbox + objectName: "checkbox" + text: "checkbox" + KeyNavigation.up: button2 + KeyNavigation.down: checkbox1 + KeyNavigation.left: button2 + KeyNavigation.right: checkbox1 + } + GroupBox { + id: groupbox1 + objectName: "groupbox1" + title: "grouppox1" + Column { + anchors.fill: parent + CheckBox { + id: checkbox1 + objectName: "checkbox1" + text: "checkbox1" + KeyNavigation.up: checkbox + KeyNavigation.down: checkbox2 + KeyNavigation.left: checkbox + KeyNavigation.right: checkbox2 + } + CheckBox { + id: checkbox2 + objectName: "checkbox2" + text: "checkbox2" + KeyNavigation.up: checkbox1 + KeyNavigation.down: radiobutton + KeyNavigation.left: checkbox1 + KeyNavigation.right: radiobutton + } + } + } + Label { + id: label + objectName: "label" + text: "label" + } + PageIndicator { + id: pageindicator + objectName: "pageindicator" + } + ProgressBar { + id: progressbar + objectName: "progressbar" + indeterminate: true + } + RadioButton { + id: radiobutton + objectName: "radiobutton" + text: "radiobutton" + KeyNavigation.up: checkbox2 + KeyNavigation.down: radiobutton1 + KeyNavigation.left: checkbox2 + KeyNavigation.right: radiobutton1 + } + GroupBox { + id: groupbox2 + objectName: "groupbox2" + title: "groupbox2" + Column { + anchors.fill: parent + RadioButton { + id: radiobutton1 + objectName: "radiobutton1" + text: "radiobutton1" + KeyNavigation.up: radiobutton + KeyNavigation.down: radiobutton2 + KeyNavigation.left: radiobutton + KeyNavigation.right: radiobutton2 + } + RadioButton { + id: radiobutton2 + objectName: "radiobutton2" + text: "radiobutton2" + KeyNavigation.up: radiobutton1 + KeyNavigation.down: rangeslider + KeyNavigation.left: radiobutton1 + KeyNavigation.right: spinbox + } + } + } + RangeSlider { + id: rangeslider + objectName: "rangeslider" + first.handle.objectName: "rangeslider.first" + second.handle.objectName: "rangeslider.second" + KeyNavigation.up: radiobutton2 + KeyNavigation.down: slider + } + // ScrollBar + ScrollIndicator { + id: scrollindicator + objectName: "scrollindicator" + } + Slider { + id: slider + objectName: "slider" + value: 0.5 + KeyNavigation.up: rangeslider + KeyNavigation.down: swtich + } + SpinBox { + id: spinbox + objectName: "spinbox" + editable: true + value: 50 + KeyNavigation.left: radiobutton2 + KeyNavigation.right: swtich + } + // StackView + Switch { + id: swtich // switch + objectName: "switch" + text: "switch" + KeyNavigation.up: slider + KeyNavigation.down: tabbutton1 + KeyNavigation.left: spinbox + KeyNavigation.right: tabbutton1 + } + TabBar { + width: parent.width + id: tabbar + objectName: "tabbar" + TabButton { + id: tabbutton1 + objectName: "tabbutton1" + text: "tabbutton1" + KeyNavigation.up: swtich + KeyNavigation.down: tabbutton2 + KeyNavigation.left: swtich + KeyNavigation.right: tabbutton2 + } + TabButton { + id: tabbutton2 + objectName: "tabbutton2" + text: "tabbutton2" + KeyNavigation.up: tabbutton1 + KeyNavigation.down: textfield + KeyNavigation.left: tabbutton1 + KeyNavigation.right: toolbutton + } + } + TextField { + id: textfield + objectName: "textfield" + text: "abc" + KeyNavigation.up: tabbutton2 + KeyNavigation.down: toolbutton + } + ToolBar { + width: parent.width + id: toolbar + objectName: "toolbar" + ToolButton { + id: toolbutton + objectName: "toolbutton" + text: "toolbutton" + KeyNavigation.up: textfield + KeyNavigation.down: textarea + KeyNavigation.left: tabbutton2 + KeyNavigation.right: button1 + } + } + TextArea { + id: textarea + objectName: "textarea" + text: "abc" + KeyNavigation.up: toolbutton + KeyNavigation.down: button1 + } + } +} diff --git a/tests/auto/focus/data/visualFocus.qml b/tests/auto/focus/data/visualFocus.qml new file mode 100644 index 00000000..0af87652 --- /dev/null +++ b/tests/auto/focus/data/visualFocus.qml @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.5 +import QtQuick.Controls 2.0 + +Column { + width: 400 + height: 400 + Button { + text: "Button" + property bool showFocus: visualFocus + } + TextField { + text: "TextField" + } +} diff --git a/tests/auto/focus/focus.pro b/tests/auto/focus/focus.pro new file mode 100644 index 00000000..790445e3 --- /dev/null +++ b/tests/auto/focus/focus.pro @@ -0,0 +1,11 @@ +CONFIG += testcase +TARGET = tst_focus +osx:CONFIG -= app_bundle + +SOURCES += tst_focus.cpp + +include (../shared/util.pri) + +TESTDATA = data/* + +QT += core-private gui-private qml-private quick-private quicktemplates2-private testlib diff --git a/tests/auto/focus/tst_focus.cpp b/tests/auto/focus/tst_focus.cpp new file mode 100644 index 00000000..3f3b1ae5 --- /dev/null +++ b/tests/auto/focus/tst_focus.cpp @@ -0,0 +1,281 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qtest.h> +#include <QtTest/QSignalSpy> +#include <QtQml/qqmlengine.h> +#include <QtQml/qqmlcomponent.h> +#include <QtQml/qqmlcontext.h> +#include <QtQuick/qquickview.h> +#include <QtQuick/private/qquickitem_p.h> +#include <QtQuickTemplates2/private/qquickcontrol_p.h> +#include <QtGui/private/qguiapplication_p.h> +#include <QtGui/qstylehints.h> +#include "../shared/util.h" +#include "../shared/visualtestutil.h" + +using namespace QQuickVisualTestUtil; + +class tst_focus : public QQmlDataTest +{ + Q_OBJECT + +private slots: + void initTestCase(); + + void navigation_data(); + void navigation(); + + void policy(); + + void reason_data(); + void reason(); + + void visualFocus(); +}; + +void tst_focus::initTestCase() +{ + QQmlDataTest::initTestCase(); +} + +void tst_focus::navigation_data() +{ + QTest::addColumn<Qt::Key>("key"); + QTest::addColumn<QString>("testFile"); + QTest::addColumn<Qt::TabFocusBehavior>("behavior"); + QTest::addColumn<QStringList>("order"); + + QTest::newRow("tab-all-controls") << Qt::Key_Tab << QString("activeFocusOnTab.qml") << Qt::TabFocusAllControls << (QStringList() << "button2" << "checkbox" << "checkbox1" << "checkbox2" << "radiobutton" << "radiobutton1" << "radiobutton2" << "rangeslider.first" << "rangeslider.second" << "slider" << "spinbox" << "switch" << "tabbutton1" << "tabbutton2" << "textfield" << "toolbutton" << "textarea" << "button1"); + QTest::newRow("backtab-all-controls") << Qt::Key_Backtab << QString("activeFocusOnTab.qml") << Qt::TabFocusAllControls << (QStringList() << "textarea" << "toolbutton" << "textfield" << "tabbutton2" << "tabbutton1" << "switch" << "spinbox" << "slider" << "rangeslider.second" << "rangeslider.first" << "radiobutton2" << "radiobutton1" << "radiobutton" << "checkbox2" << "checkbox1" << "checkbox" << "button2" << "button1"); + + QTest::newRow("tab-text-controls") << Qt::Key_Tab << QString("activeFocusOnTab.qml") << Qt::TabFocusTextControls << (QStringList() << "spinbox" << "textfield" << "textarea"); + QTest::newRow("backtab-text-controls") << Qt::Key_Backtab << QString("activeFocusOnTab.qml") << Qt::TabFocusTextControls << (QStringList() << "textarea" << "textfield" << "spinbox"); + + QTest::newRow("key-up") << Qt::Key_Up << QString("keyNavigation.qml") << Qt::TabFocusAllControls << (QStringList() << "textarea" << "toolbutton" << "textfield" << "tabbutton2" << "tabbutton1" << "switch" << "slider" << "rangeslider.first" << "radiobutton2" << "radiobutton1" << "radiobutton" << "checkbox2" << "checkbox1" << "checkbox" << "button2" << "button1"); + QTest::newRow("key-down") << Qt::Key_Down << QString("keyNavigation.qml") << Qt::TabFocusAllControls << (QStringList() << "button2" << "checkbox" << "checkbox1" << "checkbox2" << "radiobutton" << "radiobutton1" << "radiobutton2" << "rangeslider.first" << "slider" << "switch" << "tabbutton1" << "tabbutton2" << "textfield" << "toolbutton" << "textarea" << "button1"); + QTest::newRow("key-left") << Qt::Key_Left << QString("keyNavigation.qml") << Qt::TabFocusAllControls << (QStringList() << "toolbutton" << "tabbutton2" << "tabbutton1" << "switch" << "spinbox" << "radiobutton2" << "radiobutton1" << "radiobutton" << "checkbox2" << "checkbox1" << "checkbox" << "button2" << "button1"); + QTest::newRow("key-right") << Qt::Key_Right << QString("keyNavigation.qml") << Qt::TabFocusAllControls << (QStringList() << "button2" << "checkbox" << "checkbox1" << "checkbox2" << "radiobutton" << "radiobutton1" << "radiobutton2" << "spinbox" << "switch" << "tabbutton1" << "tabbutton2" << "toolbutton" << "button1"); +} + +void tst_focus::navigation() +{ + QFETCH(Qt::Key, key); + QFETCH(QString, testFile); + QFETCH(Qt::TabFocusBehavior, behavior); + QFETCH(QStringList, order); + + QGuiApplication::styleHints()->setTabFocusBehavior(behavior); + + QQuickView view; + view.contentItem()->setObjectName("contentItem"); + + view.setSource(testFileUrl(testFile)); + view.show(); + view.requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(&view)); + QVERIFY(QGuiApplication::focusWindow() == &view); + + for (const QString &name : qAsConst(order)) { + QKeyEvent event(QEvent::KeyPress, key, Qt::NoModifier); + QGuiApplication::sendEvent(&view, &event); + QVERIFY(event.isAccepted()); + + QQuickItem *item = findItem<QQuickItem>(view.rootObject(), name); + QVERIFY2(item, qPrintable(name)); + QVERIFY2(item->hasActiveFocus(), qPrintable(QString("expected: '%1', actual: '%2'").arg(name).arg(view.activeFocusItem() ? view.activeFocusItem()->objectName() : "null"))); + } + + QGuiApplication::styleHints()->setTabFocusBehavior(Qt::TabFocusBehavior(-1)); +} + +void tst_focus::policy() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData("import QtQuick.Controls 2.0; ApplicationWindow { width: 100; height: 100; Control { anchors.fill: parent } }", QUrl()); + + QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(component.create())); + QVERIFY(window); + + QQuickControl *control = qobject_cast<QQuickControl *>(window->contentItem()->childItems().first()); + QVERIFY(control); + + QVERIFY(!control->hasActiveFocus()); + QVERIFY(!control->hasVisualFocus()); + + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + + // Qt::TabFocus vs. QQuickItem::activeFocusOnTab + control->setActiveFocusOnTab(true); + QCOMPARE(control->focusPolicy(), Qt::TabFocus); + control->setActiveFocusOnTab(false); + QCOMPARE(control->focusPolicy(), Qt::NoFocus); + + control->setFocusPolicy(Qt::TabFocus); + QCOMPARE(control->focusPolicy(), Qt::TabFocus); + QCOMPARE(control->activeFocusOnTab(), true); + + // Qt::TabFocus + QGuiApplication::styleHints()->setTabFocusBehavior(Qt::TabFocusAllControls); + QTest::keyClick(window.data(), Qt::Key_Tab); + QVERIFY(control->hasActiveFocus()); + QVERIFY(control->hasVisualFocus()); + QGuiApplication::styleHints()->setTabFocusBehavior(Qt::TabFocusBehavior(-1)); + + // reset + control->setFocus(false); + QVERIFY(!control->hasActiveFocus()); + + // Qt::ClickFocus + control->setAcceptedMouseButtons(Qt::LeftButton); + QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(control->width() / 2, control->height() / 2)); + QVERIFY(!control->hasActiveFocus()); + QVERIFY(!control->hasVisualFocus()); + + control->setFocusPolicy(Qt::ClickFocus); + QCOMPARE(control->focusPolicy(), Qt::ClickFocus); + QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(control->width() / 2, control->height() / 2)); + QVERIFY(control->hasActiveFocus()); + QVERIFY(!control->hasVisualFocus()); + + // reset + control->setFocus(false); + QVERIFY(!control->hasActiveFocus()); + + // Qt::WheelFocus + QWheelEvent wheelEvent(QPoint(control->width() / 2, control->height() / 2), 10, Qt::NoButton, Qt::NoModifier); + QGuiApplication::sendEvent(control, &wheelEvent); + QVERIFY(!control->hasActiveFocus()); + QVERIFY(!control->hasVisualFocus()); + + control->setFocusPolicy(Qt::WheelFocus); + QCOMPARE(control->focusPolicy(), Qt::WheelFocus); + + QGuiApplication::sendEvent(control, &wheelEvent); + QVERIFY(control->hasActiveFocus()); + QVERIFY(!control->hasVisualFocus()); +} + +void tst_focus::reason_data() +{ + QTest::addColumn<QString>("name"); + + QTest::newRow("Control") << "Control"; + QTest::newRow("TextField") << "TextField"; + QTest::newRow("TextArea") << "TextArea"; + QTest::newRow("SpinBox") << "SpinBox"; + QTest::newRow("ComboBox") << "ComboBox"; +} + +void tst_focus::reason() +{ + QFETCH(QString, name); + + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData(QString("import QtQuick.Controls 2.0; ApplicationWindow { width: 100; height: 100; %1 { anchors.fill: parent } }").arg(name).toUtf8(), QUrl()); + + QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(component.create())); + QVERIFY(window.data()); + + QQuickItem *control = window->contentItem()->childItems().first(); + QVERIFY(control); + + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + + QCOMPARE(control->property("focusReason").toInt(), int(Qt::OtherFocusReason)); + control->forceActiveFocus(Qt::MouseFocusReason); + QVERIFY(control->hasActiveFocus()); + QCOMPARE(control->property("focusReason").toInt(), int(Qt::MouseFocusReason)); + + QEXPECT_FAIL("TextArea", "TODO: TextArea::visualFocus?", Continue); + QEXPECT_FAIL("TextField", "TODO: TextField::visualFocus?", Continue); + QCOMPARE(control->property("visualFocus"), QVariant(false)); + + window->contentItem()->setFocus(false, Qt::TabFocusReason); + QVERIFY(!control->hasActiveFocus()); + QCOMPARE(control->property("focusReason").toInt(), int(Qt::TabFocusReason)); + + QEXPECT_FAIL("TextArea", "", Continue); + QEXPECT_FAIL("TextField", "", Continue); + QCOMPARE(control->property("visualFocus"), QVariant(false)); + + control->forceActiveFocus(Qt::TabFocusReason); + QVERIFY(control->hasActiveFocus()); + QCOMPARE(control->property("focusReason").toInt(), int(Qt::TabFocusReason)); + + QEXPECT_FAIL("TextArea", "", Continue); + QEXPECT_FAIL("TextField", "", Continue); + QCOMPARE(control->property("visualFocus"), QVariant(true)); +} + +void tst_focus::visualFocus() +{ + QQuickView view; + view.setSource(testFileUrl("visualFocus.qml")); + view.show(); + view.requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(&view)); + + QQuickItem *column = view.rootObject(); + QVERIFY(column); + QCOMPARE(column->childItems().count(), 2); + + QQuickControl *button = qobject_cast<QQuickControl *>(column->childItems().first()); + QVERIFY(button); + + QQuickItem *textfield = column->childItems().last(); + QVERIFY(textfield); + + button->forceActiveFocus(Qt::TabFocusReason); + QVERIFY(button->hasActiveFocus()); + QVERIFY(button->hasVisualFocus()); + QVERIFY(button->property("showFocus").toBool()); + + QTest::mouseClick(&view, Qt::LeftButton, Qt::NoModifier, QPoint(textfield->x() + textfield->width() / 2, textfield->y() + textfield->height() / 2)); + QVERIFY(!button->hasActiveFocus()); + QVERIFY(!button->hasVisualFocus()); + QVERIFY(!button->property("showFocus").toBool()); +} + +QTEST_MAIN(tst_focus) + +#include "tst_focus.moc" diff --git a/tests/auto/menu/data/addItem.qml b/tests/auto/menu/data/addItem.qml new file mode 100644 index 00000000..7bf07ecb --- /dev/null +++ b/tests/auto/menu/data/addItem.qml @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 2.0 + +ApplicationWindow { + width: 200 + height: 200 + + property alias menu: menu + + MenuItem { + id: newMenuItem + text: qsTr("New") + } + + Menu { + id: menu + y: parent.height + + Component.onCompleted: addItem(newMenuItem) + } +} diff --git a/tests/auto/menu/data/applicationwindow.qml b/tests/auto/menu/data/applicationwindow.qml index cb55e3f6..03bbe67b 100644 --- a/tests/auto/menu/data/applicationwindow.qml +++ b/tests/auto/menu/data/applicationwindow.qml @@ -39,7 +39,7 @@ ****************************************************************************/ import QtQuick 2.6 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 ApplicationWindow { title: "Test Application Window" diff --git a/tests/auto/menu/menu.pro b/tests/auto/menu/menu.pro index 2dd2ac7f..649f3fd4 100644 --- a/tests/auto/menu/menu.pro +++ b/tests/auto/menu/menu.pro @@ -4,7 +4,7 @@ SOURCES += tst_menu.cpp osx:CONFIG -= app_bundle -QT += core-private gui-private qml-private quick-private testlib labstemplates-private +QT += core-private gui-private qml-private quick-private testlib quicktemplates2-private include (../shared/util.pri) diff --git a/tests/auto/menu/tst_menu.cpp b/tests/auto/menu/tst_menu.cpp index 825867cf..7617cfcc 100644 --- a/tests/auto/menu/tst_menu.cpp +++ b/tests/auto/menu/tst_menu.cpp @@ -45,11 +45,11 @@ #include "../shared/util.h" #include "../shared/visualtestutil.h" -#include <QtLabsTemplates/private/qquickapplicationwindow_p.h> -#include <QtLabsTemplates/private/qquickoverlay_p.h> -#include <QtLabsTemplates/private/qquickbutton_p.h> -#include <QtLabsTemplates/private/qquickmenu_p.h> -#include <QtLabsTemplates/private/qquickmenuitem_p.h> +#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h> +#include <QtQuickTemplates2/private/qquickoverlay_p.h> +#include <QtQuickTemplates2/private/qquickbutton_p.h> +#include <QtQuickTemplates2/private/qquickmenu_p.h> +#include <QtQuickTemplates2/private/qquickmenuitem_p.h> using namespace QQuickVisualTestUtil; @@ -64,13 +64,14 @@ private slots: void mouse(); void contextMenuKeyboard(); void menuButton(); + void addItem(); }; void tst_menu::defaults() { QQuickApplicationHelper helper(this, QLatin1String("applicationwindow.qml")); - QQuickMenu *emptyMenu = helper.window->property("emptyMenu").value<QQuickMenu*>(); + QQuickMenu *emptyMenu = helper.appWindow->property("emptyMenu").value<QQuickMenu*>(); QCOMPARE(emptyMenu->isVisible(), false); QCOMPARE(emptyMenu->contentItem()->property("currentIndex"), QVariant(-1)); } @@ -79,7 +80,7 @@ void tst_menu::mouse() { QQuickApplicationHelper helper(this, QLatin1String("applicationwindow.qml")); - QQuickApplicationWindow *window = helper.window; + QQuickApplicationWindow *window = helper.appWindow; window->show(); QVERIFY(QTest::qWaitForWindowActive(window)); @@ -151,7 +152,7 @@ void tst_menu::contextMenuKeyboard() QQuickApplicationHelper helper(this, QLatin1String("applicationwindow.qml")); - QQuickApplicationWindow *window = helper.window; + QQuickApplicationWindow *window = helper.appWindow; window->show(); window->requestActivate(); QVERIFY(QTest::qWaitForWindowActive(window)); @@ -229,7 +230,7 @@ void tst_menu::menuButton() QQuickApplicationHelper helper(this, QLatin1String("applicationwindow.qml")); - QQuickApplicationWindow *window = helper.window; + QQuickApplicationWindow *window = helper.appWindow; window->show(); window->requestActivate(); QVERIFY(QTest::qWaitForWindowActive(window)); @@ -250,6 +251,27 @@ void tst_menu::menuButton() QVERIFY(firstItem->hasActiveFocus()); } +void tst_menu::addItem() +{ + QQuickApplicationHelper helper(this, QLatin1String("addItem.qml")); + QQuickApplicationWindow *window = helper.appWindow; + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + QQuickMenu *menu = window->property("menu").value<QQuickMenu*>(); + QVERIFY(menu); + menu->open(); + QVERIFY(menu->isVisible()); + + QQuickItem *menuItem = menu->itemAt(0); + QVERIFY(menuItem); + QTRY_VERIFY(!QQuickItemPrivate::get(menuItem)->culled); // QTBUG-53262 + + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, + menuItem->mapToScene(QPointF(menuItem->width() / 2, menuItem->height() / 2)).toPoint()); + QTRY_VERIFY(!menu->isVisible()); +} + QTEST_MAIN(tst_menu) #include "tst_menu.moc" diff --git a/tests/auto/popup/data/activeFocusOnClose1.qml b/tests/auto/popup/data/activeFocusOnClose1.qml new file mode 100644 index 00000000..e1a4cec2 --- /dev/null +++ b/tests/auto/popup/data/activeFocusOnClose1.qml @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 2.0 + +ApplicationWindow { + width: 400 + height: 400 + + property alias focusedPopup: focusedPopup + property alias nonFocusedPopup: nonFocusedPopup + + Popup { + id: focusedPopup + focus: true + } + + Popup { + id: nonFocusedPopup + } +} diff --git a/tests/auto/popup/data/activeFocusOnClose2.qml b/tests/auto/popup/data/activeFocusOnClose2.qml new file mode 100644 index 00000000..9418d521 --- /dev/null +++ b/tests/auto/popup/data/activeFocusOnClose2.qml @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 2.0 + +ApplicationWindow { + width: 400 + height: 400 + + property alias popup1: popup1 + property alias popup2: popup2 + property alias closePopup2Button: closePopup2Button + + Popup { + id: popup1 + focus: true + } + + Popup { + id: popup2 + focus: true + + Button { + id: closePopup2Button + onClicked: { + popup1.contentItem.forceActiveFocus(); + popup2.close(); + } + } + } +} diff --git a/tests/auto/popup/data/activeFocusOnClose3.qml b/tests/auto/popup/data/activeFocusOnClose3.qml new file mode 100644 index 00000000..5a1c8231 --- /dev/null +++ b/tests/auto/popup/data/activeFocusOnClose3.qml @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 2.0 + +ApplicationWindow { + width: 400 + height: 400 + + property alias popup1: popup1 + property alias popup2: popup2 + + Button { + focus: true + } + + Popup { + id: popup1 + focus: true + enter: Transition { PauseAnimation { duration: 200 } } + exit: Transition { PauseAnimation { duration: 200 } } + } + + Popup { + id: popup2 + focus: true + enter: Transition { PauseAnimation { duration: 100 } } + exit: Transition { PauseAnimation { duration: 100 } } + } +} diff --git a/tests/auto/popup/data/applicationwindow-hover.qml b/tests/auto/popup/data/applicationwindow-hover.qml new file mode 100644 index 00000000..044d983c --- /dev/null +++ b/tests/auto/popup/data/applicationwindow-hover.qml @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 2.0 + +ApplicationWindow { + width: 400 + height: 400 + + property alias popup: popup + property alias parentButton: parentButton + property alias childButton: childButton + + Button { + id: parentButton + text: "Parent" + anchors.fill: parent + + Popup { + id: popup + x: 1 + y: 1 + padding: 1 + + Button { + id: childButton + text: "Child" + } + } + } +} diff --git a/tests/auto/popup/data/applicationwindow-wheel.qml b/tests/auto/popup/data/applicationwindow-wheel.qml new file mode 100644 index 00000000..a655713e --- /dev/null +++ b/tests/auto/popup/data/applicationwindow-wheel.qml @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Window 2.2 +import QtQuick.Controls 2.0 + +ApplicationWindow { + id: window + width: 400 + height: 400 + + property alias popup: popup + property alias popupSlider: popupSlider + property alias contentSlider: contentSlider + + Slider { + id: contentSlider + anchors.fill: parent + wheelEnabled: true + } + + Popup { + id: popup + x: 50; y: 50 + implicitWidth: parent.width - 100 + implicitHeight: parent.height - 100 + clip: true + contentItem: Slider { + id: popupSlider + wheelEnabled: true + } + } +} diff --git a/tests/auto/popup/data/applicationwindow.qml b/tests/auto/popup/data/applicationwindow.qml index 34dbe7e8..2e868192 100644 --- a/tests/auto/popup/data/applicationwindow.qml +++ b/tests/auto/popup/data/applicationwindow.qml @@ -39,13 +39,14 @@ ****************************************************************************/ import QtQuick 2.6 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 ApplicationWindow { width: 400 height: 400 property alias popup: popup + property alias popup2: popup2 property alias button: button Button { @@ -69,4 +70,14 @@ ApplicationWindow { } } } + + Popup { + id: popup2 + y: popup.y + z: 1 + contentItem: Text { + text: "Popup2" + font.pixelSize: 36 + } + } } diff --git a/tests/auto/popup/data/grabber.qml b/tests/auto/popup/data/grabber.qml new file mode 100644 index 00000000..6cd5f765 --- /dev/null +++ b/tests/auto/popup/data/grabber.qml @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 2.0 + +ApplicationWindow { + width: 400 + height: 400 + + property alias menu: menu + property alias popup: popup + property alias combo: combo.popup + + Menu { + id: menu + MenuItem { + onTriggered: popup.open() + } + } + + Popup { + id: popup + modal: true + width: 200 + height: 200 + + ComboBox { + id: combo + model: 3 + } + } +} diff --git a/tests/auto/popup/data/nested.qml b/tests/auto/popup/data/nested.qml new file mode 100644 index 00000000..bf9e86c5 --- /dev/null +++ b/tests/auto/popup/data/nested.qml @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 2.0 + +ApplicationWindow { + width: 400 + height: 400 + + property alias modalPopup: modalPopup + property alias modelessPopup: modelessPopup + + Popup { + id: modalPopup + modal: true + width: 200 + height: 200 + } + + Popup { + id: modelessPopup + modal: false + width: 100 + height: 100 + } +} diff --git a/tests/auto/popup/data/window-hover.qml b/tests/auto/popup/data/window-hover.qml new file mode 100644 index 00000000..78d650fa --- /dev/null +++ b/tests/auto/popup/data/window-hover.qml @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Window 2.2 +import QtQuick.Controls 2.0 + +Window { + width: 400 + height: 400 + + property alias popup: popup + property alias parentButton: parentButton + property alias childButton: childButton + + Button { + id: parentButton + text: "Parent" + anchors.fill: parent + + Popup { + id: popup + x: 1 + y: 1 + padding: 1 + + Button { + id: childButton + text: "Child" + } + } + } +} diff --git a/tests/auto/popup/data/window-wheel.qml b/tests/auto/popup/data/window-wheel.qml new file mode 100644 index 00000000..2ffe4bf6 --- /dev/null +++ b/tests/auto/popup/data/window-wheel.qml @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Window 2.2 +import QtQuick.Controls 2.0 + +Window { + id: window + width: 400 + height: 400 + + property alias popup: popup + property alias popupSlider: popupSlider + property alias contentSlider: contentSlider + + Slider { + id: contentSlider + anchors.fill: parent + wheelEnabled: true + } + + Popup { + id: popup + x: 50; y: 50 + implicitWidth: parent.width - 100 + implicitHeight: parent.height - 100 + clip: true + contentItem: Slider { + id: popupSlider + wheelEnabled: true + } + } +} diff --git a/tests/auto/popup/data/window.qml b/tests/auto/popup/data/window.qml new file mode 100644 index 00000000..92bfbd70 --- /dev/null +++ b/tests/auto/popup/data/window.qml @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Window 2.2 +import QtQuick.Controls 2.0 + +Window { + width: 400 + height: 400 + + property alias popup: popup + property alias popup2: popup2 + property alias button: button + + Button { + id: button + text: "Open" + anchors.centerIn: parent + anchors.verticalCenterOffset: -height + + Popup { + id: popup + y: parent.height + + Text { + color: "white" + text: "Hello, world!" + + MouseArea { + anchors.fill: parent + onClicked: popup.close() + } + } + } + } + + Popup { + id: popup2 + y: popup.y + z: 1 + contentItem: Text { + text: "Popup2" + font.pixelSize: 36 + } + } +} diff --git a/tests/auto/popup/popup.pro b/tests/auto/popup/popup.pro index 87aca3b3..af4db794 100644 --- a/tests/auto/popup/popup.pro +++ b/tests/auto/popup/popup.pro @@ -4,7 +4,7 @@ SOURCES += tst_popup.cpp osx:CONFIG -= app_bundle -QT += core-private gui-private qml-private quick-private testlib labstemplates-private +QT += core-private gui-private qml-private quick-private testlib quicktemplates2-private include (../shared/util.pri) diff --git a/tests/auto/popup/tst_popup.cpp b/tests/auto/popup/tst_popup.cpp index 61bf999c..fbd0605b 100644 --- a/tests/auto/popup/tst_popup.cpp +++ b/tests/auto/popup/tst_popup.cpp @@ -39,10 +39,11 @@ #include "../shared/util.h" #include "../shared/visualtestutil.h" -#include <QtLabsTemplates/private/qquickapplicationwindow_p.h> -#include <QtLabsTemplates/private/qquickoverlay_p.h> -#include <QtLabsTemplates/private/qquickpopup_p.h> -#include <QtLabsTemplates/private/qquickbutton_p.h> +#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h> +#include <QtQuickTemplates2/private/qquickoverlay_p.h> +#include <QtQuickTemplates2/private/qquickpopup_p.h> +#include <QtQuickTemplates2/private/qquickbutton_p.h> +#include <QtQuickTemplates2/private/qquickslider_p.h> using namespace QQuickVisualTestUtil; @@ -51,73 +52,168 @@ class tst_popup : public QQmlDataTest Q_OBJECT private slots: + void visible_data(); void visible(); + void state(); + void overlay_data(); void overlay(); + void zOrder_data(); + void zOrder(); + void windowChange(); void closePolicy_data(); void closePolicy(); + void activeFocusOnClose1(); + void activeFocusOnClose2(); + void activeFocusOnClose3(); + void hover_data(); + void hover(); + void wheel_data(); + void wheel(); + void parentDestroyed(); + void nested(); + void grabber(); }; +void tst_popup::visible_data() +{ + QTest::addColumn<QString>("source"); + QTest::newRow("Window") << "window.qml"; + QTest::newRow("ApplicationWindow") << "applicationwindow.qml"; +} + void tst_popup::visible() { - QQuickApplicationHelper helper(this, QStringLiteral("applicationwindow.qml")); + QFETCH(QString, source); + QQuickApplicationHelper helper(this, source); - QQuickApplicationWindow *window = helper.window; + QQuickWindow *window = helper.window; window->show(); + window->requestActivate(); QVERIFY(QTest::qWaitForWindowActive(window)); - QQuickPopup *popup = helper.window->property("popup").value<QQuickPopup*>(); + QQuickPopup *popup = window->property("popup").value<QQuickPopup*>(); QVERIFY(popup); QQuickItem *popupItem = popup->popupItem(); popup->open(); QVERIFY(popup->isVisible()); - QVERIFY(window->overlay()->childItems().contains(popupItem)); + + QQuickOverlay *overlay = QQuickOverlay::overlay(window); + QVERIFY(overlay); + QVERIFY(overlay->childItems().contains(popupItem)); popup->close(); QVERIFY(!popup->isVisible()); - QVERIFY(!window->overlay()->childItems().contains(popupItem)); + QVERIFY(!overlay->childItems().contains(popupItem)); popup->setVisible(true); QVERIFY(popup->isVisible()); - QVERIFY(window->overlay()->childItems().contains(popupItem)); + QVERIFY(overlay->childItems().contains(popupItem)); popup->setVisible(false); QVERIFY(!popup->isVisible()); - QVERIFY(!window->overlay()->childItems().contains(popupItem)); + QVERIFY(!overlay->childItems().contains(popupItem)); +} + +void tst_popup::state() +{ + QQuickApplicationHelper helper(this, "applicationwindow.qml"); + + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + QQuickPopup *popup = window->property("popup").value<QQuickPopup*>(); + QVERIFY(popup); + + QCOMPARE(popup->isVisible(), false); + + QSignalSpy visibleChangedSpy(popup, SIGNAL(visibleChanged())); + QSignalSpy aboutToShowSpy(popup, SIGNAL(aboutToShow())); + QSignalSpy aboutToHideSpy(popup, SIGNAL(aboutToHide())); + QSignalSpy openedSpy(popup, SIGNAL(opened())); + QSignalSpy closedSpy(popup, SIGNAL(closed())); + + QVERIFY(visibleChangedSpy.isValid()); + QVERIFY(aboutToShowSpy.isValid()); + QVERIFY(aboutToHideSpy.isValid()); + QVERIFY(openedSpy.isValid()); + QVERIFY(closedSpy.isValid()); + + popup->open(); + QCOMPARE(visibleChangedSpy.count(), 1); + QCOMPARE(aboutToShowSpy.count(), 1); + QCOMPARE(aboutToHideSpy.count(), 0); + QTRY_COMPARE(openedSpy.count(), 1); + QCOMPARE(closedSpy.count(), 0); + + popup->close(); + QCOMPARE(visibleChangedSpy.count(), 2); + QCOMPARE(aboutToShowSpy.count(), 1); + QCOMPARE(aboutToHideSpy.count(), 1); + QCOMPARE(openedSpy.count(), 1); + QTRY_COMPARE(closedSpy.count(), 1); +} + +void tst_popup::overlay_data() +{ + QTest::addColumn<QString>("source"); + QTest::newRow("Window") << "window.qml"; + QTest::newRow("ApplicationWindow") << "applicationwindow.qml"; } void tst_popup::overlay() { - QQuickApplicationHelper helper(this, QStringLiteral("applicationwindow.qml")); + QFETCH(QString, source); + QQuickApplicationHelper helper(this, source); - QQuickApplicationWindow *window = helper.window; + QQuickWindow *window = helper.window; window->show(); + window->requestActivate(); QVERIFY(QTest::qWaitForWindowActive(window)); - QQuickItem *overlay = window->overlay(); + QQuickOverlay *overlay = QQuickOverlay::overlay(window); + QVERIFY(overlay); + QSignalSpy overlayPressedSignal(overlay, SIGNAL(pressed())); QSignalSpy overlayReleasedSignal(overlay, SIGNAL(released())); QVERIFY(overlayPressedSignal.isValid()); QVERIFY(overlayReleasedSignal.isValid()); - QTest::mousePress(window, Qt::LeftButton); - QCOMPARE(overlayPressedSignal.count(), 1); - QCOMPARE(overlayReleasedSignal.count(), 0); + QVERIFY(!overlay->isVisible()); // no popups open - QTest::mouseRelease(window, Qt::LeftButton); - QCOMPARE(overlayPressedSignal.count(), 1); - QCOMPARE(overlayReleasedSignal.count(), 0); // no modal popups open + QTest::mouseClick(window, Qt::LeftButton); + QCOMPARE(overlayPressedSignal.count(), 0); + QCOMPARE(overlayReleasedSignal.count(), 0); - QQuickPopup *popup = helper.window->property("popup").value<QQuickPopup*>(); + QQuickPopup *popup = window->property("popup").value<QQuickPopup*>(); QVERIFY(popup); - QQuickButton *button = helper.window->property("button").value<QQuickButton*>(); + QQuickButton *button = window->property("button").value<QQuickButton*>(); QVERIFY(button); + popup->open(); + QVERIFY(popup->isVisible()); + QVERIFY(overlay->isVisible()); + + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1)); + QCOMPARE(overlayPressedSignal.count(), 1); + QCOMPARE(overlayReleasedSignal.count(), 0); + + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1)); + QCOMPARE(overlayPressedSignal.count(), 1); + QCOMPARE(overlayReleasedSignal.count(), 0); // no modal-popups open + + popup->close(); + QVERIFY(!popup->isVisible()); + QVERIFY(!overlay->isVisible()); + popup->setModal(true); + popup->setClosePolicy(QQuickPopup::CloseOnReleaseOutside); popup->open(); QVERIFY(popup->isVisible()); + QVERIFY(overlay->isVisible()); QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1)); QCOMPARE(overlayPressedSignal.count(), 2); @@ -127,45 +223,118 @@ void tst_popup::overlay() QCOMPARE(overlayPressedSignal.count(), 2); QCOMPARE(overlayReleasedSignal.count(), 1); - QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, QPoint(button->x() + popup->x() + popup->width() / 2, - button->y() + popup->y() + popup->height() / 2)); - QCOMPARE(overlayPressedSignal.count(), 2); - QCOMPARE(overlayReleasedSignal.count(), 1); + QVERIFY(!popup->isVisible()); + QVERIFY(!overlay->isVisible()); +} + +void tst_popup::zOrder_data() +{ + QTest::addColumn<QString>("source"); + QTest::newRow("Window") << "window.qml"; + QTest::newRow("ApplicationWindow") << "applicationwindow.qml"; +} + +void tst_popup::zOrder() +{ + QFETCH(QString, source); + QQuickApplicationHelper helper(this, source); + + QQuickWindow *window = helper.window; + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + QQuickPopup *popup = window->property("popup").value<QQuickPopup*>(); + QVERIFY(popup); + popup->setModal(true); + + QQuickPopup *popup2 = window->property("popup2").value<QQuickPopup*>(); + QVERIFY(popup2); + popup2->setModal(true); + + // show popups in reverse order. popup2 has higher z-order so it appears + // on top and must be closed first, even if the other popup was opened last + popup2->open(); + popup->open(); + QVERIFY(popup2->isVisible()); + QVERIFY(popup->isVisible()); + + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1)); + QVERIFY(!popup2->isVisible()); + QVERIFY(popup->isVisible()); + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1)); + QVERIFY(!popup2->isVisible()); QVERIFY(!popup->isVisible()); } +void tst_popup::windowChange() +{ + QQuickPopup popup; + QSignalSpy spy(&popup, SIGNAL(windowChanged(QQuickWindow*))); + QVERIFY(spy.isValid()); + + QQuickItem item; + popup.setParentItem(&item); + QVERIFY(!popup.window()); + QCOMPARE(spy.count(), 0); + + QQuickWindow window; + item.setParentItem(window.contentItem()); + QCOMPARE(popup.window(), &window); + QCOMPARE(spy.count(), 1); + + item.setParentItem(nullptr); + QVERIFY(!popup.window()); + QCOMPARE(spy.count(), 2); + + popup.setParentItem(window.contentItem()); + QCOMPARE(popup.window(), &window); + QCOMPARE(spy.count(), 3); +} + Q_DECLARE_METATYPE(QQuickPopup::ClosePolicy) void tst_popup::closePolicy_data() { qRegisterMetaType<QQuickPopup::ClosePolicy>(); + QTest::addColumn<QString>("source"); QTest::addColumn<QQuickPopup::ClosePolicy>("closePolicy"); - QTest::newRow("NoAutoClose") << static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::NoAutoClose); - QTest::newRow("OnPressOutside") << static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::OnPressOutside); - QTest::newRow("OnPressOutsideParent") << static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::OnPressOutsideParent); - QTest::newRow("OnPressOutside|Parent") << static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::OnPressOutside | QQuickPopup::OnPressOutsideParent); - QTest::newRow("OnReleaseOutside") << static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::OnReleaseOutside); - QTest::newRow("OnReleaseOutside|Parent") << static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::OnReleaseOutside | QQuickPopup::OnReleaseOutsideParent); - QTest::newRow("OnEscape") << static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::OnEscape); + QTest::newRow("Window:NoAutoClose") << "window.qml"<< static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::NoAutoClose); + QTest::newRow("Window:CloseOnPressOutside") << "window.qml"<< static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::CloseOnPressOutside); + QTest::newRow("Window:CloseOnPressOutsideParent") << "window.qml"<< static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::CloseOnPressOutsideParent); + QTest::newRow("Window:CloseOnPressOutside|Parent") << "window.qml"<< static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::CloseOnPressOutside | QQuickPopup::CloseOnPressOutsideParent); + QTest::newRow("Window:CloseOnReleaseOutside") << "window.qml"<< static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::CloseOnReleaseOutside); + QTest::newRow("Window:CloseOnReleaseOutside|Parent") << "window.qml"<< static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::CloseOnReleaseOutside | QQuickPopup::CloseOnReleaseOutsideParent); + QTest::newRow("Window:CloseOnEscape") << "window.qml"<< static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::CloseOnEscape); + + QTest::newRow("ApplicationWindow:NoAutoClose") << "applicationwindow.qml"<< static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::NoAutoClose); + QTest::newRow("ApplicationWindow:CloseOnPressOutside") << "applicationwindow.qml"<< static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::CloseOnPressOutside); + QTest::newRow("ApplicationWindow:CloseOnPressOutsideParent") << "applicationwindow.qml"<< static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::CloseOnPressOutsideParent); + QTest::newRow("ApplicationWindow:CloseOnPressOutside|Parent") << "applicationwindow.qml"<< static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::CloseOnPressOutside | QQuickPopup::CloseOnPressOutsideParent); + QTest::newRow("ApplicationWindow:CloseOnReleaseOutside") << "applicationwindow.qml"<< static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::CloseOnReleaseOutside); + QTest::newRow("ApplicationWindow:CloseOnReleaseOutside|Parent") << "applicationwindow.qml"<< static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::CloseOnReleaseOutside | QQuickPopup::CloseOnReleaseOutsideParent); + QTest::newRow("ApplicationWindow:CloseOnEscape") << "applicationwindow.qml"<< static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::CloseOnEscape); } void tst_popup::closePolicy() { + QFETCH(QString, source); QFETCH(QQuickPopup::ClosePolicy, closePolicy); - QQuickApplicationHelper helper(this, QStringLiteral("applicationwindow.qml")); + QQuickApplicationHelper helper(this, source); - QQuickApplicationWindow *window = helper.window; + QQuickWindow *window = helper.window; window->show(); + window->requestActivate(); QVERIFY(QTest::qWaitForWindowActive(window)); - QQuickPopup *popup = helper.window->property("popup").value<QQuickPopup*>(); + QQuickPopup *popup = window->property("popup").value<QQuickPopup*>(); QVERIFY(popup); - QQuickButton *button = helper.window->property("button").value<QQuickButton*>(); + QQuickButton *button = window->property("button").value<QQuickButton*>(); QVERIFY(button); popup->setModal(true); @@ -177,7 +346,7 @@ void tst_popup::closePolicy() // press outside popup and its parent QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1)); - if (closePolicy.testFlag(QQuickPopup::OnPressOutside) || closePolicy.testFlag(QQuickPopup::OnPressOutsideParent)) + if (closePolicy.testFlag(QQuickPopup::CloseOnPressOutside) || closePolicy.testFlag(QQuickPopup::CloseOnPressOutsideParent)) QVERIFY(!popup->isVisible()); else QVERIFY(popup->isVisible()); @@ -187,7 +356,7 @@ void tst_popup::closePolicy() // release outside popup and its parent QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1)); - if (closePolicy.testFlag(QQuickPopup::OnReleaseOutside)) + if (closePolicy.testFlag(QQuickPopup::CloseOnReleaseOutside)) QVERIFY(!popup->isVisible()); else QVERIFY(popup->isVisible()); @@ -197,7 +366,7 @@ void tst_popup::closePolicy() // press outside popup but inside its parent QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(button->x(), button->y())); - if (closePolicy.testFlag(QQuickPopup::OnPressOutside) && !closePolicy.testFlag(QQuickPopup::OnPressOutsideParent)) + if (closePolicy.testFlag(QQuickPopup::CloseOnPressOutside) && !closePolicy.testFlag(QQuickPopup::CloseOnPressOutsideParent)) QVERIFY(!popup->isVisible()); else QVERIFY(popup->isVisible()); @@ -207,7 +376,7 @@ void tst_popup::closePolicy() // release outside popup but inside its parent QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(button->x(), button->y())); - if (closePolicy.testFlag(QQuickPopup::OnReleaseOutside) && !closePolicy.testFlag(QQuickPopup::OnReleaseOutsideParent)) + if (closePolicy.testFlag(QQuickPopup::CloseOnReleaseOutside) && !closePolicy.testFlag(QQuickPopup::CloseOnReleaseOutsideParent)) QVERIFY(!popup->isVisible()); else QVERIFY(popup->isVisible()); @@ -217,12 +386,341 @@ void tst_popup::closePolicy() // escape QTest::keyClick(window, Qt::Key_Escape); - if (closePolicy.testFlag(QQuickPopup::OnEscape)) + if (closePolicy.testFlag(QQuickPopup::CloseOnEscape)) QVERIFY(!popup->isVisible()); else QVERIFY(popup->isVisible()); } +void tst_popup::activeFocusOnClose1() +{ + // Test that a popup that never sets focus: true (e.g. ToolTip) doesn't affect + // the active focus item when it closes. + QQuickApplicationHelper helper(this, QStringLiteral("activeFocusOnClose1.qml")); + QQuickApplicationWindow *window = helper.appWindow; + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + QQuickPopup *focusedPopup = helper.appWindow->property("focusedPopup").value<QQuickPopup*>(); + QVERIFY(focusedPopup); + + QQuickPopup *nonFocusedPopup = helper.appWindow->property("nonFocusedPopup").value<QQuickPopup*>(); + QVERIFY(nonFocusedPopup); + + focusedPopup->open(); + QVERIFY(focusedPopup->isVisible()); + QVERIFY(focusedPopup->hasActiveFocus()); + + nonFocusedPopup->open(); + QVERIFY(nonFocusedPopup->isVisible()); + QVERIFY(focusedPopup->hasActiveFocus()); + + nonFocusedPopup->close(); + QVERIFY(!nonFocusedPopup->isVisible()); + QVERIFY(focusedPopup->hasActiveFocus()); +} + +void tst_popup::activeFocusOnClose2() +{ + // Test that a popup that sets focus: true but relinquishes focus (e.g. by + // calling forceActiveFocus() on another item) before it closes doesn't + // affect the active focus item when it closes. + QQuickApplicationHelper helper(this, QStringLiteral("activeFocusOnClose2.qml")); + QQuickApplicationWindow *window = helper.appWindow; + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + QQuickPopup *popup1 = helper.appWindow->property("popup1").value<QQuickPopup*>(); + QVERIFY(popup1); + + QQuickPopup *popup2 = helper.appWindow->property("popup2").value<QQuickPopup*>(); + QVERIFY(popup2); + + QQuickButton *closePopup2Button = helper.appWindow->property("closePopup2Button").value<QQuickButton*>(); + QVERIFY(closePopup2Button); + + popup1->open(); + QVERIFY(popup1->isVisible()); + QVERIFY(popup1->hasActiveFocus()); + + popup2->open(); + QVERIFY(popup2->isVisible()); + 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()); + QVERIFY(popup1->hasActiveFocus()); +} + +void tst_popup::activeFocusOnClose3() +{ + // Test that a closing popup that had focus doesn't steal focus from + // another popup that the focus was transferred to. + QQuickApplicationHelper helper(this, QStringLiteral("activeFocusOnClose3.qml")); + QQuickApplicationWindow *window = helper.appWindow; + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + QQuickPopup *popup1 = helper.appWindow->property("popup1").value<QQuickPopup*>(); + QVERIFY(popup1); + + QQuickPopup *popup2 = helper.appWindow->property("popup2").value<QQuickPopup*>(); + QVERIFY(popup2); + + popup1->open(); + QVERIFY(popup1->isVisible()); + QTRY_VERIFY(popup1->hasActiveFocus()); + + popup2->open(); + popup1->close(); + + QSignalSpy closedSpy(popup1, SIGNAL(closed())); + QVERIFY(closedSpy.isValid()); + QVERIFY(closedSpy.wait()); + + QVERIFY(!popup1->isVisible()); + QVERIFY(popup2->isVisible()); + QTRY_VERIFY(popup2->hasActiveFocus()); +} + +void tst_popup::hover_data() +{ + QTest::addColumn<QString>("source"); + QTest::addColumn<bool>("modal"); + + QTest::newRow("Window:modal") << "window-hover.qml" << true; + QTest::newRow("Window:modeless") << "window-hover.qml" << false; + QTest::newRow("ApplicationWindow:modal") << "applicationwindow-hover.qml" << true; + QTest::newRow("ApplicationWindow:modeless") << "applicationwindow-hover.qml" << false; +} + +void tst_popup::hover() +{ + QFETCH(QString, source); + QFETCH(bool, modal); + + QQuickApplicationHelper helper(this, source); + QQuickWindow *window = helper.window; + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + QQuickPopup *popup = window->property("popup").value<QQuickPopup*>(); + QVERIFY(popup); + popup->setModal(modal); + + QQuickButton *parentButton = window->property("parentButton").value<QQuickButton*>(); + QVERIFY(parentButton); + parentButton->setHoverEnabled(true); + + QQuickButton *childButton = window->property("childButton").value<QQuickButton*>(); + QVERIFY(childButton); + childButton->setHoverEnabled(true); + + QSignalSpy openedSpy(popup, SIGNAL(opened())); + QVERIFY(openedSpy.isValid()); + popup->open(); + QVERIFY(openedSpy.count() == 1 || openedSpy.wait()); + + // hover the parent button outside the popup + QTest::mouseMove(window, QPoint(window->width() - 1, window->height() - 1)); + QCOMPARE(parentButton->isHovered(), !modal); + QVERIFY(!childButton->isHovered()); + + // hover the popup background + QTest::mouseMove(window, QPoint(1, 1)); + QVERIFY(!parentButton->isHovered()); + QVERIFY(!childButton->isHovered()); + + // hover the child button in a popup + QTest::mouseMove(window, QPoint(2, 2)); + QVERIFY(!parentButton->isHovered()); + QVERIFY(childButton->isHovered()); + + QSignalSpy closedSpy(popup, SIGNAL(closed())); + QVERIFY(closedSpy.isValid()); + popup->close(); + QVERIFY(closedSpy.count() == 1 || closedSpy.wait()); + + // hover the parent button after closing the popup + QTest::mouseMove(window, QPoint(window->width() / 2, window->height() / 2)); + QVERIFY(parentButton->isHovered()); +} + +void tst_popup::wheel_data() +{ + QTest::addColumn<QString>("source"); + QTest::addColumn<bool>("modal"); + + QTest::newRow("Window:modal") << "window-wheel.qml" << true; + QTest::newRow("Window:modeless") << "window-wheel.qml" << false; + QTest::newRow("ApplicationWindow:modal") << "applicationwindow-wheel.qml" << true; + QTest::newRow("ApplicationWindow:modeless") << "applicationwindow-wheel.qml" << false; +} + +static bool sendWheelEvent(QQuickItem *item, const QPoint &localPos, int degrees) +{ + QQuickWindow *window = item->window(); + QWheelEvent wheelEvent(localPos, item->window()->mapToGlobal(localPos), QPoint(0, 0), QPoint(0, 8 * degrees), 0, Qt::Vertical, Qt::NoButton, 0); + QSpontaneKeyEvent::setSpontaneous(&wheelEvent); + return qGuiApp->notify(window, &wheelEvent); +} + +void tst_popup::wheel() +{ + QFETCH(QString, source); + QFETCH(bool, modal); + + QQuickApplicationHelper helper(this, source); + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + QQuickSlider *contentSlider = window->property("contentSlider").value<QQuickSlider*>(); + QVERIFY(contentSlider); + + QQuickPopup *popup = window->property("popup").value<QQuickPopup*>(); + QVERIFY(popup && popup->contentItem()); + popup->setModal(modal); + + QQuickSlider *popupSlider = window->property("popupSlider").value<QQuickSlider*>(); + QVERIFY(popupSlider); + + { + // wheel over the content + qreal oldContentValue = contentSlider->value(); + qreal oldPopupValue = popupSlider->value(); + + QVERIFY(sendWheelEvent(contentSlider, QPoint(contentSlider->width() / 2, contentSlider->height() / 2), 15)); + + QVERIFY(!qFuzzyCompare(contentSlider->value(), oldContentValue)); // must have moved + QVERIFY(qFuzzyCompare(popupSlider->value(), oldPopupValue)); // must not have moved + } + + QSignalSpy openedSpy(popup, SIGNAL(opened())); + QVERIFY(openedSpy.isValid()); + popup->open(); + QVERIFY(openedSpy.count() == 1 || openedSpy.wait()); + + { + // wheel over the popup content + qreal oldContentValue = contentSlider->value(); + qreal oldPopupValue = popupSlider->value(); + + QVERIFY(sendWheelEvent(popupSlider, QPoint(popupSlider->width() / 2, popupSlider->height() / 2), 15)); + + QVERIFY(qFuzzyCompare(contentSlider->value(), oldContentValue)); // must not have moved + QVERIFY(!qFuzzyCompare(popupSlider->value(), oldPopupValue)); // must have moved + } + + { + // wheel over the overlay + qreal oldContentValue = contentSlider->value(); + qreal oldPopupValue = popupSlider->value(); + + QVERIFY(sendWheelEvent(QQuickOverlay::overlay(window), QPoint(0, 0), 15)); + + if (modal) { + // the content below a modal overlay must not move + QVERIFY(qFuzzyCompare(contentSlider->value(), oldContentValue)); + } else { + // the content below a modeless overlay must move + QVERIFY(!qFuzzyCompare(contentSlider->value(), oldContentValue)); + } + QVERIFY(qFuzzyCompare(popupSlider->value(), oldPopupValue)); // must not have moved + } +} + +void tst_popup::parentDestroyed() +{ + QQuickPopup popup; + popup.setParentItem(new QQuickItem); + delete popup.parentItem(); + QVERIFY(!popup.parentItem()); +} + +void tst_popup::nested() +{ + QQuickApplicationHelper helper(this, QStringLiteral("nested.qml")); + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + QQuickPopup *modalPopup = window->property("modalPopup").value<QQuickPopup *>(); + QVERIFY(modalPopup); + + QQuickPopup *modelessPopup = window->property("modelessPopup").value<QQuickPopup *>(); + QVERIFY(modelessPopup); + + modalPopup->open(); + QCOMPARE(modalPopup->isVisible(), true); + + modelessPopup->open(); + QCOMPARE(modelessPopup->isVisible(), true); + + // click outside the modeless popup on the top, but inside the modal popup below + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, QPoint(150, 150)); + + QTRY_COMPARE(modelessPopup->isVisible(), false); + QCOMPARE(modalPopup->isVisible(), true); +} + +// QTBUG-56697 +void tst_popup::grabber() +{ + QQuickApplicationHelper helper(this, QStringLiteral("grabber.qml")); + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + QQuickPopup *menu = window->property("menu").value<QQuickPopup *>(); + QVERIFY(menu); + + QQuickPopup *popup = window->property("popup").value<QQuickPopup *>(); + QVERIFY(popup); + + QQuickPopup *combo = window->property("combo").value<QQuickPopup *>(); + QVERIFY(combo); + + menu->open(); + QCOMPARE(menu->isVisible(), 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); + QCOMPARE(combo->isVisible(), false); + + combo->open(); + QCOMPARE(menu->isVisible(), false); + QCOMPARE(popup->isVisible(), true); + QCOMPARE(combo->isVisible(), 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); + + menu->open(); + QCOMPARE(menu->isVisible(), 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); + QCOMPARE(popup->isVisible(), false); + QCOMPARE(combo->isVisible(), false); +} + QTEST_MAIN(tst_popup) #include "tst_popup.moc" diff --git a/tests/auto/pressandhold/data/dependencies.qml b/tests/auto/pressandhold/data/dependencies.qml new file mode 100644 index 00000000..caf89569 --- /dev/null +++ b/tests/auto/pressandhold/data/dependencies.qml @@ -0,0 +1,4 @@ +import QtQuick 2.6 +import QtQuick.Controls 2.0 + +Control { } diff --git a/tests/auto/pressandhold/tst_pressandhold.cpp b/tests/auto/pressandhold/tst_pressandhold.cpp index 8c4cf673..713cc60c 100644 --- a/tests/auto/pressandhold/tst_pressandhold.cpp +++ b/tests/auto/pressandhold/tst_pressandhold.cpp @@ -37,13 +37,14 @@ #include <QtTest> #include <QtQuick> -// TODO: add QStyleHints::setMousePressAndHoldInterval() to speedup the test - class tst_PressAndHold : public QObject { Q_OBJECT private slots: + void initTestCase(); + void cleanupTestCase(); + void pressAndHold_data(); void pressAndHold(); @@ -51,14 +52,25 @@ private slots: void keepSelection(); }; +void tst_PressAndHold::initTestCase() +{ + QGuiApplication::styleHints()->setMousePressAndHoldInterval(100); +} + +void tst_PressAndHold::cleanupTestCase() +{ + QGuiApplication::styleHints()->setMousePressAndHoldInterval(-1); +} + void tst_PressAndHold::pressAndHold_data() { QTest::addColumn<QByteArray>("data"); QTest::addColumn<QByteArray>("signal"); - QTest::newRow("Button") << QByteArray("import Qt.labs.controls 1.0; Button { text: 'Button' }") << QByteArray(SIGNAL(pressAndHold())); - QTest::newRow("TextField") << QByteArray("import Qt.labs.controls 1.0; TextField { text: 'TextField' }") << QByteArray(SIGNAL(pressAndHold(QQuickMouseEvent*))); - QTest::newRow("TextArea") << QByteArray("import Qt.labs.controls 1.0; TextArea { text: 'TextArea' }") << QByteArray(SIGNAL(pressAndHold(QQuickMouseEvent*))); + QTest::newRow("Button") << QByteArray("import QtQuick.Controls 2.0; Button { text: 'Button' }") << QByteArray(SIGNAL(pressAndHold())); + QTest::newRow("SwipeDelegate") << QByteArray("import QtQuick.Controls 2.0; SwipeDelegate { text: 'SwipeDelegate' }") << QByteArray(SIGNAL(pressAndHold())); + QTest::newRow("TextField") << QByteArray("import QtQuick.Controls 2.0; TextField { text: 'TextField' }") << QByteArray(SIGNAL(pressAndHold(QQuickMouseEvent*))); + QTest::newRow("TextArea") << QByteArray("import QtQuick.Controls 2.0; TextArea { text: 'TextArea' }") << QByteArray(SIGNAL(pressAndHold(QQuickMouseEvent*))); } void tst_PressAndHold::pressAndHold() @@ -132,8 +144,8 @@ void tst_PressAndHold::keepSelection_data() { QTest::addColumn<QByteArray>("data"); - QTest::newRow("TextField") << QByteArray("import Qt.labs.controls 1.0; TextField { text: 'TextField' }"); - QTest::newRow("TextArea") << QByteArray("import Qt.labs.controls 1.0; TextArea { text: 'TextArea' }"); + QTest::newRow("TextField") << QByteArray("import QtQuick.Controls 2.0; TextField { text: 'TextField' }"); + QTest::newRow("TextArea") << QByteArray("import QtQuick.Controls 2.0; TextArea { text: 'TextArea' }"); } void tst_PressAndHold::keepSelection() diff --git a/tests/auto/material/data/tst_material.qml b/tests/auto/qquickmaterialstyle/data/tst_material.qml index 6e9d742e..e1e100d7 100644 --- a/tests/auto/material/data/tst_material.qml +++ b/tests/auto/qquickmaterialstyle/data/tst_material.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. +** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. @@ -41,8 +41,9 @@ import QtQuick 2.2 import QtQuick.Window 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 -import Qt.labs.controls.material 1.0 +import QtQuick.Templates 2.0 as T +import QtQuick.Controls 2.0 +import QtQuick.Controls.Material 2.0 TestCase { id: testCase @@ -63,6 +64,8 @@ TestCase { Material.theme: Material.Dark Material.primary: Material.DeepOrange Material.accent: Material.DeepPurple + Material.background: Material.Green + Material.foreground: Material.Blue } } @@ -72,11 +75,18 @@ TestCase { } Component { + id: applicationWindow + ApplicationWindow { } + } + + Component { id: styledWindow Window { Material.theme: Material.Dark Material.primary: Material.Brown Material.accent: Material.Green + Material.background: Material.Yellow + Material.foreground: Material.Grey } } @@ -118,6 +128,7 @@ TestCase { visible: true property alias popup: popupInstance property alias label: labelInstance + property alias label2: labelInstance2 Popup { id: popupInstance Label { @@ -127,6 +138,14 @@ TestCase { } Component.onCompleted: open() } + T.Popup { + contentItem: Label { + id: labelInstance2 + text: "test" + color: Material.textSelectionColor + } + Component.onCompleted: open() + } } } @@ -158,12 +177,22 @@ TestCase { } } + // need to be synced with QQuickMaterialStyle::themeShade() + function themeshade(theme) { + if (theme === Material.Light) + return Material.Shade500 + else + return Material.Shade200 + } + function test_defaults() { var control = button.createObject(testCase) verify(control) verify(control.Material) compare(control.Material.primary, Material.color(Material.Indigo)) compare(control.Material.accent, Material.color(Material.Pink)) + compare(control.Material.foreground, "#dd000000") + compare(control.Material.background, "#fafafa") compare(control.Material.theme, Material.Light) control.destroy() } @@ -173,9 +202,13 @@ TestCase { verify(control) control.Material.primary = Material.Green control.Material.accent = Material.Brown + control.Material.background = Material.Red + control.Material.foreground = Material.Blue control.Material.theme = Material.Dark compare(control.Material.primary, Material.color(Material.Green)) - compare(control.Material.accent, Material.color(Material.Brown)) + compare(control.Material.accent, Material.color(Material.Brown, themeshade(control.Material.theme))) + compare(control.Material.background, Material.color(Material.Red, themeshade(control.Material.theme))) + compare(control.Material.foreground, Material.color(Material.Blue)) compare(control.Material.theme, Material.Dark) control.destroy() } @@ -184,13 +217,19 @@ TestCase { var control = styledButton.createObject(testCase) verify(control) compare(control.Material.primary, Material.color(Material.DeepOrange)) - compare(control.Material.accent, Material.color(Material.DeepPurple)) + compare(control.Material.accent, Material.color(Material.DeepPurple, themeshade(control.Material.theme))) + compare(control.Material.background, Material.color(Material.Green, themeshade(control.Material.theme))) + compare(control.Material.foreground, Material.color(Material.Blue)) compare(control.Material.theme, Material.Dark) control.Material.primary = undefined control.Material.accent = undefined + control.Material.background = undefined + control.Material.foreground = undefined control.Material.theme = undefined compare(control.Material.primary, testCase.Material.primary) compare(control.Material.accent, testCase.Material.accent) + compare(control.Material.background, testCase.Material.background) + compare(control.Material.foreground, testCase.Material.foreground) compare(control.Material.theme, testCase.Material.theme) control.destroy() } @@ -199,6 +238,8 @@ TestCase { return [ { tag: "primary", value1: Material.color(Material.Amber), value2: Material.color(Material.Indigo) }, { tag: "accent", value1: Material.color(Material.Amber), value2: Material.color(Material.Indigo) }, + { tag: "background", value1: Material.color(Material.Amber), value2: Material.color(Material.Indigo) }, + { tag: "foreground", value1: Material.color(Material.Amber), value2: Material.color(Material.Indigo) }, { tag: "theme", value1: Material.Dark, value2: Material.Light }, ] } @@ -260,16 +301,19 @@ TestCase { var popupObject = popupComponent.createObject(testCase) compare(popupObject.popup.Material.textSelectionColor.toString(), popupObject.Material.textSelectionColor.toString()) compare(popupObject.label.color.toString(), popupObject.Material.textSelectionColor.toString()) + compare(popupObject.label2.color.toString(), popupObject.Material.textSelectionColor.toString()) popupObject.Material[prop] = data.value1 compare(popupObject.Material[prop], data.value1) compare(popupObject.popup.Material.textSelectionColor.toString(), popupObject.Material.textSelectionColor.toString()) compare(popupObject.label.color.toString(), popupObject.Material.textSelectionColor.toString()) + compare(popupObject.label2.color.toString(), popupObject.Material.textSelectionColor.toString()) popupObject.Material[prop] = data.value2 compare(popupObject.Material[prop], data.value2) compare(popupObject.popup.Material.textSelectionColor.toString(), popupObject.Material.textSelectionColor.toString()) compare(popupObject.label.color.toString(), popupObject.Material.textSelectionColor.toString()) + compare(popupObject.label2.color.toString(), popupObject.Material.textSelectionColor.toString()) popupObject.destroy() } @@ -280,16 +324,22 @@ TestCase { var control = button.createObject(parent.contentItem) compare(control.Material.primary, parent.Material.primary) compare(control.Material.accent, parent.Material.accent) + compare(control.Material.background, parent.Material.background) + compare(control.Material.foreground, parent.Material.foreground) compare(control.Material.theme, parent.Material.theme) var styledChild = styledWindow.createObject(window) verify(styledChild.Material.primary !== parent.Material.primary) verify(styledChild.Material.accent !== parent.Material.accent) + verify(styledChild.Material.background !== parent.Material.background) + verify(styledChild.Material.foreground !== parent.Material.foreground) verify(styledChild.Material.theme !== parent.Material.theme) var unstyledChild = window.createObject(window) compare(unstyledChild.Material.primary, parent.Material.primary) compare(unstyledChild.Material.accent, parent.Material.accent) + compare(unstyledChild.Material.background, parent.Material.background) + compare(unstyledChild.Material.foreground, parent.Material.foreground) compare(unstyledChild.Material.theme, parent.Material.theme) parent.Material.primary = Material.Lime @@ -302,6 +352,16 @@ TestCase { verify(styledChild.Material.accent !== Material.color(Material.Cyan)) // ### TODO: compare(unstyledChild.Material.accent, Material.color(Material.Cyan)) + parent.Material.background = Material.Indigo + compare(control.Material.background, Material.color(Material.Indigo)) + verify(styledChild.Material.background !== Material.color(Material.Indigo)) + // ### TODO: compare(unstyledChild.Material.background, Material.color(Material.Indigo)) + + parent.Material.foreground = Material.Pink + compare(control.Material.foreground, Material.color(Material.Pink)) + verify(styledChild.Material.foreground !== Material.color(Material.Pink)) + // ### TODO: compare(unstyledChild.Material.foreground, Material.color(Material.Pink)) + parent.destroy() } @@ -309,19 +369,31 @@ TestCase { var control = loader.createObject(testCase) control.Material.primary = Material.Yellow control.Material.accent = Material.Lime + control.Material.background = Material.LightGreen + control.Material.foreground = Material.LightBlue control.active = true compare(control.item.Material.primary, Material.color(Material.Yellow)) compare(control.item.Material.accent, Material.color(Material.Lime)) + compare(control.item.Material.background, Material.color(Material.LightGreen)) + compare(control.item.Material.foreground, Material.color(Material.LightBlue)) control.Material.primary = Material.Red control.Material.accent = Material.Pink + control.Material.background = Material.Blue + control.Material.foreground = Material.Green compare(control.item.Material.primary, Material.color(Material.Red)) compare(control.item.Material.accent, Material.color(Material.Pink)) + compare(control.item.Material.background, Material.color(Material.Blue)) + compare(control.item.Material.foreground, Material.color(Material.Green)) control.active = false control.Material.primary = Material.Orange control.Material.accent = Material.Brown + control.Material.background = Material.Red + control.Material.foreground = Material.Pink control.active = true compare(control.item.Material.primary, Material.color(Material.Orange)) compare(control.item.Material.accent, Material.color(Material.Brown)) + compare(control.item.Material.background, Material.color(Material.Red)) + compare(control.item.Material.foreground, Material.color(Material.Pink)) control.destroy() } @@ -350,8 +422,8 @@ TestCase { compare(container.menu.Material.primary, Material.color(Material.Blue)) compare(child.Material.primary, Material.color(Material.Blue)) compare(container.Material.accent, Material.color(Material.Red)) - compare(container.menu.Material.accent, Material.color(Material.Red)) - compare(child.Material.accent, Material.color(Material.Red)) + compare(container.menu.Material.accent, Material.color(Material.Red, themeshade(container.menu.Material.theme))) + compare(child.Material.accent, Material.color(Material.Red, themeshade(child.Material.theme))) container.destroy() } @@ -375,15 +447,34 @@ TestCase { compare(window.combo.Material.primary, Material.color(Material.Blue)) compare(child.Material.primary, Material.color(Material.Blue)) compare(window.Material.accent, Material.color(Material.Red)) - compare(window.combo.Material.accent, Material.color(Material.Red)) - compare(child.Material.accent, Material.color(Material.Red)) + compare(window.combo.Material.accent, Material.color(Material.Red, themeshade(window.combo.Material.theme))) + compare(child.Material.accent, Material.color(Material.Red, themeshade(child.Material.theme))) window.destroy() } + function test_windowChange() { + var ldr = loader.createObject() + verify(ldr) + + var wnd = window.createObject() + verify(wnd) + + wnd.Material.theme = Material.Dark + compare(wnd.Material.theme, Material.Dark) + + ldr.active = true + verify(ldr.item) + compare(ldr.item.Material.theme, Material.Light) + + ldr.parent = wnd.contentItem + compare(ldr.item.Material.theme, Material.Dark) + + wnd.destroy() + } function test_colors_data() { return [ - { tag: "primary" }, { tag: "accent" } + { tag: "primary" }, { tag: "accent" }, { tag: "background" }, { tag: "foreground" } ] } @@ -422,11 +513,11 @@ TestCase { compare(control.Material[prop], "#80808080") // unknown - ignoreWarning(Qt.resolvedUrl("tst_material.qml") + ":57:9: QML Button: unknown Material." + prop + " value: 123") + ignoreWarning(Qt.resolvedUrl("tst_material.qml") + ":58:9: QML Button: unknown Material." + prop + " value: 123") control.Material[prop] = 123 - ignoreWarning(Qt.resolvedUrl("tst_material.qml") + ":57:9: QML Button: unknown Material." + prop + " value: foo") + ignoreWarning(Qt.resolvedUrl("tst_material.qml") + ":58:9: QML Button: unknown Material." + prop + " value: foo") control.Material[prop] = "foo" - ignoreWarning(Qt.resolvedUrl("tst_material.qml") + ":57:9: QML Button: unknown Material." + prop + " value: #1") + ignoreWarning(Qt.resolvedUrl("tst_material.qml") + ":58:9: QML Button: unknown Material." + prop + " value: #1") control.Material[prop] = "#1" control.destroy() @@ -450,6 +541,18 @@ TestCase { {tag: "ItemDelegate:weight", type: "ItemDelegate", attribute: "weight", value: Font.Medium, window: Font.Black, pane: Font.Bold}, {tag: "ItemDelegate:capitalization", type: "ItemDelegate", attribute: "capitalization", value: Font.MixedCase, window: Font.Capitalize, pane: Font.AllLowercase}, + {tag: "CheckDelegate:pixelSize", type: "CheckDelegate", attribute: "pixelSize", value: 16, window: 20, pane: 10}, + {tag: "CheckDelegate:weight", type: "CheckDelegate", attribute: "weight", value: Font.Normal, window: Font.Black, pane: Font.Bold}, + {tag: "CheckDelegate:capitalization", type: "CheckDelegate", attribute: "capitalization", value: Font.MixedCase, window: Font.Capitalize, pane: Font.AllLowercase}, + + {tag: "RadioDelegate:pixelSize", type: "RadioDelegate", attribute: "pixelSize", value: 16, window: 20, pane: 10}, + {tag: "RadioDelegate:weight", type: "RadioDelegate", attribute: "weight", value: Font.Normal, window: Font.Black, pane: Font.Bold}, + {tag: "RadioDelegate:capitalization", type: "RadioDelegate", attribute: "capitalization", value: Font.MixedCase, window: Font.Capitalize, pane: Font.AllLowercase}, + + {tag: "SwitchDelegate:pixelSize", type: "SwitchDelegate", attribute: "pixelSize", value: 16, window: 20, pane: 10}, + {tag: "SwitchDelegate:weight", type: "SwitchDelegate", attribute: "weight", value: Font.Normal, window: Font.Black, pane: Font.Bold}, + {tag: "SwitchDelegate:capitalization", type: "SwitchDelegate", attribute: "capitalization", value: Font.MixedCase, window: Font.Capitalize, pane: Font.AllLowercase}, + {tag: "Label:pixelSize", type: "Label", attribute: "pixelSize", value: 14, window: 20, pane: 10}, {tag: "Label:weight", type: "Label", attribute: "weight", value: Font.Normal, window: Font.Black, pane: Font.Bold}, {tag: "Label:capitalization", type: "Label", attribute: "capitalization", value: Font.MixedCase, window: Font.Capitalize, pane: Font.AllLowercase}, @@ -472,7 +575,19 @@ TestCase { {tag: "ComboBox:pixelSize", type: "ComboBox", attribute: "pixelSize", value: 16, window: 20, pane: 10}, {tag: "ComboBox:weight", type: "ComboBox", attribute: "weight", value: Font.Normal, window: Font.Black, pane: Font.Bold}, - {tag: "ComboBox:capitalization", type: "ComboBox", attribute: "capitalization", value: Font.MixedCase, window: Font.Capitalize, pane: Font.AllLowercase} + {tag: "ComboBox:capitalization", type: "ComboBox", attribute: "capitalization", value: Font.MixedCase, window: Font.Capitalize, pane: Font.AllLowercase}, + + {tag: "TextField:pixelSize", type: "TextField", attribute: "pixelSize", value: 16, window: 20, pane: 10}, + {tag: "TextField:weight", type: "TextField", attribute: "weight", value: Font.Normal, window: Font.Black, pane: Font.Bold}, + {tag: "TextField:capitalization", type: "TextField", attribute: "capitalization", value: Font.MixedCase, window: Font.Capitalize, pane: Font.AllLowercase}, + + {tag: "TextArea:pixelSize", type: "TextArea", attribute: "pixelSize", value: 16, window: 20, pane: 10}, + {tag: "TextArea:weight", type: "TextArea", attribute: "weight", value: Font.Normal, window: Font.Black, pane: Font.Bold}, + {tag: "TextArea:capitalization", type: "TextArea", attribute: "capitalization", value: Font.MixedCase, window: Font.Capitalize, pane: Font.AllLowercase}, + + {tag: "SpinBox:pixelSize", type: "SpinBox", attribute: "pixelSize", value: 16, window: 20, pane: 10}, + {tag: "SpinBox:weight", type: "SpinBox", attribute: "weight", value: Font.Normal, window: Font.Black, pane: Font.Bold}, + {tag: "SpinBox:capitalization", type: "SpinBox", attribute: "capitalization", value: Font.MixedCase, window: Font.Capitalize, pane: Font.AllLowercase} ] } @@ -481,7 +596,7 @@ TestCase { verify(window) verify(window.pane) - var control = Qt.createQmlObject("import Qt.labs.controls 1.0; " + data.type + " { }", window.pane) + var control = Qt.createQmlObject("import QtQuick.Controls 2.0; " + data.type + " { }", window.pane) verify(control) compare(control.font[data.attribute], data.value) @@ -503,4 +618,91 @@ TestCase { window.destroy() } + + Component { + id: backgroundControls + ApplicationWindow { + id: window + property Button button: Button { } + property ComboBox combobox: ComboBox { } + property Drawer drawer: Drawer { } + property GroupBox groupbox: GroupBox { Material.elevation: 10 } + property Frame frame: Frame { Material.elevation: 10 } + property Menu menu: Menu { } + property Page page: Page { } + property Pane pane: Pane { } + property Popup popup: Popup { } + property TabBar tabbar: TabBar { } + property ToolBar toolbar: ToolBar { } + property ToolTip tooltip: ToolTip { } + } + } + + function test_background_data() { + return [ + { tag: "button", inherit: false, wait: 400 }, + { tag: "combobox", inherit: false, wait: 400 }, + { tag: "drawer", inherit: true }, + { tag: "groupbox", inherit: true }, + { tag: "frame", inherit: true }, + { tag: "menu", inherit: true }, + { tag: "page", inherit: true }, + { tag: "pane", inherit: true }, + { tag: "popup", inherit: true }, + { tag: "tabbar", inherit: true }, + { tag: "toolbar", inherit: false }, + { tag: "tooltip", inherit: false } + ] + } + + function test_background(data) { + var window = backgroundControls.createObject(testCase) + verify(window) + + var control = window[data.tag] + verify(control) + + control.parent = window.contentItem + control.visible = true + + var defaultBackground = control.background.color + + window.Material.background = "#ff0000" + compare(window.color, "#ff0000") + + // For controls that have an animated background color, we wait the length + // of the color animation to be sure that the color hasn't actually changed. + if (data.wait) + wait(data.wait) + + // We want the control's background color to be equal to the window's background + // color, because we want the color to propagate to items that might actually use + // it... Button, ComboBox, ToolBar and ToolTip have a special background color, + // so they don't use the generic background color unless explicitly set, so we + // compare the actual background rect color instead. + if (data.inherit) + compare(control.background.color, "#ff0000") + else + compare(control.background.color, defaultBackground) + + control.Material.background = "#0000ff" + tryCompare(control.background, "color", "#0000ff") + + window.destroy() + } + + Component { + id: busyIndicator + BusyIndicator { } + } + + function test_shade() { + var control = busyIndicator.createObject(testCase) + + compare(control.contentItem.color.toString(), Material.color(Material.Pink, Material.Shade500)) + control.Material.theme = Material.Dark + compare(control.contentItem.color.toString(), Material.color(Material.Pink, Material.Shade200)) + + control.destroy() + } } diff --git a/tests/auto/material/material.pro b/tests/auto/qquickmaterialstyle/qquickmaterialstyle.pro index 52663fdc..eac9bdc4 100644 --- a/tests/auto/material/material.pro +++ b/tests/auto/qquickmaterialstyle/qquickmaterialstyle.pro @@ -1,12 +1,12 @@ TEMPLATE = app -TARGET = tst_material +TARGET = tst_qquickmaterialstyle CONFIG += qmltestcase SOURCES += \ - $$PWD/tst_material.cpp + $$PWD/tst_qquickmaterialstyle.cpp RESOURCES += \ - $$PWD/material.qrc + $$PWD/qquickmaterialstyle.qrc OTHER_FILES += \ $$PWD/data/* diff --git a/tests/auto/material/material.qrc b/tests/auto/qquickmaterialstyle/qquickmaterialstyle.qrc index 1df3aef9..53ba6450 100644 --- a/tests/auto/material/material.qrc +++ b/tests/auto/qquickmaterialstyle/qquickmaterialstyle.qrc @@ -1,5 +1,5 @@ <!DOCTYPE RCC><RCC version="1.0"> <qresource> - <file>qtlabscontrols.conf</file> + <file>qtquickcontrols2.conf</file> </qresource> </RCC> diff --git a/tests/auto/material/qtlabscontrols.conf b/tests/auto/qquickmaterialstyle/qtquickcontrols2.conf index b6c7c87e..b6c7c87e 100644 --- a/tests/auto/material/qtlabscontrols.conf +++ b/tests/auto/qquickmaterialstyle/qtquickcontrols2.conf diff --git a/tests/auto/controls/tst_controls.cpp b/tests/auto/qquickmaterialstyle/tst_qquickmaterialstyle.cpp index 89cc39f0..eeee1e87 100644 --- a/tests/auto/controls/tst_controls.cpp +++ b/tests/auto/qquickmaterialstyle/tst_qquickmaterialstyle.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. +** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. @@ -35,4 +35,4 @@ ****************************************************************************/ #include <QtQuickTest/quicktest.h> -QUICK_TEST_MAIN(tst_controls) +QUICK_TEST_MAIN(tst_qquickmaterialstyle) diff --git a/tests/auto/qquickmaterialstyleconf/data/applicationwindow.qml b/tests/auto/qquickmaterialstyleconf/data/applicationwindow.qml new file mode 100644 index 00000000..a1657a69 --- /dev/null +++ b/tests/auto/qquickmaterialstyleconf/data/applicationwindow.qml @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.7 +import QtQuick.Controls 2.0 + +ApplicationWindow { + width: 400 + height: 400 + + property alias label: label + + Label { + id: label + } +} diff --git a/tests/auto/qquickmaterialstyleconf/qquickmaterialstyleconf.pro b/tests/auto/qquickmaterialstyleconf/qquickmaterialstyleconf.pro new file mode 100644 index 00000000..fe8953e9 --- /dev/null +++ b/tests/auto/qquickmaterialstyleconf/qquickmaterialstyleconf.pro @@ -0,0 +1,17 @@ +CONFIG += testcase +TARGET = tst_qquickmaterialstyleconf +SOURCES += tst_qquickmaterialstyleconf.cpp + +macos:CONFIG -= app_bundle + +QT += core-private gui-private qml-private quick-private testlib quicktemplates2-private quickcontrols2-private + +include (../shared/util.pri) + +RESOURCES += qquickmaterialstyleconf.qrc + +TESTDATA = data/* + +OTHER_FILES += \ + data/* + diff --git a/tests/auto/universal/universal.qrc b/tests/auto/qquickmaterialstyleconf/qquickmaterialstyleconf.qrc index 1df3aef9..53ba6450 100644 --- a/tests/auto/universal/universal.qrc +++ b/tests/auto/qquickmaterialstyleconf/qquickmaterialstyleconf.qrc @@ -1,5 +1,5 @@ <!DOCTYPE RCC><RCC version="1.0"> <qresource> - <file>qtlabscontrols.conf</file> + <file>qtquickcontrols2.conf</file> </qresource> </RCC> diff --git a/tests/auto/qquickmaterialstyleconf/qtquickcontrols2.conf b/tests/auto/qquickmaterialstyleconf/qtquickcontrols2.conf new file mode 100644 index 00000000..78634834 --- /dev/null +++ b/tests/auto/qquickmaterialstyleconf/qtquickcontrols2.conf @@ -0,0 +1,6 @@ +[Controls] +Style=Material + +[Material] +Background=#444444 +Foreground=Red diff --git a/tests/auto/qquickmaterialstyleconf/tst_qquickmaterialstyleconf.cpp b/tests/auto/qquickmaterialstyleconf/tst_qquickmaterialstyleconf.cpp new file mode 100644 index 00000000..c0db7c49 --- /dev/null +++ b/tests/auto/qquickmaterialstyleconf/tst_qquickmaterialstyleconf.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qtest.h> +#include <QtQuick/private/qquickitem_p.h> +#include "../shared/util.h" +#include "../shared/visualtestutil.h" + +using namespace QQuickVisualTestUtil; + +class tst_qquickmaterialstyleconf : public QQmlDataTest +{ + Q_OBJECT + +public: + +private slots: + void conf(); +}; + +void tst_qquickmaterialstyleconf::conf() +{ + QQuickApplicationHelper helper(this, QLatin1String("applicationwindow.qml")); + + QQuickApplicationWindow *window = helper.appWindow; + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + // We specified a custom background color, so the window should have it. + QCOMPARE(window->property("color").value<QColor>(), QColor("#444444")); + + // We specified a custom foreground color, so the label should have it. + QQuickItem *label = window->property("label").value<QQuickItem*>(); + QVERIFY(label); + QCOMPARE(label->property("color").value<QColor>(), QColor("#F44336")); +} + +QTEST_MAIN(tst_qquickmaterialstyleconf) + +#include "tst_qquickmaterialstyleconf.moc" diff --git a/tests/auto/qquickstyle/qquickstyle.pro b/tests/auto/qquickstyle/qquickstyle.pro new file mode 100644 index 00000000..b6173c1b --- /dev/null +++ b/tests/auto/qquickstyle/qquickstyle.pro @@ -0,0 +1,7 @@ +CONFIG += testcase +TARGET = tst_qquickstyle +SOURCES += tst_qquickstyle.cpp + +osx:CONFIG -= app_bundle + +QT += quickcontrols2 testlib diff --git a/tests/auto/qquickstyle/tst_qquickstyle.cpp b/tests/auto/qquickstyle/tst_qquickstyle.cpp new file mode 100644 index 00000000..b4da3045 --- /dev/null +++ b/tests/auto/qquickstyle/tst_qquickstyle.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/qtest.h> +#include <QtQml/qqmlengine.h> +#include <QtQml/qqmlcomponent.h> +#include <QtQuickControls2/qquickstyle.h> + +class tst_QQuickStyle : public QObject +{ + Q_OBJECT + +private slots: + void lookup(); +}; + +void tst_QQuickStyle::lookup() +{ + QVERIFY(QQuickStyle::name().isEmpty()); + QVERIFY(!QQuickStyle::path().isEmpty()); + + QQuickStyle::setStyle("material"); + QCOMPARE(QQuickStyle::name(), QString("Material")); + QVERIFY(!QQuickStyle::path().isEmpty()); + + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData("import QtQuick 2.0; import QtQuick.Controls 2.0; Control { }", QUrl()); + + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + + QCOMPARE(QQuickStyle::name(), QString("Material")); + QVERIFY(!QQuickStyle::path().isEmpty()); +} + +QTEST_MAIN(tst_QQuickStyle) + +#include "tst_qquickstyle.moc" diff --git a/tests/auto/qquickstyleselector/ResourceStyle/Button.qml b/tests/auto/qquickstyleselector/ResourceStyle/Button.qml new file mode 100644 index 00000000..5b08222c --- /dev/null +++ b/tests/auto/qquickstyleselector/ResourceStyle/Button.qml @@ -0,0 +1,2 @@ +import QtQuick.Templates 2.0 as T +T.Button { } diff --git a/tests/auto/qquickstyleselector/data/Button.qml b/tests/auto/qquickstyleselector/data/Button.qml new file mode 100644 index 00000000..5b08222c --- /dev/null +++ b/tests/auto/qquickstyleselector/data/Button.qml @@ -0,0 +1,2 @@ +import QtQuick.Templates 2.0 as T +T.Button { } diff --git a/tests/auto/qquickstyleselector/data/FileSystemStyle/Button.qml b/tests/auto/qquickstyleselector/data/FileSystemStyle/Button.qml new file mode 100644 index 00000000..5b08222c --- /dev/null +++ b/tests/auto/qquickstyleselector/data/FileSystemStyle/Button.qml @@ -0,0 +1,2 @@ +import QtQuick.Templates 2.0 as T +T.Button { } diff --git a/tests/auto/qquickstyleselector/qquickstyleselector.pro b/tests/auto/qquickstyleselector/qquickstyleselector.pro new file mode 100644 index 00000000..c56e5732 --- /dev/null +++ b/tests/auto/qquickstyleselector/qquickstyleselector.pro @@ -0,0 +1,19 @@ +CONFIG += testcase +TARGET = tst_qquickstyleselector +SOURCES += tst_qquickstyleselector.cpp + +osx:CONFIG -= app_bundle + +QT += core-private gui-private qml-private quick-private quickcontrols2-private testlib + +include (../shared/util.pri) + +resourcestyle.prefix = / +resourcestyle.files += $$PWD/ResourceStyle/Button.qml +RESOURCES += resourcestyle + +TESTDATA = data/* + +OTHER_FILES += \ + data/* + diff --git a/tests/auto/qquickstyleselector/tst_qquickstyleselector.cpp b/tests/auto/qquickstyleselector/tst_qquickstyleselector.cpp new file mode 100644 index 00000000..6c2aebe4 --- /dev/null +++ b/tests/auto/qquickstyleselector/tst_qquickstyleselector.cpp @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/qtest.h> +#include <QtQuickControls2/qquickstyle.h> +#include <QtQuickControls2/private/qquickstyleselector_p.h> +#include "../shared/util.h" + +class tst_QQuickStyleSelector : public QQmlDataTest +{ + Q_OBJECT + +private slots: + void select_data(); + void select(); +}; + +void tst_QQuickStyleSelector::select_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<QString>("style"); + QTest::addColumn<QString>("path"); + QTest::addColumn<QString>("expected"); + + QTest::newRow("empty") << "Button.qml" << "" << dataDirectory() << testFileUrl("Button.qml").toString(); + QTest::newRow("no such dir") << "Button.qml" << "Foo" << dataDirectory() << testFileUrl("Button.qml").toString(); + QTest::newRow("no such file") << "Foo.qml" << "FileSystemStyle" << dataDirectory() << testFileUrl("Foo.qml").toString(); + QTest::newRow("relative/path/to/FileSystemStyle") << "Button.qml" << "FileSystemStyle" << "data" << testFileUrl("FileSystemStyle/Button.qml").toString(); + QTest::newRow("/absolute/path/to/FileSystemStyle") << "Button.qml" << "FileSystemStyle" << dataDirectory() << testFileUrl("FileSystemStyle/Button.qml").toString(); + QTest::newRow(":/ResourceStyle") << "Button.qml" << "ResourceStyle" << ":/" << "qrc:/ResourceStyle/Button.qml"; + QTest::newRow("qrc:/ResourceStyle") << "Button.qml" << "ResourceStyle" << "qrc:/" << "qrc:/ResourceStyle/Button.qml"; +} + +void tst_QQuickStyleSelector::select() +{ + QFETCH(QString, file); + QFETCH(QString, style); + QFETCH(QString, path); + QFETCH(QString, expected); + + QQuickStyle::setStyle(QDir(path).filePath(style)); + + QQuickStyleSelector selector; + selector.setBaseUrl(dataDirectoryUrl()); + QCOMPARE(selector.select(file), expected); +} + +QTEST_MAIN(tst_QQuickStyleSelector) + +#include "tst_qquickstyleselector.moc" diff --git a/tests/auto/universal/data/tst_universal.qml b/tests/auto/qquickuniversalstyle/data/tst_universal.qml index 27ffae9e..7ee14da8 100644 --- a/tests/auto/universal/data/tst_universal.qml +++ b/tests/auto/qquickuniversalstyle/data/tst_universal.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. +** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. @@ -41,8 +41,8 @@ import QtQuick 2.2 import QtQuick.Window 2.2 import QtTest 1.0 -import Qt.labs.controls 1.0 -import Qt.labs.controls.universal 1.0 +import QtQuick.Controls 2.0 +import QtQuick.Controls.Universal 2.0 TestCase { id: testCase @@ -62,6 +62,8 @@ TestCase { Button { Universal.theme: Universal.Dark Universal.accent: Universal.Violet + Universal.foreground: Universal.Brown + Universal.background: Universal.Yellow } } @@ -139,6 +141,8 @@ TestCase { verify(control) verify(control.Universal) compare(control.Universal.accent, "#3e65ff") // Universal.Cobalt + compare(control.Universal.foreground, "#000000") // SystemBaseHighColor + compare(control.Universal.background, "#ffffff") // SystemAltHighColor compare(control.Universal.theme, Universal.Light) control.destroy() } @@ -147,8 +151,12 @@ TestCase { var control = button.createObject(testCase) verify(control) control.Universal.accent = Universal.Steel + control.Universal.foreground = Universal.Red + control.Universal.background = Universal.Green control.Universal.theme = Universal.Dark compare(control.Universal.accent, "#647687") // Universal.Steel + compare(control.Universal.foreground, "#e51400") // Universal.Red + compare(control.Universal.background, "#60a917") // Universal.Green compare(control.Universal.theme, Universal.Dark) control.destroy() } @@ -157,10 +165,16 @@ TestCase { var control = styledButton.createObject(testCase) verify(control) compare(control.Universal.accent, "#aa00ff") // Universal.Violet + compare(control.Universal.foreground, "#825a2c") // Universal.Brown + compare(control.Universal.background, "#e3c800") // Universal.Yellow compare(control.Universal.theme, Universal.Dark) control.Universal.accent = undefined + control.Universal.foreground = undefined + control.Universal.background = undefined control.Universal.theme = undefined compare(control.Universal.accent, testCase.Universal.accent) + compare(control.Universal.foreground, testCase.Universal.foreground) + compare(control.Universal.background, testCase.Universal.background) compare(control.Universal.theme, testCase.Universal.theme) control.destroy() } @@ -168,6 +182,8 @@ TestCase { function test_inheritance_data() { return [ { tag: "accent", value1: "#a20025" /*Universal.Crimson*/, value2: "#6a00ff" /*Universal.Indigo*/ }, + { tag: "foreground", value1: "#a20025" /*Universal.Crimson*/, value2: "#6a00ff" /*Universal.Indigo*/ }, + { tag: "background", value1: "#a20025" /*Universal.Crimson*/, value2: "#6a00ff" /*Universal.Indigo*/ }, { tag: "theme", value1: Universal.Dark, value2: Universal.Light }, ] } @@ -302,45 +318,73 @@ TestCase { window.destroy() } - function test_colors() { + function test_windowChange() { + var ldr = loader.createObject() + verify(ldr) + + var wnd = window.createObject() + verify(wnd) + + wnd.Universal.theme = Universal.Dark + compare(wnd.Universal.theme, Universal.Dark) + + ldr.active = true + verify(ldr.item) + compare(ldr.item.Universal.theme, Universal.Light) + + ldr.parent = wnd.contentItem + compare(ldr.item.Universal.theme, Universal.Dark) + + wnd.destroy() + } + + function test_colors_data() { + return [ + { tag: "accent" }, { tag: "background" }, { tag: "foreground" } + ] + } + + function test_colors(data) { var control = button.createObject(testCase) verify(control) - // Universal.Accent - enum - control.Universal.accent = Universal.Red - compare(control.Universal.accent, "#e51400") + var prop = data.tag + + // Universal.Color - enum + control.Universal[prop] = Universal.Red + compare(control.Universal[prop], "#e51400") - // Universal.Accent - string - control.Universal.accent = "Emerald" - compare(control.Universal.accent, "#008a00") + // Universal.Color - string + control.Universal[prop] = "Emerald" + compare(control.Universal[prop], "#008a00") // SVG named color - control.Universal.accent = "tomato" - compare(control.Universal.accent, "#ff6347") + control.Universal[prop] = "tomato" + compare(control.Universal[prop], "#ff6347") // #rrggbb - control.Universal.accent = "#123456" - compare(control.Universal.accent, "#123456") + control.Universal[prop] = "#123456" + compare(control.Universal[prop], "#123456") // #aarrggbb - control.Universal.accent = "#12345678" - compare(control.Universal.accent, "#12345678") + control.Universal[prop] = "#12345678" + compare(control.Universal[prop], "#12345678") // Qt.rgba() - no alpha - control.Universal.accent = Qt.rgba(0.5, 0.5, 0.5) - compare(control.Universal.accent, "#808080") + control.Universal[prop] = Qt.rgba(0.5, 0.5, 0.5) + compare(control.Universal[prop], "#808080") // Qt.rgba() - with alpha - control.Universal.accent = Qt.rgba(0.5, 0.5, 0.5, 0.5) - compare(control.Universal.accent, "#80808080") + control.Universal[prop] = Qt.rgba(0.5, 0.5, 0.5, 0.5) + compare(control.Universal[prop], "#80808080") // unknown - ignoreWarning(Qt.resolvedUrl("tst_universal.qml") + ":57:9: QML Button: unknown Universal.accent value: 123") - control.Universal.accent = 123 - ignoreWarning(Qt.resolvedUrl("tst_universal.qml") + ":57:9: QML Button: unknown Universal.accent value: foo") - control.Universal.accent = "foo" - ignoreWarning(Qt.resolvedUrl("tst_universal.qml") + ":57:9: QML Button: unknown Universal.accent value: #1") - control.Universal.accent = "#1" + ignoreWarning(Qt.resolvedUrl("tst_universal.qml") + ":57:9: QML Button: unknown Universal." + prop + " value: 123") + control.Universal[prop] = 123 + ignoreWarning(Qt.resolvedUrl("tst_universal.qml") + ":57:9: QML Button: unknown Universal." + prop + " value: foo") + control.Universal[prop] = "foo" + ignoreWarning(Qt.resolvedUrl("tst_universal.qml") + ":57:9: QML Button: unknown Universal." + prop + " value: #1") + control.Universal[prop] = "#1" control.destroy() } @@ -362,7 +406,7 @@ TestCase { verify(window) verify(window.pane) - var control = Qt.createQmlObject("import Qt.labs.controls 1.0; " + data.type + " { }", window.pane) + var control = Qt.createQmlObject("import QtQuick.Controls 2.0; " + data.type + " { }", window.pane) verify(control) compare(control.font[data.attribute], data.value) diff --git a/tests/auto/universal/universal.pro b/tests/auto/qquickuniversalstyle/qquickuniversalstyle.pro index bb7a85ca..83bd19a5 100644 --- a/tests/auto/universal/universal.pro +++ b/tests/auto/qquickuniversalstyle/qquickuniversalstyle.pro @@ -1,12 +1,12 @@ TEMPLATE = app -TARGET = tst_universal +TARGET = tst_qquickuniversalstyle CONFIG += qmltestcase SOURCES += \ - $$PWD/tst_universal.cpp + $$PWD/tst_qquickuniversalstyle.cpp RESOURCES += \ - $$PWD/universal.qrc + $$PWD/qquickuniversalstyle.qrc OTHER_FILES += \ $$PWD/data/* diff --git a/tests/auto/qquickuniversalstyle/qquickuniversalstyle.qrc b/tests/auto/qquickuniversalstyle/qquickuniversalstyle.qrc new file mode 100644 index 00000000..53ba6450 --- /dev/null +++ b/tests/auto/qquickuniversalstyle/qquickuniversalstyle.qrc @@ -0,0 +1,5 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file>qtquickcontrols2.conf</file> +</qresource> +</RCC> diff --git a/tests/auto/universal/qtlabscontrols.conf b/tests/auto/qquickuniversalstyle/qtquickcontrols2.conf index 8c6dd807..8c6dd807 100644 --- a/tests/auto/universal/qtlabscontrols.conf +++ b/tests/auto/qquickuniversalstyle/qtquickcontrols2.conf diff --git a/tests/auto/material/tst_material.cpp b/tests/auto/qquickuniversalstyle/tst_qquickuniversalstyle.cpp index 5db9c12b..a4033412 100644 --- a/tests/auto/material/tst_material.cpp +++ b/tests/auto/qquickuniversalstyle/tst_qquickuniversalstyle.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. +** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. @@ -35,4 +35,4 @@ ****************************************************************************/ #include <QtQuickTest/quicktest.h> -QUICK_TEST_MAIN(tst_material) +QUICK_TEST_MAIN(tst_qquickuniversalstyle) diff --git a/tests/auto/qquickuniversalstyleconf/data/applicationwindow.qml b/tests/auto/qquickuniversalstyleconf/data/applicationwindow.qml new file mode 100644 index 00000000..a1657a69 --- /dev/null +++ b/tests/auto/qquickuniversalstyleconf/data/applicationwindow.qml @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.7 +import QtQuick.Controls 2.0 + +ApplicationWindow { + width: 400 + height: 400 + + property alias label: label + + Label { + id: label + } +} diff --git a/tests/auto/qquickuniversalstyleconf/qquickuniversalstyleconf.pro b/tests/auto/qquickuniversalstyleconf/qquickuniversalstyleconf.pro new file mode 100644 index 00000000..9aaedbee --- /dev/null +++ b/tests/auto/qquickuniversalstyleconf/qquickuniversalstyleconf.pro @@ -0,0 +1,17 @@ +CONFIG += testcase +TARGET = tst_qquickuniversalstyleconf +SOURCES += tst_qquickuniversalstyleconf.cpp + +macos:CONFIG -= app_bundle + +QT += core-private gui-private qml-private quick-private testlib quicktemplates2-private quickcontrols2-private + +include (../shared/util.pri) + +RESOURCES += qquickuniversalstyleconf.qrc + +TESTDATA = data/* + +OTHER_FILES += \ + data/* + diff --git a/tests/auto/qquickuniversalstyleconf/qquickuniversalstyleconf.qrc b/tests/auto/qquickuniversalstyleconf/qquickuniversalstyleconf.qrc new file mode 100644 index 00000000..53ba6450 --- /dev/null +++ b/tests/auto/qquickuniversalstyleconf/qquickuniversalstyleconf.qrc @@ -0,0 +1,5 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file>qtquickcontrols2.conf</file> +</qresource> +</RCC> diff --git a/tests/auto/qquickuniversalstyleconf/qtquickcontrols2.conf b/tests/auto/qquickuniversalstyleconf/qtquickcontrols2.conf new file mode 100644 index 00000000..836372c9 --- /dev/null +++ b/tests/auto/qquickuniversalstyleconf/qtquickcontrols2.conf @@ -0,0 +1,6 @@ +[Controls] +Style=Universal + +[Universal] +Background=#444444 +Foreground=Red diff --git a/tests/auto/qquickuniversalstyleconf/tst_qquickuniversalstyleconf.cpp b/tests/auto/qquickuniversalstyleconf/tst_qquickuniversalstyleconf.cpp new file mode 100644 index 00000000..ce018a05 --- /dev/null +++ b/tests/auto/qquickuniversalstyleconf/tst_qquickuniversalstyleconf.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qtest.h> +#include <QtQuick/private/qquickitem_p.h> +#include "../shared/util.h" +#include "../shared/visualtestutil.h" + +using namespace QQuickVisualTestUtil; + +class tst_qquickuniversalstyleconf : public QQmlDataTest +{ + Q_OBJECT + +public: + +private slots: + void conf(); +}; + +void tst_qquickuniversalstyleconf::conf() +{ + QQuickApplicationHelper helper(this, QLatin1String("applicationwindow.qml")); + + QQuickApplicationWindow *window = helper.appWindow; + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + // We specified a custom background color, so the window should have it. + QCOMPARE(window->property("color").value<QColor>(), QColor("#444444")); + + // We specified a custom foreground color, so the label should have it. + QQuickItem *label = window->property("label").value<QQuickItem*>(); + QVERIFY(label); + QCOMPARE(label->property("color").value<QColor>(), QColor("#E51400")); +} + +QTEST_MAIN(tst_qquickuniversalstyleconf) + +#include "tst_qquickuniversalstyleconf.moc" diff --git a/tests/auto/sanity/BLACKLIST b/tests/auto/sanity/BLACKLIST index ffff0c96..09cc7f3d 100644 --- a/tests/auto/sanity/BLACKLIST +++ b/tests/auto/sanity/BLACKLIST @@ -8,5 +8,9 @@ * [attachedObjects:material/ComboBox.qml] * +[attachedObjects:material/Switch.qml] +* +[attachedObjects:material/SwitchDelegate.qml] +* [attachedObjects:universal/ComboBox.qml] * diff --git a/tests/auto/sanity/data/dependencies.qml b/tests/auto/sanity/data/dependencies.qml new file mode 100644 index 00000000..caf89569 --- /dev/null +++ b/tests/auto/sanity/data/dependencies.qml @@ -0,0 +1,4 @@ +import QtQuick 2.6 +import QtQuick.Controls 2.0 + +Control { } diff --git a/tests/auto/sanity/tst_sanity.cpp b/tests/auto/sanity/tst_sanity.cpp index bc114d62..23b56384 100644 --- a/tests/auto/sanity/tst_sanity.cpp +++ b/tests/auto/sanity/tst_sanity.cpp @@ -114,7 +114,8 @@ public: QQmlJS::Parser parser(&engine); if (!parser.parse()) { - foreach (const QQmlJS::DiagnosticMessage &msg, parser.diagnosticMessages()) + const auto diagnosticMessages = parser.diagnosticMessages(); + for (const QQmlJS::DiagnosticMessage &msg : diagnosticMessages) m_errors += QString("%s:%d : %s").arg(m_fileName).arg(msg.loc.startLine).arg(msg.message); return false; } @@ -138,10 +139,11 @@ private: void tst_Sanity::initTestCase() { QDirIterator it(QQC2_IMPORT_PATH, QStringList() << "*.qml" << "*.js", QDir::Files, QDirIterator::Subdirectories); + const QStringList excludeDirs = QStringList() << QStringLiteral("snippets") << QStringLiteral("screenshots") << QStringLiteral("designer"); while (it.hasNext()) { it.next(); QFileInfo info = it.fileInfo(); - if (info.dir().dirName() != QStringLiteral("snippets") && info.dir().dirName() != QStringLiteral("designer")) + if (!excludeDirs.contains(info.dir().dirName())) files.insert(info.dir().dirName() + "/" + info.fileName(), info.filePath()); } } @@ -254,12 +256,12 @@ void tst_Sanity::anchors_data() QTest::newRow(qPrintable(it.key())) << it.key() << it.value(); } -static void addTestRows(QQmlEngine *engine, const QString &targetPath, const QStringList &skiplist = QStringList()) +static void addTestRows(QQmlEngine *engine, const QString &sourcePath, const QString &targetPath, const QStringList &skiplist = QStringList()) { // We cannot use QQmlComponent to load QML files directly from the source tree. // For styles that use internal QML types (eg. material/Ripple.qml), the source // dir would be added as an "implicit" import path overriding the actual import - // path (qtbase/qml/Qt/labs/controls/material). => The QML engine fails to load + // path (qtbase/qml/QtQuick/Controls.2/Material). => The QML engine fails to load // the style C++ plugin from the implicit import path (the source dir). // // Therefore we only use the source tree for finding out the set of QML files that @@ -267,14 +269,19 @@ static void addTestRows(QQmlEngine *engine, const QString &targetPath, const QSt // the engine's import path. This way we can use QQmlComponent to load each QML file // for benchmarking. - QFileInfoList entries = QDir(QQC2_IMPORT_PATH + targetPath).entryInfoList(QStringList("*.qml"), QDir::Files); - foreach (const QFileInfo &entry, entries) { + const QFileInfoList entries = QDir(QQC2_IMPORT_PATH "/" + sourcePath).entryInfoList(QStringList("*.qml"), QDir::Files); + for (const QFileInfo &entry : entries) { QString name = entry.baseName(); if (!skiplist.contains(name)) { - foreach (const QString &importPath, engine->importPathList()) { - QString filePath = QDir(importPath + "/Qt/labs/" + targetPath).absoluteFilePath(entry.fileName()); + const auto importPathList = engine->importPathList(); + for (const QString &importPath : importPathList) { + QString name = entry.dir().dirName() + "/" + entry.fileName(); + QString filePath = importPath + "/" + targetPath + "/" + entry.fileName(); if (QFile::exists(filePath)) { - QTest::newRow(qPrintable(entry.dir().dirName() + "/" + entry.fileName())) << QUrl::fromLocalFile(filePath); + QTest::newRow(qPrintable(name)) << QUrl::fromLocalFile(filePath); + break; + } else if (QFile::exists(QQmlFile::urlToLocalFileOrQrc(filePath))) { + QTest::newRow(qPrintable(name)) << QUrl(filePath); break; } } @@ -292,7 +299,7 @@ void tst_Sanity::attachedObjects() QSet<QString> classNames; QScopedPointer<QObject> object(component.create()); QVERIFY2(object.data(), qPrintable(component.errorString())); - foreach (QObject *object, *qt_qobjects) { + for (QObject *object : qAsConst(*qt_qobjects)) { if (object->parent() == &engine) continue; // allow "global" instances QString className = object->metaObject()->className(); @@ -305,10 +312,10 @@ void tst_Sanity::attachedObjects() void tst_Sanity::attachedObjects_data() { QTest::addColumn<QUrl>("url"); - addTestRows(&engine, "/calendar"); - addTestRows(&engine, "/controls"); - addTestRows(&engine, "/controls/material", QStringList() << "Ripple" << "SliderHandle"); - addTestRows(&engine, "/controls/universal"); + addTestRows(&engine, "calendar", "Qt/labs/calendar"); + addTestRows(&engine, "controls", "QtQuick/Controls.2", QStringList() << "CheckIndicator" << "RadioIndicator" << "SwitchIndicator"); + addTestRows(&engine, "controls/material", "QtQuick/Controls.2/Material", QStringList() << "Ripple" << "SliderHandle" << "CheckIndicator" << "RadioIndicator" << "SwitchIndicator" << "BoxShadow" << "ElevationEffect"); + addTestRows(&engine, "controls/universal", "QtQuick/Controls.2/Universal", QStringList() << "CheckIndicator" << "RadioIndicator" << "SwitchIndicator"); } QTEST_MAIN(tst_Sanity) diff --git a/tests/auto/shared/util.pri b/tests/auto/shared/util.pri index 5e6b06b6..03191511 100644 --- a/tests/auto/shared/util.pri +++ b/tests/auto/shared/util.pri @@ -1,4 +1,4 @@ -QT += core-private gui-private qml-private quick-private labstemplates-private +QT += core-private gui-private qml-private quick-private quicktemplates2-private HEADERS += $$PWD/visualtestutil.h \ $$PWD/util.h diff --git a/tests/auto/shared/visualtestutil.h b/tests/auto/shared/visualtestutil.h index b3fecf8e..c67e5bdc 100644 --- a/tests/auto/shared/visualtestutil.h +++ b/tests/auto/shared/visualtestutil.h @@ -42,7 +42,7 @@ #include <QtQuick/private/qquickitem_p.h> -#include <QtLabsTemplates/private/qquickapplicationwindow_p.h> +#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h> #include "util.h" @@ -118,9 +118,10 @@ namespace QQuickVisualTestUtil component.loadUrl(testCase->testFileUrl(testFilePath)); QObject *rootObject = component.create(); cleanup.reset(rootObject); - QVERIFY2(rootObject, qPrintable(QString::fromLatin1("Failed to create ApplicationWindow: %1").arg(component.errorString()))); + QVERIFY2(rootObject, qPrintable(QString::fromLatin1("Failed to create window: %1").arg(component.errorString()))); - window = qobject_cast<QQuickApplicationWindow*>(rootObject); + window = qobject_cast<QQuickWindow*>(rootObject); + appWindow = qobject_cast<QQuickApplicationWindow*>(rootObject); QVERIFY(window); QVERIFY(!window->isVisible()); } @@ -128,7 +129,8 @@ namespace QQuickVisualTestUtil QQmlEngine engine; QQmlComponent component; QScopedPointer<QObject> cleanup; - QQuickApplicationWindow *window; + QQuickApplicationWindow *appWindow; + QQuickWindow *window; }; } diff --git a/tests/auto/snippets/data/dependencies.qml b/tests/auto/snippets/data/dependencies.qml new file mode 100644 index 00000000..aed6ce87 --- /dev/null +++ b/tests/auto/snippets/data/dependencies.qml @@ -0,0 +1,6 @@ +import QtQuick 2.6 +import QtQuick.Layouts 1.3 +import QtQuick.Controls 2.0 +import Qt.labs.calendar 1.0 + +Control { } diff --git a/tests/auto/snippets/tst_snippets.cpp b/tests/auto/snippets/tst_snippets.cpp index 2c6fe6f8..7972591b 100644 --- a/tests/auto/snippets/tst_snippets.cpp +++ b/tests/auto/snippets/tst_snippets.cpp @@ -46,56 +46,96 @@ class tst_Snippets : public QObject private slots: void initTestCase(); + void verify(); + void verify_data(); + void screenshots(); void screenshots_data(); private: - QQuickView view; - QMap<QString, QStringPair> filePaths; + QMap<QString, QStringPair> snippetPaths; + QMap<QString, QStringPair> screenshotSnippetPaths; }; +static QMap<QString, QStringPair> findSnippets(const QDir &inputDir, const QDir &outputDir = QDir()) +{ + QMap<QString, QStringPair> snippetPaths; + QDirIterator it(inputDir.path(), QStringList() << "qtquick*.qml" << "qtlabs*.qml", QDir::Files | QDir::Readable); + while (it.hasNext()) { + QFileInfo fi(it.next()); + const QString outDirPath = !outputDir.path().isEmpty() ? outputDir.filePath(fi.baseName() + ".png") : QString(); + snippetPaths.insert(fi.baseName(), qMakePair(fi.filePath(), outDirPath)); + } + return snippetPaths; +} + void tst_Snippets::initTestCase() { - QDir outdir(QDir::current().filePath("screenshots")); - QVERIFY(outdir.exists() || QDir::current().mkpath("screenshots")); + qInfo() << "Snippets are taken from" << QQC2_SNIPPETS_PATH; - QString datadir(QQC2_SNIPPETS_PATH); - QVERIFY(!datadir.isEmpty()); + QDir snippetsDir(QQC2_SNIPPETS_PATH); + QVERIFY(!snippetsDir.path().isEmpty()); - qInfo() << datadir; + snippetPaths = findSnippets(snippetsDir); + QVERIFY(!snippetPaths.isEmpty()); - QDirIterator it(datadir, QStringList() << "qtlabs*.qml", QDir::Files | QDir::Readable, QDirIterator::Subdirectories); - while (it.hasNext()) { - QFileInfo fi(it.next()); - filePaths.insert(fi.baseName(), qMakePair(fi.filePath(), outdir.filePath(fi.baseName() + ".png"))); - } - QVERIFY(!filePaths.isEmpty()); + QDir screenshotOutputDir(QDir::current().filePath("screenshots")); + QVERIFY(screenshotOutputDir.exists() || QDir::current().mkpath("screenshots")); + + QDir screenshotSnippetsDir(QQC2_SNIPPETS_PATH "/screenshots"); + QVERIFY(!screenshotSnippetsDir.path().isEmpty()); + + screenshotSnippetPaths = findSnippets(screenshotSnippetsDir, screenshotOutputDir); + QVERIFY(!screenshotSnippetPaths.isEmpty()); } Q_DECLARE_METATYPE(QList<QQmlError>) -void tst_Snippets::screenshots() +static void loadAndShow(QQuickView *view, const QString &source) { - QFETCH(QString, input); - QFETCH(QString, output); - qRegisterMetaType<QList<QQmlError> >(); - - QSignalSpy warnings(view.engine(), SIGNAL(warnings(QList<QQmlError>))); + QSignalSpy warnings(view->engine(), SIGNAL(warnings(QList<QQmlError>))); QVERIFY(warnings.isValid()); - view.setSource(QUrl::fromLocalFile(input)); - QCOMPARE(view.status(), QQuickView::Ready); - QVERIFY(view.errors().isEmpty()); - QVERIFY(view.rootObject()); + view->setSource(QUrl::fromLocalFile(source)); + QCOMPARE(view->status(), QQuickView::Ready); + QVERIFY(view->errors().isEmpty()); + QVERIFY(view->rootObject()); QVERIFY(warnings.isEmpty()); - view.show(); - view.requestActivate(); - QVERIFY(QTest::qWaitForWindowActive(&view)); + view->show(); + view->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(view)); +} + +void tst_Snippets::verify() +{ + QFETCH(QString, input); + + QQuickView view; + loadAndShow(&view, input); + QGuiApplication::processEvents(); +} + +void tst_Snippets::verify_data() +{ + QTest::addColumn<QString>("input"); + + QMap<QString, QStringPair>::const_iterator it; + for (it = snippetPaths.constBegin(); it != snippetPaths.constEnd(); ++it) + QTest::newRow(qPrintable(it.key())) << it.value().first; +} + +void tst_Snippets::screenshots() +{ + QFETCH(QString, input); + QFETCH(QString, output); + + QQuickView view; + loadAndShow(&view, input); - QSharedPointer<QQuickItemGrabResult> result = view.rootObject()->grabToImage(); + QSharedPointer<QQuickItemGrabResult> result = view.contentItem()->grabToImage(); QSignalSpy spy(result.data(), SIGNAL(ready())); QVERIFY(spy.isValid()); QVERIFY(spy.wait()); @@ -110,7 +150,7 @@ void tst_Snippets::screenshots_data() QTest::addColumn<QString>("output"); QMap<QString, QStringPair>::const_iterator it; - for (it = filePaths.constBegin(); it != filePaths.constEnd(); ++it) + for (it = screenshotSnippetPaths.constBegin(); it != screenshotSnippetPaths.constEnd(); ++it) QTest::newRow(qPrintable(it.key())) << it.value().first << it.value().second; } diff --git a/tests/benchmarks/creationtime/data/dependencies.qml b/tests/benchmarks/creationtime/data/dependencies.qml new file mode 100644 index 00000000..4c1702cc --- /dev/null +++ b/tests/benchmarks/creationtime/data/dependencies.qml @@ -0,0 +1,7 @@ +import QtQuick 2.6 +import QtQuick.Controls 2.0 +import QtQuick.Controls.Material 2.0 +import QtQuick.Controls.Universal 2.0 +import Qt.labs.calendar 1.0 + +Control { } diff --git a/tests/benchmarks/creationtime/tst_creationtime.cpp b/tests/benchmarks/creationtime/tst_creationtime.cpp index 2a61b0ea..3eec3825 100644 --- a/tests/benchmarks/creationtime/tst_creationtime.cpp +++ b/tests/benchmarks/creationtime/tst_creationtime.cpp @@ -65,12 +65,12 @@ void tst_CreationTime::init() engine.clearComponentCache(); } -static void addTestRows(QQmlEngine *engine, const QString &targetPath, const QStringList &skiplist = QStringList()) +static void addTestRows(QQmlEngine *engine, const QString &sourcePath, const QString &targetPath, const QStringList &skiplist = QStringList()) { // We cannot use QQmlComponent to load QML files directly from the source tree. // For styles that use internal QML types (eg. material/Ripple.qml), the source // dir would be added as an "implicit" import path overriding the actual import - // path (qtbase/qml/Qt/labs/controls/material). => The QML engine fails to load + // path (qtbase/qml/QtQuick/Controls.2/Material). => The QML engine fails to load // the style C++ plugin from the implicit import path (the source dir). // // Therefore we only use the source tree for finding out the set of QML files that @@ -78,15 +78,20 @@ static void addTestRows(QQmlEngine *engine, const QString &targetPath, const QSt // the engine's import path. This way we can use QQmlComponent to load each QML file // for benchmarking. - QFileInfoList entries = QDir(QQC2_IMPORT_PATH + targetPath).entryInfoList(QStringList("*.qml"), QDir::Files); - foreach (const QFileInfo &entry, entries) { + const QFileInfoList entries = QDir(QQC2_IMPORT_PATH "/" + sourcePath).entryInfoList(QStringList("*.qml"), QDir::Files); + for (const QFileInfo &entry : entries) { QString name = entry.baseName(); if (!skiplist.contains(name)) { - foreach (const QString &importPath, engine->importPathList()) { - QString filePath = QDir(importPath + "/Qt/labs/" + targetPath).absoluteFilePath(entry.fileName()); + const auto importPathList = engine->importPathList(); + for (const QString &importPath : importPathList) { + QString name = entry.dir().dirName() + "/" + entry.fileName(); + QString filePath = importPath + "/" + targetPath + "/" + entry.fileName(); if (QFile::exists(filePath)) { QTest::newRow(qPrintable(name)) << QUrl::fromLocalFile(filePath); break; + } else if (QFile::exists(QQmlFile::urlToLocalFileOrQrc(filePath))) { + QTest::newRow(qPrintable(name)) << QUrl(filePath); + break; } } } @@ -117,7 +122,7 @@ void tst_CreationTime::controls() void tst_CreationTime::controls_data() { QTest::addColumn<QUrl>("url"); - addTestRows(&engine, "/controls"); + addTestRows(&engine, "controls", "QtQuick/Controls.2", QStringList() << "CheckIndicator" << "RadioIndicator" << "SwitchIndicator"); } void tst_CreationTime::material() @@ -129,7 +134,7 @@ void tst_CreationTime::material() void tst_CreationTime::material_data() { QTest::addColumn<QUrl>("url"); - addTestRows(&engine, "/controls/material", QStringList() << "Ripple" << "SliderHandle"); + addTestRows(&engine, "controls/material", "QtQuick/Controls.2/Material", QStringList() << "Ripple" << "SliderHandle" << "CheckIndicator" << "RadioIndicator" << "SwitchIndicator" << "BoxShadow" << "ElevationEffect"); } void tst_CreationTime::universal() @@ -141,7 +146,7 @@ void tst_CreationTime::universal() void tst_CreationTime::universal_data() { QTest::addColumn<QUrl>("url"); - addTestRows(&engine, "/controls/universal"); + addTestRows(&engine, "controls/universal", "QtQuick/Controls.2/Universal", QStringList() << "CheckIndicator" << "RadioIndicator" << "SwitchIndicator"); } void tst_CreationTime::calendar() @@ -153,7 +158,7 @@ void tst_CreationTime::calendar() void tst_CreationTime::calendar_data() { QTest::addColumn<QUrl>("url"); - addTestRows(&engine, "/calendar"); + addTestRows(&engine, "calendar", "Qt/labs/calendar"); } QTEST_MAIN(tst_CreationTime) diff --git a/tests/benchmarks/objectcount/data/dependencies.qml b/tests/benchmarks/objectcount/data/dependencies.qml new file mode 100644 index 00000000..4c1702cc --- /dev/null +++ b/tests/benchmarks/objectcount/data/dependencies.qml @@ -0,0 +1,7 @@ +import QtQuick 2.6 +import QtQuick.Controls 2.0 +import QtQuick.Controls.Material 2.0 +import QtQuick.Controls.Universal 2.0 +import Qt.labs.calendar 1.0 + +Control { } diff --git a/tests/benchmarks/objectcount/tst_objectcount.cpp b/tests/benchmarks/objectcount/tst_objectcount.cpp index b479b0e2..549d7eef 100644 --- a/tests/benchmarks/objectcount/tst_objectcount.cpp +++ b/tests/benchmarks/objectcount/tst_objectcount.cpp @@ -84,7 +84,7 @@ void tst_ObjectCount::init() // warmup QQmlComponent component(&engine); - component.setData("import QtQuick 2.0; import QtQuick.Controls 1.3 as C1; import Qt.labs.controls 1.0 as C2; Row { C1.Button {} C2.Button {} }", QUrl()); + component.setData("import QtQuick 2.0; import QtQuick.Controls 2.0; Item { Button {} }", QUrl()); delete component.create(); } @@ -100,17 +100,17 @@ static void printItems(const QList<QQuickItem *> &items) std::cout << " QQuickItems: " << items.count() << " (total of QObjects: " << qt_qobjects->count() << ")" << std::endl; if (qt_verbose) { - foreach (QObject *object, *qt_qobjects) + for (QObject *object : qAsConst(*qt_qobjects)) qInfo() << "\t" << object; } } -static void addTestRows(QQmlEngine *engine, const QString &targetPath, const QStringList &skiplist = QStringList()) +static void addTestRows(QQmlEngine *engine, const QString &sourcePath, const QString &targetPath, const QStringList &skiplist = QStringList()) { // We cannot use QQmlComponent to load QML files directly from the source tree. // For styles that use internal QML types (eg. material/Ripple.qml), the source // dir would be added as an "implicit" import path overriding the actual import - // path (qtbase/qml/Qt/labs/controls/material). => The QML engine fails to load + // path (qtbase/qml/QtQuick/Controls.2/Material). => The QML engine fails to load // the style C++ plugin from the implicit import path (the source dir). // // Therefore we only use the source tree for finding out the set of QML files that @@ -118,15 +118,20 @@ static void addTestRows(QQmlEngine *engine, const QString &targetPath, const QSt // the engine's import path. This way we can use QQmlComponent to load each QML file // for benchmarking. - QFileInfoList entries = QDir(QQC2_IMPORT_PATH + targetPath).entryInfoList(QStringList("*.qml"), QDir::Files); - foreach (const QFileInfo &entry, entries) { + const QFileInfoList entries = QDir(QQC2_IMPORT_PATH "/" + sourcePath).entryInfoList(QStringList("*.qml"), QDir::Files); + for (const QFileInfo &entry : entries) { QString name = entry.baseName(); if (!skiplist.contains(name)) { - foreach (const QString &importPath, engine->importPathList()) { - QString filePath = QDir(importPath + "/Qt/labs/" + targetPath).absoluteFilePath(entry.fileName()); + const auto importPathList = engine->importPathList(); + for (const QString &importPath : importPathList) { + QString name = entry.dir().dirName() + "/" + entry.fileName(); + QString filePath = importPath + "/" + targetPath + "/" + entry.fileName(); if (QFile::exists(filePath)) { QTest::newRow(qPrintable(name)) << QUrl::fromLocalFile(filePath); break; + } else if (QFile::exists(QQmlFile::urlToLocalFileOrQrc(filePath))) { + QTest::newRow(qPrintable(name)) << QUrl(filePath); + break; } } } @@ -144,7 +149,7 @@ static void doBenchmark(QQmlEngine *engine, const QUrl &url) QVERIFY2(object.data(), qPrintable(component.errorString())); QList<QQuickItem *> items; - foreach (QObject *object, *qt_qobjects()) { + for (QObject *object : qAsConst(*qt_qobjects)) { QQuickItem *item = qobject_cast<QQuickItem *>(object); if (item) items += item; @@ -161,7 +166,7 @@ void tst_ObjectCount::calendar() void tst_ObjectCount::calendar_data() { QTest::addColumn<QUrl>("url"); - addTestRows(&engine, "/calendar"); + addTestRows(&engine, "calendar", "Qt/labs/calendar"); } void tst_ObjectCount::controls() @@ -173,7 +178,7 @@ void tst_ObjectCount::controls() void tst_ObjectCount::controls_data() { QTest::addColumn<QUrl>("url"); - addTestRows(&engine, "/controls"); + addTestRows(&engine, "controls", "QtQuick/Controls.2", QStringList() << "CheckIndicator" << "RadioIndicator" << "SwitchIndicator"); } void tst_ObjectCount::material() @@ -185,7 +190,7 @@ void tst_ObjectCount::material() void tst_ObjectCount::material_data() { QTest::addColumn<QUrl>("url"); - addTestRows(&engine, "/controls/material", QStringList() << "Ripple" << "SliderHandle"); + addTestRows(&engine, "controls/material", "QtQuick/Controls.2/Material", QStringList() << "Ripple" << "SliderHandle" << "CheckIndicator" << "RadioIndicator" << "SwitchIndicator" << "BoxShadow" << "ElevationEffect"); } void tst_ObjectCount::universal() @@ -197,7 +202,7 @@ void tst_ObjectCount::universal() void tst_ObjectCount::universal_data() { QTest::addColumn<QUrl>("url"); - addTestRows(&engine, "/controls/universal"); + addTestRows(&engine, "controls/universal", "QtQuick/Controls.2/Universal", QStringList() << "CheckIndicator" << "RadioIndicator" << "SwitchIndicator"); } QTEST_MAIN(tst_ObjectCount) diff --git a/tests/manual/fonts/main.qml b/tests/manual/fonts/main.qml index 7bf9a0a7..883226a7 100644 --- a/tests/manual/fonts/main.qml +++ b/tests/manual/fonts/main.qml @@ -39,8 +39,8 @@ ****************************************************************************/ import QtQuick 2.6 -import Qt.labs.controls 1.0 -import Qt.labs.templates 1.0 as T +import QtQuick.Controls 2.0 +import QtQuick.Templates 2.0 as T import QtQuick.Layouts 1.2 ApplicationWindow { diff --git a/tests/manual/gifs/data/qtlabscontrols-busyindicator.qml b/tests/manual/gifs/data/qtquickcontrols2-busyindicator.qml index e68af7dd..5c655cab 100644 --- a/tests/manual/gifs/data/qtlabscontrols-busyindicator.qml +++ b/tests/manual/gifs/data/qtquickcontrols2-busyindicator.qml @@ -40,7 +40,7 @@ import QtQuick 2.6 import QtQuick.Window 2.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 Window { width: busyIndicator.implicitWidth @@ -51,7 +51,7 @@ Window { BusyIndicator { id: busyIndicator - running: false + running: true anchors.centerIn: parent } } diff --git a/tests/manual/gifs/data/qtquickcontrols2-button-flat.qml b/tests/manual/gifs/data/qtquickcontrols2-button-flat.qml new file mode 100644 index 00000000..e20e3bc2 --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-button-flat.qml @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Window 2.0 +import QtQuick.Controls 2.0 + +Window { + width: button.width + height: button.height + visible: true + + Button { + id: button + text: pressed ? "Pressed" : "Button" + flat: true + anchors.centerIn: parent + } +} diff --git a/tests/manual/gifs/data/qtquickcontrols2-button-highlighted.qml b/tests/manual/gifs/data/qtquickcontrols2-button-highlighted.qml new file mode 100644 index 00000000..b031c731 --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-button-highlighted.qml @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Window 2.0 +import QtQuick.Controls 2.0 + +Window { + width: button.width + height: button.height + visible: true + + Button { + id: button + text: pressed ? "Pressed" : "Button" + highlighted: true + anchors.centerIn: parent + } +} diff --git a/tests/manual/gifs/data/qtlabscontrols-button.qml b/tests/manual/gifs/data/qtquickcontrols2-button.qml index 3d9a4f45..31b8da47 100644 --- a/tests/manual/gifs/data/qtlabscontrols-button.qml +++ b/tests/manual/gifs/data/qtquickcontrols2-button.qml @@ -40,7 +40,7 @@ import QtQuick 2.6 import QtQuick.Window 2.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 Window { width: button.width @@ -49,7 +49,7 @@ Window { Button { id: button - text: pressed ? "Pressed" : "Normal" + text: pressed ? "Pressed" : "Button" anchors.centerIn: parent } } diff --git a/tests/manual/gifs/data/qtquickcontrols2-checkbox-tristate.qml b/tests/manual/gifs/data/qtquickcontrols2-checkbox-tristate.qml new file mode 100644 index 00000000..ef7e18d4 --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-checkbox-tristate.qml @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.1 +import QtQuick.Window 2.0 + +Window { + width: column.implicitWidth + height: column.implicitHeight + visible: true + + property alias english: english + property alias norwegian: norwegian + + ColumnLayout { + id: column + anchors.centerIn: parent + + CheckBox { + text: qsTr("Languages") + checkState: english.checked && norwegian.checked + ? Qt.Checked : (english.checked || norwegian.checked) ? Qt.PartiallyChecked : Qt.Unchecked + tristate: true + } + CheckBox { + id: english + text: qsTr("English") + checked: true + leftPadding: indicator.width + } + CheckBox { + id: norwegian + text: qsTr("Norwegian") + checked: true + leftPadding: indicator.width + } + } +} diff --git a/tests/manual/gifs/data/qtquickcontrols2-checkbox.qml b/tests/manual/gifs/data/qtquickcontrols2-checkbox.qml new file mode 100644 index 00000000..3195c1c9 --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-checkbox.qml @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.1 +import QtQuick.Window 2.0 + +Window { + width: column.implicitWidth + height: column.implicitHeight + visible: true + + property alias control2: control2 + property alias control3: control3 + + ColumnLayout { + id: column + anchors.centerIn: parent + + CheckBox { + checked: true + text: qsTr("First") + } + CheckBox { + id: control2 + text: qsTr("Second") + } + CheckBox { + id: control3 + checked: true + text: qsTr("Third") + } + } +} diff --git a/tests/manual/gifs/data/qtquickcontrols2-checkdelegate-tristate.qml b/tests/manual/gifs/data/qtquickcontrols2-checkdelegate-tristate.qml new file mode 100644 index 00000000..eddb71d5 --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-checkdelegate-tristate.qml @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.1 +import QtQuick.Window 2.0 + +Window { + id: window + width: 170 + height: column.implicitHeight + visible: true + + property alias english: english + property alias norwegian: norwegian + + ColumnLayout { + id: column + anchors.fill: parent + + CheckDelegate { + text: qsTr("Languages") + checkState: english.checked && norwegian.checked + ? Qt.Checked : (english.checked || norwegian.checked) ? Qt.PartiallyChecked : Qt.Unchecked + tristate: true + Layout.fillWidth: true + } + CheckDelegate { + id: english + text: qsTr("English") + checked: true + leftPadding: indicator.width + 14 + Layout.fillWidth: true + } + CheckDelegate { + id: norwegian + text: qsTr("Norwegian") + checked: true + leftPadding: indicator.width + 14 + Layout.fillWidth: true + } + } +} diff --git a/tests/manual/gifs/data/qtquickcontrols2-checkdelegate.qml b/tests/manual/gifs/data/qtquickcontrols2-checkdelegate.qml new file mode 100644 index 00000000..df80a417 --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-checkdelegate.qml @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Window 2.0 +import QtQuick.Controls 2.0 + +Window { + width: column.implicitWidth + height: column.implicitHeight + visible: true + + property var delegate: repeater.count > 0 ? repeater.itemAt(0) : null + + Column { + id: column + anchors.centerIn: parent + + Repeater { + id: repeater + model: ["Option 1", "Option 2", "Option 3"] + delegate: CheckDelegate { + text: modelData + } + } + } +} diff --git a/tests/manual/gifs/data/qtquickcontrols2-combobox.qml b/tests/manual/gifs/data/qtquickcontrols2-combobox.qml new file mode 100644 index 00000000..718ed166 --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-combobox.qml @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.1 +import QtQuick.Window 2.0 + +Window { + width: 140 + height: 180 + visible: true + + property alias comboBox: comboBox + + ComboBox { + id: comboBox + model: ["First", "Second", "Third"] + y: 10 + anchors.horizontalCenter: parent.horizontalCenter + } +} diff --git a/tests/manual/gifs/data/qtquickcontrols2-dial-no-wrap.qml b/tests/manual/gifs/data/qtquickcontrols2-dial-no-wrap.qml new file mode 100644 index 00000000..b280b385 --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-dial-no-wrap.qml @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Window 2.0 +import QtQuick.Controls 2.0 + +Window { + width: dial.implicitWidth + 20 + height: dial.implicitHeight + 20 + visible: true + + property alias dial: dial + + Dial { + id: dial + anchors.centerIn: parent + } +} diff --git a/tests/manual/gifs/data/qtquickcontrols2-dial-wrap.qml b/tests/manual/gifs/data/qtquickcontrols2-dial-wrap.qml new file mode 100644 index 00000000..7ecda085 --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-dial-wrap.qml @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Window 2.0 +import QtQuick.Controls 2.0 + +Window { + width: dial.implicitWidth + 20 + height: dial.implicitHeight + 20 + visible: true + + property alias dial: dial + + Dial { + id: dial + wrap: true + anchors.centerIn: parent + } +} diff --git a/tests/manual/gifs/data/qtquickcontrols2-drawer.qml b/tests/manual/gifs/data/qtquickcontrols2-drawer.qml new file mode 100644 index 00000000..49f2cf50 --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-drawer.qml @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 2.0 +import QtQuick.Window 2.0 + +ApplicationWindow { + id: window + width: 300 + height: 300 + visible: true + + property alias drawer: drawer + + Drawer { + id: drawer + width: window.width * 0.66 + height: window.height + rightPadding: 0 + + Rectangle { + border.width: 1 + anchors.fill: parent + + Label { + text: "Drawer" + font.pixelSize: 32 + anchors.centerIn: parent + } + } + } + + Rectangle { + border.width: 1 + anchors.fill: parent + + Label { + text: "Content" + font.pixelSize: 32 + anchors.centerIn: parent + } + } + + Rectangle { + z: 1 + color: "black" + width: 1 + height: parent.height + parent: window.overlay + } +} diff --git a/tests/manual/gifs/data/qtquickcontrols2-itemdelegate.qml b/tests/manual/gifs/data/qtquickcontrols2-itemdelegate.qml new file mode 100644 index 00000000..18bf942c --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-itemdelegate.qml @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Window 2.0 +import QtQuick.Controls 2.0 + +Window { + width: column.implicitWidth + height: column.implicitHeight + visible: true + + property var delegate: repeater.count > 0 ? repeater.itemAt(0) : null + + Column { + id: column + + Repeater { + id: repeater + model: ["Option 1", "Option 2", "Option 3"] + delegate: ItemDelegate { + text: modelData + } + } + } +} diff --git a/tests/manual/gifs/data/qtlabscontrols-menu.qml b/tests/manual/gifs/data/qtquickcontrols2-menu.qml index 81ea3137..332e4d2b 100644 --- a/tests/manual/gifs/data/qtlabscontrols-menu.qml +++ b/tests/manual/gifs/data/qtquickcontrols2-menu.qml @@ -39,7 +39,7 @@ ****************************************************************************/ import QtQuick 2.6 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 // TODO: restore and finish https://codereview.qt-project.org/#/c/123948/ ApplicationWindow { diff --git a/tests/manual/gifs/data/qtquickcontrols2-progressbar-indeterminate.qml b/tests/manual/gifs/data/qtquickcontrols2-progressbar-indeterminate.qml new file mode 100644 index 00000000..0785b279 --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-progressbar-indeterminate.qml @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.7 +import QtQuick.Window 2.0 +import QtQuick.Controls 2.0 + +Window { + width: progressBar.implicitWidth + height: 64 + visible: true + + property alias progressBar: progressBar + + ProgressBar { + id: progressBar + indeterminate: true + anchors.centerIn: parent + } +} diff --git a/tests/manual/gifs/data/qtquickcontrols2-progressbar.qml b/tests/manual/gifs/data/qtquickcontrols2-progressbar.qml new file mode 100644 index 00000000..13d5075d --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-progressbar.qml @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.7 +import QtQuick.Window 2.0 +import QtQuick.Controls 2.0 + +Window { + width: progressBar.implicitWidth + height: 64 + visible: true + + property alias progressBar: progressBar + + ProgressBar { + id: progressBar + value: 0.5 + anchors.centerIn: parent + + Timer { + running: true + interval: 500 + onTriggered: animation.start() + } + + NumberAnimation { + id: animation + target: progressBar + property: "value" + to: 1 + duration: 2000 + } + } +} diff --git a/tests/manual/gifs/data/qtquickcontrols2-radiobutton.qml b/tests/manual/gifs/data/qtquickcontrols2-radiobutton.qml new file mode 100644 index 00000000..576668f3 --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-radiobutton.qml @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.1 +import QtQuick.Window 2.0 + +Window { + width: column.implicitWidth + height: column.implicitHeight + visible: true + + property alias control1: control1 + property alias control2: control2 + property alias control3: control3 + + ColumnLayout { + id: column + anchors.centerIn: parent + + RadioButton { + id: control1 + text: qsTr("First") + checked: true + } + RadioButton { + id: control2 + text: qsTr("Second") + } + RadioButton { + id: control3 + text: qsTr("Third") + } + } +} diff --git a/tests/manual/gifs/data/qtquickcontrols2-radiodelegate.qml b/tests/manual/gifs/data/qtquickcontrols2-radiodelegate.qml new file mode 100644 index 00000000..60a0424f --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-radiodelegate.qml @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Window 2.0 +import QtQuick.Controls 2.0 + +Window { + width: column.implicitWidth + height: column.implicitHeight + visible: true + + property var delegate: repeater.count > 0 ? repeater.itemAt(0) : null + + ButtonGroup { + id: buttonGroup + } + + Column { + id: column + anchors.centerIn: parent + + Repeater { + id: repeater + model: ["Option 1", "Option 2", "Option 3"] + delegate: RadioDelegate { + checked: index == 0 + text: modelData + ButtonGroup.group: buttonGroup + } + } + } +} diff --git a/tests/manual/gifs/data/qtlabscontrols-rangeslider.qml b/tests/manual/gifs/data/qtquickcontrols2-rangeslider.qml index 55056cf8..4f764f8a 100644 --- a/tests/manual/gifs/data/qtlabscontrols-rangeslider.qml +++ b/tests/manual/gifs/data/qtquickcontrols2-rangeslider.qml @@ -40,7 +40,7 @@ import QtQuick 2.6 import QtQuick.Window 2.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 Window { width: slider.implicitWidth diff --git a/tests/manual/gifs/data/qtquickcontrols2-scrollbar.qml b/tests/manual/gifs/data/qtquickcontrols2-scrollbar.qml new file mode 100644 index 00000000..ce198685 --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-scrollbar.qml @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Window 2.0 +import QtQuick.Controls 2.0 + +Window { + width: 100 + height: 120 + visible: true + color: "#eeeeee" + + property alias scrollBar: scrollBar + + ListView { + anchors.fill: parent + + ScrollBar.vertical: ScrollBar { + id: scrollBar + active: true + } + + model: 10 + delegate: Label { + text: qsTr("Item %1").arg(index + 1) + width: 100 + height: 40 + leftPadding: 10 + verticalAlignment: Text.AlignVCenter + } + } +} diff --git a/tests/manual/gifs/data/qtquickcontrols2-scrollindicator.qml b/tests/manual/gifs/data/qtquickcontrols2-scrollindicator.qml new file mode 100644 index 00000000..091e5250 --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-scrollindicator.qml @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Window 2.0 +import QtQuick.Controls 2.0 + +Window { + width: 100 + height: 120 + visible: true + color: "#eeeeee" + + ListView { + anchors.fill: parent + + ScrollIndicator.vertical: ScrollIndicator { + active: true + } + + model: 10 + delegate: Label { + text: qsTr("Item %1").arg(index + 1) + width: 100 + height: 40 + leftPadding: 10 + verticalAlignment: Text.AlignVCenter + } + } +} diff --git a/tests/manual/gifs/data/qtquickcontrols2-slider-snap.qml b/tests/manual/gifs/data/qtquickcontrols2-slider-snap.qml new file mode 100644 index 00000000..aa2351fc --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-slider-snap.qml @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.7 +import QtQuick.Window 2.0 +import QtQuick.Controls 2.0 + +Window { + width: slider.implicitWidth + height: slider.implicitHeight + visible: true + + property alias slider: slider + + Slider { + id: slider + stepSize: 0.2 + anchors.centerIn: parent + + Rectangle { + anchors.fill: slider.handle + radius: width / 2 + color: slider.pressed ? "#aa666666" : "transparent" + } + + contentItem: Item { + Repeater { + id: repeater + model: 6 + + Rectangle { + x: ((slider.contentItem.width - slider.handle.width) * (index / (repeater.count - 1))) + - width / 2 + slider.handle.width / 2 + y: parent.height + width: 1 + height: 4 + color: "#888" + } + } + } + } +} diff --git a/tests/manual/gifs/data/qtlabscontrols-slider.qml b/tests/manual/gifs/data/qtquickcontrols2-slider.qml index af582d7c..d109b1d2 100644 --- a/tests/manual/gifs/data/qtlabscontrols-slider.qml +++ b/tests/manual/gifs/data/qtquickcontrols2-slider.qml @@ -40,7 +40,7 @@ import QtQuick 2.6 import QtQuick.Window 2.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 Window { width: slider.implicitWidth diff --git a/tests/manual/gifs/data/qtquickcontrols2-stackview-pop.qml b/tests/manual/gifs/data/qtquickcontrols2-stackview-pop.qml new file mode 100644 index 00000000..2b4d3ee3 --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-stackview-pop.qml @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.7 +import QtQuick.Window 2.0 +import QtQuick.Controls 2.0 + +ApplicationWindow { + width: 160 + height: 160 + visible: true + color: "#eeeeee" + + property int maxDepth: 3 + + function itemText(index) { + return String.fromCharCode(65 + index); + } + + Component { + id: labelComponent + + Label { + font.pixelSize: 60 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + } + + StackView { + id: stackView + anchors.fill: parent + + Component.onCompleted: { + for (var i = 0; i < maxDepth; ++i) { + stackView.push(labelComponent, { text: itemText(i) }, StackView.Immediate); + } + } + } + + Label { + id: operationLabel + text: "pop()" + font.pixelSize: 16 + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.margins: 10 + } + + Timer { + id: operationTimer + running: true + interval: 1500 + onTriggered: { + stackView.pop(); + hideOperationTimer.start(); + } + } + + Timer { + id: hideOperationTimer + interval: operationTimer.interval + onTriggered: operationLabel.visible = false + } +} diff --git a/tests/manual/gifs/data/qtquickcontrols2-stackview-push.qml b/tests/manual/gifs/data/qtquickcontrols2-stackview-push.qml new file mode 100644 index 00000000..dd318f1d --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-stackview-push.qml @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.7 +import QtQuick.Window 2.0 +import QtQuick.Controls 2.0 + +ApplicationWindow { + width: 160 + height: 160 + visible: true + color: "#eeeeee" + + property int itemIndex: 0 + property int maxDepth: 3 + + function itemText(index) { + return String.fromCharCode(65 + index); + } + + Component { + id: labelComponent + + Label { + font.pixelSize: 60 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + } + + StackView { + id: stackView + anchors.fill: parent + } + + Label { + id: operationLabel + text: "push(" + itemText(Math.max(0, Math.min(maxDepth - 1, itemIndex - 1))) + ")" + font.pixelSize: 16 + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.margins: 10 + } + + Timer { + id: operationTimer + running: true + interval: 1500 + repeat: stackView.depth < maxDepth - 1 + onRepeatChanged: if (!repeat) hideOperationTimer.start() + + onTriggered: stackView.push(labelComponent, { text: itemText(itemIndex++) }) + } + + Timer { + id: hideOperationTimer + interval: operationTimer.interval * 2 + onTriggered: operationLabel.visible = false + } +} diff --git a/tests/manual/gifs/data/qtquickcontrols2-stackview-replace.qml b/tests/manual/gifs/data/qtquickcontrols2-stackview-replace.qml new file mode 100644 index 00000000..2586a81b --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-stackview-replace.qml @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.7 +import QtQuick.Window 2.0 +import QtQuick.Controls 2.0 + +ApplicationWindow { + width: 160 + height: 160 + visible: true + color: "#eeeeee" + + property int maxDepth: 3 + + function itemText(index) { + return String.fromCharCode(65 + index); + } + + Component { + id: labelComponent + + Label { + font.pixelSize: 60 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + } + + StackView { + id: stackView + anchors.fill: parent + + Component.onCompleted: { + for (var i = 0; i < maxDepth; ++i) { + stackView.push(labelComponent, { text: itemText(i) }, StackView.Immediate); + } + } + } + + Label { + id: operationLabel + text: "replace(D)" + font.pixelSize: 16 + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.margins: 10 + } + + Timer { + id: operationTimer + running: true + interval: 1500 + onTriggered: { + stackView.replace(labelComponent, { text: "D" }); + hideOperationTimer.start(); + } + } + + Timer { + id: hideOperationTimer + interval: operationTimer.interval + onTriggered: operationLabel.visible = false + } +} diff --git a/tests/manual/gifs/data/qtquickcontrols2-stackview-unwind.qml b/tests/manual/gifs/data/qtquickcontrols2-stackview-unwind.qml new file mode 100644 index 00000000..6fb6b2a8 --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-stackview-unwind.qml @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.7 +import QtQuick.Window 2.0 +import QtQuick.Controls 2.0 + +ApplicationWindow { + width: 160 + height: 160 + visible: true + color: "#eeeeee" + + property int maxDepth: 3 + + function itemText(index) { + return String.fromCharCode(65 + index); + } + + Component { + id: labelComponent + + Label { + font.pixelSize: 60 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + } + + StackView { + id: stackView + anchors.fill: parent + + Component.onCompleted: { + for (var i = 0; i < maxDepth; ++i) { + stackView.push(labelComponent, { text: itemText(i) }, StackView.Immediate); + } + } + } + + Label { + id: operationLabel + text: "pop(null)" + font.pixelSize: 16 + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.margins: 10 + } + + Timer { + id: operationTimer + running: true + interval: 1500 + onTriggered: { + stackView.pop(null); + hideOperationTimer.start(); + } + } + + Timer { + id: hideOperationTimer + interval: operationTimer.interval + onTriggered: operationLabel.visible = false + } +} diff --git a/tests/manual/gifs/data/qtquickcontrols2-swipedelegate-behind.qml b/tests/manual/gifs/data/qtquickcontrols2-swipedelegate-behind.qml new file mode 100644 index 00000000..d019368e --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-swipedelegate-behind.qml @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Window 2.0 +import QtQuick.Controls 2.0 + +Window { + width: swipeDelegate.implicitWidth + height: swipeDelegate.implicitHeight + visible: true + + property alias swipeDelegate: swipeDelegate + + SwipeDelegate { + id: swipeDelegate + text: "SwipeDelegate" + anchors.centerIn: parent + + swipe.left: null + swipe.right: null + swipe.behind: Rectangle { + width: swipeDelegate.width + height: swipeDelegate.height + color: swipeDelegate.pressed ? "#333" : "#444" + + Label { + text: "Behind Action" + color: "#fff" + anchors.centerIn: parent + } + } + } +} diff --git a/tests/manual/gifs/data/qtquickcontrols2-swipedelegate-leading-trailing.qml b/tests/manual/gifs/data/qtquickcontrols2-swipedelegate-leading-trailing.qml new file mode 100644 index 00000000..ecc7924e --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-swipedelegate-leading-trailing.qml @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Window 2.0 +import QtQuick.Controls 2.0 + +Window { + width: swipeDelegate.implicitWidth + height: swipeDelegate.implicitHeight + visible: true + + property alias swipeDelegate: swipeDelegate + + SwipeDelegate { + id: swipeDelegate + text: "SwipeDelegate" + anchors.centerIn: parent + + swipe.left: Rectangle { + width: swipeDelegate.width + height: swipeDelegate.height + color: swipeDelegate.pressed ? "#333" : "#444" + anchors.right: parent.left + + Label { + text: "Left Action" + color: "#fff" + anchors.centerIn: parent + } + } + + swipe.right: Rectangle { + width: swipeDelegate.width + height: swipeDelegate.height + color: swipeDelegate.pressed ? "#333" : "#444" + anchors.left: parent.right + + Label { + text: "Right Action" + color: "#fff" + anchors.centerIn: parent + } + } + } +} diff --git a/tests/manual/gifs/data/qtquickcontrols2-swipedelegate.qml b/tests/manual/gifs/data/qtquickcontrols2-swipedelegate.qml new file mode 100644 index 00000000..9dfee7f5 --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-swipedelegate.qml @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Window 2.0 +import QtQuick.Controls 2.0 + +Window { + width: swipeDelegate.implicitWidth + height: swipeDelegate.implicitHeight + visible: true + + property alias swipeDelegate: swipeDelegate + + SwipeDelegate { + id: swipeDelegate + text: "SwipeDelegate" + anchors.centerIn: parent + + swipe.left: Rectangle { + width: swipeDelegate.width + height: swipeDelegate.height + color: swipeDelegate.pressed ? "#333" : "#444" + + Label { + text: "Left Action" + color: "#fff" + anchors.centerIn: parent + } + } + + swipe.right: Rectangle { + anchors.fill: parent + width: swipeDelegate.width + height: swipeDelegate.height + color: swipeDelegate.pressed ? "#333" : "#444" + + Label { + text: "Right Action" + color: "#fff" + anchors.centerIn: parent + } + } + } +} diff --git a/tests/manual/gifs/data/qtquickcontrols2-swipeview.qml b/tests/manual/gifs/data/qtquickcontrols2-swipeview.qml new file mode 100644 index 00000000..d721591a --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-swipeview.qml @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Window 2.0 +import QtQuick.Controls 2.0 + +Window { + width: 300 + height: 300 + visible: true + + property alias swipeView: view + + Rectangle { + border.width: 1 + anchors.fill: parent + } + + SwipeView { + id: view + anchors.fill: parent + + Label { + text: "First\nPage" + horizontalAlignment: Qt.AlignHCenter + verticalAlignment: Qt.AlignVCenter + } + + Label { + text: "Second\nPage" + horizontalAlignment: Qt.AlignHCenter + verticalAlignment: Qt.AlignVCenter + } + + Label { + text: "Third\nPage" + horizontalAlignment: Qt.AlignHCenter + verticalAlignment: Qt.AlignVCenter + } + } + + PageIndicator { + id: indicator + + count: view.count + currentIndex: view.currentIndex + + anchors.bottom: view.bottom + anchors.horizontalCenter: parent.horizontalCenter + } +} diff --git a/tests/manual/gifs/data/qtlabscontrols-switch.qml b/tests/manual/gifs/data/qtquickcontrols2-switch.qml index f6067c1b..44d07e24 100644 --- a/tests/manual/gifs/data/qtlabscontrols-switch.qml +++ b/tests/manual/gifs/data/qtquickcontrols2-switch.qml @@ -40,7 +40,7 @@ import QtQuick 2.6 import QtQuick.Window 2.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 Window { width: 100 diff --git a/tests/manual/gifs/data/qtquickcontrols2-switchdelegate.qml b/tests/manual/gifs/data/qtquickcontrols2-switchdelegate.qml new file mode 100644 index 00000000..a0ee4e03 --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-switchdelegate.qml @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Window 2.0 +import QtQuick.Controls 2.0 + +Window { + width: column.implicitWidth + height: column.implicitHeight + visible: true + + property var delegate: repeater.count > 0 ? repeater.itemAt(0) : null + + Column { + id: column + anchors.centerIn: parent + + Repeater { + id: repeater + model: ["Option 1", "Option 2", "Option 3"] + delegate: SwitchDelegate { + text: modelData + } + } + } +} diff --git a/tests/manual/gifs/data/qtlabscontrols-tabbar.qml b/tests/manual/gifs/data/qtquickcontrols2-tabbar.qml index 8ca14721..3d0568e1 100644 --- a/tests/manual/gifs/data/qtlabscontrols-tabbar.qml +++ b/tests/manual/gifs/data/qtquickcontrols2-tabbar.qml @@ -40,7 +40,7 @@ import QtQuick 2.6 import QtQuick.Window 2.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 Window { width: 300 diff --git a/tests/manual/gifs/data/qtlabscontrols-tumbler-wrap.qml b/tests/manual/gifs/data/qtquickcontrols2-tumbler-wrap.qml index 4b84c6d1..e1139177 100644 --- a/tests/manual/gifs/data/qtlabscontrols-tumbler-wrap.qml +++ b/tests/manual/gifs/data/qtquickcontrols2-tumbler-wrap.qml @@ -40,7 +40,7 @@ import QtQuick 2.6 import QtQuick.Window 2.0 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 Window { width: 200 diff --git a/tests/manual/gifs/eventcapturer.cpp b/tests/manual/gifs/eventcapturer.cpp index 5b5905cd..3c355f59 100644 --- a/tests/manual/gifs/eventcapturer.cpp +++ b/tests/manual/gifs/eventcapturer.cpp @@ -57,7 +57,8 @@ // interact with the view here, in order for the events to be captured qDebug() << "\n"; - foreach (CapturedEvent event, eventCapturer.capturedEvents()) + const auto capturedEvents = eventCapturer.capturedEvents(); + for (CapturedEvent event : capturedEvents) qDebug().noquote() << event.cppCommand(); \endcode @@ -69,7 +70,7 @@ EventCapturer::EventCapturer(QObject *parent) : QObject(parent), - mEventSource(Q_NULLPTR), + mEventSource(nullptr), mStopCaptureKey(Qt::Key_Escape), mMoveEventTrimFlags(TrimNone), mDuration(0), diff --git a/tests/manual/gifs/eventcapturer.h b/tests/manual/gifs/eventcapturer.h index b1f2b4ff..7982d6e9 100644 --- a/tests/manual/gifs/eventcapturer.h +++ b/tests/manual/gifs/eventcapturer.h @@ -74,7 +74,7 @@ public: QVector<CapturedEvent> capturedEvents() const; protected: - bool eventFilter(QObject *object, QEvent *event) Q_DECL_OVERRIDE; + bool eventFilter(QObject *object, QEvent *event) override; private slots: void stopCapturing(); diff --git a/tests/manual/gifs/gifrecorder.cpp b/tests/manual/gifs/gifrecorder.cpp index 3ba33552..1e3f141f 100644 --- a/tests/manual/gifs/gifrecorder.cpp +++ b/tests/manual/gifs/gifrecorder.cpp @@ -64,8 +64,8 @@ namespace { } GifRecorder::GifRecorder() : - QObject(Q_NULLPTR), - mWindow(Q_NULLPTR), + QObject(nullptr), + mWindow(nullptr), mHighQuality(false), mRecordingDuration(0), mRecordCursor(false), @@ -83,7 +83,7 @@ GifRecorder::GifRecorder() : void GifRecorder::setRecordingDuration(int duration) { QVERIFY2(duration >= 1, qPrintable(QString::fromLatin1("Recording duration %1 must be larger than 1 second").arg(duration))); - QVERIFY2(duration < 10, qPrintable(QString::fromLatin1("Recording duration %1 must be less than 10 seconds").arg(duration))); + QVERIFY2(duration < 20, qPrintable(QString::fromLatin1("Recording duration %1 must be less than 20 seconds").arg(duration))); mRecordingDuration = duration; } @@ -243,7 +243,7 @@ void GifRecorder::waitForFinish() if (mHighQuality) { // Indicate the end of recording and the beginning of conversion. QQmlComponent busyComponent(&mEngine); - busyComponent.setData("import QtQuick 2.6; import Qt.labs.controls 1.0; Rectangle { anchors.fill: parent; " \ + busyComponent.setData("import QtQuick 2.6; import QtQuick.Controls 2.0; Rectangle { anchors.fill: parent; " \ "BusyIndicator { width: 32; height: 32; anchors.centerIn: parent } }", QUrl()); QCOMPARE(busyComponent.status(), QQmlComponent::Ready); QQuickItem *busyRect = qobject_cast<QQuickItem*>(busyComponent.create()); diff --git a/tests/manual/gifs/tst_gifs.cpp b/tests/manual/gifs/tst_gifs.cpp index 7f2a985c..d3fb5f6d 100644 --- a/tests/manual/gifs/tst_gifs.cpp +++ b/tests/manual/gifs/tst_gifs.cpp @@ -51,16 +51,41 @@ private slots: void tumblerWrap(); void slider(); + void sliderSnap_data(); + void sliderSnap(); void rangeSlider(); void busyIndicator(); void switchGif(); + void button_data(); void button(); void tabBar(); void menu(); + void swipeView(); + void swipeDelegate_data(); + void swipeDelegate(); + void swipeDelegateBehind(); + void delegates_data(); + void delegates(); + void dial_data(); + void dial(); + void scrollBar(); + void scrollIndicator(); + void progressBar_data(); + void progressBar(); + void triState_data(); + void triState(); + void checkables_data(); + void checkables(); + void comboBox(); + void stackView_data(); + void stackView(); + void drawer(); private: void moveSmoothly(QQuickWindow *window, const QPoint &from, const QPoint &to, int movements, QEasingCurve::Type easingCurveType = QEasingCurve::OutQuint, int movementDelay = 15); + void moveSmoothlyAlongArc(QQuickWindow *window, QPoint arcCenter, qreal distanceFromCenter, + qreal startAngleRadians, qreal endAngleRadians, QEasingCurve::Type easingCurveType = QEasingCurve::OutQuint); QString dataDirPath; QDir outputDir; @@ -85,19 +110,42 @@ void tst_Gifs::moveSmoothly(QQuickWindow *window, const QPoint &from, const QPoi int yDifference = to.y() - from.y(); for (int movement = 0; movement < movements; ++movement) { QPoint pos = QPoint( - from.x() + curve.valueForProgress(movement / qreal(qAbs(xDifference))) * xDifference, - from.y() + curve.valueForProgress(movement / qreal(qAbs(yDifference))) * yDifference); + from.x() + qRound(curve.valueForProgress(movement / qreal(qAbs(xDifference))) * xDifference), + from.y() + qRound(curve.valueForProgress(movement / qreal(qAbs(yDifference))) * yDifference)); QTest::mouseMove(window, pos, movementDelay); } } +QPoint posAlongArc(QPoint arcCenter, qreal startAngleRadians, qreal endAngleRadians, + qreal distanceFromCenter, qreal progress, QEasingCurve::Type easingCurveType) +{ + QEasingCurve curve(easingCurveType); + const qreal angle = startAngleRadians + curve.valueForProgress(progress) * (endAngleRadians - startAngleRadians); + return (arcCenter - QTransform().rotateRadians(angle).map(QPointF(0, distanceFromCenter))).toPoint(); +} + +void tst_Gifs::moveSmoothlyAlongArc(QQuickWindow *window, QPoint arcCenter, qreal distanceFromCenter, + qreal startAngleRadians, qreal endAngleRadians, QEasingCurve::Type easingCurveType) +{ + QEasingCurve curve(easingCurveType); + const qreal angleSpan = endAngleRadians - startAngleRadians; + const int movements = qAbs(angleSpan) * 20 + 20; + + for (int movement = 0; movement < movements; ++movement) { + const qreal progress = movement / qreal(movements); + const QPoint pos = posAlongArc(arcCenter, startAngleRadians, endAngleRadians, + distanceFromCenter, progress, easingCurveType); + QTest::mouseMove(window, pos, 15); + } +} + void tst_Gifs::tumblerWrap() { GifRecorder gifRecorder; gifRecorder.setDataDirPath(dataDirPath); gifRecorder.setOutputDir(outputDir); gifRecorder.setRecordingDuration(4); - gifRecorder.setQmlFileName("qtlabscontrols-tumbler-wrap.qml"); + gifRecorder.setQmlFileName("qtquickcontrols2-tumbler-wrap.qml"); gifRecorder.start(); @@ -156,7 +204,8 @@ void tst_Gifs::tumblerWrap() gifRecorder.waitForFinish(); - foreach (CapturedEvent event, eventCapturer.capturedEvents()) + const auto capturedEvents = eventCapturer.capturedEvents(); + for (CapturedEvent event : capturedEvents) qDebug().noquote() << event.cppCommand(); } @@ -167,7 +216,7 @@ void tst_Gifs::slider() gifRecorder.setOutputDir(outputDir); gifRecorder.setRecordingDuration(5); gifRecorder.setHighQuality(true); - gifRecorder.setQmlFileName("qtlabscontrols-slider.qml"); + gifRecorder.setQmlFileName("qtquickcontrols2-slider.qml"); gifRecorder.start(); @@ -197,6 +246,58 @@ void tst_Gifs::slider() gifRecorder.waitForFinish(); } +void tst_Gifs::sliderSnap_data() +{ + QTest::addColumn<QString>("gifBaseName"); + QTest::addColumn<int>("snapMode"); + QTest::newRow("NoSnap") << "qtquickcontrols2-slider-nosnap" << 0; + QTest::newRow("SnapAlways") << "qtquickcontrols2-slider-snapalways" << 1; + QTest::newRow("SnapOnRelease") << "qtquickcontrols2-slider-snaponrelease" << 2; +} + +void tst_Gifs::sliderSnap() +{ + QFETCH(QString, gifBaseName); + QFETCH(int, snapMode); + + GifRecorder gifRecorder; + gifRecorder.setDataDirPath(dataDirPath); + gifRecorder.setOutputDir(outputDir); + gifRecorder.setRecordingDuration(8); + gifRecorder.setHighQuality(true); + gifRecorder.setQmlFileName("qtquickcontrols2-slider-snap.qml"); + gifRecorder.setOutputFileBaseName(gifBaseName); + + gifRecorder.start(); + + QQuickWindow *window = gifRecorder.window(); + QQuickItem *slider = window->property("slider").value<QQuickItem*>(); + QVERIFY(slider); + QVERIFY(slider->setProperty("snapMode", QVariant(snapMode))); + QCOMPARE(slider->property("snapMode").toInt(), snapMode); + QQuickItem *handle = slider->property("handle").value<QQuickItem*>(); + QVERIFY(handle); + + const QPoint startPos(slider->property("leftPadding").toReal(), slider->height() / 2); + const int trackWidth = slider->property("availableWidth").toReal(); + + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, startPos, 200); + QPoint pos1 = startPos + QPoint(trackWidth * 0.3, 0); + moveSmoothly(window, startPos, pos1, pos1.x() - startPos.x(), QEasingCurve::OutQuint, 30); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, pos1, 0); + + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, startPos, 400); + const QPoint pos2 = startPos + QPoint(trackWidth * 0.6, 0); + moveSmoothly(window, pos1, pos2, pos2.x() - pos1.x(), QEasingCurve::OutQuint, 30); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, pos2, 0); + + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, pos2, 400); + moveSmoothly(window, pos2, startPos, qAbs(startPos.x() - pos2.x()) / 2, QEasingCurve::OutQuint, 30); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, startPos, 0); + + gifRecorder.waitForFinish(); +} + void tst_Gifs::rangeSlider() { GifRecorder gifRecorder; @@ -204,7 +305,7 @@ void tst_Gifs::rangeSlider() gifRecorder.setOutputDir(outputDir); gifRecorder.setRecordingDuration(7); gifRecorder.setHighQuality(true); - gifRecorder.setQmlFileName("qtlabscontrols-rangeslider.qml"); + gifRecorder.setQmlFileName("qtquickcontrols2-rangeslider.qml"); gifRecorder.start(); @@ -251,25 +352,25 @@ void tst_Gifs::busyIndicator() GifRecorder gifRecorder; gifRecorder.setDataDirPath(dataDirPath); gifRecorder.setOutputDir(outputDir); - gifRecorder.setRecordingDuration(3); + gifRecorder.setRecordingDuration(6); gifRecorder.setHighQuality(true); - gifRecorder.setQmlFileName("qtlabscontrols-busyindicator.qml"); + gifRecorder.setQmlFileName("qtquickcontrols2-busyindicator.qml"); gifRecorder.start(); QQuickWindow *window = gifRecorder.window(); // Record nothing for a bit to make it smoother. - QTest::qWait(400); + QTest::qWait(800 * 2); QQuickItem *busyIndicator = window->property("busyIndicator").value<QQuickItem*>(); QVERIFY(busyIndicator); - busyIndicator->setProperty("running", true); + busyIndicator->setProperty("running", false); // 800 ms is the duration of one rotation animation cycle for BusyIndicator. QTest::qWait(800 * 2); - busyIndicator->setProperty("running", false); + busyIndicator->setProperty("running", true); gifRecorder.waitForFinish(); } @@ -280,7 +381,7 @@ void tst_Gifs::switchGif() gifRecorder.setDataDirPath(dataDirPath); gifRecorder.setOutputDir(outputDir); gifRecorder.setRecordingDuration(3); - gifRecorder.setQmlFileName("qtlabscontrols-switch.qml"); + gifRecorder.setQmlFileName("qtquickcontrols2-switch.qml"); gifRecorder.setHighQuality(true); gifRecorder.start(); @@ -292,14 +393,23 @@ void tst_Gifs::switchGif() gifRecorder.waitForFinish(); } +void tst_Gifs::button_data() +{ + QTest::addColumn<QString>("qmlFileName"); + QTest::newRow("button") << QString::fromLatin1("qtquickcontrols2-button.qml"); + QTest::newRow("button-flat") << QString::fromLatin1("qtquickcontrols2-button-flat.qml"); + QTest::newRow("button-highlighted") << QString::fromLatin1("qtquickcontrols2-button-highlighted.qml"); +} + void tst_Gifs::button() { + QFETCH(QString, qmlFileName); + GifRecorder gifRecorder; gifRecorder.setDataDirPath(dataDirPath); gifRecorder.setOutputDir(outputDir); gifRecorder.setRecordingDuration(3); - gifRecorder.setQmlFileName("qtlabscontrols-button.qml"); - gifRecorder.setHighQuality(true); + gifRecorder.setQmlFileName(qmlFileName); gifRecorder.start(); @@ -312,7 +422,7 @@ void tst_Gifs::button() void tst_Gifs::tabBar() { - const QString qmlFileName = QStringLiteral("qtlabscontrols-tabbar.qml"); + const QString qmlFileName = QStringLiteral("qtquickcontrols2-tabbar.qml"); GifRecorder gifRecorder; gifRecorder.setDataDirPath(dataDirPath); @@ -341,7 +451,7 @@ void tst_Gifs::tabBar() void tst_Gifs::menu() { - const QString qmlFileName = QStringLiteral("qtlabscontrols-menu.qml"); + const QString qmlFileName = QStringLiteral("qtquickcontrols2-menu.qml"); GifRecorder gifRecorder; gifRecorder.setDataDirPath(dataDirPath); @@ -372,6 +482,487 @@ void tst_Gifs::menu() gifRecorder.waitForFinish(); } +void tst_Gifs::swipeView() +{ + GifRecorder gifRecorder; + gifRecorder.setDataDirPath(dataDirPath); + gifRecorder.setOutputDir(outputDir); + gifRecorder.setRecordingDuration(8); + gifRecorder.setQmlFileName(QStringLiteral("qtquickcontrols2-swipeview.qml")); + gifRecorder.setHighQuality(true); + + gifRecorder.start(); + + QQuickWindow *window = gifRecorder.window(); + QQuickItem *swipeView = window->property("swipeView").value<QQuickItem*>(); + QVERIFY(swipeView); + + QTest::qWait(1200); + swipeView->setProperty("currentIndex", 1); + QTest::qWait(2000); + swipeView->setProperty("currentIndex", 2); + QTest::qWait(2000); + swipeView->setProperty("currentIndex", 0); + + gifRecorder.waitForFinish(); +} + +void tst_Gifs::swipeDelegate_data() +{ + QTest::addColumn<QString>("qmlFileName"); + QTest::newRow("qtquickcontrols2-swipedelegate.qml") << QString::fromLatin1("qtquickcontrols2-swipedelegate.qml"); + QTest::newRow("qtquickcontrols2-swipedelegate-leading-trailing.qml") << QString::fromLatin1("qtquickcontrols2-swipedelegate-leading-trailing.qml"); +} + +void tst_Gifs::swipeDelegate() +{ + QFETCH(QString, qmlFileName); + + GifRecorder gifRecorder; + gifRecorder.setDataDirPath(dataDirPath); + gifRecorder.setOutputDir(outputDir); + gifRecorder.setRecordingDuration(10); + gifRecorder.setQmlFileName(qmlFileName); + gifRecorder.setHighQuality(true); + + gifRecorder.start(); + + QQuickWindow *window = gifRecorder.window(); + QQuickItem *swipeDelegate = window->property("swipeDelegate").value<QQuickItem*>(); + QVERIFY(swipeDelegate); + + // Show left item. + const QPoint leftTarget = QPoint(swipeDelegate->width() * 0.2, 0); + const QPoint rightTarget = QPoint(swipeDelegate->width() * 0.8, 0); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, leftTarget, 100); + const int movements = rightTarget.x() - leftTarget.x(); + moveSmoothly(window, leftTarget, rightTarget, movements, QEasingCurve::OutQuint, 5); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, rightTarget, 20); + + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, rightTarget, 1000); + moveSmoothly(window, rightTarget, leftTarget, movements, QEasingCurve::OutQuint, 5); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, leftTarget, 20); + + QTest::qWait(1000); + + // Show right item. + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, rightTarget, 1000); + moveSmoothly(window, rightTarget, leftTarget, movements, QEasingCurve::OutQuint, 5); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, leftTarget, 20); + + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, leftTarget, 1000); + moveSmoothly(window, leftTarget, rightTarget, movements, QEasingCurve::OutQuint, 5); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, rightTarget, 20); + + gifRecorder.waitForFinish(); +} + +void tst_Gifs::swipeDelegateBehind() +{ + GifRecorder gifRecorder; + gifRecorder.setDataDirPath(dataDirPath); + gifRecorder.setOutputDir(outputDir); + gifRecorder.setRecordingDuration(14); + gifRecorder.setQmlFileName(QStringLiteral("qtquickcontrols2-swipedelegate-behind.qml")); + gifRecorder.setHighQuality(true); + + gifRecorder.start(); + + QQuickWindow *window = gifRecorder.window(); + QQuickItem *swipeDelegate = window->property("swipeDelegate").value<QQuickItem*>(); + QVERIFY(swipeDelegate); + + // Show wrapping around left item. + const QPoint leftTarget = QPoint(swipeDelegate->width() * 0.2, 0); + const QPoint rightTarget = QPoint(swipeDelegate->width() * 0.8, 0); + const int movements = rightTarget.x() - leftTarget.x(); + for (int i = 0; i < 4; ++i) { + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, leftTarget, 100); + moveSmoothly(window, leftTarget, rightTarget, movements, QEasingCurve::OutQuint, 5); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, rightTarget, 20); + + QTest::qWait(500); + } + + QTest::qWait(1000); + + // Show wrapping around right item. + for (int i = 0; i < 4; ++i) { + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, rightTarget, 100); + moveSmoothly(window, rightTarget, leftTarget, movements, QEasingCurve::OutQuint, 5); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, leftTarget, 20); + + QTest::qWait(500); + } + + gifRecorder.waitForFinish(); +} + +void tst_Gifs::delegates_data() +{ + QTest::addColumn<QString>("name"); + QTest::addColumn<QVector<int> >("pressIndices"); + QTest::addColumn<int>("duration"); + + QTest::newRow("ItemDelegate") << "itemdelegate" << (QVector<int>() << 0 << 1 << 2) << 5; + QTest::newRow("CheckDelegate") << "checkdelegate" << (QVector<int>() << 0 << 0) << 5; + QTest::newRow("RadioDelegate") << "radiodelegate" << (QVector<int>() << 1 << 0) << 5; + QTest::newRow("SwitchDelegate") << "switchdelegate" << (QVector<int>() << 0 << 0) << 5; +} + +void tst_Gifs::delegates() +{ + QFETCH(QString, name); + QFETCH(QVector<int>, pressIndices); + QFETCH(int, duration); + + GifRecorder gifRecorder; + gifRecorder.setDataDirPath(dataDirPath); + gifRecorder.setOutputDir(outputDir); + gifRecorder.setRecordingDuration(duration); + gifRecorder.setQmlFileName(QString::fromLatin1("qtquickcontrols2-%1.qml").arg(name)); + gifRecorder.setHighQuality(true); + + gifRecorder.start(); + + QQuickWindow *window = gifRecorder.window(); + QQuickItem *delegate = window->property("delegate").value<QQuickItem*>(); + QVERIFY(delegate); + + for (int i = 0; i < pressIndices.size(); ++i) { + const int pressIndex = pressIndices.at(i); + const QPoint delegateCenter(delegate->mapToScene(QPointF( + delegate->width() / 2, delegate->height() / 2 + delegate->height() * pressIndex)).toPoint()); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, delegateCenter, i == 0 ? 200 : 1000); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, delegateCenter, 400); + } + + gifRecorder.waitForFinish(); +} + +void tst_Gifs::dial_data() +{ + QTest::addColumn<QString>("name"); + + QTest::newRow("dial-wrap") << "wrap"; + QTest::newRow("dial-no-wrap") << "no-wrap"; +} + +void tst_Gifs::dial() +{ + QFETCH(QString, name); + + GifRecorder gifRecorder; + gifRecorder.setDataDirPath(dataDirPath); + gifRecorder.setOutputDir(outputDir); + gifRecorder.setRecordingDuration(10); + gifRecorder.setQmlFileName(QString::fromLatin1("qtquickcontrols2-dial-%1.qml").arg(name)); + gifRecorder.setHighQuality(false); + + gifRecorder.start(); + + QQuickWindow *window = gifRecorder.window(); + QQuickItem *dial = window->property("dial").value<QQuickItem*>(); + QVERIFY(dial); + + const QPoint arcCenter = dial->mapToScene(QPoint(dial->width() / 2, dial->height() / 2)).toPoint(); + const qreal distanceFromCenter = dial->height() * 0.25; + // Go a bit past the actual min/max to ensure that we get the full range. + const qreal minAngle = qDegreesToRadians(-170.0); + const qreal maxAngle = qDegreesToRadians(170.0); + // Drag from start to end. + qreal startAngle = minAngle; + qreal endAngle = maxAngle; + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, posAlongArc( + arcCenter, startAngle, endAngle, distanceFromCenter, 0, QEasingCurve::InOutQuad), 30); + + moveSmoothlyAlongArc(window, arcCenter, distanceFromCenter, startAngle, endAngle, QEasingCurve::InOutQuad); + + // Come back from the end a bit. + startAngle = endAngle; + endAngle -= qDegreesToRadians(50.0); + moveSmoothlyAlongArc(window, arcCenter, distanceFromCenter, startAngle, endAngle, QEasingCurve::InOutQuad); + + // Try to drag over max to show what happens with different wrap settings. + startAngle = endAngle; + endAngle = qDegreesToRadians(270.0); + moveSmoothlyAlongArc(window, arcCenter, distanceFromCenter, startAngle, endAngle, QEasingCurve::InOutQuad); + + // Go back to the start so that it loops nicely. + startAngle = endAngle; + endAngle = minAngle; + moveSmoothlyAlongArc(window, arcCenter, distanceFromCenter, startAngle, endAngle, QEasingCurve::InOutQuad); + + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, posAlongArc( + arcCenter, startAngle, endAngle, distanceFromCenter, 1, QEasingCurve::InOutQuad), 30); + + gifRecorder.waitForFinish(); +} + +void tst_Gifs::checkables_data() +{ + QTest::addColumn<QString>("name"); + QTest::addColumn<QVector<int> >("pressIndices"); + + QTest::newRow("checkbox") << "checkbox" << (QVector<int>() << 1 << 2 << 2 << 1); + QTest::newRow("radiobutton") << "radiobutton" << (QVector<int>() << 1 << 2 << 1 << 0); +} + +void tst_Gifs::checkables() +{ + QFETCH(QString, name); + QFETCH(QVector<int>, pressIndices); + + GifRecorder gifRecorder; + gifRecorder.setDataDirPath(dataDirPath); + gifRecorder.setOutputDir(outputDir); + gifRecorder.setRecordingDuration(6); + gifRecorder.setQmlFileName(QString::fromLatin1("qtquickcontrols2-%1.qml").arg(name)); + + gifRecorder.start(); + + QQuickWindow *window = gifRecorder.window(); + + for (int i = 0; i < pressIndices.size(); ++i) { + const int pressIndex = pressIndices.at(i); + const char *controlId = qPrintable(QString::fromLatin1("control%1").arg(pressIndex + 1)); + QQuickItem *control = window->property(controlId).value<QQuickItem*>(); + QVERIFY(control); + + const QPoint pos = control->mapToScene(QPointF(control->width() / 2, control->height() / 2)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, pos, 800); + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, pos, 300); + } + + gifRecorder.waitForFinish(); +} + +void tst_Gifs::comboBox() +{ + GifRecorder gifRecorder; + gifRecorder.setDataDirPath(dataDirPath); + gifRecorder.setOutputDir(outputDir); + gifRecorder.setRecordingDuration(6); + gifRecorder.setQmlFileName(QStringLiteral("qtquickcontrols2-combobox.qml")); + + gifRecorder.start(); + + QQuickWindow *window = gifRecorder.window(); + QQuickItem *comboBox = window->property("comboBox").value<QQuickItem*>(); + QVERIFY(comboBox); + + // Open the popup. + const QPoint center = comboBox->mapToScene( + QPoint(comboBox->width() / 2, comboBox->height() / 2)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, center, 800); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, center, 80); + + // Select the third item. + QObject *popup = comboBox->property("popup").value<QObject*>(); + QVERIFY(popup); + QQuickItem *popupContent = popup->property("contentItem").value<QQuickItem*>(); + QVERIFY(popupContent); + const QPoint lastItemPos = popupContent->mapToScene( + QPoint(popupContent->width() / 2, popupContent->height() * 0.8)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, lastItemPos, 600); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, lastItemPos, 200); + + // Open the popup. + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, center, 1500); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, center, 80); + + // Select the first item. + const QPoint firstItemPos = popupContent->mapToScene( + QPoint(popupContent->width() / 2, popupContent->height() * 0.2)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, firstItemPos, 600); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, firstItemPos, 200); + + gifRecorder.waitForFinish(); +} + +void tst_Gifs::triState_data() +{ + QTest::addColumn<QString>("name"); + + QTest::newRow("checkbox-tristate") << "checkbox-tristate"; + QTest::newRow("checkdelegate-tristate") << "checkdelegate-tristate"; +} + +void tst_Gifs::triState() +{ + QFETCH(QString, name); + + GifRecorder gifRecorder; + gifRecorder.setDataDirPath(dataDirPath); + gifRecorder.setOutputDir(outputDir); + gifRecorder.setRecordingDuration(6); + gifRecorder.setQmlFileName(QString::fromLatin1("qtquickcontrols2-%1.qml").arg(name)); + + gifRecorder.start(); + + QQuickWindow *window = gifRecorder.window(); + QQuickItem *english = window->property("english").value<QQuickItem*>(); + QVERIFY(english); + QQuickItem *norwegian = window->property("norwegian").value<QQuickItem*>(); + QVERIFY(norwegian); + + const QPoint englishCenter = english->mapToScene( + QPointF(english->width() / 2, english->height() / 2)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, englishCenter, 1000); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, englishCenter, 300); + + const QPoint norwegianCenter = norwegian->mapToScene( + QPointF(norwegian->width() / 2, norwegian->height() / 2)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, norwegianCenter, 1000); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, norwegianCenter, 300); + + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, norwegianCenter, 1000); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, norwegianCenter, 300); + + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, englishCenter, 1000); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, englishCenter, 300); + + gifRecorder.waitForFinish(); +} + +void tst_Gifs::scrollBar() +{ + GifRecorder gifRecorder; + gifRecorder.setDataDirPath(dataDirPath); + gifRecorder.setOutputDir(outputDir); + gifRecorder.setRecordingDuration(6); + gifRecorder.setQmlFileName("qtquickcontrols2-scrollbar.qml"); + + gifRecorder.start(); + + QQuickWindow *window = gifRecorder.window(); + QQuickItem *scrollBar = window->property("scrollBar").value<QQuickItem*>(); + QVERIFY(scrollBar); + + // Flick in the center of the screen to show that there's a scroll bar. + const QPoint lhsWindowBottom = QPoint(0, window->height() - 1); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, lhsWindowBottom, 100); + QTest::mouseMove(window, lhsWindowBottom - QPoint(0, 10), 30); + QTest::mouseMove(window, lhsWindowBottom - QPoint(0, 30), 30); + QTest::mouseMove(window, lhsWindowBottom - QPoint(0, 60), 30); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, lhsWindowBottom - QPoint(0, 100), 30); + + // Scroll with the scroll bar. + const QPoint rhsWindowBottom = QPoint(window->width() - 1, window->height() - 1); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, rhsWindowBottom, 2000); + const QPoint rhsWindowTop = QPoint(window->width() - 1, 1); + moveSmoothly(window, rhsWindowBottom, rhsWindowTop, + qAbs(rhsWindowTop.y() - rhsWindowBottom.y()), QEasingCurve::InCubic, 10); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, rhsWindowTop, 20); + + gifRecorder.waitForFinish(); +} + +void tst_Gifs::scrollIndicator() +{ + GifRecorder gifRecorder; + gifRecorder.setDataDirPath(dataDirPath); + gifRecorder.setOutputDir(outputDir); + gifRecorder.setRecordingDuration(6); + gifRecorder.setQmlFileName("qtquickcontrols2-scrollindicator.qml"); + + gifRecorder.start(); + + // Flick in the center of the screen to show that there's a scroll indicator. + QQuickWindow *window = gifRecorder.window(); + const QPoint windowBottom = QPoint(0, window->height() - 1); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, windowBottom, 100); + QTest::mouseMove(window, windowBottom - QPoint(0, 10), 30); + QTest::mouseMove(window, windowBottom - QPoint(0, 30), 30); + QTest::mouseMove(window, windowBottom - QPoint(0, 60), 30); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, windowBottom - QPoint(0, 100), 30); + + // Scroll back down. + const QPoint windowTop = QPoint(0, 0); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, windowTop, 2000); + QTest::mouseMove(window, windowTop + QPoint(0, 10), 30); + QTest::mouseMove(window, windowTop + QPoint(0, 30), 30); + QTest::mouseMove(window, windowTop + QPoint(0, 60), 30); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, windowTop + QPoint(0, 100), 30); + + gifRecorder.waitForFinish(); +} + +void tst_Gifs::progressBar_data() +{ + QTest::addColumn<bool>("indeterminate"); + + QTest::newRow("indeterminate:false") << false; + QTest::newRow("indeterminate:true") << true; +} + +void tst_Gifs::progressBar() +{ + QFETCH(bool, indeterminate); + + GifRecorder gifRecorder; + gifRecorder.setDataDirPath(dataDirPath); + gifRecorder.setOutputDir(outputDir); + gifRecorder.setRecordingDuration(4); + gifRecorder.setQmlFileName(QString::fromLatin1("qtquickcontrols2-progressbar%1").arg( + indeterminate ? QLatin1String("-indeterminate.qml") : QLatin1String(".qml"))); + + gifRecorder.start(); + gifRecorder.waitForFinish(); +} + +void tst_Gifs::stackView_data() +{ + QTest::addColumn<QString>("name"); + QTest::addColumn<int>("duration"); + + QTest::newRow("push") << "push" << 8; + QTest::newRow("pop") << "pop" << 6; + QTest::newRow("unwind") << "unwind" << 6; + QTest::newRow("replace") << "replace" << 6; +} + +void tst_Gifs::stackView() +{ + QFETCH(QString, name); + QFETCH(int, duration); + + GifRecorder gifRecorder; + gifRecorder.setDataDirPath(dataDirPath); + gifRecorder.setOutputDir(outputDir); + gifRecorder.setRecordingDuration(duration); + gifRecorder.setHighQuality(true); + gifRecorder.setQmlFileName(QString::fromLatin1("qtquickcontrols2-stackview-%1.qml").arg(name)); + + gifRecorder.start(); + gifRecorder.waitForFinish(); +} + +void tst_Gifs::drawer() +{ + GifRecorder gifRecorder; + gifRecorder.setDataDirPath(dataDirPath); + gifRecorder.setOutputDir(outputDir); + gifRecorder.setRecordingDuration(4); + gifRecorder.setHighQuality(true); + gifRecorder.setQmlFileName("qtquickcontrols2-drawer.qml"); + + gifRecorder.start(); + + QQuickWindow *window = gifRecorder.window(); + QObject *drawer = window->property("drawer").value<QObject*>(); + qreal width = drawer->property("width").toReal(); + + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1), 100); + moveSmoothly(window, QPoint(1, 1), QPoint(width, 1), width, QEasingCurve::InOutBack, 1); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(width, 1), 30); + + QTest::qWait(1000); + QMetaObject::invokeMethod(drawer, "close"); + + gifRecorder.waitForFinish(); +} + QTEST_MAIN(tst_Gifs) #include "tst_gifs.moc" diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro index a85fd870..5c648cea 100644 --- a/tests/manual/manual.pro +++ b/tests/manual/manual.pro @@ -2,6 +2,8 @@ TEMPLATE = subdirs SUBDIRS += \ gifs \ fonts \ + screenshots \ + styles \ testbench qtHaveModule(widgets): SUBDIRS += viewinqwidget diff --git a/tests/manual/screenshots/qtquickcontrols2.conf b/tests/manual/screenshots/qtquickcontrols2.conf new file mode 100644 index 00000000..b6c7c87e --- /dev/null +++ b/tests/manual/screenshots/qtquickcontrols2.conf @@ -0,0 +1,2 @@ +[Controls] +Style=Material diff --git a/tests/manual/screenshots/screenshots.cpp b/tests/manual/screenshots/screenshots.cpp new file mode 100644 index 00000000..0c14ead3 --- /dev/null +++ b/tests/manual/screenshots/screenshots.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QGuiApplication> +#include <QQmlApplicationEngine> +#include <QQmlContext> +#include <QFileInfo> +#include <QDir> + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + + QQmlApplicationEngine engine; + const QUrl snippetsDir = QUrl::fromLocalFile(SNIPPETS_DIR); + Q_ASSERT(snippetsDir.isValid() && QFileInfo(snippetsDir.toLocalFile()).exists()); + engine.rootContext()->setContextProperty("snippetsDir", snippetsDir); + engine.rootContext()->setContextProperty("screenshotsDir", QUrl::fromLocalFile(QDir::currentPath())); + engine.rootContext()->setContextProperty("screenshotsDirStr", QDir::currentPath()); + engine.load(QUrl("qrc:/screenshots.qml")); + if (engine.rootObjects().isEmpty()) + return -1; + + return app.exec(); +} diff --git a/tests/manual/screenshots/screenshots.pro b/tests/manual/screenshots/screenshots.pro new file mode 100644 index 00000000..5894888f --- /dev/null +++ b/tests/manual/screenshots/screenshots.pro @@ -0,0 +1,13 @@ +TEMPLATE = app +TARGET = screenshots +QT += quick widgets + +DEFINES += SNIPPETS_DIR=\\\"$$PWD/../../../src/imports/controls/doc/snippets\\\" +message($$DEFINES) + +SOURCES += \ + screenshots.cpp + +RESOURCES += \ + screenshots.qml \ + qtquickcontrols2.conf diff --git a/tests/manual/screenshots/screenshots.qml b/tests/manual/screenshots/screenshots.qml new file mode 100644 index 00000000..afe7368b --- /dev/null +++ b/tests/manual/screenshots/screenshots.qml @@ -0,0 +1,164 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Layouts 1.3 +import QtQuick.Controls 2.0 +import Qt.labs.folderlistmodel 2.1 + +ApplicationWindow { + id: window + title: "Qt Quick Controls 2 - Screenshots" + visible: true + width: Math.max(600, loader.implicitWidth) + height: Math.max(600, loader.implicitHeight) + + property string currentFilePath + property string lastSavePath + + Shortcut { + sequence: "Ctrl+Q" + onActivated: Qt.quit() + } + + header: ToolBar { + RowLayout { + anchors.fill: parent + + ToolButton { + text: "Choose Snippet" + focusPolicy: Qt.NoFocus + onClicked: snippetDrawer.open() + } + } + } + + Drawer { + id: snippetDrawer + width: window.width / 2 + height: window.height + + ListView { + id: snippetsListView + anchors.fill: parent + model: FolderListModel { + folder: snippetsDir + nameFilters: ["*.qml"] + showDirs: false + } + delegate: ItemDelegate { + width: parent.width + text: fileName + focusPolicy: Qt.NoFocus + + readonly property string baseName: fileBaseName + + contentItem: Label { + text: parent.text + elide: Text.ElideLeft + } + onClicked: { + snippetsListView.currentIndex = index; + loader.source = "file:///" + filePath; + currentFilePath = filePath; + snippetDrawer.close(); + } + } + } + } + + Loader { + id: loader + anchors.centerIn: parent + } + + ToolTip { + id: saveResultToolTip + x: window.contentItem.width / 2 - width / 2 + y: window.contentItem.height - height - 20 + timeout: 3000 + } + + footer: ToolBar { + RowLayout { + anchors.fill: parent + + ToolButton { + text: "Open Output Folder" + focusPolicy: Qt.NoFocus + onClicked: Qt.openUrlExternally(screenshotsDir) + } + + ToolButton { + text: "Open Last Screenshot" + focusPolicy: Qt.NoFocus + enabled: lastSavePath.length > 0 + onClicked: Qt.openUrlExternally(lastSavePath) + } + + Item { + Layout.fillWidth: true + } + + ToolButton { + text: "Take Screenshot" + focusPolicy: Qt.NoFocus + enabled: loader.status === Loader.Ready + onClicked: { + if (!loader.item) + return; + + var grabSuccessful = loader.grabToImage(function(result) { + var savePath = screenshotsDirStr + "/" + snippetsListView.currentItem.baseName + ".png"; + if (result.saveToFile(savePath)) { + saveResultToolTip.text = "Successfully saved screenshot to output folder"; + lastSavePath = savePath; + } else { + saveResultToolTip.text = "Failed to save screenshot"; + } + }) + if (!grabSuccessful) + saveResultToolTip.text = "Failed to grab image"; + saveResultToolTip.open(); + } + } + } + } +} diff --git a/tests/manual/styles/styles.cpp b/tests/manual/styles/styles.cpp new file mode 100644 index 00000000..4e9c7517 --- /dev/null +++ b/tests/manual/styles/styles.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QGuiApplication> +#include <QQmlApplicationEngine> + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + + QQmlApplicationEngine engine; + engine.load(QUrl("qrc:/styles.qml")); + if (engine.rootObjects().isEmpty()) + return -1; + + return app.exec(); +} diff --git a/tests/manual/styles/styles.pro b/tests/manual/styles/styles.pro new file mode 100644 index 00000000..060ab4f7 --- /dev/null +++ b/tests/manual/styles/styles.pro @@ -0,0 +1,9 @@ +TEMPLATE = app +TARGET = styles +QT += quick quickcontrols2 + +SOURCES += \ + styles.cpp + +RESOURCES += \ + styles.qml diff --git a/tests/manual/styles/styles.qml b/tests/manual/styles/styles.qml new file mode 100644 index 00000000..277604eb --- /dev/null +++ b/tests/manual/styles/styles.qml @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Layouts 1.3 +import QtQuick.Controls 2.0 + +ApplicationWindow { + id: window + + visible: true + minimumWidth: column.implicitWidth + 80 + minimumHeight: column.implicitHeight + 80 + title: "Qt Quick Controls 2 - Styles" + + // for taking frameless screenshots: + // flags: Qt.Window | Qt.FramelessWindowHint + + ColumnLayout { + id: column + + spacing: 20 + anchors.fill: parent + anchors.margins: 40 + + GroupBox { + title: "Font Size" + topPadding: 30 + background.visible: false + + ColumnLayout { + anchors.fill: parent + anchors.leftMargin: 20 + + RadioButton { leftPadding: 0; text: "Small" } + RadioButton { leftPadding: 0; text: "Medium"; checked: true } + RadioButton { leftPadding: 0; text: "Large" } + } + } + + GroupBox { + title: "Audio" + topPadding: 30 + background.visible: false + + GridLayout { + columns: 2 + columnSpacing: 30 + anchors.fill: parent + anchors.leftMargin: 20 + + Label { text: "Volume" } + Slider { value: 1.0 } + Label { text: "Bass" } + Slider { value: 0.75 } + Label { text: "Treble" } + Slider { value: 0.5 } + } + } + + Button { + text: "Save" + Layout.alignment: Qt.AlignRight + } + + Item { Layout.fillHeight: true } + } +} diff --git a/tests/manual/testbench/main.cpp b/tests/manual/testbench/main.cpp index e0f975fe..5a54dab3 100644 --- a/tests/manual/testbench/main.cpp +++ b/tests/manual/testbench/main.cpp @@ -52,9 +52,9 @@ int main(int argc, char *argv[]) // These must be set before running. // TODO: move style selection into app UI and use settings to save choices. - // qputenv("QT_LABS_CONTROLS_STYLE", "material"); + // qputenv("QT_QUICK_CONTROLS_STYLE", "material"); QQmlApplicationEngine engine; - engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); + engine.load(QUrl(QStringLiteral("qrc:/testbench.qml"))); return app.exec(); } diff --git a/tests/manual/testbench/qml.qrc b/tests/manual/testbench/qml.qrc index 5f6483ac..9f4b1783 100644 --- a/tests/manual/testbench/qml.qrc +++ b/tests/manual/testbench/qml.qrc @@ -1,5 +1,5 @@ <RCC> <qresource prefix="/"> - <file>main.qml</file> + <file>testbench.qml</file> </qresource> </RCC> diff --git a/tests/manual/testbench/main.qml b/tests/manual/testbench/testbench.qml index 6ace3620..3e8b3d0f 100644 --- a/tests/manual/testbench/main.qml +++ b/tests/manual/testbench/testbench.qml @@ -41,9 +41,9 @@ import QtQuick 2.6 import QtQuick.Window 2.2 import QtQuick.Layouts 1.0 -import Qt.labs.controls 1.0 -import Qt.labs.controls.material 1.0 -import Qt.labs.controls.universal 1.0 +import QtQuick.Controls 2.0 +import QtQuick.Controls.Material 2.0 +import QtQuick.Controls.Universal 2.0 ApplicationWindow { id: window @@ -51,6 +51,11 @@ ApplicationWindow { width: 750 height: 1000 + Component.onCompleted: { + x = Screen.width / 2 - width / 2 + y = Screen.height / 2 - height / 2 + } + Material.theme: themeSwitch.checked ? Material.Dark : Material.Light Universal.theme: themeSwitch.checked ? Universal.Dark : Universal.Light @@ -69,6 +74,10 @@ ApplicationWindow { ToolButton { text: "Normal" + hoverEnabled: true + ToolTip.text: text + ToolTip.delay: 1000 + ToolTip.visible: hovered onClicked: menu.visible ? menu.close() : menu.open() Menu { @@ -92,16 +101,28 @@ ApplicationWindow { } ToolButton { text: "Pressed" - pressed: true + down: true + hoverEnabled: true + ToolTip.text: text + ToolTip.delay: 1000 + ToolTip.visible: hovered } ToolButton { text: "Checked" checkable: true checked: true + hoverEnabled: true + ToolTip.text: text + ToolTip.delay: 1000 + ToolTip.visible: hovered } ToolButton { text: "Highlighted" highlighted: true + hoverEnabled: true + ToolTip.text: text + ToolTip.delay: 1000 + ToolTip.visible: hovered } ToolButton { text: "Disabled" @@ -125,7 +146,7 @@ ApplicationWindow { } TabButton { text: "Pressed" - pressed: true + down: true } TabButton { text: "Disabled" @@ -153,7 +174,7 @@ ApplicationWindow { } Button { text: "Pressed" - pressed: true + down: true } Button { text: "Checked" @@ -162,7 +183,7 @@ ApplicationWindow { Button { text: "CH + PR" checked: true - pressed: true + down: true } Button { text: "Disabled" @@ -185,7 +206,7 @@ ApplicationWindow { Button { text: "HI + PR" highlighted: true - pressed: true + down: true } Button { text: "HI + CH" @@ -195,7 +216,7 @@ ApplicationWindow { Button { text: "HI+CH+PR" highlighted: true - pressed: true + down: true checked: true } Button { @@ -217,7 +238,7 @@ ApplicationWindow { } CheckBox { text: "Pressed" - pressed: true + down: true } CheckBox { text: "Checked" @@ -226,7 +247,7 @@ ApplicationWindow { CheckBox { text: "CH + PR" checked: true - pressed: true + down: true } CheckBox { text: "Disabled" @@ -245,7 +266,7 @@ ApplicationWindow { } RadioButton { text: "Pressed" - pressed: true + down: true } RadioButton { text: "Checked" @@ -254,7 +275,7 @@ ApplicationWindow { RadioButton { text: "CH + PR" checked: true - pressed: true + down: true } RadioButton { text: "Disabled" @@ -273,7 +294,7 @@ ApplicationWindow { } Switch { text: "Pressed" - pressed: true + down: true } Switch { text: "Checked" @@ -282,7 +303,7 @@ ApplicationWindow { Switch { text: "CH + PR" checked: true - pressed: true + down: true } Switch { text: "Disabled" @@ -604,14 +625,14 @@ ApplicationWindow { Frame { Tumbler { model: 5 - implicitWidth: 100 + implicitWidth: 80 implicitHeight: 100 } } Frame { Tumbler { model: 5 - implicitWidth: 100 + implicitWidth: 80 implicitHeight: 100 enabled: false } @@ -620,11 +641,147 @@ ApplicationWindow { RowLayout { Dial { + implicitWidth: 100 + implicitHeight: 100 } Dial { + implicitWidth: 100 + implicitHeight: 100 enabled: false } } + + ListModel { + id: checkableDelegateModel + ListElement { label: "Normal" } + ListElement { label: "Pressed"; press: true } + ListElement { label: "Checked"; check: true } + ListElement { label: "CH + PR"; check: true; press: true } + ListElement { label: "Disabled"; disabled: true } + } + + RowLayout { + Frame { + Column { + width: 200 + + Repeater { + model: checkableDelegateModel + delegate: CheckDelegate { + text: label + width: parent.width + down: press + checked: check + enabled: !disabled + ButtonGroup.group: radioButtonGroup + } + } + } + } + + ButtonGroup { + id: radioButtonGroup + } + + Frame { + Column { + width: 200 + + Repeater { + model: checkableDelegateModel + delegate: RadioDelegate { + text: label + down: press + width: parent.width + checked: check + enabled: !disabled + ButtonGroup.group: radioButtonGroup + } + } + } + } + + Frame { + Column { + width: 200 + + Repeater { + model: checkableDelegateModel + delegate: SwitchDelegate { + text: label + width: parent.width + checked: check + down: press + enabled: !disabled + } + } + } + } + } + + ListModel { + id: regularDelegateModel + ListElement { label: "Normal" } + ListElement { label: "Pressed"; press: true } + ListElement { label: "Disabled"; disabled: true } + } + + RowLayout { + Frame { + Column { + width: 200 + + Repeater { + model: regularDelegateModel + delegate: ItemDelegate { + text: label + width: parent.width + down: press + enabled: !disabled + } + } + } + } + Frame { + Column { + id: listView + width: 200 + clip: true + + Repeater { + model: regularDelegateModel + delegate: SwipeDelegate { + id: swipeDelegate + text: label + width: parent.width + down: press + enabled: !disabled + + Component { + id: removeComponent + + Rectangle { + color: swipeDelegate.swipe.complete && swipeDelegate.pressed ? "#333" : "#444" + width: parent.width + height: parent.height + clip: true + + Label { + font.pixelSize: swipeDelegate.font.pixelSize + text: "Boop" + color: "white" + anchors.centerIn: parent + } + } + } + + swipe.left: removeComponent + swipe.right: removeComponent + } + } + } + } + } } } } diff --git a/tests/manual/viewinqwidget/main.cpp b/tests/manual/viewinqwidget/main.cpp index ff949544..3611e071 100644 --- a/tests/manual/viewinqwidget/main.cpp +++ b/tests/manual/viewinqwidget/main.cpp @@ -68,7 +68,7 @@ int main(int argc, char *argv[]) const QUrl gallerySource(QLatin1String("qrc:/gallery.qml")); QQmlApplicationEngine engine(gallerySource); - QObject *root = engine.rootObjects().value(0, Q_NULLPTR); + QObject *root = engine.rootObjects().value(0, nullptr); if (!root || !root->isWindowType()) { qWarning() << "Load error" << gallerySource; return 1; diff --git a/tests/manual/viewinqwidget/main.qml b/tests/manual/viewinqwidget/main.qml index 36a0b133..5ad52d83 100644 --- a/tests/manual/viewinqwidget/main.qml +++ b/tests/manual/viewinqwidget/main.qml @@ -35,7 +35,7 @@ ****************************************************************************/ import QtQuick 2.6 -import Qt.labs.controls 1.0 +import QtQuick.Controls 2.0 Item { visible: true |