20QQuickControlsTestUtils::QQuickControlsApplicationHelper::QQuickControlsApplicationHelper(QQmlDataTest *testCase,
21 const QString &testFilePath,
const QVariantMap &initialProperties,
const QStringList &qmlImportPaths)
22 : QQuickApplicationHelper(testCase, testFilePath, initialProperties, qmlImportPaths)
25 appWindow = qobject_cast<QQuickApplicationWindow*>(cleanup.data());
39 if (!currentStyle.isEmpty() && style == currentStyle)
44 qmlClearTypeRegistrations();
45 engine.reset(
new QQmlEngine);
46 QQuickStyle::setStyle(style);
48 QQmlComponent component(engine.data());
49 component.setData(QString::fromUtf8(
"import QtQuick\nimport QtQuick.Controls\n Control { }").toUtf8(), QUrl());
50 if (!component.isReady())
51 qWarning() <<
"Failed to load component:" << component.errorString();
52 return component.isReady();
56 const QString &styleName,
const QString &targetPath,
const QStringList &skipList,
70 const QFileInfoList entries = QDir(qqc2ImportPath + QLatin1Char(
'/') + styleName.toLower()).entryInfoList(
71 QStringList(QStringLiteral(
"*.qml")), QDir::Files);
72 for (
const QFileInfo &entry : entries) {
73 QString name = entry.baseName();
74 if (!skipList.contains(name)) {
75 const auto importPathList = engine->importPathList();
76 for (
const QString &importPath : importPathList) {
77 const QString relativePath = entry.dir().dirName() + QLatin1Char(
'/') + entry.fileName();
78 QString filePath = importPath + QLatin1Char(
'/') + targetPath + QLatin1Char(
'/') + entry.fileName();
79 if (filePath.startsWith(QLatin1Char(
':')))
80 filePath.prepend(QStringLiteral(
"qrc"));
81 if (QFile::exists(filePath)) {
82 callback(styleName, name, relativePath, QUrl::fromLocalFile(filePath));
86 filePath = QQmlFile::urlToLocalFileOrQrc(filePath);
87 if (!filePath.isEmpty() && QFile::exists(filePath)) {
88 callback(styleName, name, relativePath, url);
142 QSignalSpy spy(button, &QQuickAbstractButton::clicked);
143 if (!spy.isValid()) {
144 qWarning() <<
"Button" << button <<
"must have a valid clicked signal";
148 const QPoint buttonCenter = button->mapToScene(QPointF(button->width() / 2, button->height() / 2)).toPoint();
149 QTest::mouseClick(button->window(), Qt::LeftButton, Qt::NoModifier, buttonCenter);
150 if (spy.size() != 1) {
151 QDebug warning(QtWarningMsg);
152 warning.nospace() <<
"The clicked signal of button " << button <<
" was not emitted after "
153 <<
"clicking at " << buttonCenter <<
".";
154 const QQuickPopup *popup = popupParent(button);
155 if (popup && !popup->isOpened()) {
156 warning <<
" The popup it's in (" << popup <<
") is no longer opened; "
157 <<
"the click may have missed the button and gone outside of the popup, "
158 <<
"causing it to close.";
206 QSignalSpy spy(button, &QQuickAbstractButton::clicked);
207 if (!spy.isValid()) {
208 qWarning() <<
"button" << button <<
"must have a valid doubleClicked signal";
212 const QPoint buttonCenter = button->mapToScene(QPointF(button->width() / 2, button->height() / 2)).toPoint();
213 QTest::mouseDClick(button->window(), Qt::LeftButton, Qt::NoModifier, buttonCenter);
214 if (spy.size() != 1) {
215 qWarning() <<
"doubleClicked signal of button" << button <<
"was not emitted after double-clicking";
252#if defined(Q_OS_ANDROID)
253 qWarning() <<
"StyleInfo is not supported when cross-compiling: QTBUG-100191";
258 QQmlComponent component(&engine);
259 component.setData(QString::fromLatin1(
260 "import QtQuick.Templates; Control { }").toUtf8(), QUrl());
262 const QStringList qmlTypeNames = QQmlMetaType::qmlTypeNames();
265 QDirIterator it(controlsImportPath, QStringList() << QLatin1String(
"*.qml") << QLatin1String(
"*.js"),
266 QDir::Files, QDirIterator::Subdirectories);
267 while (it.hasNext()) {
269 QFileInfo info = it.fileInfo();
270 if (qmlTypeNames.contains(QLatin1String(
"QtQuick.Templates/") + info.baseName())) {
271 const auto dirName = info.dir().dirName();
272 const auto typeName = info.fileName();
273 m_sourceQmlFiles.append({dirName, typeName, dirName + u"/" + typeName, info.filePath() });
278 QStringList builtInStyles = QQuickStylePrivate::builtInStyles();
281 const QStringList nativeStyles = { QLatin1String(
"macOS"), QLatin1String(
"Windows") };
282 builtInStyles.removeIf([&nativeStyles](
const QString &styleName){
283 return nativeStyles.contains(styleName);
286 QList<std::pair<QString, QString>> styleRelativePaths;
287 for (
const auto &styleName : std::as_const(builtInStyles)) {
289 styleRelativePaths.append(std::make_pair(styleName, QLatin1String(
"QtQuick/Controls/") + styleName));
293 for (
const auto &stylePathPair : styleRelativePaths) {
294 forEachControl(&engine, controlsImportPath, stylePathPair.first, stylePathPair.second, QStringList(),
295 [&](
const QString &styleName,
const QString &typeName,
const QString &relativePath,
296 const QUrl &absoluteUrl) {
297 m_installedQmlFiles.append({ styleName, typeName, relativePath, absoluteUrl.toLocalFile() });
301 std::sort(m_sourceQmlFiles.begin(), m_sourceQmlFiles.end());
302 std::sort(m_installedQmlFiles.begin(), m_installedQmlFiles.end());
352 QDebug debug(&message);
353 const auto *controlPrivate = QQuickControlPrivate::get(control);
354 const QQuickWindow *window = control->window();
355 const QString activeFocusItemStr = window
356 ? QDebug::toString(window->activeFocusItem()) : QStringLiteral(
"(unknown; control has no window)");
357 debug.nospace() <<
"control: " << control <<
" activeFocus: " << control->hasActiveFocus()
358 <<
" focusReason: " <<
static_cast<Qt::FocusReason>(controlPrivate->focusReason)
359 <<
" activeFocusItem: " << activeFocusItemStr;
void forEachControl(QQmlEngine *engine, const QString &qqc2ImportPath, const QString &styleName, const QString &targetPath, const QStringList &skipList, ForEachCallback callback)