1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include <QtCore/qabstractanimation.h>
5#include <QtCore/qdir.h>
6#include <QtCore/qmath.h>
7#include <QtCore/qelapsedtimer.h>
8#include <QtCore/qpointer.h>
9#include <QtCore/qscopedpointer.h>
10#include <QtCore/qtextstream.h>
11#include <QtCore/qregularexpression.h>
12#include <QtCore/qloggingcategory.h>
13
14#include <QtGui/QGuiApplication>
15
16#include <QtQml/qqml.h>
17#include <QtQml/qqmlengine.h>
18#include <QtQml/qqmlcomponent.h>
19#include <QtQml/qqmlcontext.h>
20#include <QtQml/qqmlfileselector.h>
21
22#include <QtQuick/qquickitem.h>
23#include <QtQuick/qquickview.h>
24
25#include <private/qabstractanimation_p.h>
26
27#ifdef QT_WIDGETS_LIB
28#include <QtWidgets/QApplication>
29#if QT_CONFIG(filedialog)
30#include <QtWidgets/QFileDialog>
31#endif // QT_CONFIG(filedialog)
32#endif // QT_WIDGETS_LIB
33
34#include <QtCore/QTranslator>
35#include <QtCore/QLibraryInfo>
36
37Q_LOGGING_CATEGORY(lcQmlsceneDeprecated, "qt.tools.qmlscene.deprecated")
38
39#ifdef QML_RUNTIME_TESTING
40class RenderStatistics
41{
42public:
43 static void updateStats();
44 static void printTotalStats();
45private:
46 static QVector<qreal> timePerFrame;
47 static QVector<int> timesPerFrames;
48};
49
50QVector<qreal> RenderStatistics::timePerFrame;
51QVector<int> RenderStatistics::timesPerFrames;
52
53void RenderStatistics::updateStats()
54{
55 static QElapsedTimer time;
56 static int frames;
57 static int lastTime;
58
59 if (frames == 0) {
60 time.start();
61 } else {
62 int elapsed = time.elapsed();
63 timesPerFrames.append(t: elapsed - lastTime);
64 lastTime = elapsed;
65
66 if (elapsed > 5000) {
67 qreal avgtime = elapsed / (qreal) frames;
68 qreal var = 0;
69 for (int i = 0; i < timesPerFrames.size(); ++i) {
70 qreal diff = timesPerFrames.at(i) - avgtime;
71 var += diff * diff;
72 }
73 var /= timesPerFrames.size();
74
75 printf(format: "Average time per frame: %f ms (%i fps), std.dev: %f ms\n", avgtime, qRound(d: 1000. / avgtime), qSqrt(v: var));
76
77 timePerFrame.append(t: avgtime);
78 timesPerFrames.clear();
79 time.start();
80 lastTime = 0;
81 frames = 0;
82 }
83 }
84 ++frames;
85}
86
87void RenderStatistics::printTotalStats()
88{
89 int count = timePerFrame.size();
90 if (count == 0)
91 return;
92
93 qreal minTime = 0;
94 qreal maxTime = 0;
95 qreal avg = 0;
96 for (int i = 0; i < count; ++i) {
97 minTime = minTime == 0 ? timePerFrame.at(i) : qMin(a: minTime, b: timePerFrame.at(i));
98 maxTime = qMax(a: maxTime, b: timePerFrame.at(i));
99 avg += timePerFrame.at(i);
100 }
101 avg /= count;
102
103 puts(s: " ");
104 puts(s: "----- Statistics -----");
105 printf(format: "Average time per frame: %f ms (%i fps)\n", avg, qRound(d: 1000. / avg));
106 printf(format: "Best time per frame: %f ms (%i fps)\n", minTime, int(1000 / minTime));
107 printf(format: "Worst time per frame: %f ms (%i fps)\n", maxTime, int(1000 / maxTime));
108 puts(s: "----------------------");
109 puts(s: " ");
110}
111#endif
112
113struct Options
114{
115 enum QmlApplicationType
116 {
117 QmlApplicationTypeGui,
118 QmlApplicationTypeWidget,
119#ifdef QT_WIDGETS_LIB
120 DefaultQmlApplicationType = QmlApplicationTypeWidget
121#else
122 DefaultQmlApplicationType = QmlApplicationTypeGui
123#endif
124 };
125
126 Options()
127 : textRenderType(QQuickWindow::textRenderType())
128 {
129 // QtWebEngine needs a shared context in order for the GPU thread to
130 // upload textures.
131 applicationAttributes.append(t: Qt::AA_ShareOpenGLContexts);
132 }
133
134 QUrl url;
135 bool originalQml = false;
136 bool originalQmlRaster = false;
137 bool maximized = false;
138 bool fullscreen = false;
139 bool transparent = false;
140 bool clip = false;
141 bool versionDetection = true;
142 bool slowAnimations = false;
143 bool quitImmediately = false;
144 bool resizeViewToRootItem = false;
145 bool multisample = false;
146 bool coreProfile = false;
147 bool verbose = false;
148 bool rhi = false;
149 bool rhiBackendSet = false;
150 QVector<Qt::ApplicationAttribute> applicationAttributes;
151 QString translationFile;
152 QmlApplicationType applicationType = DefaultQmlApplicationType;
153 QQuickWindow::TextRenderType textRenderType;
154 QString rhiBackend;
155};
156
157#if defined(QMLSCENE_BUNDLE)
158QFileInfoList findQmlFiles(const QString &dirName)
159{
160 QDir dir(dirName);
161
162 QFileInfoList ret;
163 if (dir.exists()) {
164 const QFileInfoList fileInfos = dir.entryInfoList(QStringList() << "*.qml",
165 QDir::Files | QDir::AllDirs | QDir::NoDotAndDotDot);
166
167 for (const QFileInfo &fileInfo : fileInfos) {
168 if (fileInfo.isDir())
169 ret += findQmlFiles(fileInfo.filePath());
170 else if (fileInfo.fileName().length() > 0 && fileInfo.fileName().at(0).isLower())
171 ret.append(fileInfo);
172 }
173 }
174
175 return ret;
176}
177
178static int displayOptionsDialog(Options *options)
179{
180 QDialog dialog;
181
182 QFormLayout *layout = new QFormLayout(&dialog);
183
184 QComboBox *qmlFileComboBox = new QComboBox(&dialog);
185 const QFileInfoList fileInfos = findQmlFiles(":/bundle") + findQmlFiles("./qmlscene-resources");
186
187 for (const QFileInfo &fileInfo : fileInfos)
188 qmlFileComboBox->addItem(fileInfo.dir().dirName() + QLatin1Char('/') + fileInfo.fileName(), QVariant::fromValue(fileInfo));
189
190 QCheckBox *originalCheckBox = new QCheckBox(&dialog);
191 originalCheckBox->setText("Use original QML viewer");
192 originalCheckBox->setChecked(options->originalQml);
193
194 QCheckBox *fullscreenCheckBox = new QCheckBox(&dialog);
195 fullscreenCheckBox->setText("Start fullscreen");
196 fullscreenCheckBox->setChecked(options->fullscreen);
197
198 QCheckBox *maximizedCheckBox = new QCheckBox(&dialog);
199 maximizedCheckBox->setText("Start maximized");
200 maximizedCheckBox->setChecked(options->maximized);
201
202 QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel,
203 Qt::Horizontal,
204 &dialog);
205 QObject::connect(buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept()));
206 QObject::connect(buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject()));
207
208 layout->addRow("Qml file:", qmlFileComboBox);
209 layout->addWidget(originalCheckBox);
210 layout->addWidget(maximizedCheckBox);
211 layout->addWidget(fullscreenCheckBox);
212 layout->addWidget(buttonBox);
213
214 int result = dialog.exec();
215 if (result == QDialog::Accepted) {
216 QVariant variant = qmlFileComboBox->itemData(qmlFileComboBox->currentIndex());
217 QFileInfo fileInfo = variant.value<QFileInfo>();
218
219 if (fileInfo.canonicalFilePath().startsWith(QLatin1Char(':')))
220 options->file = QUrl("qrc" + fileInfo.canonicalFilePath());
221 else
222 options->file = QUrl::fromLocalFile(fileInfo.canonicalFilePath());
223 options->originalQml = originalCheckBox->isChecked();
224 options->maximized = maximizedCheckBox->isChecked();
225 options->fullscreen = fullscreenCheckBox->isChecked();
226 }
227 return result;
228}
229#endif
230
231static bool checkVersion(const QUrl &url)
232{
233 if (!qgetenv(varName: "QMLSCENE_IMPORT_NAME").isEmpty())
234 fprintf(stderr, format: "QMLSCENE_IMPORT_NAME is no longer supported.\n");
235
236 if (!url.isLocalFile())
237 return true;
238
239 const QString fileName = url.toLocalFile();
240 QFile f(fileName);
241 if (!f.open(flags: QFile::ReadOnly | QFile::Text)) {
242 fprintf(stderr, format: "qmlscene: failed to check version of file '%s', could not open...\n",
243 qPrintable(fileName));
244 return false;
245 }
246
247 QRegularExpression quick1("^\\s*import +QtQuick +1\\.\\w*");
248 QRegularExpression qt47("^\\s*import +Qt +4\\.7");
249
250 QTextStream stream(&f);
251 bool codeFound= false;
252 while (!codeFound) {
253 if (stream.atEnd()) {
254 fprintf(stderr, format: "qmlscene: no code found in file '%s'.\n", qPrintable(fileName));
255 return false;
256 }
257 QString line = stream.readLine();
258 if (line.contains(c: QLatin1Char('{'))) {
259 codeFound = true;
260 } else {
261 QString import;
262 QRegularExpressionMatch match = quick1.match(subject: line);
263 if (match.hasMatch())
264 import = match.captured(nth: 0).trimmed();
265 else if ((match = qt47.match(subject: line)).hasMatch())
266 import = match.captured(nth: 0).trimmed();
267
268 if (!import.isNull()) {
269 fprintf(stderr, format: "qmlscene: '%s' is no longer supported.\n"
270 "Use qmlviewer to load file '%s'.\n",
271 qPrintable(import),
272 qPrintable(fileName));
273 return false;
274 }
275 }
276 }
277
278 return true;
279}
280
281static void displayFileDialog(Options *options)
282{
283#if defined(QT_WIDGETS_LIB) && QT_CONFIG(filedialog)
284 if (options->applicationType == Options::QmlApplicationTypeWidget) {
285 QString fileName = QFileDialog::getOpenFileName(parent: nullptr, caption: "Open QML file", dir: QString(), filter: "QML Files (*.qml)");
286 if (!fileName.isEmpty()) {
287 QFileInfo fi(fileName);
288 options->url = QUrl::fromLocalFile(localfile: fi.canonicalFilePath());
289 }
290 return;
291 }
292#endif // QT_WIDGETS_LIB && QT_CONFIG(filedialog)
293 Q_UNUSED(options);
294 puts(s: "No filename specified...");
295}
296
297static void loadDummyDataFiles(QQmlEngine &engine, const QString& directory)
298{
299 QDir dir(directory+"/dummydata", "*.qml");
300 QStringList list = dir.entryList();
301 for (int i = 0; i < list.size(); ++i) {
302 QString qml = list.at(i);
303 QQmlComponent comp(&engine, dir.filePath(fileName: qml));
304 QObject *dummyData = comp.create();
305
306 if(comp.isError()) {
307 const QList<QQmlError> errors = comp.errors();
308 for (const QQmlError &error : errors)
309 fprintf(stderr, format: "%s\n", qPrintable(error.toString()));
310 }
311
312 if (dummyData) {
313 fprintf(stderr, format: "Loaded dummy data: %s\n", qPrintable(dir.filePath(qml)));
314 qml.truncate(pos: qml.size()-4);
315 engine.rootContext()->setContextProperty(qml, dummyData);
316 dummyData->setParent(&engine);
317 }
318 }
319}
320
321static void usage()
322{
323 puts(s: "Usage: qmlscene [options] <filename>");
324 puts(s: " ");
325 puts(s: " Options:");
326 puts(s: " --maximized ...................... Run maximized");
327 puts(s: " --fullscreen ..................... Run fullscreen");
328 puts(s: " --transparent .................... Make the window transparent");
329 puts(s: " --multisample .................... Enable multisampling (OpenGL anti-aliasing)");
330 puts(s: " --core-profile ................... Request a core profile OpenGL context");
331 puts(s: " --rhi [vulkan|metal|d3d11|gl] .... Specify backend for the Qt graphics abstraction (RHI).\n");
332 puts(s: " --no-version-detection ........... Do not try to detect the version of the .qml file");
333 puts(s: " --slow-animations ................ Run all animations in slow motion");
334 puts(s: " --resize-to-root ................. Resize the window to the size of the root item");
335 puts(s: " --quit ........................... Quit immediately after starting");
336 puts(s: " --disable-context-sharing ........ Disable the use of a shared GL context for QtQuick Windows\n"
337 " ........ (remove AA_ShareOpenGLContexts)");
338 puts(s: " --desktop......................... Force use of desktop GL (AA_UseDesktopOpenGL)");
339 puts(s: " --gles............................ Force use of GLES (AA_UseOpenGLES)");
340 puts(s: " --software........................ Force use of software rendering (AA_UseSoftwareOpenGL)");
341 puts(s: " --verbose......................... Print version and graphical diagnostics for the run-time");
342#ifdef QT_WIDGETS_LIB
343 puts(s: " --apptype [gui|widgets] .......... Select which application class to use. Default is widgets.");
344#endif
345 puts(s: " --textrendertype [qt|native]...... Select the default render type for text-like elements.");
346 puts(s: " -I <path> ........................ Add <path> to the list of import paths");
347 puts(s: " -S <selector> .................... Add <selector> to the list of QQmlFileSelector selectors");
348 puts(s: " -P <path> ........................ Add <path> to the list of plugin paths");
349 puts(s: " -translation <translationfile> ... Set the language to run in");
350
351 puts(s: " ");
352 exit(status: 1);
353}
354
355static void setWindowTitle(bool verbose, const QObject *topLevel, QWindow *window)
356{
357 const QString oldTitle = window->title();
358 QString newTitle = oldTitle;
359 if (newTitle.isEmpty()) {
360 newTitle = QLatin1String("qmlscene");
361 if (!qobject_cast<const QWindow *>(o: topLevel) && !topLevel->objectName().isEmpty())
362 newTitle += QLatin1String(": ") + topLevel->objectName();
363 }
364 if (verbose) {
365 newTitle += QLatin1String(" [Qt ") + QLatin1String(QT_VERSION_STR) + QLatin1Char(' ')
366 + QGuiApplication::platformName() + QLatin1Char(' ');
367 newTitle += QLatin1Char(']');
368 }
369 if (oldTitle != newTitle)
370 window->setTitle(newTitle);
371}
372
373static QUrl parseUrlArgument(const QString &arg)
374{
375 const QUrl url = QUrl::fromUserInput(userInput: arg, workingDirectory: QDir::currentPath(), options: QUrl::AssumeLocalFile);
376 if (!url.isValid()) {
377 fprintf(stderr, format: "Invalid URL: \"%s\"\n", qPrintable(arg));
378 return QUrl();
379 }
380 if (url.isLocalFile()) {
381 const QFileInfo fi(url.toLocalFile());
382 if (!fi.exists()) {
383 fprintf(stderr, format: "\"%s\" does not exist.\n",
384 qPrintable(QDir::toNativeSeparators(fi.absoluteFilePath())));
385 return QUrl();
386 }
387 }
388 return url;
389}
390
391static QQuickWindow::TextRenderType parseTextRenderType(const QString &renderType)
392{
393 if (renderType == QLatin1String("qt"))
394 return QQuickWindow::QtTextRendering;
395 else if (renderType == QLatin1String("native"))
396 return QQuickWindow::NativeTextRendering;
397
398 usage();
399
400 Q_UNREACHABLE_RETURN(QQuickWindow::QtTextRendering);
401}
402
403int main(int argc, char ** argv)
404{
405 Options options;
406
407 QStringList imports;
408 QStringList customSelectors;
409 QStringList pluginPaths;
410
411 qCWarning(lcQmlsceneDeprecated()) << "Warning: qmlscene is deprecated and will be removed in a future version of Qt. Please use qml instead.";
412
413 // Parse arguments for application attributes to be applied before Q[Gui]Application creation.
414 for (int i = 1; i < argc; ++i) {
415 const char *arg = argv[i];
416 if (!qstrcmp(str1: arg, str2: "--disable-context-sharing")) {
417 options.applicationAttributes.removeAll(t: Qt::AA_ShareOpenGLContexts);
418 } else if (!qstrcmp(str1: arg, str2: "--gles")) {
419 options.applicationAttributes.append(t: Qt::AA_UseOpenGLES);
420 } else if (!qstrcmp(str1: arg, str2: "--software")) {
421 options.applicationAttributes.append(t: Qt::AA_UseSoftwareOpenGL);
422 } else if (!qstrcmp(str1: arg, str2: "--desktop")) {
423 options.applicationAttributes.append(t: Qt::AA_UseDesktopOpenGL);
424 } else if (!qstrcmp(str1: arg, str2: "--transparent")) {
425 options.transparent = true;
426 } else if (!qstrcmp(str1: arg, str2: "--multisample")) {
427 options.multisample = true;
428 } else if (!qstrcmp(str1: arg, str2: "--core-profile")) {
429 options.coreProfile = true;
430 } else if (!qstrcmp(str1: arg, str2: "--apptype")) {
431 if (++i >= argc)
432 usage();
433 if (!qstrcmp(str1: argv[i], str2: "gui"))
434 options.applicationType = Options::QmlApplicationTypeGui;
435 }
436 }
437
438 if (qEnvironmentVariableIsSet(varName: "QMLSCENE_CORE_PROFILE")
439 || qEnvironmentVariableIsSet(varName: "QSG_CORE_PROFILE"))
440 options.coreProfile = true;
441
442 // Set default surface format before creating the window
443 QSurfaceFormat surfaceFormat;
444 surfaceFormat.setStencilBufferSize(8);
445 surfaceFormat.setDepthBufferSize(24);
446 if (options.multisample)
447 surfaceFormat.setSamples(16);
448 if (options.transparent)
449 surfaceFormat.setAlphaBufferSize(8);
450 if (options.coreProfile) {
451 surfaceFormat.setVersion(major: 4, minor: 1);
452 surfaceFormat.setProfile(QSurfaceFormat::CoreProfile);
453 }
454 QSurfaceFormat::setDefaultFormat(surfaceFormat);
455
456 for (Qt::ApplicationAttribute a : std::as_const(t&: options.applicationAttributes))
457 QCoreApplication::setAttribute(attribute: a);
458 QScopedPointer<QGuiApplication> app;
459#ifdef QT_WIDGETS_LIB
460 if (options.applicationType == Options::QmlApplicationTypeWidget)
461 app.reset(other: new QApplication(argc, argv));
462#endif
463 if (app.isNull())
464 app.reset(other: new QGuiApplication(argc, argv));
465 QCoreApplication::setApplicationName(QStringLiteral("QtQmlViewer"));
466 QCoreApplication::setOrganizationName(QStringLiteral("QtProject"));
467 QCoreApplication::setOrganizationDomain(QStringLiteral("qt-project.org"));
468 QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR));
469
470 const QStringList arguments = QCoreApplication::arguments();
471 for (int i = 1, size = arguments.size(); i < size; ++i) {
472 if (!arguments.at(i).startsWith(c: QLatin1Char('-'))) {
473 options.url = parseUrlArgument(arg: arguments.at(i));
474 } else {
475 const QString lowerArgument = arguments.at(i).toLower();
476 if (lowerArgument == QLatin1String("--maximized"))
477 options.maximized = true;
478 else if (lowerArgument == QLatin1String("--fullscreen"))
479 options.fullscreen = true;
480 else if (lowerArgument == QLatin1String("--clip"))
481 options.clip = true;
482 else if (lowerArgument == QLatin1String("--no-version-detection"))
483 options.versionDetection = false;
484 else if (lowerArgument == QLatin1String("--slow-animations"))
485 options.slowAnimations = true;
486 else if (lowerArgument == QLatin1String("--quit"))
487 options.quitImmediately = true;
488 else if (lowerArgument == QLatin1String("-translation"))
489 options.translationFile = QLatin1String(argv[++i]);
490 else if (lowerArgument == QLatin1String("--resize-to-root"))
491 options.resizeViewToRootItem = true;
492 else if (lowerArgument == QLatin1String("--verbose"))
493 options.verbose = true;
494 else if (lowerArgument == QLatin1String("--rhi")) {
495 options.rhi = true;
496 if (i + 1 < size && !arguments.at(i: i + 1).startsWith(c: QLatin1Char('-'))) {
497 options.rhiBackendSet = true;
498 options.rhiBackend = arguments.at(i: ++i);
499 }
500 } else if (lowerArgument == QLatin1String("-i") && i + 1 < size)
501 imports.append(t: arguments.at(i: ++i));
502 else if (lowerArgument == QLatin1String("-s") && i + 1 < size)
503 customSelectors.append(t: arguments.at(i: ++i));
504 else if (lowerArgument == QLatin1String("-p") && i + 1 < size)
505 pluginPaths.append(t: arguments.at(i: ++i));
506 else if (lowerArgument == QLatin1String("--apptype"))
507 ++i; // Consume previously parsed argument
508 else if (lowerArgument == QLatin1String("--textrendertype") && i + 1 < size)
509 options.textRenderType = parseTextRenderType(renderType: arguments.at(i: ++i));
510 else if (lowerArgument == QLatin1String("--help")
511 || lowerArgument == QLatin1String("-help")
512 || lowerArgument == QLatin1String("--h")
513 || lowerArgument == QLatin1String("-h"))
514 usage();
515 }
516 }
517
518#if QT_CONFIG(translation)
519 QLocale locale;
520 QTranslator qtTranslator;
521 if (qtTranslator.load(locale, filename: QLatin1String("qt"), prefix: QLatin1String("_"), directory: QLibraryInfo::path(p: QLibraryInfo::TranslationsPath)))
522 QCoreApplication::installTranslator(messageFile: &qtTranslator);
523 QTranslator translator;
524 if (translator.load(locale, filename: QLatin1String("qmlscene"), prefix: QLatin1String("_"), directory: QLibraryInfo::path(p: QLibraryInfo::TranslationsPath)))
525 QCoreApplication::installTranslator(messageFile: &translator);
526
527 QTranslator qmlTranslator;
528 if (!options.translationFile.isEmpty()) {
529 if (qmlTranslator.load(filename: options.translationFile)) {
530 QCoreApplication::installTranslator(messageFile: &qmlTranslator);
531 } else {
532 fprintf(stderr, format: "Could not load the translation file \"%s\"\n",
533 qPrintable(options.translationFile));
534 }
535 }
536#endif
537
538 QQuickWindow::setTextRenderType(options.textRenderType);
539
540 QUnifiedTimer::instance()->setSlowModeEnabled(options.slowAnimations);
541
542 if (options.rhi) {
543 if (options.rhiBackendSet)
544 qputenv(varName: "QSG_RHI_BACKEND", value: options.rhiBackend.toLatin1());
545 else
546 qunsetenv(varName: "QSG_RHI_BACKEND");
547 }
548
549 if (options.url.isEmpty())
550#if defined(QMLSCENE_BUNDLE)
551 displayOptionsDialog(&options);
552#else
553 displayFileDialog(options: &options);
554#endif
555
556 int exitCode = 0;
557
558 if (options.verbose)
559 puts(s: QLibraryInfo::build());
560
561 if (!options.url.isEmpty()) {
562 if (!options.versionDetection || checkVersion(url: options.url)) {
563 // TODO: as soon as the engine construction completes, the debug service is
564 // listening for connections. But actually we aren't ready to debug anything.
565 QQmlEngine engine;
566 QQmlFileSelector* selector = new QQmlFileSelector(&engine, &engine);
567 selector->setExtraSelectors(customSelectors);
568 QPointer<QQmlComponent> component = new QQmlComponent(&engine);
569 for (int i = 0; i < imports.size(); ++i)
570 engine.addImportPath(dir: imports.at(i));
571 for (int i = 0; i < pluginPaths.size(); ++i)
572 engine.addPluginPath(dir: pluginPaths.at(i));
573 if (options.url.isLocalFile()) {
574 QFileInfo fi(options.url.toLocalFile());
575#if QT_CONFIG(translation)
576 QTranslator *translator = new QTranslator(app.get());
577 if (translator->load(locale: QLocale(), filename: QLatin1String("qml"), prefix: QLatin1String("_"), directory: fi.path() + QLatin1String("/i18n")))
578 QCoreApplication::installTranslator(messageFile: translator);
579#endif
580 loadDummyDataFiles(engine, directory: fi.path());
581 }
582 QObject::connect(sender: &engine, SIGNAL(quit()), receiver: QCoreApplication::instance(), SLOT(quit()));
583 QObject::connect(sender: &engine, signal: &QQmlEngine::exit, context: QCoreApplication::instance(), slot: &QCoreApplication::exit);
584 component->loadUrl(url: options.url);
585 while (component->isLoading())
586 QCoreApplication::processEvents();
587 if ( !component->isReady() ) {
588 fprintf(stderr, format: "%s\n", qPrintable(component->errorString()));
589 return -1;
590 }
591
592 QObject *topLevel = component->create();
593 if (!topLevel && component->isError()) {
594 fprintf(stderr, format: "%s\n", qPrintable(component->errorString()));
595 return -1;
596 }
597
598 QScopedPointer<QQuickWindow> window(qobject_cast<QQuickWindow *>(object: topLevel));
599 if (window) {
600 engine.setIncubationController(window->incubationController());
601 } else {
602 QQuickItem *contentItem = qobject_cast<QQuickItem *>(o: topLevel);
603 if (contentItem) {
604 QQuickView* qxView = new QQuickView(&engine, nullptr);
605 window.reset(other: qxView);
606 // Set window default properties; the qml can still override them
607 if (options.resizeViewToRootItem)
608 qxView->setResizeMode(QQuickView::SizeViewToRootObject);
609 else
610 qxView->setResizeMode(QQuickView::SizeRootObjectToView);
611 qxView->setContent(url: options.url, component, item: contentItem);
612 }
613 }
614
615 if (window) {
616 setWindowTitle(verbose: options.verbose, topLevel, window: window.data());
617 if (options.transparent) {
618 window->setColor(QColor(Qt::transparent));
619 window->setFlags(Qt::FramelessWindowHint);
620 }
621 window->setFormat(surfaceFormat);
622
623 if (window->flags() == Qt::Window) // Fix window flags unless set by QML.
624 window->setFlags(Qt::Window | Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint | Qt::WindowFullscreenButtonHint);
625
626 if (options.fullscreen)
627 window->showFullScreen();
628 else if (options.maximized)
629 window->showMaximized();
630 else if (!window->isVisible())
631 window->show();
632 }
633
634 if (options.quitImmediately)
635 QMetaObject::invokeMethod(obj: QCoreApplication::instance(), member: "quit", c: Qt::QueuedConnection);
636
637 // Now would be a good time to inform the debug service to start listening.
638
639 exitCode = app->exec();
640
641#ifdef QML_RUNTIME_TESTING
642 RenderStatistics::printTotalStats();
643#endif
644 // Ready to exit. Notice that the component might be owned by
645 // QQuickView if one was created. That case is tracked by
646 // QPointer, so it is safe to delete the component here.
647 delete component;
648 } else {
649 exitCode = 1;
650 }
651 }
652
653 return exitCode;
654}
655

source code of qtdeclarative/tools/qmlscene/main.cpp