2022-08-19 15:59:36 +02:00
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
2021-10-06 12:35:52 +03:00
# include "generatecmakelists.h"
2021-11-22 13:41:20 +02:00
# include "generatecmakelistsconstants.h"
2021-11-03 11:37:48 +02:00
# include "cmakegeneratordialog.h"
2021-10-06 12:35:52 +03:00
# include <coreplugin/actionmanager/actionmanager.h>
# include <coreplugin/actionmanager/actioncontainer.h>
2021-12-10 14:53:00 +02:00
# include <projectexplorer/buildsystem.h>
2021-10-06 12:35:52 +03:00
# include <projectexplorer/projectexplorerconstants.h>
# include <projectexplorer/project.h>
# include <projectexplorer/session.h>
2021-12-10 14:53:00 +02:00
# include <projectexplorer/target.h>
2021-10-06 12:35:52 +03:00
2022-11-30 15:43:04 +01:00
# include <qmlprojectmanager/qmlmainfileaspect.h>
2021-12-10 14:53:00 +02:00
# include <qmlprojectmanager/qmlproject.h>
2021-10-06 12:35:52 +03:00
# include <qmlprojectmanager/qmlprojectmanagerconstants.h>
# include <utils/fileutils.h>
# include <QAction>
2022-11-30 15:43:04 +01:00
# include <QMenu>
2021-11-17 12:18:35 +02:00
# include <QMessageBox>
2021-10-06 12:35:52 +03:00
# include <QRegularExpression>
# include <QStringList>
2021-10-12 13:30:14 +02:00
# include <QTextStream>
2022-11-30 15:43:04 +01:00
# include <QtConcurrent>
2021-10-06 12:35:52 +03:00
using namespace Utils ;
2022-05-11 15:45:41 +03:00
using namespace QmlProjectManager : : GenerateCmake : : Constants ;
2021-10-06 12:35:52 +03:00
2022-05-11 15:45:41 +03:00
namespace QmlProjectManager {
2021-10-06 12:35:52 +03:00
2021-10-20 17:37:22 +03:00
namespace GenerateCmake {
2021-10-06 12:35:52 +03:00
2021-11-03 11:37:48 +02:00
bool operator = = ( const GeneratableFile & left , const GeneratableFile & right )
{
return ( left . filePath = = right . filePath & & left . content = = right . content ) ;
}
2021-11-17 12:18:35 +02:00
enum ProjectDirectoryError {
2021-11-18 10:49:26 +01:00
NoError = 0 ,
MissingContentDir = 1 < < 1 ,
MissingImportDir = 1 < < 2 ,
2022-02-18 20:22:19 +01:00
MissingAssetDir = 1 < < 3 ,
MissingAssetImportDir = 1 < < 4 ,
MissingCppDir = 1 < < 5 ,
MissingMainCMake = 1 < < 6 ,
MissingMainQml = 1 < < 7 ,
MissingAppMainQml = 1 < < 8 ,
MissingQmlModules = 1 < < 9 ,
MissingMainCpp = 1 < < 10 ,
MissingMainCppHeader = 1 < < 11 ,
MissingEnvHeader = 1 < < 12
2021-11-17 12:18:35 +02:00
} ;
2022-02-18 20:22:19 +01:00
const QString MENU_ITEM_GENERATE = QCoreApplication : : translate ( " QmlDesigner::GenerateCmake " ,
2022-11-30 15:43:04 +01:00
" Generate CMake Build Files... " ) ;
2021-11-03 11:37:48 +02:00
2022-06-27 14:24:35 +02:00
void generateMenuEntry ( QObject * parent )
2021-10-06 12:35:52 +03:00
{
2022-11-30 15:43:04 +01:00
Core : : ActionContainer * menu = Core : : ActionManager : : actionContainer ( Core : : Constants : : M_FILE ) ;
Core : : ActionContainer * exportMenu = Core : : ActionManager : : createMenu (
QmlProjectManager : : Constants : : EXPORT_MENU ) ;
exportMenu - > menu ( ) - > setTitle (
QCoreApplication : : translate ( " QmlDesigner::GenerateCmake " , " Export Project " ) ) ;
menu - > addMenu ( exportMenu , Core : : Constants : : G_FILE_EXPORT ) ;
exportMenu - > appendGroup ( QmlProjectManager : : Constants : : G_EXPORT_GENERATE ) ;
exportMenu - > appendGroup ( QmlProjectManager : : Constants : : G_EXPORT_CONVERT ) ;
exportMenu - > addSeparator ( QmlProjectManager : : Constants : : G_EXPORT_CONVERT ) ;
2022-06-27 14:24:35 +02:00
auto action = new QAction ( MENU_ITEM_GENERATE , parent ) ;
2021-10-20 17:37:22 +03:00
QObject : : connect ( action , & QAction : : triggered , GenerateCmake : : onGenerateCmakeLists ) ;
2021-10-06 12:35:52 +03:00
Core : : Command * cmd = Core : : ActionManager : : registerAction ( action , " QmlProject.CreateCMakeLists " ) ;
2022-11-30 15:43:04 +01:00
exportMenu - > addAction ( cmd , QmlProjectManager : : Constants : : G_EXPORT_GENERATE ) ;
2021-10-06 12:35:52 +03:00
2022-07-20 10:36:44 +02:00
action - > setEnabled ( false ) ;
2021-10-06 12:35:52 +03:00
QObject : : connect ( ProjectExplorer : : SessionManager : : instance ( ) ,
2022-07-20 10:36:44 +02:00
& ProjectExplorer : : SessionManager : : startupProjectChanged ,
[ action ] ( ) {
auto qmlProject = qobject_cast < QmlProject * > (
ProjectExplorer : : SessionManager : : startupProject ( ) ) ;
action - > setEnabled ( qmlProject ! = nullptr ) ;
} ) ;
2021-10-06 12:35:52 +03:00
}
void onGenerateCmakeLists ( )
{
2021-10-20 17:37:22 +03:00
FilePath rootDir = ProjectExplorer : : SessionManager : : startupProject ( ) - > projectDirectory ( ) ;
2021-11-17 12:18:35 +02:00
int projectDirErrors = isProjectCorrectlyFormed ( rootDir ) ;
2021-11-18 10:49:26 +01:00
if ( projectDirErrors ! = NoError ) {
2021-11-17 12:18:35 +02:00
showProjectDirErrorDialog ( projectDirErrors ) ;
if ( isErrorFatal ( projectDirErrors ) )
return ;
}
2022-02-18 20:22:19 +01:00
CmakeFileGenerator cmakeGen ;
cmakeGen . prepare ( rootDir ) ;
FilePaths allFiles ;
for ( const GeneratableFile & file : cmakeGen . fileQueue ( ) . queuedFiles ( ) )
allFiles . append ( file . filePath ) ;
CmakeGeneratorDialog dialog ( rootDir , allFiles ) ;
if ( dialog . exec ( ) ) {
FilePaths confirmedFiles = dialog . getFilePaths ( ) ;
cmakeGen . filterFileQueue ( confirmedFiles ) ;
cmakeGen . execute ( ) ;
}
2021-11-03 11:37:48 +02:00
}
2021-11-17 12:18:35 +02:00
bool isErrorFatal ( int error )
{
2021-11-18 10:49:26 +01:00
if ( error & MissingContentDir | |
error & MissingImportDir | |
error & MissingCppDir | |
error & MissingAppMainQml )
2021-11-17 12:18:35 +02:00
return true ;
return false ;
}
int isProjectCorrectlyFormed ( const FilePath & rootDir )
{
2021-11-18 10:49:26 +01:00
int errors = NoError ;
2021-11-17 12:18:35 +02:00
if ( ! rootDir . pathAppended ( DIRNAME_CONTENT ) . exists ( ) )
2021-11-18 10:49:26 +01:00
errors | = MissingContentDir ;
2021-11-17 12:18:35 +02:00
if ( ! rootDir . pathAppended ( DIRNAME_CONTENT ) . pathAppended ( FILENAME_APPMAINQML ) . exists ( ) )
2021-11-18 10:49:26 +01:00
errors | = MissingAppMainQml ;
2021-11-17 12:18:35 +02:00
if ( ! rootDir . pathAppended ( DIRNAME_IMPORT ) . exists ( ) )
2021-11-18 10:49:26 +01:00
errors | = MissingImportDir ;
2022-02-18 20:22:19 +01:00
if ( ! rootDir . pathAppended ( DIRNAME_ASSETIMPORT ) . exists ( ) )
2021-11-29 19:34:43 +02:00
errors | = MissingAssetImportDir ;
2021-11-17 12:18:35 +02:00
if ( ! rootDir . pathAppended ( DIRNAME_CPP ) . exists ( ) )
2021-11-18 10:49:26 +01:00
errors | = MissingCppDir ;
2021-11-17 12:18:35 +02:00
if ( ! rootDir . pathAppended ( DIRNAME_CPP ) . pathAppended ( FILENAME_MAINCPP ) . exists ( ) )
2021-11-18 10:49:26 +01:00
errors | = MissingMainCpp ;
2021-11-17 12:18:35 +02:00
if ( ! rootDir . pathAppended ( DIRNAME_CPP ) . pathAppended ( FILENAME_MAINCPP_HEADER ) . exists ( ) )
2021-11-18 10:49:26 +01:00
errors | = MissingMainCppHeader ;
2021-12-10 14:53:00 +02:00
if ( ! rootDir . pathAppended ( DIRNAME_CPP ) . pathAppended ( FILENAME_ENV_HEADER ) . exists ( ) )
errors | = MissingEnvHeader ;
2021-11-17 12:18:35 +02:00
if ( ! rootDir . pathAppended ( FILENAME_CMAKELISTS ) . exists ( ) )
2021-11-18 10:49:26 +01:00
errors | = MissingMainCMake ;
2021-11-17 12:18:35 +02:00
if ( ! rootDir . pathAppended ( FILENAME_MODULES ) . exists ( ) )
2021-11-18 10:49:26 +01:00
errors | = MissingQmlModules ;
2021-11-17 12:18:35 +02:00
if ( ! rootDir . pathAppended ( FILENAME_MAINQML ) . exists ( ) )
2021-11-18 10:49:26 +01:00
errors | = MissingMainQml ;
2021-11-17 12:18:35 +02:00
return errors ;
}
2021-11-19 13:46:03 +02:00
const QString WARNING_MISSING_STRUCTURE_FATAL = QCoreApplication : : translate ( " QmlDesigner::GenerateCmake " ,
2021-11-17 12:18:35 +02:00
" The project is not properly structured for automatically generating CMake files. \n \n Aborting process. \n \n The following files or directories are missing: \n \n %1 " ) ;
2021-12-27 12:18:58 +02:00
//const QString WARNING_MISSING_STRUCTURE_NONFATAL = QCoreApplication::translate("QmlDesigner::GenerateCmake",
// "The project is not properly structured for automatically generating CMake files.\n\nThe following files or directories are missing and may be created:\n\n%1");
2021-11-19 13:46:03 +02:00
const QString WARNING_TITLE_FATAL = QCoreApplication : : translate ( " QmlDesigner::GenerateCmake " ,
2021-11-17 12:18:35 +02:00
" Cannot Generate CMake Files " ) ;
2021-12-27 12:18:58 +02:00
//const QString WARNING_TITLE_NONFATAL = QCoreApplication::translate("QmlDesigner::GenerateCmake",
// "Problems with Generating CMake Files");
2021-11-17 12:18:35 +02:00
void showProjectDirErrorDialog ( int error )
{
bool isFatal = isErrorFatal ( error ) ;
if ( isFatal ) {
2021-12-27 12:18:58 +02:00
QString fatalList ;
if ( error & MissingContentDir )
fatalList . append ( QString ( DIRNAME_CONTENT ) + " \n " ) ;
if ( error & MissingAppMainQml )
fatalList . append ( QString ( DIRNAME_CONTENT )
+ QDir : : separator ( )
+ QString ( FILENAME_APPMAINQML )
+ " \n " ) ;
if ( error & MissingCppDir )
fatalList . append ( QString ( DIRNAME_CPP ) + " \n " ) ;
if ( error & MissingImportDir )
fatalList . append ( QString ( DIRNAME_IMPORT ) + " \n " ) ;
2021-11-17 12:18:35 +02:00
QMessageBox : : critical ( nullptr ,
WARNING_TITLE_FATAL ,
2021-12-27 12:18:58 +02:00
WARNING_MISSING_STRUCTURE_FATAL . arg ( fatalList ) ) ;
2021-11-17 12:18:35 +02:00
}
}
2022-02-18 20:22:19 +01:00
bool FileQueue : : queueFile ( const FilePath & filePath , const QString & fileContent )
2021-11-03 11:37:48 +02:00
{
GeneratableFile file ;
file . filePath = filePath ;
file . content = fileContent ;
2021-11-17 12:18:35 +02:00
file . fileExists = filePath . exists ( ) ;
2022-02-18 20:22:19 +01:00
m_queuedFiles . append ( file ) ;
2021-11-03 11:37:48 +02:00
return true ;
}
2022-02-18 20:22:19 +01:00
const QVector < GeneratableFile > FileQueue : : queuedFiles ( ) const
2021-11-03 11:37:48 +02:00
{
2022-02-18 20:22:19 +01:00
return m_queuedFiles ;
}
bool FileQueue : : writeQueuedFiles ( )
{
for ( GeneratableFile & file : m_queuedFiles )
2021-11-03 11:37:48 +02:00
if ( ! writeFile ( file ) )
return false ;
return true ;
2021-10-20 17:37:22 +03:00
}
2022-02-18 20:22:19 +01:00
bool FileQueue : : writeFile ( const GeneratableFile & file )
2021-10-20 17:37:22 +03:00
{
2021-11-03 11:37:48 +02:00
QFile fileHandle ( file . filePath . toString ( ) ) ;
fileHandle . open ( QIODevice : : WriteOnly ) ;
QTextStream stream ( & fileHandle ) ;
stream < < file . content ;
fileHandle . close ( ) ;
2021-10-20 17:37:22 +03:00
return true ;
2021-10-06 12:35:52 +03:00
}
2022-02-18 20:22:19 +01:00
void FileQueue : : filterFiles ( const Utils : : FilePaths keepFiles )
{
QtConcurrent : : blockingFilter ( m_queuedFiles , [ keepFiles ] ( const GeneratableFile & qf ) {
return keepFiles . contains ( qf . filePath ) ;
} ) ;
}
2021-11-11 18:36:48 +02:00
QString readTemplate ( const QString & templatePath )
{
QFile templatefile ( templatePath ) ;
templatefile . open ( QIODevice : : ReadOnly ) ;
QTextStream stream ( & templatefile ) ;
QString content = stream . readAll ( ) ;
templatefile . close ( ) ;
return content ;
}
2022-02-18 20:22:19 +01:00
const QString projectEnvironmentVariable ( const QString & key )
{
QString value = { } ;
2021-10-20 17:37:22 +03:00
2022-02-18 20:22:19 +01:00
auto * target = ProjectExplorer : : SessionManager : : startupProject ( ) - > activeTarget ( ) ;
if ( target & & target - > buildSystem ( ) ) {
auto buildSystem = qobject_cast < QmlProjectManager : : QmlBuildSystem * > ( target - > buildSystem ( ) ) ;
if ( buildSystem ) {
auto envItems = buildSystem - > environment ( ) ;
auto confEnv = std : : find_if ( envItems . begin ( ) , envItems . end ( ) ,
[ key ] ( NameValueItem & item ) { return item . name = = key ; } ) ;
if ( confEnv ! = envItems . end ( ) )
value = confEnv - > value ;
}
}
return value ;
}
2021-11-11 18:36:48 +02:00
2021-10-20 17:37:22 +03:00
const QDir : : Filters FILES_ONLY = QDir : : Files ;
const QDir : : Filters DIRS_ONLY = QDir : : Dirs | QDir : : Readable | QDir : : NoDotAndDotDot ;
2021-11-17 12:18:35 +02:00
const char MAIN_CMAKEFILE_TEMPLATE_PATH [ ] = " :/boilerplatetemplates/qmlprojectmaincmakelists.tpl " ;
const char QMLMODULES_FILE_TEMPLATE_PATH [ ] = " :/boilerplatetemplates/qmlprojectmodules.tpl " ;
2021-10-20 17:37:22 +03:00
2022-02-18 20:22:19 +01:00
bool CmakeFileGenerator : : prepare ( const FilePath & rootDir , bool checkFileBelongs )
2021-10-06 12:35:52 +03:00
{
2022-02-18 20:22:19 +01:00
m_checkFileIsInProject = checkFileBelongs ;
2021-10-06 12:35:52 +03:00
2021-11-29 19:34:43 +02:00
FilePath contentDir = rootDir . pathAppended ( DIRNAME_CONTENT ) ;
FilePath importDir = rootDir . pathAppended ( DIRNAME_IMPORT ) ;
2022-02-18 20:22:19 +01:00
FilePath assetImportDir = rootDir . pathAppended ( DIRNAME_ASSETIMPORT ) ;
2021-10-06 12:35:52 +03:00
2021-11-11 18:36:48 +02:00
generateModuleCmake ( contentDir ) ;
generateImportCmake ( importDir ) ;
2022-02-18 20:22:19 +01:00
generateImportCmake ( assetImportDir ) ;
2021-11-11 18:36:48 +02:00
generateMainCmake ( rootDir ) ;
2022-02-18 20:22:19 +01:00
generateEntryPointFiles ( rootDir ) ;
2021-10-06 12:35:52 +03:00
2021-11-11 18:36:48 +02:00
return true ;
2021-10-06 12:35:52 +03:00
}
2022-02-18 20:22:19 +01:00
const FileQueue CmakeFileGenerator : : fileQueue ( ) const
{
return m_fileQueue ;
}
void CmakeFileGenerator : : filterFileQueue ( const Utils : : FilePaths & keepFiles )
{
m_fileQueue . filterFiles ( keepFiles ) ;
}
bool CmakeFileGenerator : : execute ( )
{
return m_fileQueue . writeQueuedFiles ( ) ;
}
2021-11-29 19:34:43 +02:00
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 " ;
2022-02-18 20:22:19 +01:00
void CmakeFileGenerator : : generateMainCmake ( const FilePath & rootDir )
2021-10-06 12:35:52 +03:00
{
//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 ( ) ;
2021-11-11 18:36:48 +02:00
QString appName = projectName + " App " ;
2021-10-06 12:35:52 +03:00
2022-02-18 20:22:19 +01:00
QString fileSection = " " ;
const QString qtcontrolsConfFile = GenerateCmake : : projectEnvironmentVariable ( ENV_VARIABLE_CONTROLCONF ) ;
if ( ! qtcontrolsConfFile . isEmpty ( ) )
fileSection = QString ( " FILES \n %1 " ) . arg ( qtcontrolsConfFile ) ;
QString cmakeFileContent = GenerateCmake : : readTemplate ( MAIN_CMAKEFILE_TEMPLATE_PATH )
. arg ( appName )
. arg ( fileSection ) ;
2021-11-11 18:36:48 +02:00
queueCmakeFile ( rootDir , cmakeFileContent ) ;
2021-11-29 19:34:43 +02:00
QString subdirIncludes ;
subdirIncludes . append ( QString ( ADD_SUBDIR ) . arg ( DIRNAME_CONTENT ) ) ;
subdirIncludes . append ( QString ( ADD_SUBDIR ) . arg ( DIRNAME_IMPORT ) ) ;
2022-02-18 20:22:19 +01:00
if ( rootDir . pathAppended ( DIRNAME_ASSETIMPORT ) . exists ( ) )
subdirIncludes . append ( QString ( ADD_SUBDIR ) . arg ( DIRNAME_ASSETIMPORT ) ) ;
2021-11-29 19:34:43 +02:00
2021-11-11 18:36:48 +02:00
QString modulesAsPlugins ;
2022-02-18 20:22:19 +01:00
for ( const QString & moduleName : m_moduleNames )
2021-11-11 18:36:48 +02:00
modulesAsPlugins . append ( " " + moduleName + " plugin \n " ) ;
2021-11-29 19:34:43 +02:00
QString moduleFileContent = GenerateCmake : : readTemplate ( QMLMODULES_FILE_TEMPLATE_PATH )
. arg ( appName )
. arg ( subdirIncludes )
. arg ( modulesAsPlugins ) ;
2022-02-18 20:22:19 +01:00
m_fileQueue . queueFile ( rootDir . pathAppended ( FILENAME_MODULES ) , moduleFileContent ) ;
2021-11-11 18:36:48 +02:00
}
2021-10-06 12:35:52 +03:00
2022-02-18 20:22:19 +01:00
void CmakeFileGenerator : : generateImportCmake ( const FilePath & dir , const QString & modulePrefix )
2021-11-11 18:36:48 +02:00
{
2021-11-29 19:34:43 +02:00
if ( ! dir . exists ( ) )
return ;
2021-10-06 12:35:52 +03:00
QString fileContent ;
2021-11-11 18:36:48 +02:00
fileContent . append ( DO_NOT_EDIT_FILE_COMMENT ) ;
FilePaths subDirs = dir . dirEntries ( DIRS_ONLY ) ;
2021-10-06 12:35:52 +03:00
for ( FilePath & subDir : subDirs ) {
2021-11-29 19:34:43 +02:00
if ( isDirBlacklisted ( subDir ) )
continue ;
if ( getDirectoryTreeQmls ( subDir ) . isEmpty ( ) & & getDirectoryTreeResources ( subDir ) . isEmpty ( ) )
continue ;
2021-11-11 18:36:48 +02:00
fileContent . append ( QString ( ADD_SUBDIR ) . arg ( subDir . fileName ( ) ) ) ;
2021-11-29 19:34:43 +02:00
QString prefix = modulePrefix . isEmpty ( ) ?
modulePrefix % subDir . fileName ( ) :
QString ( modulePrefix + ' . ' ) + subDir . fileName ( ) ;
if ( getDirectoryQmls ( subDir ) . isEmpty ( ) ) {
generateImportCmake ( subDir , prefix ) ;
} else {
generateModuleCmake ( subDir , prefix ) ;
}
2021-10-06 12:35:52 +03:00
}
2021-11-11 18:36:48 +02:00
queueCmakeFile ( dir , fileContent ) ;
2021-10-06 12:35:52 +03:00
}
const char MODULEFILE_PROPERTY_SINGLETON [ ] = " QT_QML_SINGLETON_TYPE " ;
2021-11-11 18:36:48 +02:00
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 " ;
2021-10-06 12:35:52 +03:00
2022-02-18 20:22:19 +01:00
void CmakeFileGenerator : : generateModuleCmake ( const FilePath & dir , const QString & uri )
2021-10-06 12:35:52 +03:00
{
2021-11-11 18:36:48 +02:00
QString fileTemplate = GenerateCmake : : readTemplate ( MODULEFILE_TEMPLATE_PATH ) ;
2021-10-06 12:35:52 +03:00
2021-11-11 18:36:48 +02:00
QString singletonContent ;
2022-01-21 12:22:54 +01:00
FilePaths qmldirFileList = dir . dirEntries ( { QStringList ( FILENAME_QMLDIR ) , FILES_ONLY } ) ;
2021-10-06 12:35:52 +03:00
if ( ! qmldirFileList . isEmpty ( ) ) {
QStringList singletons = getSingletonsFromQmldirFile ( qmldirFileList . first ( ) ) ;
for ( QString & singleton : singletons ) {
2021-11-11 18:36:48 +02:00
singletonContent . append ( QString ( MODULEFILE_PROPERTY_SET ) . arg ( singleton ) . arg ( MODULEFILE_PROPERTY_SINGLETON ) . arg ( " true " ) ) ;
2021-10-06 12:35:52 +03:00
}
}
2021-10-18 12:02:58 +03:00
QStringList qmlFileList = getDirectoryTreeQmls ( dir ) ;
2021-10-06 12:35:52 +03:00
QString qmlFiles ;
2021-10-18 12:02:58 +03:00
for ( QString & qmlFile : qmlFileList )
2021-11-11 18:36:48 +02:00
qmlFiles . append ( QString ( " %1 \n " ) . arg ( qmlFile ) ) ;
2021-10-06 12:35:52 +03:00
QStringList resourceFileList = getDirectoryTreeResources ( dir ) ;
QString resourceFiles ;
2021-10-18 12:02:58 +03:00
for ( QString & resourceFile : resourceFileList )
2021-11-11 18:36:48 +02:00
resourceFiles . append ( QString ( " %1 \n " ) . arg ( resourceFile ) ) ;
2021-10-06 12:35:52 +03:00
QString moduleContent ;
if ( ! qmlFiles . isEmpty ( ) ) {
2021-11-11 18:36:48 +02:00
moduleContent . append ( QString ( " QML_FILES \n %1 " ) . arg ( qmlFiles ) ) ;
2021-10-06 12:35:52 +03:00
}
if ( ! resourceFiles . isEmpty ( ) ) {
2021-11-11 18:36:48 +02:00
moduleContent . append ( QString ( " RESOURCES \n %1 " ) . arg ( resourceFiles ) ) ;
2021-10-06 12:35:52 +03:00
}
2021-11-29 19:34:43 +02:00
QString moduleUri = uri . isEmpty ( ) ?
dir . fileName ( ) :
uri ;
2022-02-18 20:22:19 +01:00
2022-02-16 16:07:59 +02:00
QString moduleName = QString ( moduleUri ) . replace ( ' . ' , ' _ ' ) ;
2022-02-18 20:22:19 +01:00
m_moduleNames . append ( moduleName ) ;
2021-10-06 12:35:52 +03:00
QString fileContent ;
2021-11-29 19:34:43 +02:00
fileContent . append ( fileTemplate . arg ( singletonContent , moduleName , moduleUri , moduleContent ) ) ;
2021-11-11 18:36:48 +02:00
queueCmakeFile ( dir , fileContent ) ;
2021-10-06 12:35:52 +03:00
}
2022-02-18 20:22:19 +01:00
QStringList CmakeFileGenerator : : getSingletonsFromQmldirFile ( const FilePath & filePath )
2021-10-06 12:35:52 +03:00
{
QStringList singletons ;
QFile f ( filePath . toString ( ) ) ;
f . open ( QIODevice : : ReadOnly ) ;
QTextStream stream ( & f ) ;
while ( ! stream . atEnd ( ) ) {
QString line = stream . readLine ( ) ;
if ( line . startsWith ( " singleton " , Qt : : CaseInsensitive ) ) {
QStringList tokenizedLine = line . split ( QRegularExpression ( " \\ s+ " ) ) ;
QString fileName = tokenizedLine . last ( ) ;
if ( fileName . endsWith ( " .qml " , Qt : : CaseInsensitive ) ) {
singletons . append ( fileName ) ;
}
}
}
f . close ( ) ;
return singletons ;
}
2022-02-18 20:22:19 +01:00
QStringList CmakeFileGenerator : : getDirectoryQmls ( const FilePath & dir )
2021-11-29 19:34:43 +02:00
{
2022-02-18 20:22:19 +01:00
QStringList moduleFiles ;
const QStringList qmlFilesOnly ( FILENAME_FILTER_QML ) ;
2022-01-21 12:22:54 +01:00
FilePaths allFiles = dir . dirEntries ( { qmlFilesOnly , FILES_ONLY } ) ;
2021-11-29 19:34:43 +02:00
for ( FilePath & file : allFiles ) {
2022-02-18 20:22:19 +01:00
if ( includeFile ( file ) ) {
moduleFiles . append ( file . fileName ( ) ) ;
2021-11-29 19:34:43 +02:00
}
}
return moduleFiles ;
}
2022-02-18 20:22:19 +01:00
QStringList CmakeFileGenerator : : getDirectoryResources ( const FilePath & dir )
2021-10-18 12:02:58 +03:00
{
2022-02-18 20:22:19 +01:00
QStringList moduleFiles ;
2021-10-18 12:02:58 +03:00
2022-02-18 20:22:19 +01:00
FilePaths allFiles = dir . dirEntries ( FILES_ONLY ) ;
for ( FilePath & file : allFiles ) {
if ( ! file . fileName ( ) . endsWith ( " .qml " , Qt : : CaseInsensitive ) & &
includeFile ( file ) ) {
moduleFiles . append ( file . fileName ( ) ) ;
2021-10-18 12:02:58 +03:00
}
}
2022-02-18 20:22:19 +01:00
return moduleFiles ;
}
QStringList CmakeFileGenerator : : getDirectoryTreeQmls ( const FilePath & dir )
{
QStringList qmlFileList ;
qmlFileList . append ( getDirectoryQmls ( dir ) ) ;
2021-10-18 12:02:58 +03:00
FilePaths subDirsList = dir . dirEntries ( DIRS_ONLY ) ;
for ( FilePath & subDir : subDirsList ) {
2021-11-29 19:34:43 +02:00
if ( isDirBlacklisted ( subDir ) )
continue ;
2021-10-18 12:02:58 +03:00
QStringList subDirQmlFiles = getDirectoryTreeQmls ( subDir ) ;
for ( QString & qmlFile : subDirQmlFiles ) {
qmlFileList . append ( subDir . fileName ( ) . append ( ' / ' ) . append ( qmlFile ) ) ;
}
}
return qmlFileList ;
}
2022-02-18 20:22:19 +01:00
QStringList CmakeFileGenerator : : getDirectoryTreeResources ( const FilePath & dir )
2021-10-06 12:35:52 +03:00
{
QStringList resourceFileList ;
2022-02-18 20:22:19 +01:00
resourceFileList . append ( getDirectoryResources ( dir ) ) ;
2021-10-06 12:35:52 +03:00
FilePaths subDirsList = dir . dirEntries ( DIRS_ONLY ) ;
for ( FilePath & subDir : subDirsList ) {
2021-11-29 19:34:43 +02:00
if ( isDirBlacklisted ( subDir ) )
continue ;
2021-10-06 12:35:52 +03:00
QStringList subDirResources = getDirectoryTreeResources ( subDir ) ;
for ( QString & resource : subDirResources ) {
resourceFileList . append ( subDir . fileName ( ) . append ( ' / ' ) . append ( resource ) ) ;
}
}
return resourceFileList ;
}
2022-02-18 20:22:19 +01:00
void CmakeFileGenerator : : queueCmakeFile ( const FilePath & dir , const QString & content )
2021-10-06 12:35:52 +03:00
{
2021-11-22 13:41:20 +02:00
FilePath filePath = dir . pathAppended ( FILENAME_CMAKELISTS ) ;
2022-02-18 20:22:19 +01:00
m_fileQueue . queueFile ( filePath , content ) ;
2021-10-06 12:35:52 +03:00
}
2022-02-18 20:22:19 +01:00
bool CmakeFileGenerator : : isFileBlacklisted ( const QString & fileName )
2021-10-06 12:35:52 +03:00
{
2021-11-22 13:41:20 +02:00
return ( ! fileName . compare ( FILENAME_QMLDIR ) | |
! fileName . compare ( FILENAME_CMAKELISTS ) ) ;
2021-10-06 12:35:52 +03:00
}
2022-02-18 20:22:19 +01:00
bool CmakeFileGenerator : : isDirBlacklisted ( const FilePath & dir )
2021-11-29 19:34:43 +02:00
{
return ( ! dir . fileName ( ) . compare ( DIRNAME_DESIGNER ) ) ;
}
2022-02-18 20:22:19 +01:00
bool CmakeFileGenerator : : includeFile ( const FilePath & filePath )
{
if ( m_checkFileIsInProject ) {
ProjectExplorer : : Project * project = ProjectExplorer : : SessionManager : : startupProject ( ) ;
if ( ! project - > isKnownFile ( filePath ) )
return false ;
}
return ! isFileBlacklisted ( filePath . fileName ( ) ) ;
2021-10-06 12:35:52 +03:00
}
2021-10-20 17:37:22 +03:00
2022-02-18 20:22:19 +01:00
bool CmakeFileGenerator : : generateEntryPointFiles ( const FilePath & dir )
2021-10-20 17:37:22 +03:00
{
2022-02-18 20:22:19 +01:00
const QString qtcontrolsConf = GenerateCmake : : projectEnvironmentVariable ( ENV_VARIABLE_CONTROLCONF ) ;
if ( ! qtcontrolsConf . isEmpty ( ) )
m_resourceFileLocations . append ( qtcontrolsConf ) ;
2021-10-20 17:37:22 +03:00
bool cppOk = generateMainCpp ( dir ) ;
bool qmlOk = generateMainQml ( dir ) ;
return cppOk & & qmlOk ;
}
2021-11-11 18:36:48 +02:00
const char MAIN_CPPFILE_TEMPLATE_PATH [ ] = " :/boilerplatetemplates/qmlprojectmaincpp.tpl " ;
const char MAIN_CPPFILE_HEADER_TEMPLATE_PATH [ ] = " :/boilerplatetemplates/qmlprojectmaincppheader.tpl " ;
const char MAIN_CPPFILE_HEADER_PLUGIN_LINE [ ] = " Q_IMPORT_QML_PLUGIN(%1) \n " ;
2021-12-10 14:53:00 +02:00
const char ENV_HEADER_TEMPLATE_PATH [ ] = " :/boilerplatetemplates/qmlprojectenvheader.tpl " ;
const char ENV_HEADER_VARIABLE_LINE [ ] = " qputenv( \" %1 \" , \" %2 \" ); \n " ;
2021-10-20 17:37:22 +03:00
2022-02-18 20:22:19 +01:00
bool CmakeFileGenerator : : generateMainCpp ( const FilePath & dir )
2021-10-20 17:37:22 +03:00
{
2021-11-22 13:41:20 +02:00
FilePath srcDir = dir . pathAppended ( DIRNAME_CPP ) ;
2021-10-20 17:37:22 +03:00
2021-11-11 18:36:48 +02:00
QString cppContent = GenerateCmake : : readTemplate ( MAIN_CPPFILE_TEMPLATE_PATH ) ;
2021-11-22 13:41:20 +02:00
FilePath cppFilePath = srcDir . pathAppended ( FILENAME_MAINCPP ) ;
2022-02-18 20:22:19 +01:00
bool cppOk = m_fileQueue . queueFile ( cppFilePath , cppContent ) ;
2021-11-11 18:36:48 +02:00
QString modulesAsPlugins ;
2022-02-18 20:22:19 +01:00
for ( const QString & moduleName : m_moduleNames )
2021-11-11 18:36:48 +02:00
modulesAsPlugins . append (
2021-12-10 13:06:54 +02:00
QString ( MAIN_CPPFILE_HEADER_PLUGIN_LINE ) . arg ( moduleName + " Plugin " ) ) ;
2021-11-11 18:36:48 +02:00
QString headerContent = GenerateCmake : : readTemplate ( MAIN_CPPFILE_HEADER_TEMPLATE_PATH )
. arg ( modulesAsPlugins ) ;
2021-11-22 13:41:20 +02:00
FilePath headerFilePath = srcDir . pathAppended ( FILENAME_MAINCPP_HEADER ) ;
2022-02-18 20:22:19 +01:00
bool pluginHeaderOk = m_fileQueue . queueFile ( headerFilePath , headerContent ) ;
2021-12-10 14:53:00 +02:00
bool envHeaderOk = true ;
QString environment ;
auto * target = ProjectExplorer : : SessionManager : : startupProject ( ) - > activeTarget ( ) ;
if ( target & & target - > buildSystem ( ) ) {
auto buildSystem = qobject_cast < QmlProjectManager : : QmlBuildSystem * > ( target - > buildSystem ( ) ) ;
if ( buildSystem ) {
for ( EnvironmentItem & envItem : buildSystem - > environment ( ) ) {
QString key = envItem . name ;
QString value = envItem . value ;
2021-12-20 15:55:59 +02:00
if ( isFileResource ( value ) )
value . prepend ( " :/ " ) ;
2021-12-10 14:53:00 +02:00
environment . append ( QString ( ENV_HEADER_VARIABLE_LINE ) . arg ( key ) . arg ( value ) ) ;
}
QString envHeaderContent = GenerateCmake : : readTemplate ( ENV_HEADER_TEMPLATE_PATH )
. arg ( environment ) ;
FilePath envHeaderPath = srcDir . pathAppended ( FILENAME_ENV_HEADER ) ;
2022-02-18 20:22:19 +01:00
envHeaderOk = m_fileQueue . queueFile ( envHeaderPath , envHeaderContent ) ;
2021-12-10 14:53:00 +02:00
}
}
2021-11-11 18:36:48 +02:00
2021-12-10 14:53:00 +02:00
return cppOk & & pluginHeaderOk & & envHeaderOk ;
2021-10-06 12:35:52 +03:00
}
2021-10-20 17:37:22 +03:00
2021-11-17 12:18:35 +02:00
const char MAIN_QMLFILE_TEMPLATE_PATH [ ] = " :/boilerplatetemplates/qmlprojectmainqml.tpl " ;
2021-10-20 17:37:22 +03:00
2022-02-18 20:22:19 +01:00
bool CmakeFileGenerator : : generateMainQml ( const FilePath & dir )
2021-10-20 17:37:22 +03:00
{
2021-11-17 12:18:35 +02:00
QString content = GenerateCmake : : readTemplate ( MAIN_QMLFILE_TEMPLATE_PATH ) ;
2021-11-22 13:41:20 +02:00
FilePath filePath = dir . pathAppended ( FILENAME_MAINQML ) ;
2022-02-18 20:22:19 +01:00
return m_fileQueue . queueFile ( filePath , content ) ;
2021-10-20 17:37:22 +03:00
}
2022-02-18 20:22:19 +01:00
bool CmakeFileGenerator : : isFileResource ( const QString & relativeFilePath )
2021-12-20 15:55:59 +02:00
{
2022-02-18 20:22:19 +01:00
if ( m_resourceFileLocations . contains ( relativeFilePath ) )
2021-12-20 15:55:59 +02:00
return true ;
2021-10-20 17:37:22 +03:00
2021-12-20 15:55:59 +02:00
return false ;
2021-10-20 17:37:22 +03:00
}
2022-02-18 20:22:19 +01:00
} //GenerateCmake
2022-05-11 15:45:41 +03:00
} //QmlProjectManager
2021-12-20 15:55:59 +02:00