aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/qml/main.cpp13
-rw-r--r--tools/qml/qml.pro2
-rw-r--r--tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in (renamed from tools/qmlcachegen/Qt5QuickCompilerConfig.cmake)37
-rw-r--r--tools/qmlcachegen/qmlcachegen.cpp163
-rw-r--r--tools/qmlcachegen/qmlcachegen.pro16
-rw-r--r--tools/qmlcachegen/qtquickcompiler.prf6
-rw-r--r--tools/qmlcachegen/resourcefilemapper.cpp2
-rw-r--r--tools/qmlcachegen/resourcefilter.cpp4
-rw-r--r--tools/qmljs/qmljs.cpp63
-rw-r--r--tools/qmlmin/main.cpp104
-rw-r--r--tools/qmlplugindump/main.cpp197
-rw-r--r--tools/qmlpreview/main.cpp36
-rw-r--r--tools/qmlpreview/qmlpreview.pro13
-rw-r--r--tools/qmlpreview/qmlpreviewapplication.cpp266
-rw-r--r--tools/qmlpreview/qmlpreviewapplication.h83
-rw-r--r--tools/qmlprofiler/qmlprofilerapplication.cpp6
-rw-r--r--tools/qmlprofiler/qmlprofilerclient.cpp4
-rw-r--r--tools/qmlprofiler/qmlprofilerclient.h2
-rw-r--r--tools/qmlscene/main.cpp12
-rw-r--r--tools/tools.pro24
20 files changed, 791 insertions, 262 deletions
diff --git a/tools/qml/main.cpp b/tools/qml/main.cpp
index 73b2700ba4..7dfae2b53d 100644
--- a/tools/qml/main.cpp
+++ b/tools/qml/main.cpp
@@ -55,7 +55,9 @@
#include <QLibraryInfo>
#include <qqml.h>
#include <qqmldebug.h>
-#if QT_CONFIG(animation)
+
+#include <private/qtqmlglobal_p.h>
+#if QT_CONFIG(qml_animation)
#include <private/qabstractanimation_p.h>
#endif
@@ -483,7 +485,7 @@ int main(int argc, char *argv[])
break;
else if (arg == QLatin1String("-verbose"))
verboseMode = true;
-#if QT_CONFIG(animation)
+#if QT_CONFIG(qml_animation)
else if (arg == QLatin1String("-slow-animations"))
QUnifiedTimer::instance()->setSlowModeEnabled(true);
else if (arg == QLatin1String("-fixed-animations"))
@@ -533,10 +535,9 @@ int main(int argc, char *argv[])
verboseMode = false;
#if QT_CONFIG(translation)
- //qt_ translations loaded by QQmlApplicationEngine
- QString sysLocale = QLocale::system().name();
-
- if (!translationFile.isEmpty()) { //Note: installed before QQmlApplicationEngine's automatic translation loading
+ // Need to be installed before QQmlApplicationEngine's automatic translation loading
+ // (qt_ translations are loaded there)
+ if (!translationFile.isEmpty()) {
QTranslator translator;
if (translator.load(translationFile)) {
diff --git a/tools/qml/qml.pro b/tools/qml/qml.pro
index 04704f9314..3f41707275 100644
--- a/tools/qml/qml.pro
+++ b/tools/qml/qml.pro
@@ -1,4 +1,4 @@
-QT = qml core-private
+QT = qml-private core-private
qtHaveModule(gui): QT += gui
qtHaveModule(widgets): QT += widgets
diff --git a/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake b/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in
index 49ba4edde9..a5c531fb0d 100644
--- a/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake
+++ b/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in
@@ -2,9 +2,10 @@ include(CMakeParseArguments)
function(QTQUICK_COMPILER_DETERMINE_OUTPUT_FILENAME outvariable filename)
file(RELATIVE_PATH relpath ${CMAKE_CURRENT_SOURCE_DIR} ${filename})
- string(REPLACE ".qml" "_qml" relpath ${relpath})
- string(REPLACE ".js" "_js" relpath ${relpath})
- string(REPLACE "/" "_" relpath ${relpath})
+ string(REPLACE \".qml\" \"_qml\" relpath ${relpath})
+ string(REPLACE \".js\" \"_js\" relpath ${relpath})
+ string(REPLACE \".mjs\" \"_mjs\" relpath ${relpath})
+ string(REPLACE \"/\" \"_\" relpath ${relpath})
set(${outvariable} ${CMAKE_CURRENT_BINARY_DIR}/${relpath}.cpp PARENT_SCOPE)
endfunction()
@@ -13,11 +14,26 @@ function(QTQUICK_COMPILER_ADD_RESOURCES outfiles)
set(oneValueArgs)
set(multiValueArgs OPTIONS)
- cmake_parse_arguments(_RCC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+ cmake_parse_arguments(_RCC \"${options}\" \"${oneValueArgs}\" \"${multiValueArgs}\" ${ARGN})
find_package(Qt5 COMPONENTS Qml Core)
- set(compiler_path "${_qt5Core_install_prefix}/bin/qmlcachegen")
+!!IF isEmpty(CMAKE_BIN_DIR_IS_ABSOLUTE)
+ set(compiler_path \"${_qt5Core_install_prefix}/$${CMAKE_BIN_DIR}qmlcachegen$$CMAKE_BIN_SUFFIX\")
+!!ELSE
+ set(compiler_path \"$${CMAKE_BIN_DIR}qmlcachegen$$CMAKE_BIN_SUFFIX\")
+!!ENDIF
+ if(NOT EXISTS \"${compiler_path}\" )
+ message(FATAL_ERROR \"The package \\\"Qt5QuickCompilerConfig\\\" references the file
+ \\\"${compiler_path}\\\"
+but this file does not exist. Possible reasons include:
+* The file was deleted, renamed, or moved to another location.
+* An install or uninstall procedure did not complete successfully.
+* The installation package was faulty and contained
+ \\\"${CMAKE_CURRENT_LIST_FILE}\\\"
+but not all the files it references.
+\")
+ endif()
get_target_property(rcc_path ${Qt5Core_RCC_EXECUTABLE} IMPORTED_LOCATION)
@@ -37,18 +53,18 @@ function(QTQUICK_COMPILER_ADD_RESOURCES outfiles)
execute_process(COMMAND ${compiler_path} -filter-resource-file ${input_resource} -o ${new_resource_file} OUTPUT_VARIABLE remaining_files)
if(remaining_files)
list(APPEND filtered_rcc_files ${new_resource_file})
- list(APPEND loader_flags "--resource-file-mapping=${_resource}=${new_resource_file}")
+ list(APPEND loader_flags \"--resource-file-mapping=${_resource}=${new_resource_file}\")
else()
- list(APPEND loader_flags "--resource-file-mapping=${_resource}")
+ list(APPEND loader_flags \"--resource-file-mapping=${_resource}\")
endif()
set(rcc_file_with_compilation_units)
- execute_process(COMMAND ${rcc_path} -list "${input_resource}" OUTPUT_VARIABLE rcc_contents)
- string(REGEX REPLACE "[\r\n]+" ";" rcc_contents ${rcc_contents})
+ execute_process(COMMAND ${rcc_path} -list \"${input_resource}\" OUTPUT_VARIABLE rcc_contents)
+ string(REGEX REPLACE \"[\r\n]+\" \";\" rcc_contents ${rcc_contents})
foreach(it ${rcc_contents})
get_filename_component(extension ${it} EXT)
- if(extension STREQUAL ".qml" OR extension STREQUAL ".js" OR extension STREQUAL ".ui.qml")
+ if(extension STREQUAL \".qml\" OR extension STREQUAL \".js\" OR extension STREQUAL \".ui.qml\" OR extension STREQUAL \".mjs\")
qtquick_compiler_determine_output_filename(output_file ${it})
add_custom_command(OUTPUT ${output_file} COMMAND ${compiler_path} ARGS --resource=${input_resource} ${it} -o ${output_file} DEPENDS ${it})
list(APPEND compiler_output ${output_file})
@@ -70,4 +86,3 @@ function(QTQUICK_COMPILER_ADD_RESOURCES outfiles)
qt5_add_resources(output_resources ${filtered_rcc_files} OPTIONS ${options})
set(${outfiles} ${output_resources} ${compiler_output} PARENT_SCOPE)
endfunction()
-
diff --git a/tools/qmlcachegen/qmlcachegen.cpp b/tools/qmlcachegen/qmlcachegen.cpp
index 8a2776e808..762f6e7221 100644
--- a/tools/qmlcachegen/qmlcachegen.cpp
+++ b/tools/qmlcachegen/qmlcachegen.cpp
@@ -34,9 +34,12 @@
#include <QDateTime>
#include <QHashFunctions>
#include <QSaveFile>
+#include <QScopedPointer>
+#include <QScopeGuard>
#include <private/qqmlirbuilder_p.h>
#include <private/qqmljsparser_p.h>
+#include <private/qqmljslexer_p.h>
#include "resourcefilemapper.h"
@@ -66,6 +69,7 @@ struct Error
QString message;
void print();
Error augment(const QString &contextErrorMessage) const;
+ void appendDiagnostics(const QString &inputFileName, const QList<QQmlJS::DiagnosticMessage> &diagnostics);
};
void Error::print()
@@ -95,6 +99,15 @@ QString diagnosticErrorMessage(const QString &fileName, const QQmlJS::Diagnostic
return message;
}
+void Error::appendDiagnostics(const QString &inputFileName, const QList<DiagnosticMessage> &diagnostics)
+{
+ for (const QQmlJS::DiagnosticMessage &parseError: diagnostics) {
+ if (!message.isEmpty())
+ message += QLatin1Char('\n');
+ message += diagnosticErrorMessage(inputFileName, parseError);
+ }
+}
+
// Ensure that ListElement objects keep all property assignments in their string form
static void annotateListElements(QmlIR::Document *document)
{
@@ -161,7 +174,7 @@ static bool checkArgumentsObjectUseInSignalHandlers(const QmlIR::Document &doc,
return true;
}
-using SaveFunction = std::function<bool (QV4::CompiledData::CompilationUnit *, QString *)>;
+using SaveFunction = std::function<bool (const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &, QString *)>;
static bool compileQmlFile(const QString &inputFileName, SaveFunction saveFunction, Error *error)
{
@@ -184,11 +197,7 @@ static bool compileQmlFile(const QString &inputFileName, SaveFunction saveFuncti
{
QmlIR::IRBuilder irBuilder(illegalNames);
if (!irBuilder.generateFromQml(sourceCode, inputFileName, &irDocument)) {
- for (const QQmlJS::DiagnosticMessage &parseError: qAsConst(irBuilder.errors)) {
- if (!error->message.isEmpty())
- error->message += QLatin1Char('\n');
- error->message += diagnosticErrorMessage(inputFileName, parseError);
- }
+ error->appendDiagnostics(inputFileName, irBuilder.errors);
return false;
}
}
@@ -212,11 +221,7 @@ static bool compileQmlFile(const QString &inputFileName, SaveFunction saveFuncti
const QVector<int> runtimeFunctionIndices = v4CodeGen.generateJSCodeForFunctionsAndBindings(functionsToCompile);
QList<QQmlJS::DiagnosticMessage> jsErrors = v4CodeGen.errors();
if (!jsErrors.isEmpty()) {
- for (const QQmlJS::DiagnosticMessage &e: qAsConst(jsErrors)) {
- if (!error->message.isEmpty())
- error->message += QLatin1Char('\n');
- error->message += diagnosticErrorMessage(inputFileName, e);
- }
+ error->appendDiagnostics(inputFileName, jsErrors);
return false;
}
@@ -231,10 +236,10 @@ static bool compileQmlFile(const QString &inputFileName, SaveFunction saveFuncti
QmlIR::QmlUnitGenerator generator;
irDocument.javaScriptCompilationUnit = v4CodeGen.generateCompilationUnit(/*generate unit*/false);
- QV4::CompiledData::Unit *unit = generator.generate(irDocument);
+ generator.generate(irDocument);
+ QV4::CompiledData::Unit *unit = const_cast<QV4::CompiledData::Unit*>(irDocument.javaScriptCompilationUnit->data);
unit->flags |= QV4::CompiledData::Unit::StaticData;
unit->flags |= QV4::CompiledData::Unit::PendingTypeCompilation;
- irDocument.javaScriptCompilationUnit->data = unit;
if (!saveFunction(irDocument.javaScriptCompilationUnit, &error->message))
return false;
@@ -246,7 +251,8 @@ static bool compileQmlFile(const QString &inputFileName, SaveFunction saveFuncti
static bool compileJSFile(const QString &inputFileName, const QString &inputFileUrl, SaveFunction saveFunction, Error *error)
{
- QmlIR::Document irDocument(/*debugMode*/false);
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit;
+ QScopedPointer<QV4::CompiledData::Unit, QScopedPointerPodDeleter> unitDataToFree;
QString sourceCode;
{
@@ -262,79 +268,83 @@ static bool compileJSFile(const QString &inputFileName, const QString &inputFile
}
}
- QQmlJS::Engine *engine = &irDocument.jsParserEngine;
- QmlIR::ScriptDirectivesCollector directivesCollector(&irDocument);
- QQmlJS::Directives *oldDirs = engine->directives();
- engine->setDirectives(&directivesCollector);
+ const bool isModule = inputFileName.endsWith(QLatin1String(".mjs"));
+ if (isModule) {
+ QList<QQmlJS::DiagnosticMessage> diagnostics;
+ // Precompiled files are relocatable and the final location will be set when loading.
+ QString url;
+ unit = QV4::ExecutionEngine::compileModule(/*debugMode*/false, url, sourceCode, QDateTime(), &diagnostics);
+ error->appendDiagnostics(inputFileName, diagnostics);
+ if (!unit)
+ return false;
+ } else {
+ QmlIR::Document irDocument(/*debugMode*/false);
- QQmlJS::AST::Program *program = nullptr;
+ QQmlJS::Engine *engine = &irDocument.jsParserEngine;
+ QmlIR::ScriptDirectivesCollector directivesCollector(&irDocument);
+ QQmlJS::Directives *oldDirs = engine->directives();
+ engine->setDirectives(&directivesCollector);
+ auto directivesGuard = qScopeGuard([engine, oldDirs]{
+ engine->setDirectives(oldDirs);
+ });
- {
- QQmlJS::Lexer lexer(engine);
- lexer.setCode(sourceCode, /*line*/1, /*parseAsBinding*/false);
- QQmlJS::Parser parser(engine);
+ QQmlJS::AST::Program *program = nullptr;
- bool parsed = parser.parseProgram();
+ {
+ QQmlJS::Lexer lexer(engine);
+ lexer.setCode(sourceCode, /*line*/1, /*parseAsBinding*/false);
+ QQmlJS::Parser parser(engine);
- for (const QQmlJS::DiagnosticMessage &parseError: parser.diagnosticMessages()) {
- if (!error->message.isEmpty())
- error->message += QLatin1Char('\n');
- error->message += diagnosticErrorMessage(inputFileName, parseError);
- }
+ bool parsed = parser.parseProgram();
- if (!parsed) {
- engine->setDirectives(oldDirs);
- return false;
- }
+ error->appendDiagnostics(inputFileName, parser.diagnosticMessages());
- program = QQmlJS::AST::cast<QQmlJS::AST::Program*>(parser.rootNode());
- if (!program) {
- lexer.setCode(QStringLiteral("undefined;"), 1, false);
- parsed = parser.parseProgram();
- Q_ASSERT(parsed);
- program = QQmlJS::AST::cast<QQmlJS::AST::Program*>(parser.rootNode());
- Q_ASSERT(program);
- }
- }
+ if (!parsed)
+ return false;
- {
- QmlIR::JSCodeGen v4CodeGen(irDocument.code, &irDocument.jsGenerator,
- &irDocument.jsModule, &irDocument.jsParserEngine,
- irDocument.program, /*import cache*/nullptr,
- &irDocument.jsGenerator.stringTable, illegalNames);
- v4CodeGen.setUseFastLookups(false); // Disable lookups in non-standalone (aka QML) mode
- v4CodeGen.generateFromProgram(inputFileName, inputFileUrl, sourceCode, program,
- &irDocument.jsModule, QV4::Compiler::GlobalCode);
- QList<QQmlJS::DiagnosticMessage> jsErrors = v4CodeGen.errors();
- if (!jsErrors.isEmpty()) {
- for (const QQmlJS::DiagnosticMessage &e: qAsConst(jsErrors)) {
- if (!error->message.isEmpty())
- error->message += QLatin1Char('\n');
- error->message += diagnosticErrorMessage(inputFileName, e);
+ program = QQmlJS::AST::cast<QQmlJS::AST::Program*>(parser.rootNode());
+ if (!program) {
+ lexer.setCode(QStringLiteral("undefined;"), 1, false);
+ parsed = parser.parseProgram();
+ Q_ASSERT(parsed);
+ program = QQmlJS::AST::cast<QQmlJS::AST::Program*>(parser.rootNode());
+ Q_ASSERT(program);
}
- engine->setDirectives(oldDirs);
- return false;
}
- QmlIR::QmlUnitGenerator generator;
-
- irDocument.javaScriptCompilationUnit = v4CodeGen.generateCompilationUnit(/*generate unit*/false);
- QV4::CompiledData::Unit *unit = generator.generate(irDocument);
- unit->flags |= QV4::CompiledData::Unit::StaticData;
- irDocument.javaScriptCompilationUnit->data = unit;
+ {
+ QmlIR::JSCodeGen v4CodeGen(irDocument.code, &irDocument.jsGenerator,
+ &irDocument.jsModule, &irDocument.jsParserEngine,
+ irDocument.program, /*import cache*/nullptr,
+ &irDocument.jsGenerator.stringTable, illegalNames);
+ v4CodeGen.setUseFastLookups(false); // Disable lookups in non-standalone (aka QML) mode
+ v4CodeGen.generateFromProgram(inputFileName, inputFileUrl, sourceCode, program,
+ &irDocument.jsModule, QV4::Compiler::ContextType::Global);
+ QList<QQmlJS::DiagnosticMessage> jsErrors = v4CodeGen.errors();
+ if (!jsErrors.isEmpty()) {
+ error->appendDiagnostics(inputFileName, jsErrors);
+ return false;
+ }
- if (!saveFunction(irDocument.javaScriptCompilationUnit, &error->message)) {
- engine->setDirectives(oldDirs);
- return false;
+ // Precompiled files are relocatable and the final location will be set when loading.
+ irDocument.jsModule.fileName.clear();
+ irDocument.jsModule.finalUrl.clear();
+
+ irDocument.javaScriptCompilationUnit = v4CodeGen.generateCompilationUnit(/*generate unit*/false);
+ QmlIR::QmlUnitGenerator generator;
+ generator.generate(irDocument);
+ QV4::CompiledData::Unit *unitData = const_cast<QV4::CompiledData::Unit*>(irDocument.javaScriptCompilationUnit->data);
+ unitData->flags |= QV4::CompiledData::Unit::StaticData;
+ unitDataToFree.reset(unitData);
+ unit = irDocument.javaScriptCompilationUnit;
}
-
- free(unit);
}
- engine->setDirectives(oldDirs);
- return true;
+
+ return saveFunction(unit, &error->message);
}
-static bool saveUnitAsCpp(const QString &inputFileName, const QString &outputFileName, QV4::CompiledData::CompilationUnit *unit, QString *errorString)
+static bool saveUnitAsCpp(const QString &inputFileName, const QString &outputFileName,
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit, QString *errorString)
{
QSaveFile f(outputFileName);
if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
@@ -434,9 +444,6 @@ int main(int argc, char **argv)
QCommandLineOption outputFileOption(QStringLiteral("o"), QCoreApplication::translate("main", "Output file name"), QCoreApplication::translate("main", "file name"));
parser.addOption(outputFileOption);
- QCommandLineOption checkIfSupportedOption(QStringLiteral("check-if-supported"), QCoreApplication::translate("main", "Check if cache generate is supported on the specified target architecture"));
- parser.addOption(checkIfSupportedOption);
-
parser.addPositionalArgument(QStringLiteral("[qml file]"),
QStringLiteral("QML source file to generate cache for."));
@@ -525,12 +532,12 @@ int main(int argc, char **argv)
inputFileUrl = QStringLiteral("qrc://") + inputResourcePath;
- saveFunction = [inputResourcePath, outputFileName](QV4::CompiledData::CompilationUnit *unit, QString *errorString) {
+ saveFunction = [inputResourcePath, outputFileName](const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit, QString *errorString) {
return saveUnitAsCpp(inputResourcePath, outputFileName, unit, errorString);
};
} else {
- saveFunction = [outputFileName](QV4::CompiledData::CompilationUnit *unit, QString *errorString) {
+ saveFunction = [outputFileName](const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit, QString *errorString) {
return unit->saveToDisk(outputFileName, errorString);
};
}
@@ -544,7 +551,7 @@ int main(int argc, char **argv)
error.augment(QLatin1String("Error compiling qml file: ")).print();
return EXIT_FAILURE;
}
- } else if (inputFile.endsWith(QLatin1String(".js"))) {
+ } else if (inputFile.endsWith(QLatin1String(".js")) || inputFile.endsWith(QLatin1String(".mjs"))) {
Error error;
if (!compileJSFile(inputFile, inputFileUrl, saveFunction, &error)) {
error.augment(QLatin1String("Error compiling js file: ")).print();
diff --git a/tools/qmlcachegen/qmlcachegen.pro b/tools/qmlcachegen/qmlcachegen.pro
index 391f0c3889..9662690395 100644
--- a/tools/qmlcachegen/qmlcachegen.pro
+++ b/tools/qmlcachegen/qmlcachegen.pro
@@ -14,7 +14,21 @@ build_integration.path = $$[QT_HOST_DATA]/mkspecs/features
prefix_build: INSTALLS += build_integration
else: COPIES += build_integration
-cmake_build_integration.files = Qt5QuickCompilerConfig.cmake
+load(cmake_functions)
+
+CMAKE_BIN_DIR = $$cmakeRelativePath($$[QT_HOST_BINS], $$[QT_INSTALL_PREFIX])
+contains(CMAKE_BIN_DIR, "^\\.\\./.*") {
+ CMAKE_BIN_DIR = $$[QT_HOST_BINS]/
+ CMAKE_BIN_DIR_IS_ABSOLUTE = True
+}
+
+load(qt_build_paths)
+
+cmake_config_file.input = $$PWD/Qt5QuickCompilerConfig.cmake.in
+cmake_config_file.output = $$MODULE_BASE_OUTDIR/lib/cmake/Qt5QuickCompiler/Qt5QuickCompilerConfig.cmake
+QMAKE_SUBSTITUTES += cmake_config_file
+
+cmake_build_integration.files = $$cmake_config_file.output
cmake_build_integration.path = $$[QT_INSTALL_LIBS]/cmake/Qt5QuickCompiler
prefix_build: INSTALLS += cmake_build_integration
else: COPIES += cmake_build_integration
diff --git a/tools/qmlcachegen/qtquickcompiler.prf b/tools/qmlcachegen/qtquickcompiler.prf
index d05908560d..608b5c9143 100644
--- a/tools/qmlcachegen/qtquickcompiler.prf
+++ b/tools/qmlcachegen/qtquickcompiler.prf
@@ -6,6 +6,7 @@ isEmpty(QMLCACHE_DIR): QMLCACHE_DIR = .
defineReplace(qmlCacheResourceFileOutputName) {
name = $$relative_path($$1, $$_PRO_FILE_PWD_)
+ contains(name, ^\\.\\..*): name = $$relative_path($$1, $$OUT_PWD)
name = $$replace(name,/,_)
name = $$replace(name, \\.qrc$, _qmlcache.qrc)
name = $$replace(name,\.\.,)
@@ -35,7 +36,7 @@ for(res, RESOURCES) {
absRes = $$absolute_path($$res, $$_PRO_FILE_PWD_)
rccContents = $$system($$QMAKE_RCC_DEP -list $$system_quote($$absRes),lines)
- contains(rccContents,.*\\.js$)|contains(rccContents,.*\\.qml$) {
+ contains(rccContents,.*\\.js$)|contains(rccContents,.*\\.qml$)|contains(rccContents,.*\\.mjs$) {
new_resource = $$qmlCacheResourceFileOutputName($$res)
mkpath($$dirname(new_resource))
remaining_files = $$system($$QML_CACHEGEN_FILTER -filter-resource-file -o $$system_quote($$new_resource) $$system_quote($$absRes),lines)
@@ -49,7 +50,7 @@ for(res, RESOURCES) {
QMLCACHE_RESOURCE_FILES += $$absRes
for(candidate, rccContents) {
- contains(candidate,.*\\.js$)|contains(candidate,.*\\.qml$) {
+ contains(candidate,.*\\.js$)|contains(candidate,.*\\.qml$)|contains(candidate,.*\\.mjs$) {
QMLCACHE_FILES += $$candidate
}
}
@@ -70,6 +71,7 @@ defineReplace(qmlCacheOutputName) {
name = $$relative_path($$name, $$_PRO_FILE_PWD_)
name = $$replace(name, \\.qml$, _qml)
name = $$replace(name, \\.js$, _js)
+ name = $$replace(name, \\.mjs$, _mjs)
name = $$replace(name,/,_)
name = $$QMLCACHE_DIR/$${name}
return($${name})
diff --git a/tools/qmlcachegen/resourcefilemapper.cpp b/tools/qmlcachegen/resourcefilemapper.cpp
index c2fd057541..6a00b39f2e 100644
--- a/tools/qmlcachegen/resourcefilemapper.cpp
+++ b/tools/qmlcachegen/resourcefilemapper.cpp
@@ -67,7 +67,7 @@ QStringList ResourceFileMapper::qmlCompilerFiles() const
it != end; ++it) {
const QString &qrcPath = it.key();
const QString suffix = QFileInfo(qrcPath).suffix();
- if (suffix != QStringLiteral("qml") && suffix != QStringLiteral("js"))
+ if (suffix != QStringLiteral("qml") && suffix != QStringLiteral("js") && suffix != QStringLiteral("mjs"))
continue;
files << qrcPath;
}
diff --git a/tools/qmlcachegen/resourcefilter.cpp b/tools/qmlcachegen/resourcefilter.cpp
index 196dbd4a75..3ad6e9ca0d 100644
--- a/tools/qmlcachegen/resourcefilter.cpp
+++ b/tools/qmlcachegen/resourcefilter.cpp
@@ -139,7 +139,9 @@ int filterResourceFile(const QString &input, const QString &output)
if (currentFileName.isEmpty())
continue;
- if (!currentFileName.endsWith(QStringLiteral(".qml")) && !currentFileName.endsWith(QStringLiteral(".js"))) {
+ if (!currentFileName.endsWith(QStringLiteral(".qml"))
+ && !currentFileName.endsWith(QStringLiteral(".js"))
+ && !currentFileName.endsWith(QStringLiteral(".mjs"))) {
writer.writeStartElement(QStringLiteral("file"));
if (!fileAttributes.hasAttribute(QStringLiteral("alias")))
diff --git a/tools/qmljs/qmljs.cpp b/tools/qmljs/qmljs.cpp
index ea014f3beb..56d4a7d383 100644
--- a/tools/qmljs/qmljs.cpp
+++ b/tools/qmljs/qmljs.cpp
@@ -37,6 +37,7 @@
#include "private/qv4context_p.h"
#include "private/qv4script_p.h"
#include "private/qv4string_p.h"
+#include "private/qv4module_p.h"
#include "private/qqmlbuiltinfunctions_p.h"
#include <QtCore/QCoreApplication>
@@ -77,14 +78,29 @@ int main(int argc, char *argv[])
args.removeFirst();
bool runAsQml = false;
+ bool runAsModule = false;
bool cache = false;
if (!args.isEmpty()) {
+ if (args.constFirst() == QLatin1String("--jit")) {
+ qputenv("QV4_JIT_CALL_THRESHOLD", QByteArray("0"));
+ args.removeFirst();
+ }
+ if (args.constFirst() == QLatin1String("--interpret")) {
+ qputenv("QV4_FORCE_INTERPRETER", QByteArray("1"));
+ args.removeFirst();
+ }
+
if (args.constFirst() == QLatin1String("--qml")) {
runAsQml = true;
args.removeFirst();
}
+ if (args.constFirst() == QLatin1String("--module")) {
+ runAsModule = true;
+ args.removeFirst();
+ }
+
if (args.constFirst() == QLatin1String("--cache")) {
cache = true;
args.removeFirst();
@@ -104,8 +120,21 @@ int main(int argc, char *argv[])
QV4::GlobalExtensions::init(vm.globalObject, QJSEngine::ConsoleExtension | QJSEngine::GarbageCollectionExtension);
for (const QString &fn : qAsConst(args)) {
- QFile file(fn);
- if (file.open(QFile::ReadOnly)) {
+ QV4::ScopedValue result(scope);
+ if (runAsModule) {
+ auto moduleUnit = vm.loadModule(QUrl::fromLocalFile(QFileInfo(fn).absoluteFilePath()));
+ if (moduleUnit) {
+ if (moduleUnit->instantiate(&vm))
+ moduleUnit->evaluate();
+ } else {
+ vm.throwError(QStringLiteral("Could not load module file"));
+ }
+ } else {
+ QFile file(fn);
+ if (!file.open(QFile::ReadOnly)) {
+ std::cerr << "Error: cannot open file " << fn.toUtf8().constData() << std::endl;
+ return EXIT_FAILURE;
+ }
QScopedPointer<QV4::Script> script;
if (cache && QFile::exists(fn + QLatin1Char('c'))) {
QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = QV4::Compiler::Codegen::createUnitForLoading();
@@ -120,16 +149,15 @@ int main(int argc, char *argv[])
const QString code = QString::fromUtf8(file.readAll());
file.close();
- script.reset(new QV4::Script(ctx, QV4::Compiler::GlobalCode, code, fn));
+ script.reset(new QV4::Script(ctx, QV4::Compiler::ContextType::Global, code, fn));
script->parseAsBinding = runAsQml;
script->parse();
}
- QV4::ScopedValue result(scope);
if (!scope.engine->hasException) {
const auto unit = script->compilationUnit;
- if (cache && unit && !(unit->data->flags & QV4::CompiledData::Unit::StaticData)) {
- if (unit->data->sourceTimeStamp == 0) {
- const_cast<QV4::CompiledData::Unit*>(unit->data)->sourceTimeStamp = QFileInfo(fn).lastModified().toMSecsSinceEpoch();
+ if (cache && unit && !(unit->unitData()->flags & QV4::CompiledData::Unit::StaticData)) {
+ if (unit->unitData()->sourceTimeStamp == 0) {
+ const_cast<QV4::CompiledData::Unit*>(unit->unitData())->sourceTimeStamp = QFileInfo(fn).lastModified().toMSecsSinceEpoch();
}
QString saveError;
if (!unit->saveToDisk(QUrl::fromLocalFile(fn), &saveError)) {
@@ -140,20 +168,17 @@ int main(int argc, char *argv[])
result = script->run();
// std::cout << t.elapsed() << " ms. elapsed" << std::endl;
}
- if (scope.engine->hasException) {
- QV4::StackTrace trace;
- QV4::ScopedValue ex(scope, scope.engine->catchException(&trace));
- showException(ctx, ex, trace);
- return EXIT_FAILURE;
- }
- if (!result->isUndefined()) {
- if (! qgetenv("SHOW_EXIT_VALUE").isEmpty())
- std::cout << "exit value: " << qPrintable(result->toQString()) << std::endl;
- }
- } else {
- std::cerr << "Error: cannot open file " << fn.toUtf8().constData() << std::endl;
+ }
+ if (scope.engine->hasException) {
+ QV4::StackTrace trace;
+ QV4::ScopedValue ex(scope, scope.engine->catchException(&trace));
+ showException(ctx, ex, trace);
return EXIT_FAILURE;
}
+ if (!result->isUndefined()) {
+ if (! qgetenv("SHOW_EXIT_VALUE").isEmpty())
+ std::cout << "exit value: " << qPrintable(result->toQString()) << std::endl;
+ }
}
return EXIT_SUCCESS;
diff --git a/tools/qmlmin/main.cpp b/tools/qmlmin/main.cpp
index 5641e6348e..26833d2a08 100644
--- a/tools/qmlmin/main.cpp
+++ b/tools/qmlmin/main.cpp
@@ -57,15 +57,48 @@ class QmlminLexer: protected Lexer, public Directives
QString _fileName;
QString _directives;
+protected:
+ QVector<int> _stateStack;
+ QList<int> _tokens;
+ QList<QString> _tokenStrings;
+ int yytoken = -1;
+ QString yytokentext;
+
+ void lex() {
+ if (_tokens.isEmpty()) {
+ _tokens.append(Lexer::lex());
+ _tokenStrings.append(tokenText());
+ }
+
+ yytoken = _tokens.takeFirst();
+ yytokentext = _tokenStrings.takeFirst();
+ }
+
+ int lookaheadToken()
+ {
+ if (yytoken < 0)
+ lex();
+ return yytoken;
+ }
+
+ void pushToken(int token)
+ {
+ _tokens.prepend(yytoken);
+ _tokenStrings.prepend(yytokentext);
+ yytoken = token;
+ yytokentext = QString();
+ }
+
public:
- QmlminLexer(): Lexer(&_engine) {}
+ QmlminLexer()
+ : Lexer(&_engine), _stateStack(128) {}
virtual ~QmlminLexer() {}
QString fileName() const { return _fileName; }
bool operator()(const QString &fileName, const QString &code)
{
- int startToken = T_FEED_JS_PROGRAM;
+ int startToken = T_FEED_JS_SCRIPT;
const QFileInfo fileInfo(fileName);
if (fileInfo.suffix().toLower() == QLatin1String("qml"))
startToken = T_FEED_UI_PROGRAM;
@@ -154,6 +187,24 @@ protected:
ruleno == J_SCRIPT_REGEXPLITERAL_RULE2;
}
+ void handleLookaheads(int ruleno) {
+ if (ruleno == J_SCRIPT_EXPRESSIONSTATEMENTLOOKAHEAD_RULE) {
+ int token = lookaheadToken();
+ if (token == T_LBRACE)
+ pushToken(T_FORCE_BLOCK);
+ else if (token == T_FUNCTION || token == T_CLASS || token == T_LET || token == T_CONST)
+ pushToken(T_FORCE_DECLARATION);
+ } else if (ruleno == J_SCRIPT_CONCISEBODYLOOKAHEAD_RULE) {
+ int token = lookaheadToken();
+ if (token == T_LBRACE)
+ pushToken(T_FORCE_BLOCK);
+ } else if (ruleno == J_SCRIPT_EXPORTDECLARATIONLOOKAHEAD_RULE) {
+ int token = lookaheadToken();
+ if (token == T_FUNCTION || token == T_CLASS)
+ pushToken(T_FORCE_DECLARATION);
+ }
+ }
+
bool scanRestOfRegExp(int ruleno, QString *restOfRegExp)
{
if (! scanRegExp(ruleno == J_SCRIPT_REGEXPLITERAL_RULE1 ? Lexer::NoPrefix : Lexer::EqualPrefix))
@@ -187,9 +238,6 @@ protected:
class Minify: public QmlminLexer
{
- QVector<int> _stateStack;
- QList<int> _tokens;
- QList<QString> _tokenStrings;
QString _minifiedCode;
int _maxWidth;
int _width;
@@ -206,7 +254,7 @@ protected:
};
Minify::Minify(int maxWidth)
- : _stateStack(128), _maxWidth(maxWidth), _width(0)
+ : _maxWidth(maxWidth), _width(0)
{
}
@@ -250,16 +298,14 @@ void Minify::escape(const QChar &ch, QString *out)
bool Minify::parse(int startToken)
{
int yyaction = 0;
- int yytoken = -1;
int yytos = -1;
- QString yytokentext;
QString assembled;
_minifiedCode.clear();
_tokens.append(startToken);
_tokenStrings.append(QString());
- if (startToken == T_FEED_JS_PROGRAM) {
+ if (startToken == T_FEED_JS_SCRIPT) {
// parse optional pragma directive
DiagnosticMessage error;
if (scanDirectives(this, &error)) {
@@ -282,15 +328,8 @@ bool Minify::parse(int startToken)
_stateStack[yytos] = yyaction;
again:
- if (yytoken == -1 && action_index[yyaction] != -TERMINAL_COUNT) {
- if (_tokens.isEmpty()) {
- _tokens.append(lex());
- _tokenStrings.append(tokenText());
- }
-
- yytoken = _tokens.takeFirst();
- yytokentext = _tokenStrings.takeFirst();
- }
+ if (yytoken == -1 && action_index[yyaction] != -TERMINAL_COUNT)
+ lex();
yyaction = t_action(yyaction, yytoken);
if (yyaction > 0) {
@@ -366,6 +405,8 @@ bool Minify::parse(int startToken)
const int ruleno = -yyaction - 1;
yytos -= rhs[ruleno];
+ handleLookaheads(ruleno);
+
if (isRegExpRule(ruleno)) {
QString restOfRegExp;
@@ -398,13 +439,10 @@ bool Minify::parse(int startToken)
class Tokenize: public QmlminLexer
{
- QVector<int> _stateStack;
- QList<int> _tokens;
- QList<QString> _tokenStrings;
QStringList _minifiedCode;
public:
- Tokenize();
+ Tokenize() {}
QStringList tokenStream() const;
@@ -412,11 +450,6 @@ protected:
bool parse(int startToken) override;
};
-Tokenize::Tokenize()
- : _stateStack(128)
-{
-}
-
QStringList Tokenize::tokenStream() const
{
return _minifiedCode;
@@ -425,15 +458,13 @@ QStringList Tokenize::tokenStream() const
bool Tokenize::parse(int startToken)
{
int yyaction = 0;
- int yytoken = -1;
int yytos = -1;
- QString yytokentext;
_minifiedCode.clear();
_tokens.append(startToken);
_tokenStrings.append(QString());
- if (startToken == T_FEED_JS_PROGRAM) {
+ if (startToken == T_FEED_JS_SCRIPT) {
// parse optional pragma directive
DiagnosticMessage error;
if (scanDirectives(this, &error)) {
@@ -457,15 +488,8 @@ bool Tokenize::parse(int startToken)
_stateStack[yytos] = yyaction;
again:
- if (yytoken == -1 && action_index[yyaction] != -TERMINAL_COUNT) {
- if (_tokens.isEmpty()) {
- _tokens.append(lex());
- _tokenStrings.append(tokenText());
- }
-
- yytoken = _tokens.takeFirst();
- yytokentext = _tokenStrings.takeFirst();
- }
+ if (yytoken == -1 && action_index[yyaction] != -TERMINAL_COUNT)
+ lex();
yyaction = t_action(yyaction, yytoken);
if (yyaction > 0) {
@@ -484,6 +508,8 @@ bool Tokenize::parse(int startToken)
const int ruleno = -yyaction - 1;
yytos -= rhs[ruleno];
+ handleLookaheads(ruleno);
+
if (isRegExpRule(ruleno)) {
QString restOfRegExp;
diff --git a/tools/qmlplugindump/main.cpp b/tools/qmlplugindump/main.cpp
index 08fc0168dd..f5bd6d2291 100644
--- a/tools/qmlplugindump/main.cpp
+++ b/tools/qmlplugindump/main.cpp
@@ -76,9 +76,9 @@
namespace {
const uint qtQmlMajorVersion = 2;
-const uint qtQmlMinorVersion = 2;
+const uint qtQmlMinorVersion = QT_VERSION_MINOR;
const uint qtQuickMajorVersion = 2;
-const uint qtQuickMinorVersion = 8;
+const uint qtQuickMinorVersion = QT_VERSION_MINOR;
const QString qtQuickQualifiedName = QString::fromLatin1("QtQuick %1.%2")
.arg(qtQuickMajorVersion)
@@ -121,14 +121,14 @@ void collectReachableMetaObjects(QObject *object, QSet<const QMetaObject *> *met
const QMetaObject *meta = object->metaObject();
if (verbose)
- std::cerr << "Processing object" << qPrintable( meta->className() ) << std::endl;
+ std::cerr << "Processing object " << qPrintable( meta->className() ) << std::endl;
collectReachableMetaObjects(meta, metas);
for (int index = 0; index < meta->propertyCount(); ++index) {
QMetaProperty prop = meta->property(index);
if (QQmlMetaType::isQObject(prop.userType())) {
if (verbose)
- std::cerr << " Processing property" << qPrintable( prop.name() ) << std::endl;
+ std::cerr << " Processing property " << qPrintable( prop.name() ) << std::endl;
currentProperty = QString("%1::%2").arg(meta->className(), prop.name());
// if the property was not initialized during construction,
@@ -143,7 +143,7 @@ void collectReachableMetaObjects(QObject *object, QSet<const QMetaObject *> *met
void collectReachableMetaObjects(QQmlEnginePrivate *engine, const QQmlType &ty, QSet<const QMetaObject *> *metas)
{
- collectReachableMetaObjects(ty.metaObject(), metas, ty.isExtendedType());
+ collectReachableMetaObjects(ty.baseMetaObject(), metas, ty.isExtendedType());
if (ty.attachedPropertiesType(engine))
collectReachableMetaObjects(ty.attachedPropertiesType(engine), metas);
}
@@ -211,7 +211,7 @@ QByteArray convertToId(const QMetaObject *mo)
void collectReachableMetaObjectsWithoutQmlName(QQmlEnginePrivate *engine, QSet<const QMetaObject *>& metas ) {
const auto qmlAllTypes = QQmlMetaType::qmlAllTypes();
for (const QQmlType &ty : qmlAllTypes) {
- if ( ! metas.contains(ty.metaObject()) ) {
+ if (!metas.contains(ty.baseMetaObject())) {
if (!ty.isComposite()) {
collectReachableMetaObjects(engine, ty, &metas);
} else {
@@ -229,55 +229,20 @@ QSet<const QMetaObject *> collectReachableMetaObjects(QQmlEngine *engine,
QSet<const QMetaObject *> metas;
metas.insert(FriendlyQObject::qtMeta());
- QHash<QByteArray, QSet<QByteArray> > extensions;
const auto qmlTypes = QQmlMetaType::qmlTypes();
for (const QQmlType &ty : qmlTypes) {
if (!ty.isCreatable())
- noncreatables.insert(ty.metaObject());
+ noncreatables.insert(ty.baseMetaObject());
if (ty.isSingleton())
- singletons.insert(ty.metaObject());
+ singletons.insert(ty.baseMetaObject());
if (!ty.isComposite()) {
- qmlTypesByCppName[ty.metaObject()->className()].insert(ty);
- if (ty.isExtendedType())
- extensions[ty.typeName()].insert(ty.metaObject()->className());
+ qmlTypesByCppName[ty.baseMetaObject()->className()].insert(ty);
collectReachableMetaObjects(QQmlEnginePrivate::get(engine), ty, &metas);
} else {
qmlTypesByCompositeName[ty.elementName()].insert(ty);
}
}
- // Adjust exports of the base object if there are extensions.
- // For each export of a base object there can be a single extension object overriding it.
- // Example: QDeclarativeGraphicsWidget overrides the QtQuick/QGraphicsWidget export
- // of QGraphicsWidget.
- for (auto it = extensions.cbegin(), end = extensions.cend(); it != end; ++it) {
- QSet<QQmlType> baseExports = qmlTypesByCppName.value(it.key());
-
- const QSet<QByteArray> extensionCppNames = it.value();
- for (const QByteArray &extensionCppName : extensionCppNames) {
- const QSet<QQmlType> extensionExports = qmlTypesByCppName.value(extensionCppName);
-
- // remove extension exports from base imports
- // unfortunately the QQmlType pointers don't match, so can't use QSet::subtract
- QSet<QQmlType> newBaseExports;
- for (const QQmlType &baseExport : qAsConst(baseExports)) {
- bool match = false;
- for (const QQmlType &extensionExport : extensionExports) {
- if (baseExport.qmlTypeName() == extensionExport.qmlTypeName()
- && baseExport.majorVersion() == extensionExport.majorVersion()
- && baseExport.minorVersion() == extensionExport.minorVersion()) {
- match = true;
- break;
- }
- }
- if (!match)
- newBaseExports.insert(baseExport);
- }
- baseExports = newBaseExports;
- }
- qmlTypesByCppName[it.key()] = baseExports;
- }
-
if (creatable) {
// find even more QMetaObjects by instantiating QML types and running
// over the instances
@@ -334,7 +299,7 @@ QSet<const QMetaObject *> collectReachableMetaObjects(QQmlEngine *engine,
collectReachableMetaObjects(object, &metas);
object->deleteLater();
} else {
- std::cerr << "Could not create" << qPrintable(tyName) << std::endl;
+ std::cerr << "Could not create " << qPrintable(tyName) << std::endl;
}
}
}
@@ -402,15 +367,7 @@ public:
void writeMetaContent(const QMetaObject *meta, KnownAttributes *knownAttributes = nullptr)
{
- QSet<QString> implicitSignals;
- for (int index = meta->propertyOffset(); index < meta->propertyCount(); ++index) {
- const QMetaProperty &property = meta->property(index);
- dump(property, knownAttributes);
- if (knownAttributes)
- knownAttributes->knownMethod(QByteArray(property.name()).append("Changed"),
- 0, property.revision());
- implicitSignals.insert(QString("%1Changed").arg(QString::fromUtf8(property.name())));
- }
+ QSet<QString> implicitSignals = dumpMetaProperties(meta, 0, knownAttributes);
if (meta == &QObject::staticMetaObject) {
// for QObject, hide deleteLater() and onDestroyed
@@ -530,6 +487,27 @@ public:
qml->writeEndObject();
}
+ QString getDefaultProperty(const QMetaObject *meta)
+ {
+ for (int index = meta->classInfoCount() - 1; index >= 0; --index) {
+ QMetaClassInfo classInfo = meta->classInfo(index);
+ if (QLatin1String(classInfo.name()) == QLatin1String("DefaultProperty")) {
+ return QLatin1String(classInfo.value());
+ }
+ }
+ return QString();
+ }
+
+ struct QmlTypeInfo {
+ QmlTypeInfo() {}
+ QmlTypeInfo(const QString &exportString, int revision, const QMetaObject *extendedObject, QByteArray attachedTypeId)
+ : exportString(exportString), revision(revision), extendedObject(extendedObject), attachedTypeId(attachedTypeId) {}
+ QString exportString;
+ int revision = 0;
+ const QMetaObject *extendedObject = nullptr;
+ QByteArray attachedTypeId;
+ };
+
void dump(QQmlEnginePrivate *engine, const QMetaObject *meta, bool isUncreatable, bool isSingleton)
{
qml->writeStartObject("Component");
@@ -537,29 +515,58 @@ public:
QByteArray id = convertToId(meta);
qml->writeScriptBinding(QLatin1String("name"), enquote(id));
- for (int index = meta->classInfoCount() - 1 ; index >= 0 ; --index) {
- QMetaClassInfo classInfo = meta->classInfo(index);
- if (QLatin1String(classInfo.name()) == QLatin1String("DefaultProperty")) {
- qml->writeScriptBinding(QLatin1String("defaultProperty"), enquote(QLatin1String(classInfo.value())));
- break;
+ // collect type information
+ QVector<QmlTypeInfo> typeInfo;
+ for (QQmlType type : qmlTypesByCppName.value(meta->className())) {
+ const QMetaObject *extendedObject = type.extensionFunction() ? type.metaObject() : nullptr;
+ QByteArray attachedTypeId;
+ if (const QMetaObject *attachedType = type.attachedPropertiesType(engine)) {
+ // Can happen when a type is registered that returns itself as attachedPropertiesType()
+ // because there is no creatable type to attach to.
+ if (attachedType != meta)
+ attachedTypeId = convertToId(attachedType);
+ }
+ const QString exportString = getExportString(type.qmlTypeName(), type.majorVersion(), type.minorVersion());
+ int metaObjectRevision = type.metaObjectRevision();
+ if (extendedObject) {
+ // emulate custom metaobjectrevision out of import
+ metaObjectRevision = type.majorVersion() * 100 + type.minorVersion();
+ }
+
+ QmlTypeInfo info = { exportString, metaObjectRevision, extendedObject, attachedTypeId };
+ typeInfo.append(info);
+ }
+
+ // sort to ensure stable output
+ std::sort(typeInfo.begin(), typeInfo.end(), [](const QmlTypeInfo &i1, const QmlTypeInfo &i2) {
+ return i1.revision < i2.revision;
+ });
+
+ // determine default property
+ // TODO: support revisioning of default property
+ QString defaultProperty = getDefaultProperty(meta);
+ if (defaultProperty.isEmpty()) {
+ for (const QmlTypeInfo &iter : typeInfo) {
+ if (iter.extendedObject) {
+ defaultProperty = getDefaultProperty(iter.extendedObject);
+ if (!defaultProperty.isEmpty())
+ break;
+ }
}
}
+ if (!defaultProperty.isEmpty())
+ qml->writeScriptBinding(QLatin1String("defaultProperty"), enquote(defaultProperty));
if (meta->superClass())
qml->writeScriptBinding(QLatin1String("prototype"), enquote(convertToId(meta->superClass())));
- const QSet<QQmlType> qmlTypes = qmlTypesByCppName.value(meta->className());
- if (!qmlTypes.isEmpty()) {
- QHash<QString, QQmlType> exports;
-
- for (const QQmlType &qmlTy : qmlTypes) {
- const QString exportString = getExportString(qmlTy.qmlTypeName(), qmlTy.majorVersion(), qmlTy.minorVersion());
- exports.insert(exportString, qmlTy);
- }
+ if (!typeInfo.isEmpty()) {
+ QMap<QString, QString> exports; // sort exports
+ for (const QmlTypeInfo &iter : typeInfo)
+ exports.insert(iter.exportString, QString::number(iter.revision));
- // ensure exports are sorted and don't change order when the plugin is dumped again
QStringList exportStrings = exports.keys();
- std::sort(exportStrings.begin(), exportStrings.end());
+ QStringList metaObjectRevisions = exports.values();
qml->writeArrayBinding(QLatin1String("exports"), exportStrings);
if (isUncreatable)
@@ -568,20 +575,12 @@ public:
if (isSingleton)
qml->writeBooleanBinding(QLatin1String("isSingleton"), true);
- // write meta object revisions
- QStringList metaObjectRevisions;
- for (const QString &exportString : qAsConst(exportStrings)) {
- int metaObjectRevision = exports[exportString].metaObjectRevision();
- metaObjectRevisions += QString::number(metaObjectRevision);
- }
qml->writeArrayBinding(QLatin1String("exportMetaObjectRevisions"), metaObjectRevisions);
- if (const QMetaObject *attachedType = (*qmlTypes.begin()).attachedPropertiesType(engine)) {
- // Can happen when a type is registered that returns itself as attachedPropertiesType()
- // because there is no creatable type to attach to.
- if (attachedType != meta) {
- qml->writeScriptBinding(QLatin1String("attachedType"), enquote(
- convertToId(attachedType)));
+ for (const QmlTypeInfo &iter : typeInfo) {
+ if (!iter.attachedTypeId.isEmpty()) {
+ qml->writeScriptBinding(QLatin1String("attachedType"), enquote(iter.attachedTypeId));
+ break;
}
}
}
@@ -591,6 +590,12 @@ public:
writeMetaContent(meta);
+ // dump properties from extended metaobjects last
+ for (auto iter : typeInfo) {
+ if (iter.extendedObject)
+ dumpMetaProperties(iter.extendedObject, iter.revision);
+ }
+
qml->writeEndObject();
}
@@ -639,9 +644,9 @@ private:
qml->writeScriptBinding(QLatin1String("isPointer"), QLatin1String("true"));
}
- void dump(const QMetaProperty &prop, KnownAttributes *knownAttributes = nullptr)
+ void dump(const QMetaProperty &prop, int metaRevision = -1, KnownAttributes *knownAttributes = nullptr)
{
- int revision = prop.revision();
+ int revision = metaRevision ? metaRevision : prop.revision();
QByteArray propName = prop.name();
if (knownAttributes && knownAttributes->knownProperty(propName, revision))
return;
@@ -654,6 +659,20 @@ private:
qml->writeEndObject();
}
+ QSet<QString> dumpMetaProperties(const QMetaObject *meta, int metaRevision = -1, KnownAttributes *knownAttributes = nullptr)
+ {
+ QSet<QString> implicitSignals;
+ for (int index = meta->propertyOffset(); index < meta->propertyCount(); ++index) {
+ const QMetaProperty &property = meta->property(index);
+ dump(property, metaRevision, knownAttributes);
+ if (knownAttributes)
+ knownAttributes->knownMethod(QByteArray(property.name()).append("Changed"),
+ 0, property.revision());
+ implicitSignals.insert(QString("%1Changed").arg(QString::fromUtf8(property.name())));
+ }
+ return implicitSignals;
+ }
+
void dump(const QMetaMethod &meth, const QSet<QString> &implicitSignals,
KnownAttributes *knownAttributes = nullptr)
{
@@ -822,9 +841,11 @@ static bool getDependencies(const QQmlEngine &engine, const QString &pluginImpor
const QString &pluginImportVersion, QStringList *dependencies,
bool forceQtQuickDependency)
{
+ QString importScannerExe = QLatin1String("qmlimportscanner");
QFileInfo selfExe(QCoreApplication::applicationFilePath());
- QString command = selfExe.absoluteDir().filePath(QLatin1String("qmlimportscanner")
- + selfExe.suffix());
+ if (!selfExe.suffix().isEmpty())
+ importScannerExe += QLatin1String(".") + selfExe.suffix();
+ QString command = selfExe.absoluteDir().filePath(importScannerExe);
QStringList commandArgs = QStringList()
<< QLatin1String("-qmlFiles")
@@ -989,7 +1010,7 @@ int main(int argc, char *argv[])
#endif // QT_WIDGETS_LIB
QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR));
- const QStringList args = app->arguments();
+ QStringList args = app->arguments();
const QString appName = QFileInfo(app->applicationFilePath()).baseName();
if (args.size() < 2) {
printUsage(appName);
@@ -1021,6 +1042,10 @@ int main(int argc, char *argv[])
return EXIT_INVALIDARGUMENTS;
}
dependenciesFile = args.at(iArg);
+
+ // Remove absolute path so that it does not show up in the
+ // printed command line inside the plugins.qmltypes file.
+ args[iArg] = QFileInfo(args.at(iArg)).fileName();
} else if (arg == QLatin1String("--merge")
|| arg == QLatin1String("-merge")) {
if (++iArg == args.size()) {
diff --git a/tools/qmlpreview/main.cpp b/tools/qmlpreview/main.cpp
new file mode 100644
index 0000000000..c7a32da258
--- /dev/null
+++ b/tools/qmlpreview/main.cpp
@@ -0,0 +1,36 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmlpreviewapplication.h"
+
+int main(int argc, char *argv[])
+{
+ QmlPreviewApplication app(argc, argv);
+ app.parseArguments();
+ return app.exec();
+}
diff --git a/tools/qmlpreview/qmlpreview.pro b/tools/qmlpreview/qmlpreview.pro
new file mode 100644
index 0000000000..7d443b5f6c
--- /dev/null
+++ b/tools/qmlpreview/qmlpreview.pro
@@ -0,0 +1,13 @@
+QT = network core qmldebug-private
+CONFIG += no_import_scan
+
+SOURCES += \
+ main.cpp \
+ qmlpreviewapplication.cpp
+
+HEADERS += \
+ qmlpreviewapplication.h
+
+QMAKE_TARGET_DESCRIPTION = QML Preview
+
+load(qt_tool)
diff --git a/tools/qmlpreview/qmlpreviewapplication.cpp b/tools/qmlpreview/qmlpreviewapplication.cpp
new file mode 100644
index 0000000000..618769502c
--- /dev/null
+++ b/tools/qmlpreview/qmlpreviewapplication.cpp
@@ -0,0 +1,266 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmlpreviewapplication.h"
+
+#include <QtCore/QStringList>
+#include <QtCore/QTextStream>
+#include <QtCore/QProcess>
+#include <QtCore/QTimer>
+#include <QtCore/QDateTime>
+#include <QtCore/QFileInfo>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QCommandLineParser>
+#include <QtCore/QTemporaryFile>
+#include <QtCore/QUrl>
+
+QmlPreviewApplication::QmlPreviewApplication(int &argc, char **argv) :
+ QCoreApplication(argc, argv),
+ m_verbose(false),
+ m_connectionAttempts(0)
+{
+ m_connection.reset(new QQmlDebugConnection);
+ m_qmlPreviewClient.reset(new QQmlPreviewClient(m_connection.data()));
+ m_connectTimer.setInterval(1000);
+
+ m_loadTimer.setInterval(100);
+ m_loadTimer.setSingleShot(true);
+ connect(&m_loadTimer, &QTimer::timeout, this, [this]() {
+ m_qmlPreviewClient->triggerLoad(QUrl());
+ });
+
+ connect(&m_connectTimer, &QTimer::timeout, this, &QmlPreviewApplication::tryToConnect);
+ connect(m_connection.data(), &QQmlDebugConnection::connected, &m_connectTimer, &QTimer::stop);
+
+ connect(m_qmlPreviewClient.data(), &QQmlPreviewClient::error,
+ this, &QmlPreviewApplication::logError);
+ connect(m_qmlPreviewClient.data(), &QQmlPreviewClient::request,
+ this, &QmlPreviewApplication::serveRequest);
+
+ connect(&m_watcher, &QFileSystemWatcher::fileChanged,
+ this, &QmlPreviewApplication::sendFile);
+ connect(&m_watcher, &QFileSystemWatcher::directoryChanged,
+ this, &QmlPreviewApplication::sendDirectory);
+}
+
+QmlPreviewApplication::~QmlPreviewApplication()
+{
+ if (m_process && m_process->state() != QProcess::NotRunning) {
+ logStatus("Terminating process ...");
+ m_process->disconnect();
+ m_process->terminate();
+ if (!m_process->waitForFinished(1000)) {
+ logStatus("Killing process ...");
+ m_process->kill();
+ }
+ }
+}
+
+void QmlPreviewApplication::parseArguments()
+{
+ setApplicationName(QLatin1String("qmlpreview"));
+ setApplicationVersion(QLatin1String(qVersion()));
+
+ QCommandLineParser parser;
+ parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
+ parser.setOptionsAfterPositionalArgumentsMode(QCommandLineParser::ParseAsPositionalArguments);
+
+ parser.setApplicationDescription(QChar::LineFeed + tr(
+ "The QML Preview tool watches QML and JavaScript files on disk and updates\n"
+ "the application live with any changes. The application to be previewed\n"
+ "has to enable QML debugging. See the Qt Creator documentation on how to do\n"
+ "this for different Qt versions."));
+
+ QCommandLineOption verbose(QStringList() << QLatin1String("verbose"),
+ tr("Print debugging output."));
+ parser.addOption(verbose);
+
+ parser.addHelpOption();
+ parser.addVersionOption();
+
+ parser.addPositionalArgument(QLatin1String("program"),
+ tr("The program to be started and profiled."),
+ QLatin1String("[program]"));
+ parser.addPositionalArgument(QLatin1String("parameters"),
+ tr("Parameters for the program to be started."),
+ QLatin1String("[parameters...]"));
+
+ parser.process(*this);
+
+ QTemporaryFile file;
+ if (file.open())
+ m_socketFile = file.fileName();
+
+ if (parser.isSet(verbose))
+ m_verbose = true;
+
+ m_programArguments = parser.positionalArguments();
+ if (!m_programArguments.isEmpty())
+ m_programPath = m_programArguments.takeFirst();
+
+ if (m_programPath.isEmpty()) {
+ logError(tr("You have to specify a program to start."));
+ parser.showHelp(2);
+ }
+}
+
+int QmlPreviewApplication::exec()
+{
+ QTimer::singleShot(0, this, &QmlPreviewApplication::run);
+ return QCoreApplication::exec();
+}
+
+void QmlPreviewApplication::run()
+{
+ logStatus(QString("Listening on %1 ...").arg(m_socketFile));
+ m_connection->startLocalServer(m_socketFile);
+ m_process.reset(new QProcess(this));
+ QStringList arguments;
+ arguments << QString("-qmljsdebugger=file:%1,block,services:QmlPreview").arg(m_socketFile);
+ arguments << m_programArguments;
+
+ m_process->setProcessChannelMode(QProcess::MergedChannels);
+ connect(m_process.data(), &QIODevice::readyRead,
+ this, &QmlPreviewApplication::processHasOutput);
+ connect(m_process.data(), static_cast<void(QProcess::*)(int)>(&QProcess::finished),
+ this, [this](int){ processFinished(); });
+ logStatus(QString("Starting '%1 %2' ...").arg(m_programPath, arguments.join(QLatin1Char(' '))));
+ m_process->start(m_programPath, arguments);
+ if (!m_process->waitForStarted()) {
+ logError(QString("Could not run '%1': %2").arg(m_programPath, m_process->errorString()));
+ exit(1);
+ }
+ m_connectTimer.start();
+}
+
+void QmlPreviewApplication::tryToConnect()
+{
+ Q_ASSERT(!m_connection->isConnected());
+ ++m_connectionAttempts;
+
+ if (m_verbose && !(m_connectionAttempts % 5)) {// print every 5 seconds
+ logError(QString("No connection received on %1 for %2 seconds ...")
+ .arg(m_socketFile).arg(m_connectionAttempts));
+ }
+}
+
+void QmlPreviewApplication::processHasOutput()
+{
+ Q_ASSERT(m_process);
+ while (m_process->bytesAvailable()) {
+ QTextStream out(stderr);
+ out << m_process->readAll();
+ }
+}
+
+void QmlPreviewApplication::processFinished()
+{
+ Q_ASSERT(m_process);
+ int exitCode = 0;
+ if (m_process->exitStatus() == QProcess::NormalExit) {
+ logStatus(QString("Process exited (%1).").arg(m_process->exitCode()));
+ } else {
+ logError("Process crashed!");
+ exitCode = 3;
+ }
+ exit(exitCode);
+}
+
+void QmlPreviewApplication::logError(const QString &error)
+{
+ QTextStream err(stderr);
+ err << "Error: " << error << endl;
+}
+
+void QmlPreviewApplication::logStatus(const QString &status)
+{
+ if (!m_verbose)
+ return;
+ QTextStream err(stderr);
+ err << status << endl;
+}
+
+void QmlPreviewApplication::serveRequest(const QString &path)
+{
+ QFileInfo info(path);
+
+ if (info.isDir()) {
+ m_qmlPreviewClient->sendDirectory(path, QDir(path).entryList());
+ m_watcher.addPath(path);
+ } else {
+ QFile file(path);
+ if (file.open(QIODevice::ReadOnly)) {
+ m_qmlPreviewClient->sendFile(path, file.readAll());
+ m_watcher.addPath(path);
+
+ // Also watch the directory, because editors will rather replace a file than change it.
+ // Therefore when the file changes, we can't read it, but when the file is re-added we can
+ // see that from the directory changing.
+ m_watcher.addPath(info.absolutePath());
+ } else {
+ logStatus(QString("Could not open file %1 for reading: %2").arg(path)
+ .arg(file.errorString()));
+ m_qmlPreviewClient->sendError(path);
+ }
+ }
+}
+
+bool QmlPreviewApplication::sendFile(const QString &path)
+{
+ QFile file(path);
+ if (file.open(QIODevice::ReadOnly)) {
+ m_qmlPreviewClient->sendFile(path, file.readAll());
+ m_pendingFiles.removeAll(path);
+ // Defer the Load, because files tend to change multiple times in a row.
+ m_loadTimer.start();
+ return true;
+ }
+ if (!m_pendingFiles.contains(path))
+ m_pendingFiles.append(path);
+ logStatus(QString("Could not open file %1 for reading: %2").arg(path).arg(file.errorString()));
+ return false;
+}
+
+void QmlPreviewApplication::sendDirectory(const QString &path)
+{
+ m_qmlPreviewClient->sendDirectory(path, QDir(path).entryList());
+ for (auto it = m_pendingFiles.begin(); it != m_pendingFiles.end();) {
+ const QString filePath = *it;
+ QFile file(filePath);
+ if (file.open(QIODevice::ReadOnly)) {
+ logStatus(QString("Sending replaced file %1.").arg(filePath));
+ m_qmlPreviewClient->sendFile(filePath, file.readAll());
+ m_watcher.addPath(filePath);
+ it = m_pendingFiles.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ m_loadTimer.start();
+}
diff --git a/tools/qmlpreview/qmlpreviewapplication.h b/tools/qmlpreview/qmlpreviewapplication.h
new file mode 100644
index 0000000000..eb363b0eb6
--- /dev/null
+++ b/tools/qmlpreview/qmlpreviewapplication.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMLPREVIEWAPPLICATION_H
+#define QMLPREVIEWAPPLICATION_H
+
+#include <private/qqmlpreviewclient_p.h>
+#include <private/qqmldebugconnection_p.h>
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qprocess.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qfilesystemwatcher.h>
+
+#include <QtNetwork/qabstractsocket.h>
+
+class QmlPreviewApplication : public QCoreApplication
+{
+ Q_OBJECT
+public:
+ QmlPreviewApplication(int &argc, char **argv);
+ ~QmlPreviewApplication();
+
+ void parseArguments();
+ int exec();
+
+private:
+ void run();
+ void tryToConnect();
+ void processHasOutput();
+ void processFinished();
+
+ void logError(const QString &error);
+ void logStatus(const QString &status);
+
+ void serveRequest(const QString &request);
+ bool sendFile(const QString &path);
+ void sendDirectory(const QString &path);
+
+ QString m_programPath;
+ QStringList m_programArguments;
+ QScopedPointer<QProcess> m_process;
+ bool m_verbose;
+
+ QString m_socketFile;
+
+ QScopedPointer<QQmlDebugConnection> m_connection;
+ QScopedPointer<QQmlPreviewClient> m_qmlPreviewClient;
+ QFileSystemWatcher m_watcher;
+
+ QTimer m_loadTimer;
+ QTimer m_connectTimer;
+ uint m_connectionAttempts;
+
+ QStringList m_pendingFiles;
+};
+
+#endif // QMLPREVIEWAPPLICATION_H
diff --git a/tools/qmlprofiler/qmlprofilerapplication.cpp b/tools/qmlprofiler/qmlprofilerapplication.cpp
index 0b63a91e5b..6732766b46 100644
--- a/tools/qmlprofiler/qmlprofilerapplication.cpp
+++ b/tools/qmlprofiler/qmlprofilerapplication.cpp
@@ -120,6 +120,10 @@ QmlProfilerApplication::~QmlProfilerApplication()
logStatus("Killing process ...");
m_process->kill();
}
+ if (isInteractive()) {
+ QTextStream err(stderr);
+ err << endl;
+ }
delete m_process;
}
@@ -366,7 +370,7 @@ void QmlProfilerApplication::userCommand(const QString &command)
m_pendingRequest = REQUEST_NONE;
prompt();
} else {
- prompt(tr("The application is still generating data. Really quit (y/n)?"));
+ prompt(tr("Really quit (y/n)?"));
}
return;
}
diff --git a/tools/qmlprofiler/qmlprofilerclient.cpp b/tools/qmlprofiler/qmlprofilerclient.cpp
index b69c7e73e1..f6cc6f39fe 100644
--- a/tools/qmlprofiler/qmlprofilerclient.cpp
+++ b/tools/qmlprofiler/qmlprofilerclient.cpp
@@ -57,6 +57,8 @@ QmlProfilerClient::QmlProfilerClient(QQmlDebugConnection *connection, QmlProfile
{
Q_D(QmlProfilerClient);
setRequestedFeatures(std::numeric_limits<quint64>::max());
+ connect(this, &QQmlDebugClient::stateChanged,
+ this, &QmlProfilerClient::onStateChanged);
connect(this, &QQmlProfilerClient::traceStarted,
d->data, &QmlProfilerData::setTraceStartTime);
connect(this, &QQmlProfilerClient::traceFinished,
@@ -65,7 +67,7 @@ QmlProfilerClient::QmlProfilerClient(QQmlDebugConnection *connection, QmlProfile
d->data, &QmlProfilerData::complete);
}
-void QmlProfilerClient::stateChanged(State state)
+void QmlProfilerClient::onStateChanged(State state)
{
Q_D(QmlProfilerClient);
if ((d->enabled && state != Enabled) || (!d->enabled && state == Enabled)) {
diff --git a/tools/qmlprofiler/qmlprofilerclient.h b/tools/qmlprofiler/qmlprofilerclient.h
index 30f4a51751..7355688222 100644
--- a/tools/qmlprofiler/qmlprofilerclient.h
+++ b/tools/qmlprofiler/qmlprofilerclient.h
@@ -48,7 +48,7 @@ signals:
void error(const QString &error);
private:
- void stateChanged(State state) override;
+ void onStateChanged(State state);
};
#endif // QMLPROFILERCLIENT_H
diff --git a/tools/qmlscene/main.cpp b/tools/qmlscene/main.cpp
index bc7fe72d4c..4d18a868a2 100644
--- a/tools/qmlscene/main.cpp
+++ b/tools/qmlscene/main.cpp
@@ -51,8 +51,10 @@
#ifdef QT_WIDGETS_LIB
#include <QtWidgets/QApplication>
+#if QT_CONFIG(filedialog)
#include <QtWidgets/QFileDialog>
#endif
+#endif
#include <QtCore/QTranslator>
#include <QtCore/QLibraryInfo>
@@ -311,7 +313,7 @@ static void displayFileDialog(Options *options)
#if QT_CONFIG(translation)
static void loadTranslationFile(QTranslator &translator, const QString& directory)
{
- translator.load(QLatin1String("qml_" )+QLocale::system().name(), directory + QLatin1String("/i18n"));
+ translator.load(QLocale(), QLatin1String("qml"), QLatin1String("_"), directory + QLatin1String("/i18n"));
QCoreApplication::installTranslator(&translator);
}
#endif
@@ -549,12 +551,12 @@ int main(int argc, char ** argv)
}
#if QT_CONFIG(translation)
- QTranslator translator;
+ QLocale locale;
QTranslator qtTranslator;
- QString sysLocale = QLocale::system().name();
- if (qtTranslator.load(QLatin1String("qt_") + sysLocale, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
+ if (qtTranslator.load(locale, QLatin1String("qt"), QLatin1String("_"), QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
app->installTranslator(&qtTranslator);
- if (translator.load(QLatin1String("qmlscene_") + sysLocale, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
+ QTranslator translator;
+ if (translator.load(locale, QLatin1String("qmlscene"), QLatin1String("_"), QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
app->installTranslator(&translator);
QTranslator qmlTranslator;
diff --git a/tools/tools.pro b/tools/tools.pro
index 856906cc53..3f5f23eb32 100644
--- a/tools/tools.pro
+++ b/tools/tools.pro
@@ -1,17 +1,21 @@
TEMPLATE = subdirs
QT_FOR_CONFIG += qml-private
-SUBDIRS += \
- qmlmin \
- qmlimportscanner
-qtConfig(commandlineparser):qtConfig(xmlstreamwriter): SUBDIRS += qmlcachegen
+qtConfig(qml-devtools) {
+ SUBDIRS += \
+ qmlmin \
+ qmlimportscanner
+
+ qtConfig(commandlineparser):qtConfig(xmlstreamwriter): SUBDIRS += qmlcachegen
+}
-!android|android_app {
+qtConfig(thread):!android|android_app {
SUBDIRS += \
- qml \
- qmllint
+ qml
+ qtConfig(qml-devtools): SUBDIRS += qmllint
qtConfig(qml-profiler): SUBDIRS += qmlprofiler
+ qtConfig(qml-preview): SUBDIRS += qmlpreview
qtHaveModule(quick) {
!static: {
@@ -30,8 +34,10 @@ qtConfig(commandlineparser):qtConfig(xmlstreamwriter): SUBDIRS += qmlcachegen
qtConfig(private_tests): SUBDIRS += qmljs
}
-qml.depends = qmlimportscanner
-qmleasing.depends = qmlimportscanner
+qtConfig(qml-devtools) {
+ qml.depends = qmlimportscanner
+ qmleasing.depends = qmlimportscanner
+}
# qmlmin, qmlimportscanner & qmlcachegen are build tools.
# qmlscene is needed by the autotests.