diff options
Diffstat (limited to 'tests/auto/quickcontrols2/shared/visualtestutil.h')
-rw-r--r-- | tests/auto/quickcontrols2/shared/visualtestutil.h | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/tests/auto/quickcontrols2/shared/visualtestutil.h b/tests/auto/quickcontrols2/shared/visualtestutil.h new file mode 100644 index 0000000000..142aefd209 --- /dev/null +++ b/tests/auto/quickcontrols2/shared/visualtestutil.h @@ -0,0 +1,252 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKVISUALTESTUTIL_H +#define QQUICKVISUALTESTUTIL_H + +#include <functional> + +#include <QtCore/QPointer> +#include <QtQuick/QQuickItem> +#include <QtQml/QQmlExpression> +#include <QtQuick/private/qquickitem_p.h> +#include <QtQuick/private/qquickitemview_p.h> +#include <QtQuickTest/quicktest.h> +#include <QtQuickControls2/qquickstyle.h> +#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h> +#include <QtQuickTemplates2/private/qquickabstractbutton_p.h> + +#include "util.h" + +namespace QQuickVisualTestUtil +{ + QQuickItem *findVisibleChild(QQuickItem *parent, const QString &objectName); + + void dumpTree(QQuickItem *parent, int depth = 0); + + bool delegateVisible(QQuickItem *item); + + void centerOnScreen(QQuickWindow *window); + + void moveMouseAway(QQuickWindow *window); + + /* + Find an item with the specified objectName. If index is supplied then the + item must also evaluate the {index} expression equal to index + */ + template<typename T> + T *findItem(QQuickItem *parent, const QString &objectName, int index = -1) + { + const QMetaObject &mo = T::staticMetaObject; + for (int i = 0; i < parent->childItems().count(); ++i) { + QQuickItem *item = qobject_cast<QQuickItem*>(parent->childItems().at(i)); + if (!item) + continue; + if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) { + if (index != -1) { + QQmlExpression e(qmlContext(item), item, "index"); + if (e.evaluate().toInt() == index) + return static_cast<T*>(item); + } else { + return static_cast<T*>(item); + } + } + item = findItem<T>(item, objectName, index); + if (item) + return static_cast<T*>(item); + } + + return 0; + } + + template<typename T> + QList<T*> findItems(QQuickItem *parent, const QString &objectName, bool visibleOnly = true) + { + QList<T*> items; + const QMetaObject &mo = T::staticMetaObject; + for (int i = 0; i < parent->childItems().count(); ++i) { + QQuickItem *item = qobject_cast<QQuickItem*>(parent->childItems().at(i)); + if (!item || (visibleOnly && (!item->isVisible() || QQuickItemPrivate::get(item)->culled))) + continue; + if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) + items.append(static_cast<T*>(item)); + items += findItems<T>(item, objectName); + } + + return items; + } + + template<typename T> + QList<T*> findItems(QQuickItem *parent, const QString &objectName, const QList<int> &indexes) + { + QList<T*> items; + for (int i=0; i<indexes.count(); i++) + items << qobject_cast<QQuickItem*>(findItem<T>(parent, objectName, indexes[i])); + return items; + } + + enum class FindViewDelegateItemFlag { + None = 0x0, + PositionViewAtIndex = 0x01 + }; + Q_DECLARE_FLAGS(FindViewDelegateItemFlags, FindViewDelegateItemFlag) + + QQuickItem* findViewDelegateItem(QQuickItemView *itemView, int index, + FindViewDelegateItemFlags flags = FindViewDelegateItemFlag::PositionViewAtIndex); + + /*! + \internal + + Same as above except allows use in QTRY_* functions without having to call it again + afterwards to assign the delegate. + */ + template<typename T> + bool findViewDelegateItem(QQuickItemView *itemView, int index, T &delegateItem, + FindViewDelegateItemFlags flags = FindViewDelegateItemFlag::PositionViewAtIndex) + { + delegateItem = qobject_cast<T>(findViewDelegateItem(itemView, index, flags)); + return delegateItem != nullptr; + } + + class QQuickApplicationHelper + { + public: + QQuickApplicationHelper(QQmlDataTest *testCase, const QString &testFilePath, + const QStringList &qmlImportPaths = {}, + const QVariantMap &initialProperties = {}) + { + for (const auto &path : qmlImportPaths) + engine.addImportPath(path); + + QQmlComponent component(&engine); + + component.loadUrl(testCase->testFileUrl(testFilePath)); + QVERIFY2(component.isReady(), qPrintable(component.errorString())); + QObject *rootObject = component.createWithInitialProperties(initialProperties); + cleanup.reset(rootObject); + if (component.isError() || !rootObject) { + errorMessage = QString::fromUtf8("Failed to create window: %1").arg(component.errorString()).toUtf8(); + return; + } + + window = qobject_cast<QQuickWindow*>(rootObject); + appWindow = qobject_cast<QQuickApplicationWindow*>(rootObject); + if (!window) { + errorMessage = QString::fromUtf8("Root object %1 must be a QQuickWindow subclass").arg(QDebug::toString(window)).toUtf8(); + return; + } + + if (window->isVisible()) { + errorMessage = QString::fromUtf8("Expected window not to be visible, but it is").toUtf8(); + return; + } + + ready = true; + } + + // Return a C-style string instead of QString because that's what QTest uses for error messages, + // so it saves code at the calling site. + inline const char *failureMessage() const + { + return errorMessage.constData(); + } + + QQmlEngine engine; + QScopedPointer<QObject> cleanup; + QQuickApplicationWindow *appWindow = nullptr; + QQuickWindow *window = nullptr; + + bool ready = false; + // Store as a byte array so that we can return its raw data safely; + // using qPrintable() in failureMessage() will construct a throwaway QByteArray + // that is destroyed before the function returns. + QByteArray errorMessage; + }; + + struct QQuickStyleHelper + { + bool updateStyle(const QString &style) + { + // If it's not the first time a style has been set and the new style is not different, do nothing. + if (!currentStyle.isEmpty() && style == currentStyle) + return false; + + engine.reset(); + currentStyle = style; + qmlClearTypeRegistrations(); + engine.reset(new QQmlEngine); + QQuickStyle::setStyle(style); + + QQmlComponent component(engine.data()); + component.setData(QString("import QtQuick\nimport QtQuick.Controls\n Control { }").toUtf8(), QUrl()); + + return true; + } + + QString currentStyle; + QScopedPointer<QQmlEngine> engine; + }; + + typedef std::function<void(const QString &/*relativePath*/, const QUrl &/*absoluteUrl*/)> ForEachCallback; + + void forEachControl(QQmlEngine *engine, const QString &sourcePath, const QString &targetPath, const QStringList &skipList, ForEachCallback callback); + void addTestRowForEachControl(QQmlEngine *engine, const QString &sourcePath, const QString &targetPath, const QStringList &skipList = QStringList()); + + // Helper to simulate Alt itself and Alt+<key> events. + class MnemonicKeySimulator + { + Q_DISABLE_COPY(MnemonicKeySimulator) + public: + explicit MnemonicKeySimulator(QWindow *window); + + void press(Qt::Key key); + void release(Qt::Key key); + void click(Qt::Key key); + + private: + QPointer<QWindow> m_window; + Qt::KeyboardModifiers m_modifiers; + }; + + [[nodiscard]] bool verifyButtonClickable(QQuickAbstractButton *button); + [[nodiscard]] bool clickButton(QQuickAbstractButton *button); + [[nodiscard]] bool doubleClickButton(QQuickAbstractButton *button); +} + +#define QQUICK_VERIFY_POLISH(item) \ + QTRY_COMPARE(QQuickItemPrivate::get(item)->polishScheduled, false) + +#endif // QQUICKVISUALTESTUTIL_H |