1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#ifndef QQUICKVISUALTESTUTILS_P_H
5#define QQUICKVISUALTESTUTILS_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtQml/qqmlexpression.h>
19#include <QtQuick/private/qquickitem_p.h>
20
21#include <private/qmlutils_p.h>
22
23QT_BEGIN_NAMESPACE
24
25class QQuickItemView;
26class QQuickWindow;
27
28namespace QQuickVisualTestUtils
29{
30 QQuickItem *findVisibleChild(QQuickItem *parent, const QString &objectName);
31
32 void dumpTree(QQuickItem *parent, int depth = 0);
33
34 void moveMouseAway(QQuickWindow *window);
35 void centerOnScreen(QQuickWindow *window);
36
37 template<typename F>
38 void forEachStep(int steps, F &&func)
39 {
40 for (int i = 0; i < steps; ++i) {
41 const qreal progress = qreal(i) / steps;
42 func(progress);
43 }
44 }
45
46 [[nodiscard]] QPoint lerpPoints(const QPoint &point1, const QPoint &point2, qreal t);
47
48 class [[nodiscard]] PointLerper
49 {
50 public:
51 PointLerper(QQuickWindow *window,
52 const QPointingDevice *pointingDevice = QPointingDevice::primaryPointingDevice());
53
54 void move(const QPoint &pos, int steps = 10, int delayInMilliseconds = 1);
55 void move(int x, int y, int steps = 10, int delayInMilliseconds = 1);
56
57 private:
58 QQuickWindow *mWindow = nullptr;
59 const QPointingDevice *mPointingDevice = nullptr;
60 QPoint mFrom;
61 };
62
63 [[nodiscard]] bool delegateVisible(QQuickItem *item);
64
65 /*
66 Find an item with the specified objectName. If index is supplied then the
67 item must also evaluate the {index} expression equal to index
68 */
69 template<typename T>
70 T *findItem(QQuickItem *parent, const QString &objectName, int index = -1)
71 {
72 using namespace Qt::StringLiterals;
73
74 const QMetaObject &mo = T::staticMetaObject;
75 for (int i = 0; i < parent->childItems().size(); ++i) {
76 QQuickItem *item = qobject_cast<QQuickItem*>(o: parent->childItems().at(i));
77 if (!item)
78 continue;
79 if (mo.cast(obj: item) && (objectName.isEmpty() || item->objectName() == objectName)) {
80 if (index != -1) {
81 QQmlContext *context = qmlContext(item);
82 if (!context->isValid())
83 continue;
84 QQmlExpression e(context, item, u"index"_s);
85 if (e.evaluate().toInt() == index)
86 return static_cast<T*>(item);
87 } else {
88 return static_cast<T*>(item);
89 }
90 }
91 item = findItem<T>(item, objectName, index);
92 if (item)
93 return static_cast<T*>(item);
94 }
95
96 return 0;
97 }
98
99 template<typename T>
100 QList<T*> findItems(QQuickItem *parent, const QString &objectName, bool visibleOnly = true)
101 {
102 QList<T*> items;
103 const QMetaObject &mo = T::staticMetaObject;
104 for (int i = 0; i < parent->childItems().size(); ++i) {
105 QQuickItem *item = qobject_cast<QQuickItem*>(o: parent->childItems().at(i));
106 if (!item || (visibleOnly && (!item->isVisible() || QQuickItemPrivate::get(item)->culled)))
107 continue;
108 if (mo.cast(obj: item) && (objectName.isEmpty() || item->objectName() == objectName))
109 items.append(static_cast<T*>(item));
110 items += findItems<T>(item, objectName);
111 }
112
113 return items;
114 }
115
116 template<typename T>
117 QList<T*> findItems(QQuickItem *parent, const QString &objectName, const QList<int> &indexes)
118 {
119 QList<T*> items;
120 for (int i=0; i<indexes.size(); i++)
121 items << qobject_cast<QQuickItem*>(findItem<T>(parent, objectName, indexes[i]));
122 return items;
123 }
124
125 bool compareImages(const QImage &ia, const QImage &ib, QString *errorMessage);
126
127 struct SignalMultiSpy : public QObject
128 {
129 Q_OBJECT
130 public:
131 QList<QObject *> senders;
132 QList<QByteArray> signalNames;
133
134 template <typename Func1>
135 QMetaObject::Connection connectToSignal(const typename QtPrivate::FunctionPointer<Func1>::Object *obj, Func1 signal,
136 Qt::ConnectionType type = Qt::AutoConnection)
137 {
138 return connect(obj, signal, this, &SignalMultiSpy::receive, type);
139 }
140
141 void clear() {
142 senders.clear();
143 signalNames.clear();
144 }
145
146 public Q_SLOTS:
147 void receive() {
148 QMetaMethod m = sender()->metaObject()->method(index: senderSignalIndex());
149 senders << sender();
150 signalNames << m.name();
151 }
152 };
153
154 enum class FindViewDelegateItemFlag {
155 None = 0x0,
156 PositionViewAtIndex = 0x01
157 };
158 Q_DECLARE_FLAGS(FindViewDelegateItemFlags, FindViewDelegateItemFlag)
159
160#if QT_CONFIG(quick_itemview)
161 QQuickItem* findViewDelegateItem(QQuickItemView *itemView, int index,
162 FindViewDelegateItemFlags flags = FindViewDelegateItemFlag::PositionViewAtIndex);
163#endif
164
165 /*!
166 \internal
167
168 Same as above except allows use in QTRY_* functions without having to call it again
169 afterwards to assign the delegate.
170 */
171 template<typename T>
172 [[nodiscard]] bool findViewDelegateItem(QQuickItemView *itemView, int index, T &delegateItem,
173 FindViewDelegateItemFlags flags = FindViewDelegateItemFlag::PositionViewAtIndex)
174 {
175 delegateItem = qobject_cast<T>(findViewDelegateItem(itemView, index, flags));
176 return delegateItem != nullptr;
177 }
178
179 class QQuickApplicationHelper
180 {
181 public:
182 QQuickApplicationHelper(QQmlDataTest *testCase, const QString &testFilePath,
183 const QVariantMap &initialProperties = {},
184 const QStringList &qmlImportPaths = {});
185
186 // Return a C-style string instead of QString because that's what QTest uses for error messages,
187 // so it saves code at the calling site.
188 inline const char *failureMessage() const
189 {
190 return errorMessage.constData();
191 }
192
193 QQmlEngine engine;
194 QScopedPointer<QObject> cleanup;
195 QQuickWindow *window = nullptr;
196
197 bool ready = false;
198 // Store as a byte array so that we can return its raw data safely;
199 // using qPrintable() in failureMessage() will construct a throwaway QByteArray
200 // that is destroyed before the function returns.
201 QByteArray errorMessage;
202 };
203
204 class MnemonicKeySimulator
205 {
206 Q_DISABLE_COPY(MnemonicKeySimulator)
207 public:
208 explicit MnemonicKeySimulator(QWindow *window);
209
210 void press(Qt::Key key);
211 void release(Qt::Key key);
212 void click(Qt::Key key);
213
214 private:
215 QPointer<QWindow> m_window;
216 Qt::KeyboardModifiers m_modifiers;
217 };
218
219 QPoint mapCenterToWindow(const QQuickItem *item);
220 QPoint mapToWindow(const QQuickItem *item, qreal relativeX, qreal relativeY);
221 QPoint mapToWindow(const QQuickItem *item, const QPointF &relativePos);
222}
223
224#define QQUICK_VERIFY_POLISH(item) \
225 QTRY_COMPARE(QQuickItemPrivate::get(item)->polishScheduled, false)
226
227QT_END_NAMESPACE
228
229#endif // QQUICKVISUALTESTUTILS_P_H
230

source code of qtdeclarative/src/quicktestutils/quick/visualtestutils_p.h