1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include <qtest.h>
30#include <QtQml/qqmlcomponent.h>
31#include <QtQml/qqmlengine.h>
32#include <QtQuick/qquickitem.h>
33#include <QtQuick/qquickview.h>
34#include <QtGui/qinputmethod.h>
35#include <QtGui/qstylehints.h>
36#include <qpa/qwindowsysteminterface.h>
37#include <qpa/qplatformintegration.h>
38#include <private/qguiapplication_p.h>
39#include "../../shared/util.h"
40
41class tst_qquickapplication : public QQmlDataTest
42{
43 Q_OBJECT
44public:
45 tst_qquickapplication();
46
47private slots:
48 void active();
49 void state();
50 void layoutDirection();
51 void font();
52 void inputMethod();
53 void styleHints();
54 void cleanup();
55 void displayName();
56 void platformName();
57
58private:
59 QQmlEngine engine;
60};
61
62tst_qquickapplication::tst_qquickapplication()
63{
64}
65
66void tst_qquickapplication::cleanup()
67{
68 if (QGuiApplicationPrivate::platformIntegration()->hasCapability(cap: QPlatformIntegration::ApplicationState)) {
69 QWindowSystemInterface::handleApplicationStateChanged(newState: Qt::ApplicationInactive);
70 QCoreApplication::processEvents();
71 }
72}
73
74void tst_qquickapplication::active()
75{
76 QQmlComponent component(&engine);
77 component.setData("import QtQuick 2.0; "
78 "Item { "
79 " property bool active: Qt.application.active; "
80 " property bool active2: false; "
81 " Connections { "
82 " target: Qt.application; "
83 " onActiveChanged: active2 = Qt.application.active; "
84 " } "
85 "}", baseUrl: QUrl::fromLocalFile(localfile: ""));
86 QQuickItem *item = qobject_cast<QQuickItem *>(object: component.create());
87 QVERIFY(item);
88 QQuickWindow window;
89 item->setParentItem(window.contentItem());
90
91 // If the platform plugin has the ApplicationState capability, app activation originate from it
92 // as a result of a system event. We therefore have to simulate these events here.
93 if (QGuiApplicationPrivate::platformIntegration()->hasCapability(cap: QPlatformIntegration::ApplicationState)) {
94
95 // Flush pending events, in case the platform have already queued real application state events
96 QWindowSystemInterface::flushWindowSystemEvents();
97
98 QWindowSystemInterface::handleApplicationStateChanged(newState: Qt::ApplicationActive);
99 QWindowSystemInterface::flushWindowSystemEvents();
100 QVERIFY(item->property("active").toBool());
101 QVERIFY(item->property("active2").toBool());
102
103 QWindowSystemInterface::handleApplicationStateChanged(newState: Qt::ApplicationInactive);
104 QWindowSystemInterface::flushWindowSystemEvents();
105 QVERIFY(!item->property("active").toBool());
106 QVERIFY(!item->property("active2").toBool());
107 } else {
108 // Otherwise, app activation is triggered by window activation.
109 window.show();
110 window.requestActivate();
111 QVERIFY(QTest::qWaitForWindowActive(&window));
112 QCOMPARE(QGuiApplication::focusWindow(), &window);
113 QVERIFY(item->property("active").toBool());
114 QVERIFY(item->property("active2").toBool());
115
116 // not active again
117 QWindowSystemInterface::handleWindowActivated(window: nullptr);
118 QTRY_VERIFY(QGuiApplication::focusWindow() != &window);
119 QVERIFY(!item->property("active").toBool());
120 QVERIFY(!item->property("active2").toBool());
121 }
122}
123
124void tst_qquickapplication::state()
125{
126 QQmlComponent component(&engine);
127 component.setData("import QtQuick 2.0; "
128 "Item { "
129 " property int state: Qt.application.state; "
130 " property int state2: Qt.ApplicationInactive; "
131 " Connections { "
132 " target: Qt.application; "
133 " onStateChanged: state2 = Qt.application.state; "
134 " } "
135 " Component.onCompleted: state2 = Qt.application.state; "
136 "}", baseUrl: QUrl::fromLocalFile(localfile: ""));
137 QQuickItem *item = qobject_cast<QQuickItem *>(object: component.create());
138 QVERIFY(item);
139 QQuickWindow window;
140 item->setParentItem(window.contentItem());
141
142 // If the platform plugin has the ApplicationState capability, state changes originate from it
143 // as a result of a system event. We therefore have to simulate these events here.
144 if (QGuiApplicationPrivate::platformIntegration()->hasCapability(cap: QPlatformIntegration::ApplicationState)) {
145
146 // Flush pending events, in case the platform have already queued real application state events
147 QWindowSystemInterface::flushWindowSystemEvents();
148
149 QWindowSystemInterface::handleApplicationStateChanged(newState: Qt::ApplicationActive);
150 QWindowSystemInterface::flushWindowSystemEvents();
151 QCOMPARE(Qt::ApplicationState(item->property("state").toInt()), Qt::ApplicationActive);
152 QCOMPARE(Qt::ApplicationState(item->property("state2").toInt()), Qt::ApplicationActive);
153
154 QWindowSystemInterface::handleApplicationStateChanged(newState: Qt::ApplicationInactive);
155 QWindowSystemInterface::flushWindowSystemEvents();
156 QCOMPARE(Qt::ApplicationState(item->property("state").toInt()), Qt::ApplicationInactive);
157 QCOMPARE(Qt::ApplicationState(item->property("state2").toInt()), Qt::ApplicationInactive);
158
159 QWindowSystemInterface::handleApplicationStateChanged(newState: Qt::ApplicationSuspended);
160 QWindowSystemInterface::flushWindowSystemEvents();
161 QCOMPARE(Qt::ApplicationState(item->property("state").toInt()), Qt::ApplicationSuspended);
162 QCOMPARE(Qt::ApplicationState(item->property("state2").toInt()), Qt::ApplicationSuspended);
163
164 QWindowSystemInterface::handleApplicationStateChanged(newState: Qt::ApplicationHidden);
165 QWindowSystemInterface::flushWindowSystemEvents();
166 QCOMPARE(Qt::ApplicationState(item->property("state").toInt()), Qt::ApplicationHidden);
167 QCOMPARE(Qt::ApplicationState(item->property("state2").toInt()), Qt::ApplicationHidden);
168
169 } else {
170 // Otherwise, the application can only be in two states, Active and Inactive. These are
171 // triggered by window activation.
172 window.show();
173 window.requestActivate();
174 QVERIFY(QTest::qWaitForWindowActive(&window));
175 QCOMPARE(QGuiApplication::focusWindow(), &window);
176 QCOMPARE(Qt::ApplicationState(item->property("state").toInt()), Qt::ApplicationActive);
177 QCOMPARE(Qt::ApplicationState(item->property("state2").toInt()), Qt::ApplicationActive);
178
179 // not active again
180 QWindowSystemInterface::handleWindowActivated(window: nullptr);
181 QTRY_VERIFY(QGuiApplication::focusWindow() != &window);
182 QCOMPARE(Qt::ApplicationState(item->property("state").toInt()), Qt::ApplicationInactive);
183 QCOMPARE(Qt::ApplicationState(item->property("state2").toInt()), Qt::ApplicationInactive);
184 }
185}
186
187void tst_qquickapplication::layoutDirection()
188{
189
190 QQmlComponent component(&engine);
191 component.setData("import QtQuick 2.0; Item { property bool layoutDirection: Qt.application.layoutDirection }", baseUrl: QUrl::fromLocalFile(localfile: ""));
192 QQuickItem *item = qobject_cast<QQuickItem *>(object: component.create());
193 QVERIFY(item);
194 QQuickView view;
195 item->setParentItem(view.rootObject());
196
197 // not mirrored
198 QCOMPARE(Qt::LayoutDirection(item->property("layoutDirection").toInt()), Qt::LeftToRight);
199
200 // mirrored
201 QGuiApplication::setLayoutDirection(Qt::RightToLeft);
202 QCOMPARE(Qt::LayoutDirection(item->property("layoutDirection").toInt()), Qt::RightToLeft);
203
204 // not mirrored again
205 QGuiApplication::setLayoutDirection(Qt::LeftToRight);
206 QCOMPARE(Qt::LayoutDirection(item->property("layoutDirection").toInt()), Qt::LeftToRight);
207}
208
209void tst_qquickapplication::font()
210{
211 QQmlComponent component(&engine);
212 component.setData("import QtQuick 2.0; Item { property font defaultFont: Qt.application.font }", baseUrl: QUrl::fromLocalFile(localfile: ""));
213 QQuickItem *item = qobject_cast<QQuickItem *>(object: component.create());
214 QVERIFY(item);
215 QQuickView view;
216 item->setParentItem(view.rootObject());
217
218 QVariant defaultFontProperty = item->property(name: "defaultFont");
219 QVERIFY(defaultFontProperty.isValid());
220 QCOMPARE(defaultFontProperty.type(), QVariant::Font);
221 QCOMPARE(defaultFontProperty.value<QFont>(), qApp->font());
222}
223
224void tst_qquickapplication::inputMethod()
225{
226 // technically not in QQuickApplication, but testing anyway here
227 QQmlComponent component(&engine);
228 component.setData("import QtQuick 2.0; Item { property variant inputMethod: Qt.inputMethod }", baseUrl: QUrl::fromLocalFile(localfile: ""));
229 QQuickItem *item = qobject_cast<QQuickItem *>(object: component.create());
230 QVERIFY(item);
231 QQuickView view;
232 item->setParentItem(view.rootObject());
233
234 // check that the inputMethod property maches with application's input method
235 QCOMPARE(qvariant_cast<QObject*>(item->property("inputMethod")), qApp->inputMethod());
236}
237
238void tst_qquickapplication::styleHints()
239{
240 // technically not in QQuickApplication, but testing anyway here
241 QQmlComponent component(&engine);
242 component.setData("import QtQuick 2.0; Item { property variant styleHints: Qt.styleHints }", baseUrl: QUrl::fromLocalFile(localfile: ""));
243 QQuickItem *item = qobject_cast<QQuickItem *>(object: component.create());
244 QVERIFY(item);
245 QQuickView view;
246 item->setParentItem(view.rootObject());
247
248 QCOMPARE(qvariant_cast<QObject*>(item->property("styleHints")), qApp->styleHints());
249}
250
251void tst_qquickapplication::displayName()
252{
253 QString name[3] = { QStringLiteral("APP NAME 0"),
254 QStringLiteral("APP NAME 1"),
255 QStringLiteral("APP NAME 2")
256 };
257
258 QQmlComponent component(&engine, testFileUrl(fileName: "tst_displayname.qml"));
259 QQuickItem *item = qobject_cast<QQuickItem *>(object: component.create());
260 QVERIFY(item);
261 QQuickView view;
262 item->setParentItem(view.rootObject());
263
264 QCoreApplication::setApplicationName(name[0]);
265 QCOMPARE(qvariant_cast<QString>(item->property("displayName")), name[0]);
266
267 QGuiApplication::setApplicationName(name[1]);
268 QCOMPARE(qvariant_cast<QString>(item->property("displayName")), name[1]);
269
270 QMetaObject::invokeMethod(obj: item, member: "updateDisplayName", Q_ARG(QVariant, QVariant(name[2])));
271 QCOMPARE(QGuiApplication::applicationDisplayName(), name[2]);
272}
273
274void tst_qquickapplication::platformName()
275{
276 // Set up QML component
277 QQmlComponent component(&engine, testFileUrl(fileName: "tst_platformname.qml"));
278 QQuickItem *item = qobject_cast<QQuickItem *>(object: component.create());
279 QVERIFY(item);
280 QQuickView view;
281 item->setParentItem(view.rootObject());
282
283 // Get native platform name
284 QString guiApplicationPlatformName = QGuiApplication::platformName();
285 QVERIFY(!guiApplicationPlatformName.isEmpty());
286
287 // Get platform name from QML component and verify it's same
288 QString qmlPlatformName = qvariant_cast<QString>(v: item->property(name: "platformName"));
289 QCOMPARE(qmlPlatformName, guiApplicationPlatformName);
290}
291
292QTEST_MAIN(tst_qquickapplication)
293
294#include "tst_qquickapplication.moc"
295

source code of qtdeclarative/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp