diff --git a/src/plugins/qmldesigner/boilerplate.qrc b/src/plugins/qmldesigner/boilerplate.qrc index 2680ec0da9c..3e2106beaa0 100644 --- a/src/plugins/qmldesigner/boilerplate.qrc +++ b/src/plugins/qmldesigner/boilerplate.qrc @@ -1,5 +1,10 @@ qmlprojectmaincpp.tpl + qmlprojectmaincppheader.tpl + qmlprojectmodules.tpl + qmlprojectmaincmakelists.tpl + qmlprojectmodulecmakelists.tpl + qmlprojectmainqml.tpl diff --git a/src/plugins/qmldesigner/generatecmakelists.cpp b/src/plugins/qmldesigner/generatecmakelists.cpp index feeaa2fe19e..24faa267397 100644 --- a/src/plugins/qmldesigner/generatecmakelists.cpp +++ b/src/plugins/qmldesigner/generatecmakelists.cpp @@ -78,7 +78,7 @@ void onGenerateCmakeLists() { queuedFiles.clear(); FilePath rootDir = ProjectExplorer::SessionManager::startupProject()->projectDirectory(); - GenerateCmakeLists::generateMainCmake(rootDir); + GenerateCmakeLists::generateCmakes(rootDir); GenerateEntryPoints::generateMainCpp(rootDir); GenerateEntryPoints::generateMainQml(rootDir); if (showConfirmationDialog(rootDir)) @@ -139,138 +139,125 @@ bool writeFile(const GeneratableFile &file) return true; } +QString readTemplate(const QString &templatePath) +{ + QFile templatefile(templatePath); + templatefile.open(QIODevice::ReadOnly); + QTextStream stream(&templatefile); + QString content = stream.readAll(); + templatefile.close(); + + return content; +} + } namespace GenerateCmakeLists { +QStringList moduleNames; + const QDir::Filters FILES_ONLY = QDir::Files; const QDir::Filters DIRS_ONLY = QDir::Dirs|QDir::Readable|QDir::NoDotAndDotDot; const char CMAKEFILENAME[] = "CMakeLists.txt"; const char QMLDIRFILENAME[] = "qmldir"; +const char MODULEFILENAME[] = "qmlmodules"; -QStringList processDirectory(const FilePath &dir) +bool generateCmakes(const FilePath &rootDir) { - QStringList moduleNames; + moduleNames.clear(); - FilePaths files = dir.dirEntries(FILES_ONLY); - for (FilePath &file : files) { - if (!file.fileName().compare(CMAKEFILENAME)) - files.removeAll(file); - } + FilePath contentDir = rootDir.pathAppended("content"); + FilePath importDir = rootDir.pathAppended("imports"); - if (files.isEmpty()) { - generateSubdirCmake(dir); - FilePaths subDirs = dir.dirEntries(DIRS_ONLY); - for (FilePath &subDir : subDirs) { - QStringList subDirModules = processDirectory(subDir); - moduleNames.append(subDirModules); - } - } - else { - QString moduleName = generateModuleCmake(dir); - if (!moduleName.isEmpty()) { - moduleNames.append(moduleName); - } - } + generateModuleCmake(contentDir); + generateImportCmake(importDir); + generateMainCmake(rootDir); - return moduleNames; + return true; } -const char MAINFILE_REQUIRED_VERSION[] = "cmake_minimum_required(VERSION 3.18)\n\n"; -const char MAINFILE_PROJECT[] = "project(%1 LANGUAGES CXX)\n\n"; -const char MAINFILE_CMAKE_OPTIONS[] = "set(CMAKE_INCLUDE_CURRENT_DIR ON)\nset(CMAKE_AUTOMOC ON)\n\n"; -const char MAINFILE_PACKAGES[] = "find_package(Qt6 COMPONENTS Gui Qml Quick)\n"; -const char MAINFILE_LIBRARIES[] = "set(QT_QML_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/qml)\n\n"; -const char MAINFILE_CPP[] = "add_executable(%1 main.cpp)\n\n"; -const char MAINFILE_MAINMODULE[] = "qt6_add_qml_module(%1\n\tURI \"Main\"\n\tVERSION 1.0\n\tNO_PLUGIN\n\tQML_FILES main.qml\n)\n\n"; -const char MAINFILE_LINK_LIBRARIES[] = "target_link_libraries(%1 PRIVATE\n\tQt${QT_VERSION_MAJOR}::Core\n\tQt${QT_VERSION_MAJOR}::Gui\n\tQt${QT_VERSION_MAJOR}::Quick\n\tQt${QT_VERSION_MAJOR}::Qml\n)\n\n"; - -const char ADD_SUBDIR[] = "add_subdirectory(%1)\n"; +const char MAIN_CMAKEFILE_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmaincmakelists.tpl"; +const char QMLMODULES_FILE_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmodules.tpl"; void generateMainCmake(const FilePath &rootDir) { //TODO startupProject() may be a terrible way to try to get "current project". It's not necessarily the same thing at all. QString projectName = ProjectExplorer::SessionManager::startupProject()->displayName(); + QString appName = projectName + "App"; - FilePaths subDirs = rootDir.dirEntries(DIRS_ONLY); + QString cmakeFileContent = GenerateCmake::readTemplate(MAIN_CMAKEFILE_TEMPLATE_PATH).arg(appName); + queueCmakeFile(rootDir, cmakeFileContent); + QString modulesAsPlugins; + for (const QString &moduleName : moduleNames) + modulesAsPlugins.append(" " + moduleName + "plugin\n"); + + QString moduleFileContent = GenerateCmake::readTemplate(QMLMODULES_FILE_TEMPLATE_PATH).arg(appName).arg(modulesAsPlugins); + GenerateCmake::queueFile(rootDir.pathAppended(MODULEFILENAME), moduleFileContent); +} + +const char DO_NOT_EDIT_FILE_COMMENT[] = "### This file is automatically generated by Qt Design Studio.\n### Do not change\n\n"; +const char ADD_SUBDIR[] = "add_subdirectory(%1)\n"; + +void generateImportCmake(const FilePath &dir) +{ QString fileContent; - fileContent.append(MAINFILE_REQUIRED_VERSION); - fileContent.append(QString(MAINFILE_PROJECT).arg(projectName)); - fileContent.append(MAINFILE_CMAKE_OPTIONS); - fileContent.append(MAINFILE_PACKAGES); - fileContent.append(QString(MAINFILE_CPP).arg(projectName)); - fileContent.append(QString(MAINFILE_MAINMODULE).arg(projectName)); - fileContent.append(MAINFILE_LIBRARIES); + fileContent.append(DO_NOT_EDIT_FILE_COMMENT); + + FilePaths subDirs = dir.dirEntries(DIRS_ONLY); for (FilePath &subDir : subDirs) { - QStringList subDirModules = processDirectory(subDir); - if (!subDirModules.isEmpty()) - fileContent.append(QString(ADD_SUBDIR).arg(subDir.fileName())); + fileContent.append(QString(ADD_SUBDIR).arg(subDir.fileName())); + generateModuleCmake(subDir); } - fileContent.append("\n"); - fileContent.append(QString(MAINFILE_LINK_LIBRARIES).arg(projectName)); - - createCmakeFile(rootDir, fileContent); + queueCmakeFile(dir, fileContent); } const char MODULEFILE_PROPERTY_SINGLETON[] = "QT_QML_SINGLETON_TYPE"; -const char MODULEFILE_PROPERTY_SET[] = "set_source_files_properties(%1\n\tPROPERTIES\n\t\t%2 %3\n)\n\n"; -const char MODULEFILE_CREATE_MODULE[] = "qt6_add_qml_module(%1\n\tURI \"%1\"\n\tVERSION 1.0\n%2)\n\n"; +const char MODULEFILE_PROPERTY_SET[] = "set_source_files_properties(%1\n PROPERTIES\n %2 %3\n)\n\n"; +const char MODULEFILE_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmodulecmakelists.tpl"; - -QString generateModuleCmake(const FilePath &dir) +void generateModuleCmake(const FilePath &dir) { - QString fileContent; + QString fileTemplate = GenerateCmake::readTemplate(MODULEFILE_TEMPLATE_PATH); const QStringList qmldirFilesOnly(QMLDIRFILENAME); + QString singletonContent; FilePaths qmldirFileList = dir.dirEntries(qmldirFilesOnly, FILES_ONLY); if (!qmldirFileList.isEmpty()) { QStringList singletons = getSingletonsFromQmldirFile(qmldirFileList.first()); for (QString &singleton : singletons) { - fileContent.append(QString(MODULEFILE_PROPERTY_SET).arg(singleton).arg(MODULEFILE_PROPERTY_SINGLETON).arg("true")); + singletonContent.append(QString(MODULEFILE_PROPERTY_SET).arg(singleton).arg(MODULEFILE_PROPERTY_SINGLETON).arg("true")); } } QStringList qmlFileList = getDirectoryTreeQmls(dir); QString qmlFiles; for (QString &qmlFile : qmlFileList) - qmlFiles.append(QString("\t\t%1\n").arg(qmlFile)); + qmlFiles.append(QString(" %1\n").arg(qmlFile)); QStringList resourceFileList = getDirectoryTreeResources(dir); QString resourceFiles; for (QString &resourceFile : resourceFileList) - resourceFiles.append(QString("\t\t%1\n").arg(resourceFile)); + resourceFiles.append(QString(" %1\n").arg(resourceFile)); QString moduleContent; if (!qmlFiles.isEmpty()) { - moduleContent.append(QString("\tQML_FILES\n%1").arg(qmlFiles)); + moduleContent.append(QString(" QML_FILES\n%1").arg(qmlFiles)); } if (!resourceFiles.isEmpty()) { - moduleContent.append(QString("\tRESOURCES\n%1").arg(resourceFiles)); + moduleContent.append(QString(" RESOURCES\n%1").arg(resourceFiles)); } QString moduleName = dir.fileName(); - fileContent.append(QString(MODULEFILE_CREATE_MODULE).arg(moduleName).arg(moduleContent)); + moduleNames.append(moduleName); - createCmakeFile(dir, fileContent); - - return moduleName; -} - -void generateSubdirCmake(const FilePath &dir) -{ QString fileContent; - FilePaths subDirs = dir.dirEntries(DIRS_ONLY); - - for (FilePath &subDir : subDirs) { - fileContent.append(QString(ADD_SUBDIR).arg(subDir.fileName())); - } - - createCmakeFile(dir, fileContent); + fileContent.append(fileTemplate.arg(singletonContent).arg(moduleName).arg(moduleContent)); + queueCmakeFile(dir, fileContent); } QStringList getSingletonsFromQmldirFile(const FilePath &filePath) @@ -347,7 +334,7 @@ QStringList getDirectoryTreeResources(const FilePath &dir) return resourceFileList; } -void createCmakeFile(const FilePath &dir, const QString &content) +void queueCmakeFile(const FilePath &dir, const QString &content) { FilePath filePath = dir.pathAppended(CMAKEFILENAME); GenerateCmake::queueFile(filePath, content); @@ -370,35 +357,42 @@ bool generateEntryPointFiles(const FilePath &dir) return cppOk && qmlOk; } -const char MAIN_CPPFILE_CONTENT[] = ":/boilerplatetemplates/qmlprojectmaincpp.tpl"; +const char MAIN_CPPFILE_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmaincpp.tpl"; +const char MAIN_CPPFILE_DIR[] = "src"; const char MAIN_CPPFILE_NAME[] = "main.cpp"; +const char MAIN_CPPFILE_HEADER_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmaincppheader.tpl"; +const char MAIN_CPPFILE_HEADER_NAME[] = "import_qml_plugins.h"; +const char MAIN_CPPFILE_HEADER_PLUGIN_LINE[] = "Q_IMPORT_QML_PLUGIN(%1)\n"; bool generateMainCpp(const FilePath &dir) { - QFile templatefile(MAIN_CPPFILE_CONTENT); - templatefile.open(QIODevice::ReadOnly); - QTextStream stream(&templatefile); - QString content = stream.readAll(); - templatefile.close(); + FilePath srcDir = dir.pathAppended(MAIN_CPPFILE_DIR); - FilePath filePath = dir.pathAppended(MAIN_CPPFILE_NAME); - return GenerateCmake::queueFile(filePath, content); + QString cppContent = GenerateCmake::readTemplate(MAIN_CPPFILE_TEMPLATE_PATH); + FilePath cppFilePath = srcDir.pathAppended(MAIN_CPPFILE_NAME); + bool cppOk = GenerateCmake::queueFile(cppFilePath, cppContent); + + QString modulesAsPlugins; + for (const QString &moduleName : GenerateCmakeLists::moduleNames) + modulesAsPlugins.append( + QString(MAIN_CPPFILE_HEADER_PLUGIN_LINE).arg(moduleName + "plugin")); + + QString headerContent = GenerateCmake::readTemplate(MAIN_CPPFILE_HEADER_TEMPLATE_PATH) + .arg(modulesAsPlugins); + FilePath headerFilePath = srcDir.pathAppended(MAIN_CPPFILE_HEADER_NAME); + bool headerOk = GenerateCmake::queueFile(headerFilePath, headerContent); + + return cppOk && headerOk; } -const char MAIN_QMLFILE_CONTENT[] = "import %1Qml\n\n%2 {\n}\n"; +const char MAIN_QMLFILE_PATH[] = ":/boilerplatetemplates/qmlprojectmainqml.tpl"; const char MAIN_QMLFILE_NAME[] = "main.qml"; bool generateMainQml(const FilePath &dir) { + QString content = GenerateCmake::readTemplate(MAIN_QMLFILE_PATH); FilePath filePath = dir.pathAppended(MAIN_QMLFILE_NAME); - QString projectName = ProjectExplorer::SessionManager::startupProject()->displayName(); - ProjectExplorer::RunConfiguration *runConfiguration = ProjectExplorer::SessionManager::startupRunConfiguration(); - QString mainClass; - - if (const auto aspect = runConfiguration->aspect()) - mainClass = FilePath::fromString(aspect->mainScript()).baseName(); - - return GenerateCmake::queueFile(filePath, QString(MAIN_QMLFILE_CONTENT).arg(projectName).arg(mainClass)); + return GenerateCmake::queueFile(filePath, content); } } diff --git a/src/plugins/qmldesigner/generatecmakelists.h b/src/plugins/qmldesigner/generatecmakelists.h index d1603a1860b..b9f225e9465 100644 --- a/src/plugins/qmldesigner/generatecmakelists.h +++ b/src/plugins/qmldesigner/generatecmakelists.h @@ -45,16 +45,17 @@ bool showConfirmationDialog(const Utils::FilePath &rootDir); bool queueFile(const Utils::FilePath &filePath, const QString &fileContent); bool writeFile(const GeneratableFile &file); bool writeQueuedFiles(); +QString readTemplate(const QString &templatePath); } namespace GenerateCmakeLists { +bool generateCmakes(const Utils::FilePath &rootDir); void generateMainCmake(const Utils::FilePath &rootDir); -void generateSubdirCmake(const Utils::FilePath &dir); -QString generateModuleCmake(const Utils::FilePath &dir); -QStringList processDirectory(const Utils::FilePath &dir); +void generateImportCmake(const Utils::FilePath &dir); +void generateModuleCmake(const Utils::FilePath &dir); QStringList getSingletonsFromQmldirFile(const Utils::FilePath &filePath); QStringList getDirectoryTreeQmls(const Utils::FilePath &dir); QStringList getDirectoryTreeResources(const Utils::FilePath &dir); -void createCmakeFile(const Utils::FilePath &filePath, const QString &content); +void queueCmakeFile(const Utils::FilePath &filePath, const QString &content); bool isFileBlacklisted(const QString &fileName); } namespace GenerateEntryPoints { diff --git a/src/plugins/qmldesigner/qmlprojectmaincmakelists.tpl b/src/plugins/qmldesigner/qmlprojectmaincmakelists.tpl new file mode 100644 index 00000000000..926f7b43be9 --- /dev/null +++ b/src/plugins/qmldesigner/qmlprojectmaincmakelists.tpl @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.18) + +project(%1 LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_AUTOMOC ON) + +find_package(Qt6 COMPONENTS Gui Qml Quick) +add_executable(%1 src/main.cpp) + +target_link_libraries(%1 PRIVATE + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::Gui + Qt${QT_VERSION_MAJOR}::Quick + Qt${QT_VERSION_MAJOR}::Qml +) + +include(${CMAKE_CURRENT_SOURCE_DIR}/qmlmodules) + diff --git a/src/plugins/qmldesigner/qmlprojectmaincppheader.tpl b/src/plugins/qmldesigner/qmlprojectmaincppheader.tpl new file mode 100644 index 00000000000..60cef09a82c --- /dev/null +++ b/src/plugins/qmldesigner/qmlprojectmaincppheader.tpl @@ -0,0 +1,8 @@ +/* + * This file is automatically generated by Qt Design Studio. + * Do not change. +*/ + +#include + +%1 diff --git a/src/plugins/qmldesigner/qmlprojectmainqml.tpl b/src/plugins/qmldesigner/qmlprojectmainqml.tpl new file mode 100644 index 00000000000..fa8f6d1cc18 --- /dev/null +++ b/src/plugins/qmldesigner/qmlprojectmainqml.tpl @@ -0,0 +1,6 @@ +import QtQuick +import content + +App { +} + diff --git a/src/plugins/qmldesigner/qmlprojectmodulecmakelists.tpl b/src/plugins/qmldesigner/qmlprojectmodulecmakelists.tpl new file mode 100644 index 00000000000..46132d8c1a4 --- /dev/null +++ b/src/plugins/qmldesigner/qmlprojectmodulecmakelists.tpl @@ -0,0 +1,11 @@ +### This file is automatically generated by Qt Design Studio. +### Do not change + +%1 + +qt_add_library(%2 STATIC) +qt6_add_qml_module(%2 + URI "%2" + VERSION 1.0 +%3 +) diff --git a/src/plugins/qmldesigner/qmlprojectmodules.tpl b/src/plugins/qmldesigner/qmlprojectmodules.tpl new file mode 100644 index 00000000000..2cae6017cc3 --- /dev/null +++ b/src/plugins/qmldesigner/qmlprojectmodules.tpl @@ -0,0 +1,16 @@ +### This file is automatically generated by Qt Design Studio. +### Do not change + +qt6_add_qml_module(%1 + URI "Main" + VERSION 1.0 + NO_PLUGIN + QML_FILES main.qml +) + +add_subdirectory(content) +add_subdirectory(imports) + +target_link_libraries(%1 PRIVATE +%2 +)