diff options
author | Sami Nurmenniemi <sami.nurmenniemi@qt.io> | 2019-01-24 14:45:19 +0200 |
---|---|---|
committer | Sami Nurmenniemi <sami.nurmenniemi@qt.io> | 2019-02-04 11:39:20 +0000 |
commit | 32bd51b0ee16696488f1476c004e944b44f76eb6 (patch) | |
tree | 13b90fd9411dc22de79706c2b916111db8d53ffb | |
parent | 64f65e26feb4f6b0b3ac31cfc4e22c5971c1c41d (diff) |
Enable boot2qt launcher automatic demo mode
Task-number: QTBUG-72852
Change-Id: I8e2ab58a2a0b13f5a1ce67a24c5c75b809683324
Reviewed-by: Tuomas Heimonen <tuomas.heimonen@qt.io>
-rw-r--r-- | qml.qrc | 4 | ||||
-rw-r--r-- | qml/DemoHeader.qml | 1 | ||||
-rw-r--r-- | qml/DemoMode.qml | 395 | ||||
-rw-r--r-- | qml/DetailView.qml | 2 | ||||
-rw-r--r-- | qml/GlobalIndicator.qml (renamed from qml/FpsIndicator.qml) | 12 | ||||
-rw-r--r-- | qml/Header.qml | 1 | ||||
-rw-r--r-- | qml/LaunchScreen.qml | 1 | ||||
-rw-r--r-- | qml/LauncherCheckBox.qml | 74 | ||||
-rw-r--r-- | qml/LayoutSettings.qml | 56 | ||||
-rw-r--r-- | qml/MainWindow.qml | 40 | ||||
-rw-r--r-- | src/automationhelper.cpp | 91 | ||||
-rw-r--r-- | src/automationhelper.h | 47 | ||||
-rw-r--r-- | src/main.cpp | 2 | ||||
-rw-r--r-- | src/settingsmanager.cpp | 13 | ||||
-rw-r--r-- | src/settingsmanager.h | 6 | ||||
-rw-r--r-- | startup.pro | 6 |
16 files changed, 701 insertions, 50 deletions
@@ -22,6 +22,8 @@ <file>qml/BusyIndicator.qml</file> <file>qml/MainWindow.qml</file> <file>qml/FlickSlider.qml</file> - <file>qml/FpsIndicator.qml</file> + <file>qml/LauncherCheckBox.qml</file> + <file>qml/DemoMode.qml</file> + <file>qml/GlobalIndicator.qml</file> </qresource> </RCC> diff --git a/qml/DemoHeader.qml b/qml/DemoHeader.qml index 18c4016..555fff2 100644 --- a/qml/DemoHeader.qml +++ b/qml/DemoHeader.qml @@ -91,6 +91,7 @@ Rectangle { Image { id: applicationCloseButton + objectName: "applicationCloseButton" height: parent.height width: height source: "icons/close_icon.svg" diff --git a/qml/DemoMode.qml b/qml/DemoMode.qml new file mode 100644 index 0000000..f5b8dcd --- /dev/null +++ b/qml/DemoMode.qml @@ -0,0 +1,395 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Device Creation. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +import QtQuick 2.0 +import AutomationHelper 1.0 + +Item { + property var visibleItem + property var demoHeader + property var launcherHeader + property var visibleItemName: visibleItem ? visibleItem.objectName : 0 + property bool demoModeSeleted: globalSettings.demoModeSelected + property bool demoIsRunning: false + + property int demoInitialStartTime: 2000 // How fast demo starts after turning the demo on + property int demoIdleStartTime: 2 * 60 * 1000 // How fast demo starts after idle + property int demoStepDuration: 2000 + property int applicationWaitDuration: 1000 + property int verticalFlickVelocity: 1000 + property int horizontalFlickVelocity: 1000 + + onDemoModeSeletedChanged: { + if (demoModeSeleted) { + demoStartCounter.interval = demoInitialStartTime + demoStartCounter.start() + } else { + demoStartCounter.stop() + stopDemos() + } + } + + /* + Start the demo sequence. First demo to start depends on the current screen. + */ + function startDemos() { + console.log("Start automatic demo mode") + if (visibleItemName === "settingsView") { + settingsDemoAnimation.start() + } else if ((visibleItemName === "launchScreen") || (visibleItemName === "detailView")) { + switchToSettingScreenAnimation.start() + } else { + exitFromRunningDemoAnimation.start() + } + + demoIsRunning = true + } + + /* + Stop all currently running demos + */ + function stopDemos() { + console.log("Stop automatic demo mode") + switchToSettingScreenAnimation.stop() + settingsDemoAnimation.stop() + gridViewDemoAnimation.stop() + graphicsEffectsDemoAnimation.stop() + qtChartsDemoAnimation.stop() + switchToDetailViewAnimation.stop() + detailViewDemoAnimation.stop() + eBikeViewDemoAnimation.stop() + demoIsRunning = false + + // Restart demo after idle time + if (demoModeSeleted) { + demoStartCounter.interval = demoIdleStartTime + demoStartCounter.restart() + } + } + + Timer { + id: demoStartCounter + repeat: false + onTriggered: startDemos() + } + + /* + Cet index of with \a title from the \a applicationList + */ + function applicationIndex(applicationList, title) { + var i + var applicationListModel = applicationList.model + + // count and get() do not work on QAbstractItemModel, rowCount and query must be used + for (i=0; i<applicationListModel.rowCount(); i++) { + if (applicationListModel.query(i, "name") === title) { + return i + } + } + return -1 + } + + /* + Click application with \a title from the launcher with \a launcherName + + Returns \c true if application launcher was clicked + */ + function clickApplicationLauncher(launcherName, title) { + var applicationList = automationHelper.findChildObject(visibleItem, launcherName) + var index = applicationIndex(applicationList, title) + + if (index !== -1) { + applicationList.currentIndex = index; + automationHelper.click(applicationList.currentItem) + return true + } + return false + } + + /* + Flick flickable with objectName \a objName with \a amountHorizontal and \a amountVertical + */ + function flickUpDown(objName, amountHorizontal, amountVertical) { + var gridView = automationHelper.findChildObject(visibleItem, objName) + if (gridView) + gridView.flick(amountHorizontal, amountVertical) + else + console.log("no child " + objName) + } + + AutomationHelper { + id: automationHelper + } + + // Exit from already running demo + SequentialAnimation { + id: exitFromRunningDemoAnimation + ScriptAction { script: console.log("Exit from running demo") } + PauseAnimation { duration: demoStepDuration } + ScriptAction { script: automationHelper.clickChildObject(demoHeader, "applicationCloseButton") } + PauseAnimation { duration: applicationWaitDuration } + + // Start next demo + ScriptAction { script: switchToSettingScreenAnimation.start() } + } + + // Switch to settings screen + SequentialAnimation { + id: switchToSettingScreenAnimation + ScriptAction { script: console.log("Switch to settings screen") } + PauseAnimation { duration: demoStepDuration } + ScriptAction { script: automationHelper.clickChildObject(launcherHeader, "settingsMenuIcon") } + PauseAnimation { duration: applicationWaitDuration } + + // Start next demo + ScriptAction { script: settingsDemoAnimation.start() } + } + + // Settings screen + SequentialAnimation { + id: settingsDemoAnimation + + function clickSettingsItem(title) { + var i + var settingsList = automationHelper.findChildObject(visibleItem, "settingsList") + var settingsModel = settingsList.model + + // count + get() can be used on ListModel + for (i=0; i<settingsModel.count; i++) { + if (settingsModel.get(i).title === title) { + settingsList.currentIndex = i + automationHelper.click(settingsList.currentItem) + } + } + } + + ScriptAction { script: console.log("Settings demo") } + PauseAnimation { duration: applicationWaitDuration } + + // Make sure the grid layout is on + ScriptAction { script: automationHelper.clickChildObject(visibleItem, "gridLayoutButton") } + PauseAnimation { duration: demoStepDuration } + + // Show some settings pages + ScriptAction { script: settingsDemoAnimation.clickSettingsItem("Network") } + PauseAnimation { duration: demoStepDuration } + ScriptAction { script: settingsDemoAnimation.clickSettingsItem("Date & Time") } + PauseAnimation { duration: demoStepDuration } + ScriptAction { script: settingsDemoAnimation.clickSettingsItem("About Qt") } + PauseAnimation { duration: demoStepDuration } + + // Go back to launcher screen and start next demo + ScriptAction { script: automationHelper.clickChildObject(visibleItem, "settingsBackButton") } + ScriptAction { script: gridViewDemoAnimation.start() } + } + + // Grid view demo + SequentialAnimation { + id: gridViewDemoAnimation + + // Flick the grid up and down + ScriptAction { script: console.log("Grid view demo") } + PauseAnimation { duration: applicationWaitDuration } + ScriptAction { script: flickUpDown("launcherGridView", 0, -verticalFlickVelocity) } + PauseAnimation { duration: demoStepDuration } + ScriptAction { script: flickUpDown("launcherGridView", 0, verticalFlickVelocity) } + + // Start next demo + ScriptAction { script: graphicsEffectsDemoAnimation.start() } + } + + // Graphics effects demo + SequentialAnimation { + id: graphicsEffectsDemoAnimation + + function clickGraphicsEffectItem(title) { + var i + var effectList = automationHelper.findChildObject(visibleItem, "graphicsEffectsList") + var effectListModel = effectList.model + + // count + get() can be used on ListModel + for (i=0; i<effectListModel.count; i++) { + if (effectListModel.get(i).name === title) { + effectList.currentIndex = i + automationHelper.click(effectList.currentItem) + } + } + } + + // Start the demo application + ScriptAction { script: console.log("Graphics effects demo") } + PauseAnimation { duration: demoStepDuration } + ScriptAction { + script: { + // If the application does not exist, move on to next demo + if (!clickApplicationLauncher("launcherGridView", "Graphical Effects")) { + qtChartsDemoAnimation.start() + graphicsEffectsDemoAnimation.stop() + } + } + } + PauseAnimation { duration: applicationWaitDuration } + + // Show few graphics effects + ScriptAction { script: graphicsEffectsDemoAnimation.clickGraphicsEffectItem("Colorize") } + PauseAnimation { duration: demoStepDuration } + ScriptAction { script: graphicsEffectsDemoAnimation.clickGraphicsEffectItem("Gaussian Blur") } + PauseAnimation { duration: demoStepDuration } + ScriptAction { script: graphicsEffectsDemoAnimation.clickGraphicsEffectItem("Wave (custom)") } + PauseAnimation { duration: demoStepDuration } + ScriptAction { script: automationHelper.clickChildObject(demoHeader, "applicationCloseButton") } + + // Start next demo + ScriptAction { script: qtChartsDemoAnimation.start() } + } + + // Qt charts demo + SequentialAnimation { + id: qtChartsDemoAnimation + property var chartsList + + // Start the demo application and get the chart list + ScriptAction { script: console.log("Qt charts demo") } + PauseAnimation { duration: demoStepDuration } + ScriptAction { script: flickUpDown("launcherGridView", 0, -1.5 * verticalFlickVelocity) } + PauseAnimation { duration: demoStepDuration } + ScriptAction { + script: { + // If the application does not exist, move on to next demo + if (!clickApplicationLauncher("launcherGridView", "Qt Charts - Gallery")) { + switchToDetailViewAnimation.start() + qtChartsDemoAnimation.stop() + } + } + } + PauseAnimation { duration: applicationWaitDuration } + ScriptAction { script: qtChartsDemoAnimation.chartsList = automationHelper.findChildObject(visibleItem, "chartsListView") } + + // Flick through some of the charts + ScriptAction { script: qtChartsDemoAnimation.chartsList.currentIndex = 1 } + PauseAnimation { duration: demoStepDuration } + ScriptAction { script: qtChartsDemoAnimation.chartsList.currentIndex = 2 } + PauseAnimation { duration: demoStepDuration } + ScriptAction { script: qtChartsDemoAnimation.chartsList.currentIndex = 3 } + PauseAnimation { duration: demoStepDuration } + ScriptAction { script: qtChartsDemoAnimation.chartsList.currentIndex = 4 } + PauseAnimation { duration: demoStepDuration } + ScriptAction { script: qtChartsDemoAnimation.chartsList.currentIndex = 5 } + PauseAnimation { duration: demoStepDuration } + ScriptAction { script: qtChartsDemoAnimation.chartsList.currentIndex = 6 } + PauseAnimation { duration: demoStepDuration } + ScriptAction { script: qtChartsDemoAnimation.chartsList.currentIndex = 7 } + PauseAnimation { duration: demoStepDuration } + ScriptAction { script: qtChartsDemoAnimation.chartsList.currentIndex = 8 } + PauseAnimation { duration: demoStepDuration } + ScriptAction { script: qtChartsDemoAnimation.chartsList.currentIndex = 9 } + PauseAnimation { duration: demoStepDuration } + ScriptAction { script: automationHelper.clickChildObject(demoHeader, "applicationCloseButton") } + + // Start next demo + ScriptAction { script: switchToDetailViewAnimation.start() } + } + + // Switch to detail view demo + SequentialAnimation { + id: switchToDetailViewAnimation + ScriptAction { script: console.log("Switch to detail view demo") } + PauseAnimation { duration: demoStepDuration } + ScriptAction { script: automationHelper.clickChildObject(launcherHeader, "settingsMenuIcon") } + PauseAnimation { duration: applicationWaitDuration } + ScriptAction { script: automationHelper.clickChildObject(visibleItem, "detailLayoutButton") } + PauseAnimation { duration: demoStepDuration } + ScriptAction { script: automationHelper.clickChildObject(visibleItem, "settingsBackButton") } + + // Start next demo + ScriptAction { script: detailViewDemoAnimation.start() } + } + + // Detail view demo + SequentialAnimation { + id: detailViewDemoAnimation + + // Flick the list left and right + ScriptAction { script: console.log("Detail view demo") } + PauseAnimation { duration: applicationWaitDuration } + ScriptAction { script: flickUpDown("detailListView", -horizontalFlickVelocity, 0) } + PauseAnimation { duration: demoStepDuration } + ScriptAction { script: flickUpDown("detailListView", horizontalFlickVelocity, 0) } + PauseAnimation { duration: demoStepDuration } + ScriptAction { script: clickApplicationLauncher("detailListView", "Media Player") } + PauseAnimation { duration: demoStepDuration } + ScriptAction { script: clickApplicationLauncher("detailListView", "Quick Controls 2") } + + // Start next demo + ScriptAction { script: eBikeViewDemoAnimation.start() } + } + + // E-Bike view demo + SequentialAnimation { + id: eBikeViewDemoAnimation + + // Start the demo application + ScriptAction { script: console.log("E-Bike demo") } + PauseAnimation { duration: demoStepDuration } + ScriptAction { + script: { + // If the application does not exist, move on to next demo + if (!clickApplicationLauncher("detailListView", "E-Bike")) { + startDemos() + eBikeViewDemoAnimation.stop() + } + } + } + PauseAnimation { duration: demoStepDuration } + ScriptAction { script: automationHelper.clickChildObject(visibleItem, "detailStartButton") } + PauseAnimation { duration: applicationWaitDuration } + + // Turn on lights + ScriptAction { script: automationHelper.clickChildObject(visibleItem, "ebikeLightsButton") } + PauseAnimation { duration: demoStepDuration } + + // Go to navigation view and come back + ScriptAction { script: automationHelper.clickChildObject(visibleItem, "ebikeNaviButton") } + PauseAnimation { duration: demoStepDuration } + ScriptAction { script: automationHelper.clickChildObject(visibleItem, "ebikeSpeedView") } + PauseAnimation { duration: demoStepDuration } + + // Go to stats view and come back + ScriptAction { script: automationHelper.clickChildObject(visibleItem, "ebikeStatsButton") } + PauseAnimation { duration: demoStepDuration } + ScriptAction { script: automationHelper.clickChildObject(visibleItem, "ebikeSpeedView") } + PauseAnimation { duration: 5*demoStepDuration } + + // Go back to main view + ScriptAction { script: automationHelper.clickChildObject(demoHeader, "applicationCloseButton") } + + // Start demos again + PauseAnimation { duration: 2 * demoStepDuration } + ScriptAction { script: startDemos() } + } +} diff --git a/qml/DetailView.qml b/qml/DetailView.qml index 899ae7f..cd39e9d 100644 --- a/qml/DetailView.qml +++ b/qml/DetailView.qml @@ -105,6 +105,7 @@ Item { QtButton { id: startButton + objectName: "detailStartButton" height: detailInformation.height * 0.14 width: height * 3 anchors.left: parent.left @@ -129,6 +130,7 @@ Item { ListView { id: thumbList + objectName: "detailListView" anchors.fill: parent anchors.margins: viewSettings.pageMargin * 0.5 orientation: ListView.Horizontal diff --git a/qml/FpsIndicator.qml b/qml/GlobalIndicator.qml index b83cb27..f68cbbd 100644 --- a/qml/FpsIndicator.qml +++ b/qml/GlobalIndicator.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt for Device Creation. @@ -31,25 +31,25 @@ import QtQuick 2.4 Item { id: fps property bool enabled + property alias text: globalIndicatorLabel.text opacity: enabled ? 1 : 0 Behavior on opacity { NumberAnimation { duration: 500 } } anchors.bottom: parent.bottom; anchors.left: parent.left; - width: fpsLabel.width - height: fpsLabel.height + width: globalIndicatorLabel.width + height: globalIndicatorLabel.height Rectangle { color: "black" opacity: 0.5 - anchors.fill: fpsLabel + anchors.fill: globalIndicatorLabel } Text { - id: fpsLabel; + id: globalIndicatorLabel; color: "white" - text: "FPS: " + engine.fps font.pixelSize: engine.sensibleButtonSize() * 0.2 } } diff --git a/qml/Header.qml b/qml/Header.qml index 8283de6..f9cf920 100644 --- a/qml/Header.qml +++ b/qml/Header.qml @@ -38,6 +38,7 @@ Item { signal menuClicked() Image { + objectName: "settingsMenuIcon" anchors.left: parent.left anchors.top: parent.top source: "icons/settingsmenu_launcher_icon.svg" diff --git a/qml/LaunchScreen.qml b/qml/LaunchScreen.qml index 7d369b7..70e9c71 100644 --- a/qml/LaunchScreen.qml +++ b/qml/LaunchScreen.qml @@ -35,6 +35,7 @@ Item { GridView { id: grid + objectName: "launcherGridView" anchors.fill: parent anchors.margins: viewSettings.pageMargin * 0.5 anchors.topMargin: viewSettings.pageMargin diff --git a/qml/LauncherCheckBox.qml b/qml/LauncherCheckBox.qml new file mode 100644 index 0000000..bf81b80 --- /dev/null +++ b/qml/LauncherCheckBox.qml @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Device Creation. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +import QtQuick 2.9 +import QtQuick.Controls 2.2 + +CheckBox { + id: checkBox + text: qsTr("Flip screen") + + indicator: Rectangle { + implicitHeight: 26 + implicitWidth: 26 + height: pluginMain.buttonHeight + width: height + x: checkBox.leftPadding + y: parent.height / 2 - height / 2 + color: "transparent" + border.color: "#9d9faa" + border.width: 2 + radius: 4 + + Image { + anchors.centerIn: parent + sourceSize.width: parent.width + sourceSize.height: parent.height + width: parent.width * 0.9 + height: width + source: "icons/checkmark.svg" + visible: checkBox.checked + antialiasing: true + smooth: true + fillMode: Image.PreserveAspectFit + } + } + + contentItem: Text { + text: checkBox.text + font.family: appFont + font.pixelSize: pluginMain.subTitleFontSize + opacity: enabled ? 1.0 : 0.3 + color: checkBox.down ? "#17a81a" : "#41cd52" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + leftPadding: checkBox.indicator.width + checkBox.spacing + height: pluginMain.fieldTextHeight + font.styleName: checkBox.checked ? "Bold" : "Regular" + } +} diff --git a/qml/LayoutSettings.qml b/qml/LayoutSettings.qml index 8518030..4e4d08b 100644 --- a/qml/LayoutSettings.qml +++ b/qml/LayoutSettings.qml @@ -67,6 +67,7 @@ Item { spacing: root.margin ImageTextDelegate { + objectName: "gridLayoutButton" height: root.buttonSize width: height onClicked: root.gridSelected = true @@ -77,6 +78,7 @@ Item { } ImageTextDelegate { + objectName: "detailLayoutButton" height: root.buttonSize width: height onClicked: root.gridSelected = false @@ -124,54 +126,30 @@ Item { } } } - CheckBox { - id: checkBox + + LauncherCheckBox { + id: flipScreenCheckBox text: qsTr("Flip screen") checked: globalSettings.rotationSelected anchors.top: column.bottom anchors.left: parent.left anchors.topMargin: root.margin - indicator: Rectangle { - implicitHeight: 26 - implicitWidth: 26 - height: pluginMain.buttonHeight - width: height - x: checkBox.leftPadding - y: parent.height / 2 - height / 2 - color: "transparent" - border.color: "#9d9faa" - border.width: 2 - radius: 4 - - Image { - anchors.centerIn: parent - sourceSize.width: parent.width - sourceSize.height: parent.height - width: parent.width * 0.9 - height: width - source: "icons/checkmark.svg" - visible: checkBox.checked - antialiasing: true - smooth: true - fillMode: Image.PreserveAspectFit - } + onCheckedChanged: { + globalSettings.rotationSelected = checked } + } + + LauncherCheckBox { + id: demoModeCheckBox + text: qsTr("Demo mode") + checked: globalSettings.demoModeSelected + anchors.top: column.bottom + anchors.left: flipScreenCheckBox.right + anchors.topMargin: root.margin - contentItem: Text { - text: checkBox.text - font.family: appFont - font.pixelSize: pluginMain.subTitleFontSize - opacity: enabled ? 1.0 : 0.3 - color: checkBox.down ? "#17a81a" : "#41cd52" - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - leftPadding: checkBox.indicator.width + checkBox.spacing - height: pluginMain.fieldTextHeight - font.styleName: checkBox.checked ? "Bold" : "Regular" - } onCheckedChanged: { - globalSettings.rotationSelected = checked + globalSettings.demoModeSelected = checked } } } diff --git a/qml/MainWindow.qml b/qml/MainWindow.qml index 0249773..95c005d 100644 --- a/qml/MainWindow.qml +++ b/qml/MainWindow.qml @@ -45,6 +45,7 @@ Item { Component { id: gridComponent LaunchScreen { + objectName: "launchScreen" id: launchScreen } } @@ -52,6 +53,7 @@ Item { Component { id: detailComponent DetailView { + objectName: "detailView" id: detailView } } @@ -319,8 +321,44 @@ Item { } } - FpsIndicator { + GlobalIndicator { + id: fps enabled: engine.fpsEnabled + text: "FPS: " + engine.fps } + + GlobalIndicator { + id: demoModeIndicator + enabled: demoMode.demoIsRunning + text: qsTr("DEMO MODE - Tap screen to use") + anchors.bottom: fps.enabled ? fps.top : parent.bottom + } + } + + DemoMode { + id: demoMode + demoHeader: demoHeader + launcherHeader: header + visibleItem: (applicationLoader.item && (applicationLoader.item.objectName !== "empty")) ? + applicationLoader.item : contentLoader.item + } + + // MouseArea for capturing mouse clicks/presses + MouseArea { + anchors.fill: parent + propagateComposedEvents: true + enabled: demoMode.demoIsRunning + + // Press or click + function pressedOrClicked(mouse) { + mouse.accepted = false + if (mouse.source === Qt.MouseEventSynthesizedByApplication) + return + demoMode.stopDemos() + mouse.accepted = true + } + + onClicked: pressedOrClicked(mouse) + onPressed: pressedOrClicked(mouse) } } diff --git a/src/automationhelper.cpp b/src/automationhelper.cpp new file mode 100644 index 0000000..b4c6a99 --- /dev/null +++ b/src/automationhelper.cpp @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Device Creation. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "automationhelper.h" +#include <QCoreApplication> +#include <QApplication> +#include <QQuickWindow> + +AutomationHelper::AutomationHelper(QObject* parent) : + QObject(parent) +{ +} + +/*! + * \brief Click center of given QQuickItem + * \param item Item to click + */ +void AutomationHelper::click(QQuickItem* item) +{ + QQuickWindow* window = item->window(); + if (!window) { + qWarning()<<"No window for item "<<item; + return; + } + + int centerX = static_cast<int>(item->width()/2); + int centerY = static_cast<int>(item->height()/2); + QPointF globalCoordinates = item->mapToGlobal(QPoint(centerX, centerY)); + QPointF windowCoordinates = window->mapFromGlobal(globalCoordinates.toPoint()); + + QMouseEvent pressEvent(QEvent::MouseButtonPress, windowCoordinates, windowCoordinates, windowCoordinates, + Qt::MouseButton::LeftButton, Qt::NoButton, Qt::NoModifier, Qt::MouseEventSynthesizedByApplication); + QMouseEvent releaseEvent(QEvent::MouseButtonRelease, windowCoordinates, windowCoordinates, windowCoordinates, + Qt::MouseButton::LeftButton, Qt::NoButton, Qt::NoModifier, Qt::MouseEventSynthesizedByApplication); + QApplication::instance()->sendEvent(window, &pressEvent); + QApplication::instance()->sendEvent(window, &releaseEvent); +} + +/*! + * \brief Click center of child item of given QQuickItem + * \param item Item which child to click + * \param childObjectName Object name of the child to click + */ +void AutomationHelper::clickChildObject(QQuickItem* item, QString childObjectName) +{ + QQuickItem* obj = findChildObject(item, childObjectName); + if (!obj) { + qWarning()<<"No such child "<<childObjectName<<" for "<<item; + return; + } + + click(obj); +} + +/*! + * \brief Find child item of given QQuickItem + * + * This function is needed for exposing findChildObject to QML + * \param item Item which child to find + * \param childObjectName Object name of the child to find + * \return found child + */ +QQuickItem* AutomationHelper::findChildObject(QQuickItem* item, QString childObjectName) +{ + return item->findChild<QQuickItem*>(childObjectName); +} diff --git a/src/automationhelper.h b/src/automationhelper.h new file mode 100644 index 0000000..8ed5000 --- /dev/null +++ b/src/automationhelper.h @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Device Creation. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef AUTOMATIONHELPER_H +#define AUTOMATIONHELPER_H + +#include <QObject> +#include <QQuickItem> + +class AutomationHelper : public QObject +{ + Q_OBJECT +public: + AutomationHelper(QObject *parent = 0); + +public slots: + void click(QQuickItem* item); + void clickChildObject(QQuickItem* item, QString childObjectName); + QQuickItem* findChildObject(QQuickItem* item, QString childObjectName); +}; + +#endif // AUTOMATIONHELPER_H diff --git a/src/main.cpp b/src/main.cpp index 4c41ca6..792351f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -51,6 +51,7 @@ #include "settingsmanager.h" #include "imageproviders.h" #include "circularindicator.h" +#include "automationhelper.h" void displayHelp(const char *appName) { @@ -121,6 +122,7 @@ int main(int argc, char **argv) qmlRegisterType<ApplicationsModel>("com.qtcompany.B2QtLauncher", 1, 0, "LauncherApplicationsModel"); qmlRegisterType<Engine>("com.qtcompany.B2QtLauncher", 1, 0, "LauncherEngine"); qmlRegisterType<CircularIndicator>("Circle", 1, 0, "CircularIndicator"); + qmlRegisterType<AutomationHelper>("AutomationHelper", 1, 0, "AutomationHelper"); QQmlApplicationEngine engine; SettingsManager settings; diff --git a/src/settingsmanager.cpp b/src/settingsmanager.cpp index 55e5def..e8dfc77 100644 --- a/src/settingsmanager.cpp +++ b/src/settingsmanager.cpp @@ -91,3 +91,16 @@ void SettingsManager::setRotationSelected(bool enabled) setValue("rotationSelected", enabled); emit rotationSelectedChanged(enabled); } + +bool SettingsManager::demoModeSelected() +{ + return getValue("demoModeSelected", false).toBool(); +} + +void SettingsManager::setDemoModeSelected(bool enabled) +{ + if (demoModeSelected() == enabled) + return; + setValue("demoModeSelected", enabled); + emit demoModeSelectedChanged(enabled); +} diff --git a/src/settingsmanager.h b/src/settingsmanager.h index cc41a0a..50a8900 100644 --- a/src/settingsmanager.h +++ b/src/settingsmanager.h @@ -36,7 +36,7 @@ class SettingsManager : public QObject { Q_OBJECT public: - explicit SettingsManager(QObject *parent = 0); + explicit SettingsManager(QObject *parent = nullptr); ~SettingsManager(); Q_INVOKABLE QVariant getValue(const QString& key, const QVariant &defaultValue); @@ -53,14 +53,18 @@ public: void setMouseSelected(bool enabled); Q_PROPERTY (bool rotationSelected READ rotationSelected WRITE setRotationSelected NOTIFY rotationSelectedChanged) + Q_PROPERTY (bool demoModeSelected READ demoModeSelected WRITE setDemoModeSelected NOTIFY demoModeSelectedChanged) bool rotationSelected(); void setRotationSelected(bool enabled); + bool demoModeSelected(); + void setDemoModeSelected(bool enabled); signals: void gridSelectedChanged(bool enabled); void mouseSelectedChanged(bool enabled); void rotationSelectedChanged(bool enabled); + void demoModeSelectedChanged(bool enabled); private: QSettings m_settings; diff --git a/startup.pro b/startup.pro index 495271c..2aa5599 100644 --- a/startup.pro +++ b/startup.pro @@ -15,7 +15,8 @@ HEADERS += \ src/applicationsettings.h \ src/settingsmanager.h \ src/imageproviders.h \ - src/circularindicator.h + src/circularindicator.h \ + src/automationhelper.h SOURCES += src/main.cpp \ src/engine.cpp \ @@ -24,7 +25,8 @@ SOURCES += src/main.cpp \ src/applicationsettings.cpp \ src/settingsmanager.cpp \ src/imageproviders.cpp \ - src/circularindicator.cpp + src/circularindicator.cpp \ + src/automationhelper.cpp target.path = $$[INSTALL_ROOT]/usr/bin |