diff options
author | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2014-10-09 18:04:51 +0200 |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2014-10-09 18:04:51 +0200 |
commit | 9676488f7e8af1bab9752a4280d7fe6aa34a47ac (patch) | |
tree | d9a7b4097ce765685ffedf7f885396bb79e96b2c | |
parent | bb519a4001ae9ed1e780017ea8551c37c0098529 (diff) | |
parent | c36f219faaa2a1b89ac19d0822200b163c22eec0 (diff) | |
download | qtquickcontrols-9676488f7e8af1bab9752a4280d7fe6aa34a47ac.tar.gz |
Merge remote-tracking branch 'origin/5.4' into dev
Change-Id: Icc27c3f8638601b43daac37ce4a6d9678476996a
96 files changed, 2087 insertions, 444 deletions
@@ -5,12 +5,14 @@ /examples/quick/controls/calendar/calendar /examples/quick/controls/gallery/gallery /examples/quick/controls/splitview/splitview +/examples/quick/controls/styles/styles /examples/quick/controls/tableview/tableview /examples/quick/controls/touch/touch /examples/quick/controls/texteditor/texteditor /examples/quick/dialogs/systemdialogs/systemdialogs /tests/auto/activeFocusOnTab/tst_activeFocusOnTab /tests/auto/controls/tst_controls +/tests/auto/dialogs/tst_dialogs /tests/auto/qtdesktop/tst_qtdesktop /tests/auto/applicationwindow/tst_applicationwindow /tests/auto/testplugin/QtQuickControlsTests/testplugin.* diff --git a/.qmake.conf b/.qmake.conf index aa932dda..6781e4b5 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -1,4 +1,5 @@ load(qt_build_config) +CONFIG += warning_clean android|ios|qnx|winrt|isEmpty(QT.widgets.name): CONFIG += no_desktop MODULE_VERSION = 5.5.0 diff --git a/examples/quick/controls/controls.pro b/examples/quick/controls/controls.pro index 2913e298..134a25e3 100644 --- a/examples/quick/controls/controls.pro +++ b/examples/quick/controls/controls.pro @@ -5,7 +5,8 @@ SUBDIRS += \ splitview \ tableview \ touch \ - basiclayouts + basiclayouts \ + styles qtHaveModule(widgets) { SUBDIRS += texteditor diff --git a/examples/quick/controls/gallery/content/AboutDialog.qml b/examples/quick/controls/gallery/content/AboutDialog.qml index aec7b604..e4837ff7 100644 --- a/examples/quick/controls/gallery/content/AboutDialog.qml +++ b/examples/quick/controls/gallery/content/AboutDialog.qml @@ -37,6 +37,7 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ + import QtQuick 2.2 import QtQuick.Dialogs 1.1 diff --git a/examples/quick/controls/gallery/content/ChildWindow.qml b/examples/quick/controls/gallery/content/ChildWindow.qml deleted file mode 100644 index 039e20dd..00000000 --- a/examples/quick/controls/gallery/content/ChildWindow.qml +++ /dev/null @@ -1,122 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the Qt Quick Controls module 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 Digia Plc and its Subsidiary(-ies) 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 QtQuick.Window 2.1 -import QtQuick.Controls 1.2 - -Window { - id: window1 - - width: 400 - height: 400 - - title: "child window" - flags: Qt.Dialog - - Rectangle { - color: syspal.window - anchors.fill: parent - - Label { - id: dimensionsText - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - width: parent.width - horizontalAlignment: Text.AlignHCenter - } - - Label { - id: availableDimensionsText - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: dimensionsText.bottom - width: parent.width - horizontalAlignment: Text.AlignHCenter - } - - Label { - id: closeText - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: availableDimensionsText.bottom - text: "This is a new Window, press the\nbutton below to close it again." - } - Button { - anchors.horizontalCenter: closeText.horizontalCenter - anchors.top: closeText.bottom - id: closeWindowButton - text:"Close" - width: 98 - tooltip:"Press me, to close this window again" - onClicked: window1.visible = false - } - Button { - anchors.horizontalCenter: closeText.horizontalCenter - anchors.top: closeWindowButton.bottom - id: maximizeWindowButton - text:"Maximize" - width: 98 - tooltip:"Press me, to maximize this window again" - onClicked: window1.visibility = Window.Maximized; - } - Button { - anchors.horizontalCenter: closeText.horizontalCenter - anchors.top: maximizeWindowButton.bottom - id: normalizeWindowButton - text:"Normalize" - width: 98 - tooltip:"Press me, to normalize this window again" - onClicked: window1.visibility = Window.Windowed; - } - Button { - anchors.horizontalCenter: closeText.horizontalCenter - anchors.top: normalizeWindowButton.bottom - id: minimizeWindowButton - text:"Minimize" - width: 98 - tooltip:"Press me, to minimize this window again" - onClicked: window1.visibility = Window.Minimized; - } - } -} - diff --git a/examples/quick/controls/gallery/content/Controls.qml b/examples/quick/controls/gallery/content/Controls.qml index 64df4ebd..54ee99b9 100644 --- a/examples/quick/controls/gallery/content/Controls.qml +++ b/examples/quick/controls/gallery/content/Controls.qml @@ -38,10 +38,6 @@ ** ****************************************************************************/ - - - - import QtQuick 2.2 import QtQuick.Controls 1.2 import QtQuick.Layouts 1.1 @@ -54,6 +50,20 @@ Item { property int tabPosition: tabPositionGroup.current === r2 ? Qt.BottomEdge : Qt.TopEdge + property string loremIpsum: + "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor "+ + "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor "+ + "incididunt ut labore et dolore magna aliqua.\n Ut enim ad minim veniam, quis nostrud "+ + "exercitation ullamco laboris nisi ut aliquip ex ea commodo cosnsequat. "; + + ListModel { + id: choices + ListElement { text: "Banana" } + ListElement { text: "Orange" } + ListElement { text: "Apple" } + ListElement { text: "Coconut" } + } + RowLayout { id: contentRow anchors.fill:parent @@ -216,13 +226,54 @@ Item { wrapMode: wrapCheck.checked ? TextEdit.WordWrap : TextEdit.NoWrap Layout.fillWidth: true Layout.fillHeight: true - MouseArea { - id: contextMenu - parent: area.viewport - anchors.fill: parent - acceptedButtons: Qt.RightButton - onPressed: editmenu.popup() - } + menu: editmenu + } + } + } + + ExclusiveGroup { + id: textFormatGroup + + Action { + id: a1 + text: "Align &Left" + checkable: true + Component.onCompleted: checked = true + } + + Action { + id: a2 + text: "&Center" + checkable: true + } + + Action { + id: a3 + text: "Align &Right" + checkable: true + } + } + + Component { + id: editmenu + Menu { + MenuItem { action: cutAction } + MenuItem { action: copyAction } + MenuItem { action: pasteAction } + MenuSeparator {} + Menu { + title: "Text &Format" + MenuItem { action: a1 } + MenuItem { action: a2 } + MenuItem { action: a3 } + MenuSeparator { } + MenuItem { text: "Allow &Hyphenation"; checkable: true } + } + Menu { + title: "Font &Style" + MenuItem { text: "&Bold"; checkable: true } + MenuItem { text: "&Italic"; checkable: true } + MenuItem { text: "&Underline"; checkable: true } } } } diff --git a/examples/quick/controls/gallery/content/ImageViewer.qml b/examples/quick/controls/gallery/content/ImageViewer.qml index 01f24ab3..dfac2e00 100644 --- a/examples/quick/controls/gallery/content/ImageViewer.qml +++ b/examples/quick/controls/gallery/content/ImageViewer.qml @@ -37,6 +37,7 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ + import QtQuick 2.2 import QtQuick.Window 2.1 diff --git a/examples/quick/controls/gallery/content/ModelView.qml b/examples/quick/controls/gallery/content/ModelView.qml index 5474f1ba..a5d07d15 100644 --- a/examples/quick/controls/gallery/content/ModelView.qml +++ b/examples/quick/controls/gallery/content/ModelView.qml @@ -38,13 +38,8 @@ ** ****************************************************************************/ - - - - import QtQuick 2.2 import QtQuick.Controls 1.2 -//import QtQuick.XmlListModel 2.1 Item { id: root @@ -53,16 +48,6 @@ Item { anchors.fill: parent anchors.margins: Qt.platform.os === "osx" ? 12 : 6 -// XmlListModel { -// id: flickerModel -// source: "http://api.flickr.com/services/feeds/photos_public.gne?format=rss2&tags=" + "Cat" -// query: "/rss/channel/item" -// namespaceDeclarations: "declare namespace media=\"http://search.yahoo.com/mrss/\";" -// XmlRole { name: "title"; query: "title/string()" } -// XmlRole { name: "imagesource"; query: "media:thumbnail/@url/string()" } -// XmlRole { name: "credit"; query: "media:credit/string()" } -// } - ListModel { id: dummyModel Component.onCompleted: { diff --git a/examples/quick/controls/gallery/content/Styles.qml b/examples/quick/controls/gallery/content/Styles.qml index f78ab69f..03be93fd 100644 --- a/examples/quick/controls/gallery/content/Styles.qml +++ b/examples/quick/controls/gallery/content/Styles.qml @@ -38,10 +38,6 @@ ** ****************************************************************************/ - - - - import QtQuick 2.2 import QtQuick.Controls 1.2 import QtQuick.Controls.Styles 1.1 @@ -384,4 +380,3 @@ Item { leftCorner: Item { implicitWidth: 12 } } } - diff --git a/examples/quick/controls/gallery/gallery.pro b/examples/quick/controls/gallery/gallery.pro index e10e9763..992dd891 100644 --- a/examples/quick/controls/gallery/gallery.pro +++ b/examples/quick/controls/gallery/gallery.pro @@ -8,7 +8,6 @@ include(../shared/shared.pri) OTHER_FILES += \ main.qml \ content/AboutDialog.qml \ - content/ChildWindow.qml \ content/Controls.qml \ content/ImageViewer.qml \ content/ModelView.qml \ diff --git a/examples/quick/controls/gallery/images/window-new.png b/examples/quick/controls/gallery/images/window-new.png Binary files differdeleted file mode 100644 index e091702e..00000000 --- a/examples/quick/controls/gallery/images/window-new.png +++ /dev/null diff --git a/examples/quick/controls/gallery/main.qml b/examples/quick/controls/gallery/main.qml index 0a385a1b..4d013c8b 100644 --- a/examples/quick/controls/gallery/main.qml +++ b/examples/quick/controls/gallery/main.qml @@ -38,10 +38,6 @@ ** ****************************************************************************/ - - - - import QtQuick 2.2 import QtQuick.Controls 1.2 import QtQuick.Layouts 1.0 @@ -50,19 +46,13 @@ import "content" ApplicationWindow { visible: true - title: "Component Gallery" + title: "Qt Quick Controls Gallery" width: 640 height: 420 minimumHeight: 400 minimumWidth: 600 - property string loremIpsum: - "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor "+ - "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor "+ - "incididunt ut labore et dolore magna aliqua.\n Ut enim ad minim veniam, quis nostrud "+ - "exercitation ullamco laboris nisi ut aliquip ex ea commodo cosnsequat. "; - ImageViewer { id: imageViewer } FileDialog { @@ -109,71 +99,12 @@ ApplicationWindow { onTriggered: activeFocusItem.paste() } - Action { - id: aboutAction - text: "About" - onTriggered: aboutDialog.open() - } - - ExclusiveGroup { - id: textFormatGroup - - Action { - id: a1 - text: "Align &Left" - checkable: true - Component.onCompleted: checked = true - } - - Action { - id: a2 - text: "&Center" - checkable: true - } - - Action { - id: a3 - text: "Align &Right" - checkable: true - } - } - - ChildWindow { id: window1 } - - Menu { - id: editmenu - MenuItem { action: cutAction } - MenuItem { action: copyAction } - MenuItem { action: pasteAction } - MenuSeparator {} - Menu { - title: "Text &Format" - MenuItem { action: a1 } - MenuItem { action: a2 } - MenuItem { action: a3 } - MenuSeparator { } - MenuItem { text: "Allow &Hyphenation"; checkable: true } - } - Menu { - title: "Font &Style" - MenuItem { text: "&Bold"; checkable: true } - MenuItem { text: "&Italic"; checkable: true } - MenuItem { text: "&Underline"; checkable: true } - } - } - toolBar: ToolBar { id: toolbar RowLayout { id: toolbarLayout spacing: 0 anchors.fill: parent - ToolButton { - iconSource: "images/window-new.png" - onClicked: window1.visible = !window1.visible - Accessible.name: "New window" - tooltip: "Toggle visibility of the second window" - } ToolButton { action: openAction } ToolButton { Accessible.name: "Save as" @@ -194,7 +125,7 @@ ApplicationWindow { title: "&File" MenuItem { action: openAction } MenuItem { - text: "Close" + text: "E&xit" shortcut: StandardKey.Quit onTriggered: Qt.quit() } @@ -204,39 +135,16 @@ ApplicationWindow { MenuItem { action: cutAction } MenuItem { action: copyAction } MenuItem { action: pasteAction } - MenuSeparator { } - MenuItem { - text: "Do Nothing" - shortcut: "Ctrl+E,Shift+Ctrl+X" - enabled: false - } - MenuItem { - text: "Not Even There" - shortcut: "Ctrl+E,Shift+Ctrl+Y" - visible: false - } - Menu { - title: "Me Neither" - visible: false - } } Menu { title: "&Help" - MenuItem { action: aboutAction } + MenuItem { + text: "About..." + onTriggered: aboutDialog.open() + } } } - - SystemPalette {id: syspal} - color: syspal.window - ListModel { - id: choices - ListElement { text: "Banana" } - ListElement { text: "Orange" } - ListElement { text: "Apple" } - ListElement { text: "Coconut" } - } - TabView { id:frame enabled: enabledCheck.checked @@ -257,10 +165,5 @@ ApplicationWindow { title: "Styles" Styles { anchors.fill: parent } } - Tab { - title: "Layouts" - Layouts { anchors.fill:parent } - } } } - diff --git a/examples/quick/controls/gallery/resources.qrc b/examples/quick/controls/gallery/resources.qrc index ca9c6521..57d803b2 100644 --- a/examples/quick/controls/gallery/resources.qrc +++ b/examples/quick/controls/gallery/resources.qrc @@ -2,11 +2,9 @@ <qresource prefix="/"> <file>main.qml</file> <file>content/AboutDialog.qml</file> - <file>content/ChildWindow.qml</file> <file>content/Controls.qml</file> <file>content/ImageViewer.qml</file> <file>content/ModelView.qml</file> - <file>content/Layouts.qml</file> <file>content/Styles.qml</file> <file>images/document-open.png</file> <file>images/document-open@2x.png</file> @@ -15,8 +13,6 @@ <file>images/folder_new.png</file> <file>images/tab.png</file> <file>images/tab_selected.png</file> - <file>images/window-new.png</file> - <file>images/window-new@2x.png</file> <file>images/bubble.png</file> <file>images/button-pressed.png</file> <file>images/button.png</file> diff --git a/examples/quick/controls/styles/images/bubble.png b/examples/quick/controls/styles/images/bubble.png Binary files differnew file mode 100644 index 00000000..62aa1efe --- /dev/null +++ b/examples/quick/controls/styles/images/bubble.png diff --git a/examples/quick/controls/styles/images/button-pressed.png b/examples/quick/controls/styles/images/button-pressed.png Binary files differnew file mode 100644 index 00000000..d64cdaa7 --- /dev/null +++ b/examples/quick/controls/styles/images/button-pressed.png diff --git a/examples/quick/controls/styles/images/button.png b/examples/quick/controls/styles/images/button.png Binary files differnew file mode 100644 index 00000000..8ab41cc8 --- /dev/null +++ b/examples/quick/controls/styles/images/button.png diff --git a/examples/quick/controls/styles/images/progress-background.png b/examples/quick/controls/styles/images/progress-background.png Binary files differnew file mode 100644 index 00000000..55a069df --- /dev/null +++ b/examples/quick/controls/styles/images/progress-background.png diff --git a/examples/quick/controls/styles/images/progress-fill.png b/examples/quick/controls/styles/images/progress-fill.png Binary files differnew file mode 100644 index 00000000..b588c958 --- /dev/null +++ b/examples/quick/controls/styles/images/progress-fill.png diff --git a/examples/quick/controls/styles/images/slider-handle.png b/examples/quick/controls/styles/images/slider-handle.png Binary files differnew file mode 100644 index 00000000..ac4d4a0d --- /dev/null +++ b/examples/quick/controls/styles/images/slider-handle.png diff --git a/examples/quick/controls/styles/images/tab.png b/examples/quick/controls/styles/images/tab.png Binary files differnew file mode 100644 index 00000000..74fefab7 --- /dev/null +++ b/examples/quick/controls/styles/images/tab.png diff --git a/examples/quick/controls/styles/images/tab_selected.png b/examples/quick/controls/styles/images/tab_selected.png Binary files differnew file mode 100644 index 00000000..665400cc --- /dev/null +++ b/examples/quick/controls/styles/images/tab_selected.png diff --git a/examples/quick/controls/styles/images/textfield.png b/examples/quick/controls/styles/images/textfield.png Binary files differnew file mode 100644 index 00000000..1d4a38ab --- /dev/null +++ b/examples/quick/controls/styles/images/textfield.png diff --git a/examples/quick/controls/styles/main.cpp b/examples/quick/controls/styles/main.cpp new file mode 100644 index 00000000..0193c4f9 --- /dev/null +++ b/examples/quick/controls/styles/main.cpp @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module 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 Digia Plc and its Subsidiary(-ies) 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(QStringLiteral("qrc:/main.qml"))); + + return app.exec(); +} diff --git a/examples/quick/controls/styles/main.qml b/examples/quick/controls/styles/main.qml new file mode 100644 index 00000000..e804b4a8 --- /dev/null +++ b/examples/quick/controls/styles/main.qml @@ -0,0 +1,378 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module 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 Digia Plc and its Subsidiary(-ies) 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 QtQuick.Window 2.2 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 1.2 +import QtQuick.Controls.Styles 1.2 +import QtQuick.Particles 2.0 + +Window { + id: window + width: 640 + height: 480 + visible: true + title: qsTr("Styles Example") + + property int columnWidth: window.width / 5 + + GridLayout { + rowSpacing: 12 + columnSpacing: 30 + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + anchors.margins: 30 + + Button { + text: "Button" + implicitWidth: columnWidth + } + Button { + text: "Button" + style: ButtonStyle { + background: BorderImage { + source: control.pressed ? "images/button-pressed.png" : "images/button.png" + border.left: 4 ; border.right: 4 ; border.top: 4 ; border.bottom: 4 + } + } + implicitWidth: columnWidth + } + Button { + text: "Button" + style: buttonStyle + implicitWidth: columnWidth + } + + TextField { + Layout.row: 1 + implicitWidth: columnWidth + } + TextField { + style: TextFieldStyle { + background: BorderImage { + source: "images/textfield.png" + border.left: 4 ; border.right: 4 ; border.top: 4 ; border.bottom: 4 + } + } + implicitWidth: columnWidth + } + TextField { + style: textFieldStyle + implicitWidth: columnWidth + } + + Slider { + id: slider1 + Layout.row: 2 + value: 0.5 + implicitWidth: columnWidth + } + Slider { + id: slider2 + value: 0.5 + implicitWidth: columnWidth + style: SliderStyle { + groove: BorderImage { + height: 6 + border.top: 1 + border.bottom: 1 + source: "images/progress-background.png" + border.left: 6 + border.right: 6 + BorderImage { + anchors.verticalCenter: parent.verticalCenter + source: "images/progress-fill.png" + border.left: 5 ; border.top: 1 + border.right: 5 ; border.bottom: 1 + width: styleData.handlePosition + height: parent.height + } + } + handle: Item { + width: 13 + height: 13 + Image { + anchors.centerIn: parent + source: "images/slider-handle.png" + } + } + } + } + Slider { + id: slider3 + value: 0.5 + implicitWidth: columnWidth + style: sliderStyle + } + + ProgressBar { + Layout.row: 3 + value: slider1.value + implicitWidth: columnWidth + } + ProgressBar { + value: slider2.value + implicitWidth: columnWidth + style: progressBarStyle + } + ProgressBar { + value: slider3.value + implicitWidth: columnWidth + style: progressBarStyle2 + } + + CheckBox { + text: "CheckBox" + Layout.row: 4 + implicitWidth: columnWidth + } + + RadioButton { + text: "RadioButton" + implicitWidth: columnWidth + } + + ComboBox { + model: ["Paris", "Oslo", "New York"] + implicitWidth: columnWidth + } + + TabView { + Layout.row: 5 + Layout.columnSpan: 3 + Layout.fillWidth: true + implicitHeight: 30 + Tab { title: "One" ; Item {} } + Tab { title: "Two" ; Item {} } + Tab { title: "Three" ; Item {} } + Tab { title: "Four" ; Item {} } + } + + TabView { + Layout.row: 6 + Layout.columnSpan: 3 + Layout.fillWidth: true + implicitHeight: 30 + Tab { title: "One" ; Item {}} + Tab { title: "Two" ; Item {}} + Tab { title: "Three" ; Item {}} + Tab { title: "Four" ; Item {}} + style: tabViewStyle + } + } + + // Style delegates: + + property Component buttonStyle: ButtonStyle { + background: Rectangle { + implicitHeight: 22 + implicitWidth: columnWidth + color: control.pressed ? "darkGray" : control.activeFocus ? "#cdd" : "#ccc" + antialiasing: true + border.color: "gray" + radius: height/2 + Rectangle { + anchors.fill: parent + anchors.margins: 1 + color: "transparent" + antialiasing: true + visible: !control.pressed + border.color: "#aaffffff" + radius: height/2 + } + } + } + + property Component textFieldStyle: TextFieldStyle { + background: Rectangle { + implicitWidth: columnWidth + color: "#f0f0f0" + antialiasing: true + border.color: "gray" + radius: height/2 + Rectangle { + anchors.fill: parent + anchors.margins: 1 + color: "transparent" + antialiasing: true + border.color: "#aaffffff" + radius: height/2 + } + } + } + + property Component sliderStyle: SliderStyle { + handle: Rectangle { + width: 18 + height: 18 + color: control.pressed ? "darkGray" : "lightGray" + border.color: "gray" + antialiasing: true + radius: height/2 + Rectangle { + anchors.fill: parent + anchors.margins: 1 + color: "transparent" + antialiasing: true + border.color: "#eee" + radius: height/2 + } + } + + groove: Rectangle { + height: 8 + implicitWidth: columnWidth + implicitHeight: 22 + + antialiasing: true + color: "#ccc" + border.color: "#777" + radius: height/2 + Rectangle { + anchors.fill: parent + anchors.margins: 1 + color: "transparent" + antialiasing: true + border.color: "#66ffffff" + radius: height/2 + } + } + } + + property Component progressBarStyle: ProgressBarStyle { + background: BorderImage { + source: "images/progress-background.png" + border.left: 2 ; border.right: 2 ; border.top: 2 ; border.bottom: 2 + } + progress: Item { + clip: true + BorderImage { + anchors.fill: parent + anchors.rightMargin: (control.value < control.maximumValue) ? -4 : 0 + source: "images/progress-fill.png" + border.left: 10 ; border.right: 10 + Rectangle { + width: 1 + color: "#a70" + opacity: 0.8 + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.bottomMargin: 1 + anchors.right: parent.right + visible: control.value < control.maximumValue + anchors.rightMargin: -parent.anchors.rightMargin + } + } + ParticleSystem { id: bubbles; running: visible } + ImageParticle { + id: fireball + system: bubbles + source: "images/bubble.png" + opacity: 0.7 + } + Emitter { + system: bubbles + anchors.bottom: parent.bottom + anchors.margins: 4 + anchors.bottomMargin: -4 + anchors.left: parent.left + anchors.right: parent.right + size: 4 + sizeVariation: 4 + acceleration: PointDirection { y: -6; xVariation: 3 } + emitRate: 6 * control.value + lifeSpan: 3000 + } + } + } + + property Component progressBarStyle2: ProgressBarStyle { + background: Rectangle { + implicitWidth: columnWidth + implicitHeight: 24 + color: "#f0f0f0" + border.color: "gray" + } + progress: Rectangle { + color: "#ccc" + border.color: "gray" + Rectangle { + color: "transparent" + border.color: "#44ffffff" + anchors.fill: parent + anchors.margins: 1 + } + } + } + + property Component tabViewStyle: TabViewStyle { + tabOverlap: 16 + frameOverlap: 4 + tabsMovable: true + + frame: Rectangle { + gradient: Gradient { + GradientStop { color: "#e5e5e5" ; position: 0 } + GradientStop { color: "#e0e0e0" ; position: 1 } + } + border.color: "#898989" + Rectangle { anchors.fill: parent ; anchors.margins: 1 ; border.color: "white" ; color: "transparent" } + } + tab: Item { + property int totalOverlap: tabOverlap * (control.count - 1) + implicitWidth: Math.min ((styleData.availableWidth + totalOverlap)/control.count - 4, image.sourceSize.width) + implicitHeight: image.sourceSize.height + BorderImage { + id: image + anchors.fill: parent + source: styleData.selected ? "images/tab_selected.png" : "images/tab.png" + border.left: 30 + smooth: false + border.right: 30 + } + Text { + text: styleData.title + anchors.centerIn: parent + } + } + leftCorner: Item { implicitWidth: 12 } + } +} diff --git a/examples/quick/controls/styles/styles.pro b/examples/quick/controls/styles/styles.pro new file mode 100644 index 00000000..03648f4c --- /dev/null +++ b/examples/quick/controls/styles/styles.pro @@ -0,0 +1,10 @@ +TEMPLATE = app +TARGET = styles +QT += qml quick + +SOURCES += \ + main.cpp +RESOURCES += \ + styles.qrc +OTHER_FILES += \ + main.qml diff --git a/examples/quick/controls/styles/styles.qrc b/examples/quick/controls/styles/styles.qrc new file mode 100644 index 00000000..d2300c6f --- /dev/null +++ b/examples/quick/controls/styles/styles.qrc @@ -0,0 +1,14 @@ +<RCC> + <qresource prefix="/"> + <file>main.qml</file> + <file>images/bubble.png</file> + <file>images/button.png</file> + <file>images/button-pressed.png</file> + <file>images/progress-background.png</file> + <file>images/progress-fill.png</file> + <file>images/slider-handle.png</file> + <file>images/tab.png</file> + <file>images/tab_selected.png</file> + <file>images/textfield.png</file> + </qresource> +</RCC> diff --git a/examples/quick/controls/tableview/images/sort-up.png b/examples/quick/controls/tableview/images/sort-up.png Binary files differnew file mode 100644 index 00000000..27fcb191 --- /dev/null +++ b/examples/quick/controls/tableview/images/sort-up.png diff --git a/examples/quick/controls/tableview/main.qml b/examples/quick/controls/tableview/main.qml index e90e1104..b85f2d1d 100644 --- a/examples/quick/controls/tableview/main.qml +++ b/examples/quick/controls/tableview/main.qml @@ -310,6 +310,7 @@ Window { } } TableView { + id: delegatesView model: largeModel anchors.margins: 12 anchors.fill:parent @@ -338,10 +339,27 @@ Window { source: "images/header.png" border{left:2;right:2;top:2;bottom:2} Text { + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.right: indicator.visible ? indicator.left : parent.right + anchors.margins: 6 text: styleData.value - anchors.centerIn:parent + elide: Text.ElideRight color:"#333" } + // Sort indicator + Image { + id: indicator + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: 6 + source: "images/sort-up.png" + visible: delegatesView.sortIndicatorVisible && + styleData.column === delegatesView.sortIndicatorColumn + rotation: delegatesView.sortIndicatorOrder === Qt.AscendingOrder ? 180 : 0 + Behavior on rotation { NumberAnimation { } } + } + } rowDelegate: Rectangle { diff --git a/examples/quick/controls/tableview/resources.qrc b/examples/quick/controls/tableview/resources.qrc index f395013f..83d3f6a7 100644 --- a/examples/quick/controls/tableview/resources.qrc +++ b/examples/quick/controls/tableview/resources.qrc @@ -3,5 +3,6 @@ <file>main.qml</file> <file>images/selectedrow.png</file> <file>images/header.png</file> + <file>images/sort-up.png</file> </qresource> </RCC> diff --git a/src/controls/ApplicationWindow.qml b/src/controls/ApplicationWindow.qml index 94745b47..c13fdb6e 100644 --- a/src/controls/ApplicationWindow.qml +++ b/src/controls/ApplicationWindow.qml @@ -213,6 +213,7 @@ Window { anchors.fill: parent sourceComponent: __style ? __style.panel : null onStatusChanged: if (status === Loader.Error) console.error("Failed to load Style for", root) + focus: true Loader { id: styleLoader sourceComponent: style diff --git a/src/controls/Button.qml b/src/controls/Button.qml index 74d46bf1..f21d34c8 100644 --- a/src/controls/Button.qml +++ b/src/controls/Button.qml @@ -109,7 +109,11 @@ BasicButton { Connections { target: __behavior onEffectivePressedChanged: { - if (__behavior.effectivePressed && menu) + if (!Settings.hasTouchScreen && __behavior.effectivePressed && menu) + popupMenuTimer.start() + } + onReleased: { + if (Settings.hasTouchScreen && __behavior.containsMouse && menu) popupMenuTimer.start() } } @@ -120,9 +124,9 @@ BasicButton { onTriggered: { __behavior.keyPressed = false if (Qt.application.layoutDirection === Qt.RightToLeft) - menu.__popup(button.width, button.height, 0) + menu.__popup(Qt.rect(button.width, button.height, 0, 0), 0) else - menu.__popup(0, button.height, 0) + menu.__popup(Qt.rect(0, button.height, 0, 0), 0) } } } diff --git a/src/controls/ComboBox.qml b/src/controls/ComboBox.qml index 82d718c3..68429483 100644 --- a/src/controls/ComboBox.qml +++ b/src/controls/ComboBox.qml @@ -93,9 +93,9 @@ import QtQuick.Controls.Private 1.0 ListElement { text: "Coconut"; color: "Brown" } } onAccepted: { - if (editableCombo.find(currentText) === -1) { + if (find(currentText) === -1) { model.append({text: editText}) - currentIndex = editableCombo.find(editText) + currentIndex = find(editText) } } } @@ -222,6 +222,17 @@ Control { property alias validator: input.validator /*! + \since QtQuick.Controls 1.3 + + This property contains the edit \l Menu for working + with text selection. Set it to \c null if no menu + is wanted. + + \note The menu is only in use when \l editable is \c true + */ + property Component menu: input.editMenu.defaultMenu + + /*! \qmlproperty bool ComboBox::acceptableInput \since QtQuick.Controls 1.1 @@ -343,14 +354,14 @@ Control { if (comboBox.activeFocusOnPress) forceActiveFocus() if (!Settings.hasTouchScreen) - popup.show() + popup.toggleShow() else overridePressed = true } onCanceled: overridePressed = false onClicked: { if (Settings.hasTouchScreen) - popup.show() + popup.toggleShow() overridePressed = false } onWheel: { @@ -614,14 +625,18 @@ Control { updateSelectedText() } - function show() { - if (items[__selectedIndex]) - items[__selectedIndex].checked = true - __currentIndex = comboBox.currentIndex - if (Qt.application.layoutDirection === Qt.RightToLeft) - __popup(comboBox.width, y, isPopup ? __selectedIndex : 0) - else - __popup(0, y, isPopup ? __selectedIndex : 0) + function toggleShow() { + if (popup.__popupVisible) { + popup.__dismissMenu() + } else { + if (items[__selectedIndex]) + items[__selectedIndex].checked = true + __currentIndex = comboBox.currentIndex + if (Qt.application.layoutDirection === Qt.RightToLeft) + __popup(Qt.rect(comboBox.width, y, 0, 0), isPopup ? __selectedIndex : 0) + else + __popup(Qt.rect(0, y, 0, 0), isPopup ? __selectedIndex : 0) + } } function updateSelectedText() { @@ -638,8 +653,7 @@ Control { // The key bindings below will only be in use when popup is // not visible. Otherwise, native popup key handling will take place: Keys.onSpacePressed: { - if (!popup.popupVisible) - popup.show() + popup.toggleShow() } Keys.onUpPressed: __selectPrevItem() diff --git a/src/controls/MenuBar.qml b/src/controls/MenuBar.qml index 9c9fa698..5d90f91d 100644 --- a/src/controls/MenuBar.qml +++ b/src/controls/MenuBar.qml @@ -252,8 +252,8 @@ MenuBarPrivate { if (d.openedMenuIndex === index) { if (__menuItem.__usingDefaultStyle) __menuItem.style = d.style.menuStyle - __menuItem.__popup(row.LayoutMirroring.enabled ? menuItemLoader.width : 0, - menuBarLoader.height - d.heightPadding, 0) + __menuItem.__popup(Qt.rect(row.LayoutMirroring.enabled ? menuItemLoader.width : 0, + menuBarLoader.height - d.heightPadding, 0, 0), 0) if (d.preselectMenuItem) __menuItem.__currentIndex = 0 } else { diff --git a/src/controls/Private/EditMenu.qml b/src/controls/Private/EditMenu.qml index b7cebc19..f4d80bd5 100644 --- a/src/controls/Private/EditMenu.qml +++ b/src/controls/Private/EditMenu.qml @@ -47,7 +47,27 @@ Loader { property Item cursorHandle property Item selectionHandle property Flickable flickable - property Menu defaultMenu: item && item.defaultMenu ? item.defaultMenu : null + property Component defaultMenu: item && item.defaultMenu ? item.defaultMenu : null + property Menu menuInstance: null - source: Qt.platform.os === "ios" ? Qt.resolvedUrl("EditMenu_ios.qml") : "" + Connections { + target: control + onMenuChanged: { + if (menuInstance !== null) { + menuInstance.destroy() + menuInstance = null + } + } + } + + function getMenuInstance() + { + // Lazy load menu when first requested + if (!menuInstance && control.menu) { + menuInstance = control.menu.createObject(input); + } + return menuInstance; + } + + source: Qt.resolvedUrl("EditMenu_" + (Qt.platform.os === "ios" ? "ios" : "base") + ".qml") } diff --git a/src/controls/Private/EditMenu_base.qml b/src/controls/Private/EditMenu_base.qml new file mode 100644 index 00000000..597541bc --- /dev/null +++ b/src/controls/Private/EditMenu_base.qml @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick controls module 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 Digia Plc and its Subsidiary(-ies) 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 QtQuick.Controls 1.2 +import QtQuick.Controls.Private 1.0 + +Item { + id: editMenuBase + anchors.fill: parent + + Component { + id: cutAction + Action { + text: "Cu&t" + shortcut: StandardKey.Cut + iconName: "edit-cut" + enabled: !input.readOnly && selectionStart !== selectionEnd + onTriggered: { + input.cut(); + input.select(input.cursorPosition, input.cursorPosition); + } + } + } + + Component { + id: copyAction + Action { + text: "&Copy" + shortcut: StandardKey.Copy + iconName: "edit-copy" + enabled: input.selectionStart !== input.selectionEnd + onTriggered: { + input.copy(); + input.select(input.cursorPosition, input.cursorPosition); + } + } + } + + Component { + id: pasteAction + Action { + text: "&Paste" + shortcut: StandardKey.Paste + iconName: "edit-paste" + enabled: input.canPaste + onTriggered: input.paste() + } + } + + property Component defaultMenu: Menu { + MenuItem { action: cutAction.createObject(editMenuBase) } + MenuItem { action: copyAction.createObject(editMenuBase) } + MenuItem { action: pasteAction.createObject(editMenuBase) } + } + + MouseArea { + id: mouseArea + anchors.fill: parent + acceptedButtons: Qt.RightButton + + onClicked: { + if (input.selectionStart === input.selectionEnd) { + var cursorPos = input.positionAt(mouse.x, mouse.y) + input.moveHandles(cursorPos, cursorPos) + } + + input.activate() + + if (control.menu) { + getMenuInstance().__dismissMenu(); + var menuPos = mapToItem(null, mouse.x, mouse.y) + getMenuInstance().__popup(Qt.rect(menuPos.x, menuPos.y, 0, 0), -1, MenuPrivate.EditMenu); + } + } + } +} diff --git a/src/controls/Private/EditMenu_ios.qml b/src/controls/Private/EditMenu_ios.qml index e41e0cb6..aeb21b03 100644 --- a/src/controls/Private/EditMenu_ios.qml +++ b/src/controls/Private/EditMenu_ios.qml @@ -46,7 +46,7 @@ Item { anchors.fill: parent property bool __showMenuFromTouchAndHold: false - property Menu defaultMenu: Menu { + property Component defaultMenu: Menu { MenuItem { text: "cut" visible: !input.readOnly && selectionStart !== selectionEnd @@ -99,7 +99,7 @@ Item { } onClicked: { - if (control.menu && control.menu.__popupVisible) { + if (control.menu && getMenuInstance().__popupVisible) { select(input.cursorPosition, input.cursorPosition); } else { input.activate(); @@ -173,17 +173,15 @@ Item { && (!cursorHandle.pressed && !selectionHandle.pressed) && (!flickable || !flickable.moving) && (cursorHandle.delegate)) { - // center menu on top of selection: - var r1 = input.positionToRectangle(input.selectionStart); - var r2 = input.cursorRectangle; - var xMin = Math.min(r1.x, r2.x); - var xMax = Math.max(r1.x, r2.x); - var centerX = xMin + ((xMax - xMin) / 2); - var popupPos = input.mapToItem(null, centerX, r1.y); - control.menu.__dismissMenu(); - control.menu.__popup(popupPos.x, popupPos.y, -1, MenuPrivate.EditMenu); + var p1 = input.positionToRectangle(input.selectionStart); + var p2 = input.positionToRectangle(input.selectionEnd); + var topLeft = input.mapToItem(null, p1.x, p1.y); + var size = Qt.size(p2.x - p1.x + p1.width, p2.y - p1.y + p1.height) + var targetRect = Qt.rect(topLeft.x, topLeft.y, size.width, size.height); + getMenuInstance().__dismissMenu(); + getMenuInstance().__popup(targetRect, -1, MenuPrivate.EditMenu); } else { - control.menu.__dismissMenu(); + getMenuInstance().__dismissMenu(); } } } diff --git a/src/controls/Private/MenuContentItem.qml b/src/controls/Private/MenuContentItem.qml index 62e5d033..a503d1d4 100644 --- a/src/controls/Private/MenuContentItem.qml +++ b/src/controls/Private/MenuContentItem.qml @@ -207,7 +207,7 @@ Loader { if (__menu.__currentIndex === __menuItemIndex) { if (__menuItem.__usingDefaultStyle) __menuItem.style = __menu.style - __menuItem.__popup(menuFrameLoader.width - (d.style.submenuOverlap + d.style.padding.right), -d.style.padding.top, -1) + __menuItem.__popup(Qt.rect(menuFrameLoader.width - (d.style.submenuOverlap + d.style.padding.right), -d.style.padding.top, 0, 0), -1) } } else { openMenuTimer.start() diff --git a/src/controls/Private/TextInputWithHandles.qml b/src/controls/Private/TextInputWithHandles.qml index 59ba971e..f3348774 100644 --- a/src/controls/Private/TextInputWithHandles.qml +++ b/src/controls/Private/TextInputWithHandles.qml @@ -51,6 +51,8 @@ TextInput { property bool hasSelection: selectionStart !== selectionEnd readonly property int selectionPosition: selectionStart !== cursorPosition ? selectionStart : selectionEnd readonly property alias containsMouse: mouseArea.containsMouse + property alias editMenu: editMenu + cursorDelegate: __style && __style.cursorDelegate ? __style.cursorDelegate : null selectByMouse: control.selectByMouse && (!cursorHandle.delegate || !selectionHandle.delegate) @@ -115,6 +117,15 @@ TextInput { } } + EditMenu { + id: editMenu + input: parent + control: parent.control + cursorHandle: cursorHandle + selectionHandle: selectionHandle + anchors.fill: parent + } + TextHandle { id: selectionHandle diff --git a/src/controls/Private/ToolMenuButton.qml b/src/controls/Private/ToolMenuButton.qml new file mode 100644 index 00000000..111b6753 --- /dev/null +++ b/src/controls/Private/ToolMenuButton.qml @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module 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 Digia Plc and its Subsidiary(-ies) 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 QtQuick.Controls 1.3 +import QtQuick.Controls.Private 1.0 + +FocusScope { + id: button + + property Menu menu + readonly property bool pressed: behavior.containsPress || behavior.keyPressed + readonly property alias hovered: behavior.containsMouse + + property alias panel: loader.sourceComponent + property alias __panel: loader.item + + activeFocusOnTab: true + Accessible.role: Accessible.Button + implicitWidth: __panel ? __panel.implicitWidth : 0 + implicitHeight: __panel ? __panel.implicitHeight : 0 + + Loader { + id: loader + anchors.fill: parent + property QtObject styleData: QtObject { + readonly property alias pressed: button.pressed + readonly property alias hovered: button.hovered + readonly property alias activeFocus: button.activeFocus + } + onStatusChanged: if (status === Loader.Error) console.error("Failed to load Style for", button) + } + + Keys.onPressed: { + if (event.key === Qt.Key_Space && !event.isAutoRepeat && !behavior.keyPressed) + behavior.keyPressed = true + } + Keys.onReleased: { + if (event.key === Qt.Key_Space && !event.isAutoRepeat && behavior.keyPressed) + behavior.keyPressed = false + } + onFocusChanged: { + if (!focus) + behavior.keyPressed = false + } + onPressedChanged: { + if (!Settings.hasTouchScreen && !pressed && menu) + popupMenuTimer.start() + } + + MouseArea { + id: behavior + property bool keyPressed: false + + anchors.fill: parent + enabled: !keyPressed + hoverEnabled: true + + onReleased: { + if (Settings.hasTouchScreen && containsMouse && menu) + popupMenuTimer.start() + } + + Timer { + id: popupMenuTimer + interval: 10 + onTriggered: { + behavior.keyPressed = false + if (Qt.application.layoutDirection === Qt.RightToLeft) + menu.__popup(Qt.rect(button.width, button.height, 0, 0), 0) + else + menu.__popup(Qt.rect(0, 0, button.width, button.height), 0) + } + } + } + + Binding { + target: menu + property: "__minimumWidth" + value: button.width + } + + Binding { + target: menu + property: "__visualItem" + value: button + } +} diff --git a/src/controls/Private/private.pri b/src/controls/Private/private.pri index b407cbf4..e69d0a29 100644 --- a/src/controls/Private/private.pri +++ b/src/controls/Private/private.pri @@ -58,7 +58,9 @@ PRIVATE_QML_FILES += \ $$PWD/HoverButton.qml \ $$PWD/TextInputWithHandles.qml \ $$PWD/EditMenu.qml \ + $$PWD/EditMenu_base.qml \ $$PWD/EditMenu_ios.qml \ + $$PWD/ToolMenuButton.qml \ $$PWD/qmldir QML_FILES += $$PRIVATE_QML_FILES diff --git a/src/controls/Private/qmldir b/src/controls/Private/qmldir index 7ef7ae95..82e1a985 100644 --- a/src/controls/Private/qmldir +++ b/src/controls/Private/qmldir @@ -30,4 +30,6 @@ singleton TextSingleton 1.0 TextSingleton.qml TextHandle 1.0 TextHandle.qml TextInputWithHandles 1.0 TextInputWithHandles.qml EditMenu 1.0 EditMenu.qml +EditMenu_base 1.0 EditMenu_base.qml EditMenu_ios 1.0 EditMenu_ios.qml +ToolMenuButton 1.0 ToolMenuButton.qml diff --git a/src/controls/SpinBox.qml b/src/controls/SpinBox.qml index 758be809..f13e81dc 100644 --- a/src/controls/SpinBox.qml +++ b/src/controls/SpinBox.qml @@ -203,6 +203,15 @@ Control { */ readonly property bool inputMethodComposing: !!input.inputMethodComposing + /*! + \since QtQuick.Controls 1.3 + + This property contains the edit \l Menu for working + with text selection. Set it to \c null if no menu + is wanted. + */ + property Component menu: input.editMenu.defaultMenu + style: Qt.createComponent(Settings.style + "/SpinBoxStyle.qml", spinbox) /*! \internal */ diff --git a/src/controls/Styles/Android/ApplicationWindowStyle.qml b/src/controls/Styles/Android/ApplicationWindowStyle.qml index 259c8208..3db7a921 100644 --- a/src/controls/Styles/Android/ApplicationWindowStyle.qml +++ b/src/controls/Styles/Android/ApplicationWindowStyle.qml @@ -43,13 +43,78 @@ import QtQuick.Controls.Styles 1.3 import QtQuick.Controls.Styles.Android 1.0 import "drawables" -ApplicationWindowStyle { +QtObject { readonly property ApplicationWindow control: __control - property Component background: DrawableLoader { - accelerated: true - visible: !styleData.hasColor - window_focused: control.active - styleDef: AndroidStyle.styleDef.windowStyle.Window_windowBackground + property Component panel: Item { + readonly property alias contentArea: contentArea + readonly property alias menuBarArea: menuBarArea + readonly property alias toolBarArea: toolBarArea + readonly property alias statusBarArea: statusBarArea + readonly property bool hasToolBar: !!control.toolBar && control.toolBar.Accessible.role === Accessible.ToolBar + + DrawableLoader { + anchors.fill: parent + accelerated: true + visible: !styleData.hasColor + window_focused: control.active + styleDef: AndroidStyle.styleDef.windowStyle.Window_windowBackground + } + + Item { + id: contentArea + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: statusBarArea.top + anchors.topMargin: toolBarArea.implicitHeight + } + + Item { + id: toolBarArea + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + implicitHeight: childrenRect.height + height: visibleChildren.length > 0 ? implicitHeight : 0 + + Loader { + visible: active + active: !hasToolBar && !!control.menuBar + anchors.left: parent.left + anchors.right: parent.right + sourceComponent: ToolBar { + __menu: proxyMenu.items.length > 1 ? proxyMenu : + proxyMenu.items.length === 1 ? proxyMenu.items[0] : null + } + } + } + + Item { + id: statusBarArea + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + implicitHeight: childrenRect.height + height: visibleChildren.length > 0 ? implicitHeight : 0 + } + + Item { + id: menuBarArea + visible: false + + Menu { + id: proxyMenu + items: control.menuBar ? control.menuBar.menus : [] + } + + Binding { + target: control.toolBar + property: "__menu" + value: proxyMenu.items.length > 1 ? proxyMenu : + proxyMenu.items.length === 1 ? proxyMenu.items[0] : null + when: hasToolBar + } + } } } diff --git a/src/controls/Styles/Android/MenuBarStyle.qml b/src/controls/Styles/Android/MenuBarStyle.qml index 574b4b06..9c3cc15f 100644 --- a/src/controls/Styles/Android/MenuBarStyle.qml +++ b/src/controls/Styles/Android/MenuBarStyle.qml @@ -39,4 +39,8 @@ ****************************************************************************/ import QtQuick.Controls.Styles 1.2 -MenuBarStyle { } +MenuBarStyle { + __isNative: false + background: null + itemDelegate: null +} diff --git a/src/controls/Styles/Android/ToolBarStyle.qml b/src/controls/Styles/Android/ToolBarStyle.qml index 3446e7d4..bb7dfbae 100644 --- a/src/controls/Styles/Android/ToolBarStyle.qml +++ b/src/controls/Styles/Android/ToolBarStyle.qml @@ -54,6 +54,36 @@ Style { bottom: AndroidStyle.styleDef.actionBarStyle.View_paddingBottom } + property Component menuButton: Item { + readonly property var styleDef: AndroidStyle.styleDef.actionButtonStyle + + readonly property real minWidth: styleDef.View_minWidth || 0 + readonly property real minHeight: styleDef.View_minHeight || 0 + readonly property real paddingStart: styleDef.View_paddingStart || 0 + readonly property real paddingEnd: styleDef.View_paddingEnd || 0 + + implicitWidth: Math.max(minWidth, button.implicitWidth) + implicitHeight: Math.max(minHeight, button.implicitHeight) + + DrawableLoader { + id: button + anchors.fill: parent + pressed: styleData.pressed + focused: styleData.activeFocus + window_focused: control.Window.active + styleDef: parent.styleDef.View_background + } + + DrawableLoader { + id: icon + anchors.centerIn: parent + pressed: styleData.pressed + focused: styleData.activeFocus + window_focused: control.Window.active + styleDef: AndroidStyle.styleDef.actionOverflowButtonStyle.ImageView_src + } + } + property Component panel: Item { id: panel diff --git a/src/controls/Styles/Base/ComboBoxStyle.qml b/src/controls/Styles/Base/ComboBoxStyle.qml index f71c8c98..77d2e91e 100644 --- a/src/controls/Styles/Base/ComboBoxStyle.qml +++ b/src/controls/Styles/Base/ComboBoxStyle.qml @@ -317,4 +317,9 @@ Style { \endtable */ property Component selectionHandle + + /*! The cursor delegate. + \since QtQuick.Controls.Styles 1.3 + */ + property Component cursorDelegate } diff --git a/src/controls/Styles/Base/ScrollViewStyle.qml b/src/controls/Styles/Base/ScrollViewStyle.qml index e8d10995..ec53c650 100644 --- a/src/controls/Styles/Base/ScrollViewStyle.qml +++ b/src/controls/Styles/Base/ScrollViewStyle.qml @@ -259,7 +259,11 @@ Style { states: State { name: "out" - when: isTransient && panel.activeControl === "none" && !panel.on && !panel.raised + when: isTransient + && (!__stickyScrollbars || !flickableItem.moving) + && panel.activeControl === "none" + && !panel.on + && !panel.raised PropertyChanges { target: panel; opacity: 0 } } @@ -396,4 +400,6 @@ Style { property int __scrollBarFadeDelay: 450 /*! \internal */ property int __scrollBarFadeDuration: 200 + /*! \internal */ + property bool __stickyScrollbars: false } diff --git a/src/controls/Styles/Base/SpinBoxStyle.qml b/src/controls/Styles/Base/SpinBoxStyle.qml index 14d72863..1bcb6b5c 100644 --- a/src/controls/Styles/Base/SpinBoxStyle.qml +++ b/src/controls/Styles/Base/SpinBoxStyle.qml @@ -247,4 +247,9 @@ Style { \endtable */ property Component selectionHandle + + /*! The cursor delegate. + \since QtQuick.Controls.Styles 1.3 + */ + property Component cursorDelegate } diff --git a/src/controls/Styles/Base/TextAreaStyle.qml b/src/controls/Styles/Base/TextAreaStyle.qml index cc154a5d..bd3ed31e 100644 --- a/src/controls/Styles/Base/TextAreaStyle.qml +++ b/src/controls/Styles/Base/TextAreaStyle.qml @@ -141,4 +141,9 @@ ScrollViewStyle { \endtable */ property Component selectionHandle + + /*! The cursor delegate. + \since QtQuick.Controls.Styles 1.3 + */ + property Component cursorDelegate } diff --git a/src/controls/Styles/Base/TextFieldStyle.qml b/src/controls/Styles/Base/TextFieldStyle.qml index a7e5884a..c1e7a69f 100644 --- a/src/controls/Styles/Base/TextFieldStyle.qml +++ b/src/controls/Styles/Base/TextFieldStyle.qml @@ -194,4 +194,9 @@ Style { \endtable */ property Component selectionHandle + + /*! The cursor delegate. + \since QtQuick.Controls.Styles 1.3 + */ + property Component cursorDelegate } diff --git a/src/controls/Styles/Base/ToolBarStyle.qml b/src/controls/Styles/Base/ToolBarStyle.qml index 7a89cefb..5a6c3570 100644 --- a/src/controls/Styles/Base/ToolBarStyle.qml +++ b/src/controls/Styles/Base/ToolBarStyle.qml @@ -104,6 +104,21 @@ Style { } } + /*! This defines the menu button appearance on platforms + that have a unified tool bar and menu bar. + + \since QtQuick.Controls.Styles 1.3 + + The following read-only properties are available within the scope + of the menu button delegate: + \table + \row \li \b {styleData.pressed} : bool \li Whether the button is pressed. + \row \li \b {styleData.hovered} : bool \li Whether the button is hovered. + \row \li \b {styleData.activeFocus} : bool \li Whether the button has active focus. + \endtable + */ + property Component menuButton: null + property Component panel: Loader { sourceComponent: background } diff --git a/src/controls/Styles/iOS/ComboBoxStyle.qml b/src/controls/Styles/iOS/ComboBoxStyle.qml index adc585f4..147fd7fd 100644 --- a/src/controls/Styles/iOS/ComboBoxStyle.qml +++ b/src/controls/Styles/iOS/ComboBoxStyle.qml @@ -44,4 +44,5 @@ import QtQuick.Controls.Styles 1.3 ComboBoxStyle { selectionHandle: SelectionHandleStyle{} cursorHandle: CursorHandleStyle{} + cursorDelegate: CursorDelegate{} } diff --git a/src/controls/Styles/iOS/CursorDelegate.qml b/src/controls/Styles/iOS/CursorDelegate.qml new file mode 100644 index 00000000..fc2907de --- /dev/null +++ b/src/controls/Styles/iOS/CursorDelegate.qml @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module 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 Digia Plc and its Subsidiary(-ies) 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 + +Rectangle { + id: cursor + + property Item input: parent + + width: 2 + height: input.cursorRectangle.height + color: "#446cf2" + antialiasing: false + visible: input.activeFocus && input.selectionStart === input.selectionEnd + state: "on" + + Connections { + target: input + onCursorPositionChanged: { + state = "on" + timer.restart() + } + } + + Timer { + id: timer + running: cursor.visible + repeat: true + interval: 500 + onTriggered: cursor.state = cursor.state == "on" ? "off" : "on" + } + + states: [ + State { + name: "on" + PropertyChanges { target: cursor; opacity: 1 } + }, + State { + name: "off" + PropertyChanges { target: cursor; opacity: 0 } + } + ] + + transitions: [ + Transition { + from: "on" + to: "off" + NumberAnimation { property: "opacity"; duration: 150 } + } + ] +} + diff --git a/src/controls/Styles/iOS/ScrollViewStyle.qml b/src/controls/Styles/iOS/ScrollViewStyle.qml index a8265ede..e96f7e68 100644 --- a/src/controls/Styles/iOS/ScrollViewStyle.qml +++ b/src/controls/Styles/iOS/ScrollViewStyle.qml @@ -37,6 +37,77 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +import QtQuick 2.2 +import QtQuick.Controls 1.2 import QtQuick.Controls.Styles 1.3 +import QtQuick.Controls.Private 1.0 -ScrollViewStyle { } +ScrollViewStyle { + corner: null + incrementControl: null + decrementControl: null + frame: null + scrollBarBackground: null + padding { top: 0; left: 0; right: 0; bottom: 0 } + + __scrollBarFadeDelay: 50 + __scrollBarFadeDuration: 200 + __stickyScrollbars: true + + handle: Item { + implicitWidth: 2.5 + implicitHeight: 2.5 + + anchors.top: !styleData.horizontal ? parent.top : undefined + anchors.left: styleData.horizontal ? parent.left : undefined + anchors.bottom: parent.bottom + anchors.right: parent.right + + anchors.leftMargin: implicitWidth + anchors.topMargin: implicitHeight + 1 + anchors.rightMargin: implicitWidth * (!styleData.horizontal ? 2 : 4) + anchors.bottomMargin: implicitHeight * (styleData.horizontal ? 2 : 4) + + Behavior on width { enabled: !styleData.horizontal; NumberAnimation { duration: 100 } } + Behavior on height { enabled: styleData.horizontal; NumberAnimation { duration: 100 } } + + Loader { + anchors.fill: parent + sourceComponent: styleData.horizontal ? horzontalHandle : verticalHandle + } + + Component { + id: verticalHandle + Rectangle { + color: "black" + opacity: 0.3 + radius: parent.parent.implicitWidth + width: parent.width + y: overshootBottom > 0 ? parent.height - height : 0 + height: Math.max(8, parent.height - overshootTop - overshootBottom) + + property real overshootTop: -Math.min(0, __control.flickableItem.contentY) + property real overshootBottom: Math.max(0, __control.flickableItem.contentY + - __control.flickableItem.contentHeight + + __control.flickableItem.height) + } + } + + Component { + id: horzontalHandle + Rectangle { + color: "black" + opacity: 0.3 + radius: parent.parent.implicitHeight + height: parent.height + x: overshootRight > 0 ? parent.width - width : 0 + width: Math.max(8, parent.width - overshootLeft - overshootRight) + + property real overshootLeft: -Math.min(0, __control.flickableItem.contentX) + property real overshootRight: Math.max(0, __control.flickableItem.contentX + - __control.flickableItem.contentWidth + + __control.flickableItem.width) + } + } + } +} diff --git a/src/controls/Styles/iOS/SpinBoxStyle.qml b/src/controls/Styles/iOS/SpinBoxStyle.qml index 24f9712f..a764cb79 100644 --- a/src/controls/Styles/iOS/SpinBoxStyle.qml +++ b/src/controls/Styles/iOS/SpinBoxStyle.qml @@ -44,4 +44,5 @@ import QtQuick.Controls.Styles 1.3 SpinBoxStyle { selectionHandle: SelectionHandleStyle{} cursorHandle: CursorHandleStyle{} + cursorDelegate: CursorDelegate{} } diff --git a/src/controls/Styles/iOS/TableViewStyle.qml b/src/controls/Styles/iOS/TableViewStyle.qml index 65bfaaa7..9ec96c55 100644 --- a/src/controls/Styles/iOS/TableViewStyle.qml +++ b/src/controls/Styles/iOS/TableViewStyle.qml @@ -37,6 +37,26 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ -import QtQuick.Controls.Styles 1.3 +import QtQuick 2.2 +import QtQuick.Controls 1.3 +import QtQuick.Controls.Private 1.0 +import QtQuick.Controls.Styles 1.3 as Base -TableViewStyle { } +ScrollViewStyle { + id: root + + Base.TableViewStyle { + id: baseStyle + } + + readonly property TableView control: __control + property alias textColor: baseStyle.textColor + property alias backgroundColor: baseStyle.backgroundColor + property alias alternateBackgroundColor: baseStyle.alternateBackgroundColor + property alias highlightedTextColor: baseStyle.highlightedTextColor + property alias activateItemOnSingleClick: baseStyle.activateItemOnSingleClick + property alias headerDelegate: baseStyle.headerDelegate + property alias rowDelegate: baseStyle.rowDelegate + property alias itemDelegate: baseStyle.itemDelegate + padding.top: baseStyle.padding.top +} diff --git a/src/controls/Styles/iOS/TextAreaStyle.qml b/src/controls/Styles/iOS/TextAreaStyle.qml index a3bfdf80..6b8a1800 100644 --- a/src/controls/Styles/iOS/TextAreaStyle.qml +++ b/src/controls/Styles/iOS/TextAreaStyle.qml @@ -39,9 +39,19 @@ ****************************************************************************/ import QtQuick 2.2 import QtQuick.Controls 1.2 -import QtQuick.Controls.Styles 1.3 +import QtQuick.Controls.Private 1.0 -TextAreaStyle { - selectionHandle: SelectionHandleStyle{} - cursorHandle: CursorHandleStyle{} +ScrollViewStyle { + id: style + + readonly property TextArea control: __control + property font font + property color textColor: SystemPaletteSingleton.text(control.enabled) + property color selectionColor: SystemPaletteSingleton.highlight(control.enabled) + property color selectedTextColor: SystemPaletteSingleton.highlightedText(control.enabled) + property color backgroundColor: control.backgroundVisible ? SystemPaletteSingleton.base(control.enabled) : "transparent" + property int renderType: Text.QtRendering + property Component selectionHandle: SelectionHandleStyle{} + property Component cursorHandle: CursorHandleStyle{} + property Component cursorDelegate: CursorDelegate{} } diff --git a/src/controls/Styles/iOS/TextFieldStyle.qml b/src/controls/Styles/iOS/TextFieldStyle.qml index e1ed4ca0..28ad692f 100644 --- a/src/controls/Styles/iOS/TextFieldStyle.qml +++ b/src/controls/Styles/iOS/TextFieldStyle.qml @@ -44,4 +44,5 @@ import QtQuick.Controls.Styles 1.3 TextFieldStyle { selectionHandle: SelectionHandleStyle{} cursorHandle: CursorHandleStyle{} + cursorDelegate: CursorDelegate{} } diff --git a/src/controls/Styles/iOS/ToolButtonStyle.qml b/src/controls/Styles/iOS/ToolButtonStyle.qml index d3dde835..c2d2db9c 100644 --- a/src/controls/Styles/iOS/ToolButtonStyle.qml +++ b/src/controls/Styles/iOS/ToolButtonStyle.qml @@ -39,4 +39,4 @@ ****************************************************************************/ import QtQuick.Controls.Styles 1.3 -ToolBarStyle { } +ToolButtonStyle { } diff --git a/src/controls/Styles/iOS/iOS.pro b/src/controls/Styles/iOS/iOS.pro index 548e34bb..886c1dc1 100644 --- a/src/controls/Styles/iOS/iOS.pro +++ b/src/controls/Styles/iOS/iOS.pro @@ -26,6 +26,7 @@ QML_FILES += \ $$PWD/ToolBarStyle.qml \ $$PWD/ToolButtonStyle.qml \ $$PWD/CursorHandleStyle.qml \ - $$PWD/SelectionHandleStyle.qml + $$PWD/SelectionHandleStyle.qml \ + $$PWD/CursorDelegate.qml load(qml_module) diff --git a/src/controls/Tab.qml b/src/controls/Tab.qml index 355fb44a..f358181d 100644 --- a/src/controls/Tab.qml +++ b/src/controls/Tab.qml @@ -48,7 +48,17 @@ import QtQuick 2.2 \brief Tab represents the content of a tab in a TabView. A Tab item inherits from Loader and provides a similar - api. + API. + + Tabs are lazily loaded; only tabs that have been made current (for example, + by clicking on them) will have valid content. You can force loading of tabs + by setting the active property to \c true: + + \code + Tab { + active: true + } + \endcode \sa TabView */ diff --git a/src/controls/TableView.qml b/src/controls/TableView.qml index 41d0ca48..11b0662a 100644 --- a/src/controls/TableView.qml +++ b/src/controls/TableView.qml @@ -572,7 +572,7 @@ ScrollView { ListView { id: listView focus: true - activeFocusOnTab: root.activeFocusOnTab + activeFocusOnTab: false anchors.topMargin: headerVisible ? tableHeader.height : 0 anchors.fill: parent currentIndex: -1 @@ -788,6 +788,7 @@ ScrollView { } } + Keys.forwardTo: root Keys.onUpPressed: { event.accepted = false __scroller.blockUpdates = true; diff --git a/src/controls/TextArea.qml b/src/controls/TextArea.qml index 6db196b6..5e8387db 100644 --- a/src/controls/TextArea.qml +++ b/src/controls/TextArea.qml @@ -255,7 +255,7 @@ ScrollView { \li Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used. \endlist */ - property int inputMethodHints: edit.inputMethodHints || Qt.ImhNone + property alias inputMethodHints: edit.inputMethodHints /*! \qmlproperty int TextArea::length @@ -436,6 +436,17 @@ ScrollView { readonly property alias hoveredLink: edit.hoveredLink /*! + \since QtQuick.Controls 1.3 + + This property contains the edit \l Menu for working + with text selection. Set it to \c null if no menu + is wanted. + + \sa Menu + */ + property Component menu: editMenu.defaultMenu + + /*! \qmlmethod TextArea::append(string) Appends \a string as a new line to the end of the text area. @@ -707,6 +718,7 @@ ScrollView { TextEdit { id: edit focus: true + cursorDelegate: __style && __style.cursorDelegate ? __style.cursorDelegate : null Rectangle { id: colorRect @@ -849,6 +861,16 @@ ScrollView { } } + EditMenu { + id: editMenu + control: area + input: edit + cursorHandle: cursorHandle + selectionHandle: selectionHandle + flickable: flickable + anchors.fill: parent + } + TextHandle { id: selectionHandle diff --git a/src/controls/TextField.qml b/src/controls/TextField.qml index 5c602ee4..2e940bdb 100644 --- a/src/controls/TextField.qml +++ b/src/controls/TextField.qml @@ -282,6 +282,7 @@ Control { \li Qt.ImhDate - The text editor functions as a date field. \li Qt.ImhTime - The text editor functions as a time field. + \li Qt.ImhMultiLine - The text editor doesn't close software input keyboard when Return or Enter key is pressed (since QtQuick.Controls 1.3). \endlist Flags that restrict input (exclusive flags) are: @@ -301,7 +302,7 @@ Control { \li Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used. \endlist */ - property int inputMethodHints: textInput.inputMethodHints || Qt.ImhNone + property alias inputMethodHints: textInput.inputMethodHints /*! \qmlproperty int TextField::length @@ -434,6 +435,15 @@ Control { property alias validator: textInput.validator /*! + \since QtQuick.Controls 1.3 + + This property contains the edit \l Menu for working + with text selection. Set it to \c null if no menu + is wanted. + */ + property Component menu: textInput.editMenu.defaultMenu + + /*! \qmlsignal TextField::accepted() This signal is emitted when the Return or Enter key is pressed. @@ -654,7 +664,8 @@ Control { onAccepted: { Qt.inputMethod.commit() - Qt.inputMethod.hide() + if (!(textInput.inputMethodHints & Qt.ImhMultiLine)) + Qt.inputMethod.hide() textfield.accepted() } diff --git a/src/controls/ToolBar.qml b/src/controls/ToolBar.qml index 8498860c..cc07fd5c 100644 --- a/src/controls/ToolBar.qml +++ b/src/controls/ToolBar.qml @@ -115,6 +115,9 @@ FocusScope { /*! \internal */ default property alias __content: container.data + /*! \internal */ + property var __menu + /*! \qmlproperty Item ToolBar::contentItem @@ -148,7 +151,7 @@ FocusScope { anchors.topMargin: topMargin anchors.leftMargin: leftMargin - anchors.rightMargin: rightMargin + anchors.rightMargin: rightMargin + (buttonLoader.active ? buttonLoader.width : 0) anchors.bottomMargin: bottomMargin property int topMargin: __style ? __style.padding.top : 0 @@ -163,5 +166,17 @@ FocusScope { property real layoutHeight: layoutItem ? (layoutItem.implicitHeight || layoutItem.height) + (layoutItem.anchors.fill ? layoutItem.anchors.topMargin + layoutItem.anchors.bottomMargin : 0) : 0 - }] + }, + Loader { + id: buttonLoader + anchors.right: parent.right + anchors.rightMargin: container.rightMargin + anchors.verticalCenter: parent.verticalCenter + sourceComponent: ToolMenuButton { + menu: toolbar.__menu + panel: toolbar.__style.menuButton || null + } + active: !!__menu && __menu.items.length > 0 && !!__style.menuButton + } + ] } diff --git a/src/controls/doc/images/qtquickcontrols-android.png b/src/controls/doc/images/qtquickcontrols-android.png Binary files differnew file mode 100644 index 00000000..8877c09c --- /dev/null +++ b/src/controls/doc/images/qtquickcontrols-android.png diff --git a/src/controls/doc/images/qtquickcontrols-example-styles.png b/src/controls/doc/images/qtquickcontrols-example-styles.png Binary files differnew file mode 100644 index 00000000..901ff75c --- /dev/null +++ b/src/controls/doc/images/qtquickcontrols-example-styles.png diff --git a/src/controls/doc/qtquickcontrols.qdocconf b/src/controls/doc/qtquickcontrols.qdocconf index e086f885..6b4b14c7 100644 --- a/src/controls/doc/qtquickcontrols.qdocconf +++ b/src/controls/doc/qtquickcontrols.qdocconf @@ -28,7 +28,7 @@ qhp.QtQuickControls.subprojects.qtquickcontrolsstyles.title = Qt Quick Cont qhp.QtQuickControls.subprojects.qtquickcontrolsstyles.indexTitle = Qt Quick Controls Styles Structure qhp.QtQuickControls.subprojects.qtquickcontrolsstyles.type = manual -depends = qtqml qtquick qtgui qtwidgets qtdoc qtquicklayouts qtcore +depends = qtqml qtquick qtgui qtwidgets qtdoc qtquicklayouts qtquickdialogs qtcore # Specify the install path under QT_INSTALL_EXAMPLES # Examples will be installed under quick/controls - 'controls' subdirectory diff --git a/src/controls/doc/src/qtquickcontrols-examples.qdoc b/src/controls/doc/src/qtquickcontrols-examples.qdoc index 1a838e0e..8b8c1469 100644 --- a/src/controls/doc/src/qtquickcontrols-examples.qdoc +++ b/src/controls/doc/src/qtquickcontrols-examples.qdoc @@ -139,10 +139,243 @@ \brief Demonstrates UI controls for a touch interface \image qtquickcontrols-example-touch.png - This example shows how to implement a UI suitable - for touch input using \l{Qt Quick Controls}. + \e {Touch Gallery} demonstrates how to implement a UI suitable for touch + input using the following \l{Qt Quick Controls}: + + \list + \li \l ApplicationWindow + \li \l Button + \li \l ProgressBar + \li \l ScrollView + \li \l Slider + \li \l StackView + \li \l Switch + \li \l Tab + \li \l TabView + \li \l TextField + \endlist + + The appearance of the controls is customized by using + \l {Qt Quick Controls Styles}. \include examples-run.qdocinc + + \section1 Creating the Main Page + + In the main.qml file, we use a \l Rectangle type within the + \l ApplicationWindow type to create the main page of the application: + + \quotefromfile touch/main.qml + \skipto ApplicationWindow + \printuntil } + + To use the Qt Quick Controls, we must import them: + + \code + import QtQuick.Controls 1.2 + \endcode + + The \c toolBar property of the application window holds a BorderImage type + that we use to create a separator between the application name and a list of + additional pages: + + \quotefromfile touch/main.qml + \skipto toolBar + \printuntil height + + We use an \l Image type in a \l Rectangle type to create a back button. We + use the \c onClicked signal handler to call the StackView \c pop() function + that pops off the page when users tap the button: + + \printuntil pop() + \printuntil } + \printuntil } + + We use the \c opacity property to hide the back button on the main page. + + We use a \l Text type to display the application name: + + \printuntil text: + \printuntil } + + The \c x position of the \l Text type is bound to the position and width of + the back button, and animated using a \l Behavior. + + We use a ListModel type that contains ListElement definitions to define + titles and source files for the other pages in the application: + + \skipto ListModel + \printuntil ListPage + \printuntil } + \printuntil } + + \section1 Navigating in the Application + + We implement a stack-based navigation model to link the application pages + together. Items are pushed onto the stack as users navigate deeper into the + application, and popped off again when they return to the main page. + + In main.qml, we add a \l StackView type as a child of the application + window: + + \skipto StackView + \printuntil } + + The stack is used by invoking its navigation methods. To load the first item + in the stack view, we assign it to \c initialItem: + + \printuntil \printuntil /^\}/ + + We use a ListView type to display a list of the items provided by + \c pageModel. The \c AndroidDelegate custom type defines each item + instantiated by the view. + + \section1 Creating Push Buttons and Switches + + In ButtonPage.qml we use the \l Button type to create two buttons that + change color when users tap them and one that pops off the page and returns + the user to the main page: + + \quotefromfile touch/content/ButtonPage.qml + \skipto Button + \printuntil stackView + \printuntil } + + We use a \l Switch type to create two switches that users can turn on and + off. They are placed within a \l Row type to lay them out horizontally: + + \printuntil switchStyle + \printuntil switchStyle + \printuntil } + \printuntil } + + A \l ButtonStyle type creates a custom appearance for the buttons: + + \skipto Component + \printuntil } + + To use Qt Quick Controls Styles, we must import them: + + \code + import QtQuick.Controls.Styles 1.1 + \endcode + + A \l SwitchStyle type creates a custom appearance for the switches: + + \quotefromfile touch/content/ButtonPage.qml + \skipuntil Component + \skipto Component + \printuntil /^\}/ + + The \c groove property holds the background groove of the switch and the + \c handle property defines the switch handle. + + \section1 Creating Sliders + + In SliderPage.qml, we use a \l Slider type to create three horizontal + sliders that are placed within a \l Column type to lay them out in a column: + + \quotefromfile touch/content/SliderPage.qml + \skipto Column + \printuntil 1.0 + \printuntil } + \printuntil } + + The \c value property holds the initial handle position on the slider. + + A SliderStyle type creates a custom appearance for the sliders: + + \printuntil /^\}/ + + The \c handle property defines the slider handle and the \c groove property + holds the background groove of the slider. + + \section1 Indicating Progress + + In ProgressBar.qml, we use a ProgressBar type to create three progress bars: + + \quotefromfile touch/content/ProgressBarPage.qml + \skipto Column + \printuntil 1 + \printuntil 400 + \printuntil } + + We use a NumberAnimation type with a SequentialAnimation type to run two + number animations in a sequence. We apply the animations on the \c progress + custom property to animate the current value on the progress bars: + + \quotefromfile touch/content/ProgressBarPage.qml + \skipto progress + \printuntil } + \printuntil } + + A ProgressBarStyle type creates a custom appearance for the progress bars: + + \quotefromfile touch/content/ProgressBarPage.qml + \skipto Component + \printuntil /^\}/ + + \section1 Creating Tabs + + In TabBarPage.qml, we use a TabView type with a \l Tab type to provide a + tab-based navigation model for our application. We use tabs to display the + ButtonPage, SliderPage, and ProgressBarPage on separate tab pages: + + \quotefromfile touch/content/TabBarPage.qml + \skipto TabView + \printuntil ProgressBarPage + \printuntil } + + A TabViewStyle type creates a custom appearance for the tabs: + + \skipto Component + \printuntil /^\}/ + + \section1 Creating Text Input Fields + + In the TextInputPage.qml, we use a TextField type to create an input field + and a read-only text field: + + \quotefromfile touch/content/TextInputPage.qml + \skipto Column + \printuntil true + \printuntil } + \printuntil } + + A TextFieldStyle creates a custom appearance for the text fields: + + \printuntil /^\}/ + + We use a BorderImage type with an image to create borders for the fields. + + \section1 Creating Scrolling Lists + + In ListPage.qml, we use a ScrollView type to provide a scrolling page with a + vertical scoll bar: + + \quotefromfile touch/content/ListPage.qml + \skipto ScrollView + \printuntil true + + We use a ListView type to display a list of 100 items by specifying an + \l{Models and Views in Qt Quick#Integers as Models}{integer} as the value of + the \c model property. We reuse the \c AndroidDelegate custom type here to + define each item instantiated by the view. The \c text property adds the + string \c {Item #} to each list item: + + \printuntil } + \printuntil } + + A ScrollViewStyle type creates a custom appearance for the scroll view: + + \printuntil /^\}/ + + The \c transientScrollBars property is set to \c true to make the scroll + bars appear when the content is scrolled and disappear when they are no + longer needed. + + The \c handle property controls the appearance of the scroll bar handle and + the \c scrollBarBackground property that of the background. */ /*! @@ -232,3 +465,15 @@ \endcode \include examples-run.qdocinc */ + +/*! + \example styles + \title Qt Quick Controls - Styles Example + \ingroup qtquickcontrols_examples + \brief Demonstrates custom styles + \image qtquickcontrols-example-styles.png + + This example shows how to create custom styles for \l{Qt Quick Controls}. + + \include examples-run.qdocinc +*/ diff --git a/src/controls/doc/src/qtquickcontrols-index.qdoc b/src/controls/doc/src/qtquickcontrols-index.qdoc index 479d59da..0d24c06c 100644 --- a/src/controls/doc/src/qtquickcontrols-index.qdoc +++ b/src/controls/doc/src/qtquickcontrols-index.qdoc @@ -60,8 +60,10 @@ \li \l{Qt Quick} \li \l{Qt Quick Controls Overview} \li \l{Qt Quick Controls QML Types}{Qt Quick Controls QML Types} + \li \l{Qt Quick Controls Platform Notes} \li \l{Qt Quick Controls Examples} \li \l{Qt Quick Controls Styles} \li \l{Qt Quick Layouts} + \li \l{Qt Quick Dialogs} \endlist */ diff --git a/src/controls/doc/src/qtquickcontrols-platformnotes.qdoc b/src/controls/doc/src/qtquickcontrols-platformnotes.qdoc new file mode 100644 index 00000000..70f1a1bb --- /dev/null +++ b/src/controls/doc/src/qtquickcontrols-platformnotes.qdoc @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \page qtquickcontrols-platformnotes.html + \title Qt Quick Controls Platform Notes + \brief Platform specific notes for Qt Quick Controls. + + This page contains platform specific notes for creating applications + that use \l{Qt Quick Controls}. + + \section1 Android + + Qt 5.4 introduced a native Android style for Qt Quick Controls. + + \image qtquickcontrols-android.png + + \note The Android style requires Android 3.0 (API level 11) or later. + + No special actions are required to use the Android style. It is + automatically selected and deployed on Android. See \l{Getting Started + with Qt for Android} and \l{Deploying an Application on Android} for + more details on the Android essentials. + + \section2 Action Bar + + The \l{http://developer.android.com/guide/topics/ui/actionbar.html} + {Action Bar} is a special Android control that provides many key features + including various navigation modes, actions, an options menu, a back + button, and also displays the application icon and title. + + Unlike \l{Qt Widgets}, Qt Quick Controls do not use the native action + bar on Android. ToolBar and MenuBar are offered as a cross-platform + replacement. They are unified to a single "action bar" when assigned to + the appropriate ApplicationWindow properties. + + The advantage of a non-native ToolBar is that it can contain any child + items declared in QML. Just to name a few possibilities: + \list + \li ToolButton actions, + \li A TextField as a search field, + \li A ComboBox for navigation, and + \li A ProgressBar for displaying progress. + \endlist +*/ diff --git a/src/controls/qquickmenu.cpp b/src/controls/qquickmenu.cpp index 2bcd0244..faa9b1d1 100644 --- a/src/controls/qquickmenu.cpp +++ b/src/controls/qquickmenu.cpp @@ -367,20 +367,22 @@ QQuickWindow *QQuickMenu::findParentWindow() void QQuickMenu::popup() { - QPoint mousePos = QCursor::pos(); + QQuickWindow *parentWindow = findParentWindow(); + QScreen *screen = parentWindow ? parentWindow->screen() : qGuiApp->primaryScreen(); + QPoint mousePos = QCursor::pos(screen); if (mousePos.x() == int(qInf())) { // ### fixme: no mouse pos registered. Get pos from touch... - mousePos = qGuiApp->primaryScreen()->availableGeometry().center(); + mousePos = screen->availableGeometry().center(); } - if (QQuickWindow *parentWindow = findParentWindow()) + if (parentWindow) mousePos = parentWindow->mapFromGlobal(mousePos); - __popup(mousePos.x(), mousePos.y()); + __popup(QRectF(mousePos.x(), mousePos.y(), 0, 0)); } -void QQuickMenu::__popup(qreal x, qreal y, int atItemIndex, MenuType menuType) +void QQuickMenu::__popup(const QRectF &targetRect, int atItemIndex, MenuType menuType) { if (popupVisible()) { __closeMenu(); @@ -401,14 +403,16 @@ void QQuickMenu::__popup(qreal x, qreal y, int atItemIndex, MenuType menuType) parentWindow = renderWindow; // may not be a QQuickWindow anymore (happens when using QQuickWidget) if (m_platformMenu) { - QPointF screenPosition(x + m_xOffset, y + m_yOffset); + QRectF globalTargetRect = targetRect.translated(m_xOffset, m_yOffset); if (visualItem()) { - if (qGuiApp->isRightToLeft()) - screenPosition.rx() -= qMax(static_cast<qreal>(m_minimumWidth), m_menuContentItem->width()); - screenPosition = visualItem()->mapToScene(screenPosition); + if (qGuiApp->isRightToLeft()) { + qreal w = qMax(static_cast<qreal>(m_minimumWidth), m_menuContentItem->width()); + globalTargetRect.moveLeft(w - targetRect.x() - targetRect.width()); + } + globalTargetRect = visualItem()->mapRectToScene(globalTargetRect); } m_platformMenu->setMenuType(QPlatformMenu::MenuType(menuType)); - m_platformMenu->showPopup(parentWindow, screenPosition.toPoint(), atItem ? atItem->platformItem() : 0); + m_platformMenu->showPopup(parentWindow, globalTargetRect.toRect(), atItem ? atItem->platformItem() : 0); } else { m_popupWindow = new QQuickMenuPopupWindow(); if (visualItem()) @@ -421,7 +425,7 @@ void QQuickMenu::__popup(qreal x, qreal y, int atItemIndex, MenuType menuType) connect(m_popupWindow, SIGNAL(visibleChanged(bool)), this, SLOT(windowVisibleChanged(bool))); connect(m_popupWindow, SIGNAL(geometryChanged()), this, SIGNAL(__popupGeometryChanged())); - m_popupWindow->setPosition(x + m_xOffset, y + m_yOffset); + m_popupWindow->setPosition(targetRect.x() + m_xOffset, targetRect.y() + targetRect.height() + m_yOffset); m_popupWindow->show(); } } @@ -453,11 +457,8 @@ QRect QQuickMenu::popupGeometry() const void QQuickMenu::__closeMenu() { setPopupVisible(false); - if (m_platformMenu) - m_platformMenu->setVisible(false); - else if (m_popupWindow) + if (m_popupWindow) m_popupWindow->setVisible(false); - m_parentWindow = 0; emit __menuClosed(); } @@ -676,8 +677,6 @@ void QQuickMenu::setupMenuItem(QQuickMenuBase *item, int platformIndex) void QQuickMenu::append_menuItems(QQuickMenuItems *list, QObject *o) { if (QQuickMenu *menu = qobject_cast<QQuickMenu *>(list->object)) { - Q_ASSERT(o->parent() == menu); - if (QQuickMenuBase *menuItem = qobject_cast<QQuickMenuBase *>(o)) { menu->m_menuItems.append(menuItem); menu->setupMenuItem(menuItem); diff --git a/src/controls/qquickmenu_p.h b/src/controls/qquickmenu_p.h index 943c45bf..f21f2ce0 100644 --- a/src/controls/qquickmenu_p.h +++ b/src/controls/qquickmenu_p.h @@ -83,7 +83,7 @@ public: Q_INVOKABLE void removeItem(QQuickMenuBase *); Q_INVOKABLE void clear(); - Q_INVOKABLE void __popup(qreal x, qreal y, int atActionIndex = -1, MenuType menuType = DefaultMenu); + Q_INVOKABLE void __popup(const QRectF &targetRect, int atItemIndex = -1, MenuType menuType = DefaultMenu); public Q_SLOTS: void __closeMenu(); diff --git a/src/controls/qquickmenubar.cpp b/src/controls/qquickmenubar.cpp index d3503f89..33a1e9ef 100644 --- a/src/controls/qquickmenubar.cpp +++ b/src/controls/qquickmenubar.cpp @@ -85,9 +85,19 @@ void QQuickMenuBar::setNative(bool native) { bool wasNative = isNative(); if (native) { - if (!m_platformMenuBar) + if (!m_platformMenuBar) { m_platformMenuBar = QGuiApplicationPrivate::platformTheme()->createPlatformMenuBar(); + if (m_platformMenuBar) { + m_platformMenuBar->handleReparent(m_parentWindow); + foreach (QQuickMenu *menu, m_menus) + m_platformMenuBar->insertMenu(menu->platformMenu(), 0 /* append */); + } + } } else { + if (m_platformMenuBar) { + foreach (QQuickMenu *menu, m_menus) + m_platformMenuBar->removeMenu(menu->platformMenu()); + } delete m_platformMenuBar; m_platformMenuBar = 0; } diff --git a/src/controls/qquickmenupopupwindow.cpp b/src/controls/qquickmenupopupwindow.cpp index c3231fd4..52ce7219 100644 --- a/src/controls/qquickmenupopupwindow.cpp +++ b/src/controls/qquickmenupopupwindow.cpp @@ -42,8 +42,10 @@ QT_BEGIN_NAMESPACE QQuickMenuPopupWindow::QQuickMenuPopupWindow() : - QQuickPopupWindow(), m_itemAt(0) -{ } + m_itemAt(0), + m_logicalParentWindow(0) +{ +} void QQuickMenuPopupWindow::setParentItem(QQuickItem *item) { @@ -72,8 +74,11 @@ void QQuickMenuPopupWindow::setItemAt(QQuickItem *menuItem) void QQuickMenuPopupWindow::setParentWindow(QWindow *effectiveParentWindow, QQuickWindow *parentWindow) { + while (effectiveParentWindow && effectiveParentWindow->parent()) + effectiveParentWindow = effectiveParentWindow->parent(); if (transientParent() != effectiveParentWindow) setTransientParent(effectiveParentWindow); + m_logicalParentWindow = parentWindow; if (parentWindow) { connect(parentWindow, SIGNAL(destroyed()), this, SLOT(dismissPopup())); if (QQuickMenuPopupWindow *pw = qobject_cast<QQuickMenuPopupWindow *>(parentWindow)) @@ -129,6 +134,10 @@ void QQuickMenuPopupWindow::exposeEvent(QExposeEvent *e) // the popup will reposition at the last moment, so its // initial position must be captured for updateSize(). m_initialPos = position(); + if (m_logicalParentWindow && m_logicalParentWindow->parent()) { + // This must be a QQuickWindow embedded via createWindowContainer. + m_initialPos += m_logicalParentWindow->geometry().topLeft(); + } QQuickPopupWindow::exposeEvent(e); } diff --git a/src/controls/qquickmenupopupwindow_p.h b/src/controls/qquickmenupopupwindow_p.h index 0d07f687..83216373 100644 --- a/src/controls/qquickmenupopupwindow_p.h +++ b/src/controls/qquickmenupopupwindow_p.h @@ -61,6 +61,7 @@ private: QQuickItem *m_itemAt; QPointF m_oldItemPos; QPointF m_initialPos; + QQuickWindow *m_logicalParentWindow; }; QT_END_NAMESPACE diff --git a/src/controls/qquickpopupwindow.cpp b/src/controls/qquickpopupwindow.cpp index 066624d4..e10e6ae0 100644 --- a/src/controls/qquickpopupwindow.cpp +++ b/src/controls/qquickpopupwindow.cpp @@ -60,23 +60,16 @@ void QQuickPopupWindow::show() { qreal posx = x(); qreal posy = y(); - if (QQuickWindow *parentWindow = qobject_cast<QQuickWindow *>(transientParent())) { + // transientParent may not be a QQuickWindow when embedding into widgets + if (QWindow *tp = transientParent()) { if (m_parentItem) { - QPointF pos = m_parentItem->mapToItem(parentWindow->contentItem(), QPointF(posx, posy)); + QPointF pos = m_parentItem->mapToItem(m_parentItem->window()->contentItem(), QPointF(posx, posy)); posx = pos.x(); posy = pos.y(); } - - if (parentWindow->parent()) { - // If the parent window is embedded in another window, the offset needs to be relative to - // its top-level window container, or to global coordinates, which is the same in the end. - QPoint parentWindowOffset = parentWindow->mapToGlobal(QPoint()); - posx += parentWindowOffset.x(); - posy += parentWindowOffset.y(); - } else { - posx += parentWindow->geometry().left(); - posy += parentWindow->geometry().top(); - } + QPoint tlwOffset = tp->mapToGlobal(QPoint()); + posx += tlwOffset.x(); + posy += tlwOffset.y(); } else if (m_parentItem && m_parentItem->window()) { QPoint offset; QQuickWindow *quickWindow = m_parentItem->window(); @@ -85,11 +78,10 @@ void QQuickPopupWindow::show() QPointF pos = m_parentItem->mapToItem(quickWindow->contentItem(), QPointF(posx, posy)); posx = pos.x(); posy = pos.y(); - if (renderWindow) { - QPoint parentWindowOffset = renderWindow->mapToGlobal(QPoint()); - posx += offset.x() + parentWindowOffset.x(); - posy += offset.y() + parentWindowOffset.y(); - } + + QPoint parentWindowOffset = (renderWindow ? renderWindow : quickWindow)->mapToGlobal(QPoint()); + posx += offset.x() + parentWindowOffset.x(); + posy += offset.y() + parentWindowOffset.y(); } if (m_contentItem) { diff --git a/src/dialogs/DefaultFileDialog.qml b/src/dialogs/DefaultFileDialog.qml index 47d59481..feb31c4d 100644 --- a/src/dialogs/DefaultFileDialog.qml +++ b/src/dialogs/DefaultFileDialog.qml @@ -203,7 +203,7 @@ AbstractFileDialog { margins: 4 } elide: Text.ElideLeft - renderType: Text.NativeRendering + renderType: ControlsPrivate.Settings.isMobile ? Text.QtRendering : Text.NativeRendering Component.onCompleted: { sidebarSplitter.rowHeight = parent.height if (implicitWidth * 1.2 > sidebarSplitter.maxShortcutWidth) @@ -237,7 +237,7 @@ AbstractFileDialog { margins: 4 } elide: Text.ElideLeft - renderType: Text.NativeRendering + renderType: ControlsPrivate.Settings.isMobile ? Text.QtRendering : Text.NativeRendering } Menu { id: favoriteCtxMenu @@ -350,7 +350,7 @@ AbstractFileDialog { } color: styleData.textColor elide: Text.ElideRight - renderType: Text.NativeRendering + renderType: ControlsPrivate.Settings.isMobile ? Text.QtRendering : Text.NativeRendering } } } @@ -373,7 +373,7 @@ AbstractFileDialog { } color: styleData.textColor elide: Text.ElideRight - renderType: Text.NativeRendering + renderType: ControlsPrivate.Settings.isMobile ? Text.QtRendering : Text.NativeRendering } } } diff --git a/src/dialogs/DefaultFontDialog.qml b/src/dialogs/DefaultFontDialog.qml index 041be844..4bd4a1be 100644 --- a/src/dialogs/DefaultFontDialog.qml +++ b/src/dialogs/DefaultFontDialog.qml @@ -40,6 +40,7 @@ import QtQuick 2.2 import QtQuick.Controls 1.2 +import QtQuick.Controls.Private 1.0 import QtQuick.Controls.Styles 1.0 import QtQuick.Dialogs 1.1 import QtQuick.Dialogs.Private 1.1 @@ -387,6 +388,7 @@ AbstractFontDialog { anchors.centerIn: parent font: content.font onFocusChanged: if (!focus && sample.text == "") sample.text = content.writingSystemSample + renderType: Settings.isMobile ? Text.QtRendering : Text.NativeRendering } } } diff --git a/src/dialogs/DefaultMessageDialog.qml b/src/dialogs/DefaultMessageDialog.qml index b41b3743..609d060c 100644 --- a/src/dialogs/DefaultMessageDialog.qml +++ b/src/dialogs/DefaultMessageDialog.qml @@ -40,6 +40,7 @@ import QtQuick 2.2 import QtQuick.Controls 1.2 +import QtQuick.Controls.Private 1.0 import QtQuick.Dialogs 1.1 import QtQuick.Window 2.1 import "qml" @@ -115,6 +116,7 @@ AbstractMessageDialog { text: root.text font.weight: Font.Bold wrapMode: Text.WordWrap + renderType: Settings.isMobile ? Text.QtRendering : Text.NativeRendering } Text { @@ -128,6 +130,7 @@ AbstractMessageDialog { } text: root.informativeText wrapMode: Text.WordWrap + renderType: Settings.isMobile ? Text.QtRendering : Text.NativeRendering } } @@ -285,6 +288,7 @@ AbstractMessageDialog { wrapMode: Text.WordWrap readOnly: true selectByMouse: true + renderType: Settings.isMobile ? Text.QtRendering : Text.NativeRendering } } } diff --git a/src/dialogs/qml/ColorSlider.qml b/src/dialogs/qml/ColorSlider.qml index 219da0cb..60412d54 100644 --- a/src/dialogs/qml/ColorSlider.qml +++ b/src/dialogs/qml/ColorSlider.qml @@ -39,6 +39,7 @@ ****************************************************************************/ import QtQuick 2.2 +import QtQuick.Controls.Private 1.0 Item { id: colorSlider @@ -76,6 +77,7 @@ Item { text: colorSlider.text anchors.left: parent.left color: palette.windowText + renderType: Settings.isMobile ? Text.QtRendering : Text.NativeRendering } Item { diff --git a/src/dialogs/qml/IconButtonStyle.qml b/src/dialogs/qml/IconButtonStyle.qml index 3af5b6cd..f51cf253 100644 --- a/src/dialogs/qml/IconButtonStyle.qml +++ b/src/dialogs/qml/IconButtonStyle.qml @@ -49,7 +49,7 @@ ButtonStyle { id: text font.family: iconFont.name font.pointSize: TextSingleton.font.pointSize * 1.5 - renderType: Text.NativeRendering + renderType: Settings.isMobile ? Text.QtRendering : Text.NativeRendering text: control.text color: SystemPaletteSingleton.buttonText(control.enabled) verticalAlignment: Text.AlignVCenter diff --git a/src/dialogs/qmldir b/src/dialogs/qmldir index b4ae1a05..37e1efff 100644 --- a/src/dialogs/qmldir +++ b/src/dialogs/qmldir @@ -2,3 +2,5 @@ module QtQuick.Dialogs plugin dialogplugin classname QtQuick2DialogsPlugin typeinfo plugins.qmltypes +depends Qt.labs.folderlistmodel 1.0 +depends Qt.labs.settings 1.0 diff --git a/src/dialogs/qquickdialog.cpp b/src/dialogs/qquickdialog.cpp index 76f278ae..ab3d9200 100644 --- a/src/dialogs/qquickdialog.cpp +++ b/src/dialogs/qquickdialog.cpp @@ -73,7 +73,9 @@ QT_BEGIN_NAMESPACE /*! \qmlsignal Dialog::accepted() - This signal is emitted by \l accept(). + This signal is emitted when the user has pressed any button which has the + \l {QMessageBox::}{AcceptRole}: \gui OK, \gui Open, \gui Save, + \gui {Save All}, \gui Retry or \gui Ignore. The corresponding handler is \c onAccepted. */ @@ -81,7 +83,9 @@ QT_BEGIN_NAMESPACE /*! \qmlsignal Dialog::rejected() - This signal is emitted by \l reject(). + This signal is emitted when the user has dismissed the dialog, by closing + the dialog window, by pressing a \gui Cancel, \gui Close or \gui Abort + button on the dialog, or by pressing the back button or the escape key. The corresponding handler is \c onRejected. */ @@ -152,6 +156,12 @@ QT_BEGIN_NAMESPACE \sa modality */ +/*! \qmlproperty StandardButton Dialog::clickedButton + + This property holds the button pressed by the user. Its value is + one of the flags set for the standardButtons property. +*/ + /*! \qmlproperty Qt::WindowModality Dialog::modality @@ -230,7 +240,7 @@ QJSValue QQuickDialog::__standardButtonsRightModel() void QQuickDialog::setVisible(bool v) { if (v) - m_clickedButton == NoButton; + m_clickedButton = NoButton; QQuickAbstractDialog::setVisible(v); } @@ -294,12 +304,6 @@ void QQuickDialog::setStandardButtons(StandardButtons buttons) } /*! - \qmlproperty bool Dialog::visible - - This property holds whether the dialog is visible. By default this is false. -*/ - -/*! \qmlproperty QObject Dialog::contentItem The QML object which implements the dialog contents. Should be an \l Item. diff --git a/src/dialogs/qquickdialog_p.h b/src/dialogs/qquickdialog_p.h index 087f677d..3ae055f7 100644 --- a/src/dialogs/qquickdialog_p.h +++ b/src/dialogs/qquickdialog_p.h @@ -104,8 +104,8 @@ private: private: QString m_title; - StandardButton m_clickedButton; StandardButtons m_enabledButtons; + StandardButton m_clickedButton; QJSValue m_standardButtonsLeftModel; QJSValue m_standardButtonsRightModel; Q_DISABLE_COPY(QQuickDialog) diff --git a/src/dialogs/qquickplatformcolordialog.cpp b/src/dialogs/qquickplatformcolordialog.cpp index f6283311..f48c4ab7 100644 --- a/src/dialogs/qquickplatformcolordialog.cpp +++ b/src/dialogs/qquickplatformcolordialog.cpp @@ -185,13 +185,18 @@ QPlatformColorDialogHelper *QQuickPlatformColorDialog::helper() containing the dialog's parent Item, modal with respect to the whole application, or non-modal. - By default it is \l NonModal. + By default it is \c Qt.NonModal. Modality does not mean that there are any blocking calls to wait for the dialog to be accepted or rejected; it's only that the user will be prevented from interacting with the parent window and/or the application windows at the same time. + You probably need to write an onAccepted handler if you wish to change a + color after the user has pressed the OK button, or an + onCurrentColorChanged handler if you wish to react to every change the + user makes while the dialog is open. + On MacOS the color dialog is only allowed to be non-modal. */ diff --git a/src/dialogs/qquickplatformfontdialog.cpp b/src/dialogs/qquickplatformfontdialog.cpp index faf873f4..1744cb84 100644 --- a/src/dialogs/qquickplatformfontdialog.cpp +++ b/src/dialogs/qquickplatformfontdialog.cpp @@ -187,13 +187,17 @@ QPlatformFontDialogHelper *QQuickPlatformFontDialog::helper() containing the dialog's parent Item, modal with respect to the whole application, or non-modal. - By default it is \l WindowModal. + By default it is \c Qt.WindowModal. Modality does not mean that there are any blocking calls to wait for the dialog to be accepted or rejected; it's only that the user will be prevented from interacting with the parent window and/or the application - windows at the same time. You probably need to write an onAccepted handler - to actually load or save the chosen file. + windows at the same time. + + You probably need to write an onAccepted handler if you wish to change a + font after the user has pressed the OK button, or an onCurrentFontChanged + handler if you wish to react to every change the user makes while the + dialog is open. */ /*! diff --git a/src/dialogs/qquickplatformmessagedialog.cpp b/src/dialogs/qquickplatformmessagedialog.cpp index 07665fff..c7b13c7c 100644 --- a/src/dialogs/qquickplatformmessagedialog.cpp +++ b/src/dialogs/qquickplatformmessagedialog.cpp @@ -171,6 +171,12 @@ QT_BEGIN_NAMESPACE The corresponding handler is \c onReset. */ +/*! \qmlproperty StandardButton MessageDialog::clickedButton + + This property holds the button pressed by the user. Its value is + one of the flags set for the standardButtons property. +*/ + /*! \class QQuickPlatformMessageDialog \inmodule QtQuick.Dialogs diff --git a/tests/auto/applicationwindow/data/defaultFocus.qml b/tests/auto/applicationwindow/data/defaultFocus.qml new file mode 100644 index 00000000..718e809c --- /dev/null +++ b/tests/auto/applicationwindow/data/defaultFocus.qml @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtQuick.Controls 1.2 + +ApplicationWindow { + visible: true + width: 200 + height: 200 + + property bool receivedKeyPress: false + + Item { + objectName: "item" + focus: true + anchors.fill: parent + + Keys.onLeftPressed: receivedKeyPress = true + } +} + diff --git a/tests/auto/applicationwindow/tst_applicationwindow.cpp b/tests/auto/applicationwindow/tst_applicationwindow.cpp index c45edfa7..3a12c385 100644 --- a/tests/auto/applicationwindow/tst_applicationwindow.cpp +++ b/tests/auto/applicationwindow/tst_applicationwindow.cpp @@ -52,6 +52,7 @@ private slots: void qmlCreation(); void activeFocusOnTab1(); void activeFocusOnTab2(); + void defaultFocus(); }; void tst_applicationwindow::qmlCreation() @@ -183,6 +184,34 @@ void tst_applicationwindow::activeFocusOnTab2() QVERIFY(item->hasActiveFocus()); } +void tst_applicationwindow::defaultFocus() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.loadUrl(testFileUrl("defaultFocus.qml")); + QObject* created = component.create(); + QScopedPointer<QObject> cleanup(created); + Q_UNUSED(cleanup); + QVERIFY(created); + + QQuickWindow* window = qobject_cast<QQuickWindow*>(created); + QVERIFY(window); + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window)); + QVERIFY(QGuiApplication::focusWindow() == window); + + QQuickItem* contentItem = window->contentItem(); + QVERIFY(contentItem); + QVERIFY(contentItem->hasActiveFocus()); + + // A single item in an ApplicationWindow with focus: true should receive focus. + QQuickItem* item = findItem<QQuickItem>(window->contentItem(), "item"); + QVERIFY(item); + QVERIFY(item->hasFocus()); + QVERIFY(item->hasActiveFocus()); +} + QTEST_MAIN(tst_applicationwindow) #include "tst_applicationwindow.moc" diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 7eba7586..810b4678 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -1,3 +1,3 @@ TEMPLATE = subdirs -SUBDIRS += testplugin controls activeFocusOnTab applicationwindow +SUBDIRS += testplugin controls activeFocusOnTab applicationwindow dialogs controls.depends = testplugin diff --git a/examples/quick/controls/gallery/content/Layouts.qml b/tests/auto/controls/data/tableview/tv_keys.qml index 8d6b096e..2102f55c 100644 --- a/examples/quick/controls/gallery/content/Layouts.qml +++ b/tests/auto/controls/data/tableview/tv_keys.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Quick Controls module of the Qt Toolkit. @@ -40,68 +40,21 @@ import QtQuick 2.2 import QtQuick.Controls 1.2 -import QtQuick.Layouts 1.0 -Item { - id:root - anchors.fill: parent - anchors.margins: 8 - - ColumnLayout { - id: mainLayout - anchors.fill: parent - spacing: 4 - GroupBox { - id: rowBox - title: "Row layout" - Layout.fillWidth: true - RowLayout { - id: rowLayout - anchors.fill: parent - TextField { - placeholderText: "This wants to grow horizontally" - Layout.fillWidth: true - } - Button { - text: "Button" - } +Row { + width: 100 + height: 50 + spacing: 10 + property alias control1: _control1 + TableView { + id: _control1 + property bool gotit: false + Keys.onPressed: { + if ((!gotit) && (event.key === Qt.Key_Down)) { + gotit = true; + event.accepted = true; + return; } } - - GroupBox { - id: gridBox - title: "Grid layout" - Layout.fillWidth: true - - GridLayout { - id: gridLayout - anchors.fill: parent - rows: 3 - flow: GridLayout.TopToBottom - - Label { text: "Line 1" } - Label { text: "Line 2" } - Label { text: "Line 3" } - - TextField { } - TextField { } - TextField { } - - TextArea { - text: "This widget spans over three rows in the GridLayout.\n" - + "All items in the GridLayout are implicitly positioned from top to bottom." - Layout.rowSpan: 3 - Layout.fillHeight: true - Layout.fillWidth: true - } - } - } - TextArea { - id: t3 - text: "This fills the whole cell" - Layout.minimumHeight: 30 - Layout.fillHeight: true - Layout.fillWidth: true - } } } diff --git a/tests/auto/controls/data/tst_tableview.qml b/tests/auto/controls/data/tst_tableview.qml index b802e7ff..9e37f45e 100644 --- a/tests/auto/controls/data/tst_tableview.qml +++ b/tests/auto/controls/data/tst_tableview.qml @@ -179,6 +179,37 @@ TestCase { table.destroy() } + function test_keys() { + var component = Qt.createComponent("tableview/tv_keys.qml") + compare(component.status, Component.Ready) + var test = component.createObject(container); + verify(test !== null, "test control created is null") + var control1 = test.control1 + verify(control1 !== null) + + control1.forceActiveFocus() + verify(control1.activeFocus) + + control1.selectionMode = SelectionMode.SingleSelection + control1.model = 3 + control1.currentRow = -1 + + verify(control1.gotit === false) + verify(control1.currentRow === -1) + + keyClick(Qt.Key_Down); + verify(control1.activeFocus) + verify(control1.gotit === true) + verify(control1.currentRow === -1) + + keyClick(Qt.Key_Down); + verify(control1.activeFocus) + verify(control1.gotit === true) + verify(control1.currentRow === 0) + + test.destroy() + } + function test_selection() { var component = Qt.createComponent("tableview/table2_qabstractitemmodel.qml") diff --git a/tests/auto/dialogs/data/RectWithFileDialog.qml b/tests/auto/dialogs/data/RectWithFileDialog.qml new file mode 100644 index 00000000..ca4d7944 --- /dev/null +++ b/tests/auto/dialogs/data/RectWithFileDialog.qml @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module 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 Digia Plc and its Subsidiary(-ies) 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.0 +import QtQuick.Dialogs 1.0 + +Rectangle { + width: 1024 + height: 320 + property alias fileDialog: fileDialog + property alias label: label + property alias mouseArea: mouseArea + + FileDialog { + id: fileDialog + title: "Choose some files" + selectMultiple: true + nameFilters: [ "QML files (*.qml)", "All files (*)" ] + selectedNameFilter: "QML files (*.qml)" + onAccepted: label.text = fileDialog.filePaths + } + + MouseArea { + id: mouseArea + anchors.fill: parent + onClicked: fileDialog.visible = !fileDialog.visible + } + + Text { + id: label + text: "Click to open a file dialog" + wrapMode: Text.Wrap + anchors.fill: parent + anchors.margins: 10 + } +} diff --git a/tests/auto/dialogs/dialogs.pro b/tests/auto/dialogs/dialogs.pro new file mode 100644 index 00000000..cf46bed1 --- /dev/null +++ b/tests/auto/dialogs/dialogs.pro @@ -0,0 +1,20 @@ +CONFIG += testcase +TARGET = tst_dialogs +SOURCES += tst_dialogs.cpp + +include (../shared/util.pri) + +osx:CONFIG -= app_bundle +osx:CONFIG+=insignificant_test # QTBUG-30513 - test is unstable +linux-*:CONFIG+=insignificant_test # QTBUG-30513 - test is unstable +win32:CONFIG+=insignificant_test # QTBUG-30513 - test is unstable + +CONFIG += parallel_test +QT += core-private gui-private qml-private quick-private testlib + +TESTDATA = data/* + +OTHER_FILES += \ + data/RectWithFileDialog.qml + +DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/dialogs/tst_dialogs.cpp b/tests/auto/dialogs/tst_dialogs.cpp new file mode 100644 index 00000000..34af7e0c --- /dev/null +++ b/tests/auto/dialogs/tst_dialogs.cpp @@ -0,0 +1,152 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qtest.h> +#include "../shared/util.h" +#include <QtQuick/QQuickItem> +#include <QtQuick/QQuickView> +#include <QSignalSpy> + +class tst_dialogs : public QQmlDataTest +{ + Q_OBJECT +public: + +private slots: + void initTestCase() + { + QQmlDataTest::initTestCase(); + } + + // FileDialog + void fileDialogDefaultModality(); + void fileDialogNonModal(); + void fileDialogNameFilters(); + +private: +}; + +void tst_dialogs::fileDialogDefaultModality() +{ + QQuickView *window = new QQuickView; + QScopedPointer<QQuickWindow> cleanup(window); + + window->setSource(testFileUrl("RectWithFileDialog.qml")); + window->setGeometry(240,240,1024,320); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + QVERIFY(window->rootObject()); + + // Click to show + QObject *dlg = qvariant_cast<QObject *>(window->rootObject()->property("fileDialog")); + QSignalSpy spyVisibilityChanged(dlg, SIGNAL(visibilityChanged())); + QTest::mouseClick(window, Qt::LeftButton, 0, QPoint(1000, 100)); // show + QTRY_VERIFY(spyVisibilityChanged.count() > 0); + int visibilityChangedCount = spyVisibilityChanged.count(); + // Can't hide by clicking the main window, because dialog is modal. + QTest::mouseClick(window, Qt::LeftButton, 0, QPoint(1000, 100)); + /* + On OS X, if you send an event directly to a window, the modal dialog + doesn't block the event, so the window will process it normally. This + is a different code path compared to having a user click the mouse and + generate a native event; in that case the OS does the filtering itself, + and Qt will not even see the event. But simulating real events in the + test framework is generally unstable. So there isn't a good way to test + modality on OS X. + This test sometimes fails on other platforms too. Maybe it's not reliable + to try to click the main window in a location which is outside the + dialog, without checking or guaranteeing it somehow. + */ + QSKIP("Modality test is flaky in general and doesn't work at all on OS X"); + // So we expect no change in visibility. + QCOMPARE(spyVisibilityChanged.count(), visibilityChangedCount); + + QCOMPARE(dlg->property("visible").toBool(), true); + QMetaObject::invokeMethod(dlg, "close"); + QTRY_VERIFY(spyVisibilityChanged.count() > visibilityChangedCount); + visibilityChangedCount = spyVisibilityChanged.count(); + QCOMPARE(dlg->property("visible").toBool(), false); + QMetaObject::invokeMethod(dlg, "open"); + QTRY_VERIFY(spyVisibilityChanged.count() > visibilityChangedCount); + QCOMPARE(dlg->property("visible").toBool(), true); + QCOMPARE(dlg->property("modality").toInt(), (int)Qt::WindowModal); +} + +void tst_dialogs::fileDialogNonModal() +{ + QQuickView *window = new QQuickView; + QScopedPointer<QQuickWindow> cleanup(window); + + window->setSource(testFileUrl("RectWithFileDialog.qml")); + window->setGeometry(240,240,1024,320); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + QVERIFY(window->rootObject()); + + // Click to toggle visibility + QObject *dlg = qvariant_cast<QObject *>(window->rootObject()->property("fileDialog")); + dlg->setProperty("modality", QVariant((int)Qt::NonModal)); + QSignalSpy spyVisibilityChanged(dlg, SIGNAL(visibilityChanged())); + QTest::mouseClick(window, Qt::LeftButton, 0, QPoint(1000, 100)); // show + QTRY_VERIFY(spyVisibilityChanged.count() > 0); + int visibilityChangedCount = spyVisibilityChanged.count(); + QCOMPARE(dlg->property("visible").toBool(), true); + QTest::mouseClick(window, Qt::LeftButton, 0, QPoint(1000, 100)); // hide + QTRY_VERIFY(spyVisibilityChanged.count() > visibilityChangedCount); + QCOMPARE(dlg->property("visible").toBool(), false); + QCOMPARE(dlg->property("modality").toInt(), (int)Qt::NonModal); +} + +void tst_dialogs::fileDialogNameFilters() +{ + QQuickView *window = new QQuickView; + QScopedPointer<QQuickWindow> cleanup(window); + + window->setSource(testFileUrl("RectWithFileDialog.qml")); + window->setGeometry(240,240,1024,320); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + QVERIFY(window->rootObject()); + + QObject *dlg = qvariant_cast<QObject *>(window->rootObject()->property("fileDialog")); + QStringList filters; + filters << "QML files (*.qml)"; + filters << "Image files (*.jpg, *.png, *.gif)"; + filters << "All files (*)"; + dlg->setProperty("nameFilters", QVariant(filters)); + QCOMPARE(dlg->property("selectedNameFilter").toString(), filters.first()); +} + +QTEST_MAIN(tst_dialogs) + +#include "tst_dialogs.moc" |