2021-10-06 12:35:52 +03:00
/****************************************************************************
* *
* * Copyright ( C ) 2021 The Qt Company Ltd .
* * Contact : https : //www.qt.io/licensing/
* *
* * This file is part of the Qt Design Tooling
* *
* * 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.
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# 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>
2021-10-20 17:37:22 +03:00
# include <projectexplorer/runcontrol.h>
2021-10-06 12:35:52 +03:00
# include <projectexplorer/session.h>
2021-12-10 14:53:00 +02:00
# include <projectexplorer/target.h>
2021-10-06 12:35:52 +03:00
2021-12-10 14:53:00 +02:00
# include <qmlprojectmanager/qmlproject.h>
2021-10-06 12:35:52 +03:00
# include <qmlprojectmanager/qmlprojectmanagerconstants.h>
2021-10-20 17:37:22 +03:00
# include <qmlprojectmanager/qmlmainfileaspect.h>
2021-10-06 12:35:52 +03:00
# include <utils/fileutils.h>
# include <QAction>
2021-11-17 12:18:35 +02:00
# include <QMessageBox>
2021-11-03 11:37:48 +02:00
# include <QtConcurrent>
2021-10-06 12:35:52 +03:00
# include <QRegularExpression>
# include <QStringList>
2021-10-12 13:30:14 +02:00
# include <QTextStream>
2021-10-06 12:35:52 +03:00
using namespace Utils ;
2021-11-22 13:41:20 +02:00
using namespace QmlDesigner : : GenerateCmake : : Constants ;
2021-10-06 12:35:52 +03:00
namespace QmlDesigner {
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 ,
2021-11-29 19:34:43 +02:00
MissingAssetImportDir = 1 < < 3 ,
MissingCppDir = 1 < < 4 ,
MissingMainCMake = 1 < < 5 ,
MissingMainQml = 1 < < 6 ,
MissingAppMainQml = 1 < < 7 ,
MissingQmlModules = 1 < < 8 ,
MissingMainCpp = 1 < < 9 ,
2021-12-10 14:53:00 +02:00
MissingMainCppHeader = 1 < < 10 ,
MissingEnvHeader = 1 < < 11
2021-11-17 12:18:35 +02:00
} ;
2021-11-03 11:37:48 +02:00
QVector < GeneratableFile > queuedFiles ;
2021-10-06 12:35:52 +03:00
void generateMenuEntry ( )
{
Core : : ActionContainer * buildMenu =
Core : : ActionManager : : actionContainer ( ProjectExplorer : : Constants : : M_BUILDPROJECT ) ;
2021-11-19 13:46:03 +02:00
auto action = new QAction ( QCoreApplication : : translate ( " QmlDesigner::GenerateCmake " , " Generate CMakeLists.txt Files " ) ) ;
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 " ) ;
buildMenu - > addAction ( cmd , ProjectExplorer : : Constants : : G_BUILD_RUN ) ;
action - > setEnabled ( ProjectExplorer : : SessionManager : : startupProject ( ) ! = nullptr ) ;
QObject : : connect ( ProjectExplorer : : SessionManager : : instance ( ) ,
& ProjectExplorer : : SessionManager : : startupProjectChanged , [ action ] ( ) {
action - > setEnabled ( ProjectExplorer : : SessionManager : : startupProject ( ) ! = nullptr ) ;
} ) ;
}
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 ;
}
queuedFiles . clear ( ) ;
2021-11-11 18:36:48 +02:00
GenerateCmakeLists : : generateCmakes ( rootDir ) ;
2021-12-10 14:53:00 +02:00
GenerateEntryPoints : : generateEntryPointFiles ( rootDir ) ;
2021-11-03 11:37:48 +02:00
if ( showConfirmationDialog ( rootDir ) )
writeQueuedFiles ( ) ;
}
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 ;
2021-11-29 19:34:43 +02:00
if ( ! rootDir . pathAppended ( DIRNAME_ASSET ) . exists ( ) )
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-03 11:37:48 +02:00
void removeUnconfirmedQueuedFiles ( const Utils : : FilePaths confirmedFiles )
{
QtConcurrent : : blockingFilter ( queuedFiles , [ confirmedFiles ] ( const GeneratableFile & qf ) {
return confirmedFiles . contains ( qf . filePath ) ;
} ) ;
}
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
}
}
2021-11-03 11:37:48 +02:00
bool showConfirmationDialog ( const Utils : : FilePath & rootDir )
{
Utils : : FilePaths files ;
for ( GeneratableFile & file : queuedFiles )
files . append ( file . filePath ) ;
CmakeGeneratorDialog dialog ( rootDir , files ) ;
2021-12-27 12:18:58 +02:00
dialog . setMinimumWidth ( 600 ) ;
dialog . setMinimumHeight ( 640 ) ;
2021-11-03 11:37:48 +02:00
if ( dialog . exec ( ) ) {
Utils : : FilePaths confirmedFiles = dialog . getFilePaths ( ) ;
removeUnconfirmedQueuedFiles ( confirmedFiles ) ;
return true ;
}
return false ;
}
bool queueFile ( const FilePath & filePath , const QString & fileContent )
{
GeneratableFile file ;
file . filePath = filePath ;
file . content = fileContent ;
2021-11-17 12:18:35 +02:00
file . fileExists = filePath . exists ( ) ;
2021-11-03 11:37:48 +02:00
queuedFiles . append ( file ) ;
return true ;
}
bool writeQueuedFiles ( )
{
for ( GeneratableFile & file : queuedFiles )
if ( ! writeFile ( file ) )
return false ;
return true ;
2021-10-20 17:37:22 +03:00
}
2021-11-03 11:37:48 +02:00
bool 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
}
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 ;
}
2021-10-20 17:37:22 +03:00
}
namespace GenerateCmakeLists {
2021-11-11 18:36:48 +02:00
QStringList moduleNames ;
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
2021-11-11 18:36:48 +02:00
bool generateCmakes ( const FilePath & rootDir )
2021-10-06 12:35:52 +03:00
{
2021-11-11 18:36:48 +02:00
moduleNames . clear ( ) ;
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 ) ;
FilePath assetDir = rootDir . pathAppended ( DIRNAME_ASSET ) ;
2021-10-06 12:35:52 +03:00
2021-11-11 18:36:48 +02:00
generateModuleCmake ( contentDir ) ;
generateImportCmake ( importDir ) ;
2021-11-29 19:34:43 +02:00
generateImportCmake ( assetDir ) ;
2021-11-11 18:36:48 +02:00
generateMainCmake ( 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
}
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 " ;
2021-10-06 12:35:52 +03:00
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 ( ) ;
2021-11-11 18:36:48 +02:00
QString appName = projectName + " App " ;
2021-10-06 12:35:52 +03:00
2021-11-11 18:36:48 +02:00
QString cmakeFileContent = GenerateCmake : : readTemplate ( MAIN_CMAKEFILE_TEMPLATE_PATH ) . arg ( appName ) ;
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 ) ) ;
if ( rootDir . pathAppended ( DIRNAME_ASSET ) . exists ( ) )
subdirIncludes . append ( QString ( ADD_SUBDIR ) . arg ( DIRNAME_ASSET ) ) ;
2021-11-11 18:36:48 +02:00
QString modulesAsPlugins ;
for ( const QString & moduleName : moduleNames )
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 ) ;
2021-11-22 13:41:20 +02:00
GenerateCmake : : queueFile ( rootDir . pathAppended ( FILENAME_MODULES ) , moduleFileContent ) ;
2021-11-11 18:36:48 +02:00
}
2021-10-06 12:35:52 +03:00
2021-11-29 19:34:43 +02:00
void 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
2021-11-29 19:34:43 +02:00
void 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 ;
2021-11-29 19:34:43 +02: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 ;
QString moduleName = QString ( moduleUri ) . remove ( ' . ' ) ;
2021-11-11 18:36:48 +02:00
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
}
QStringList getSingletonsFromQmldirFile ( const FilePath & filePath )
{
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 ;
}
2021-11-29 19:34:43 +02:00
FilePaths getDirectoryQmls ( const FilePath & dir )
{
const QStringList qmlFilesOnly ( " *.qml " ) ;
ProjectExplorer : : Project * project = ProjectExplorer : : SessionManager : : startupProject ( ) ;
FilePaths allFiles = dir . dirEntries ( qmlFilesOnly , FILES_ONLY ) ;
FilePaths moduleFiles ;
for ( FilePath & file : allFiles ) {
if ( ! isFileBlacklisted ( file . fileName ( ) ) & &
project - > isKnownFile ( file ) ) {
moduleFiles . append ( file ) ;
}
}
return moduleFiles ;
}
2021-10-18 12:02:58 +03:00
QStringList getDirectoryTreeQmls ( const FilePath & dir )
{
const QStringList qmlFilesOnly ( " *.qml " ) ;
ProjectExplorer : : Project * project = ProjectExplorer : : SessionManager : : startupProject ( ) ;
QStringList qmlFileList ;
FilePaths thisDirFiles = dir . dirEntries ( qmlFilesOnly , FILES_ONLY ) ;
for ( FilePath & file : thisDirFiles ) {
if ( ! isFileBlacklisted ( file . fileName ( ) ) & &
project - > isKnownFile ( file ) ) {
qmlFileList . append ( file . fileName ( ) ) ;
}
}
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 ;
}
2021-10-06 12:35:52 +03:00
QStringList getDirectoryTreeResources ( const FilePath & dir )
{
ProjectExplorer : : Project * project = ProjectExplorer : : SessionManager : : startupProject ( ) ;
QStringList resourceFileList ;
FilePaths thisDirFiles = dir . dirEntries ( FILES_ONLY ) ;
for ( FilePath & file : thisDirFiles ) {
if ( ! isFileBlacklisted ( file . fileName ( ) ) & &
! file . fileName ( ) . endsWith ( " .qml " , Qt : : CaseInsensitive ) & &
project - > isKnownFile ( file ) ) {
resourceFileList . append ( file . fileName ( ) ) ;
}
}
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 ;
}
2021-11-11 18:36:48 +02:00
void 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 ) ;
2021-11-03 11:37:48 +02:00
GenerateCmake : : queueFile ( filePath , content ) ;
2021-10-06 12:35:52 +03:00
}
bool isFileBlacklisted ( const QString & fileName )
{
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
}
2021-11-29 19:34:43 +02:00
bool isDirBlacklisted ( const FilePath & dir )
{
return ( ! dir . fileName ( ) . compare ( DIRNAME_DESIGNER ) ) ;
}
2021-10-06 12:35:52 +03:00
}
2021-10-20 17:37:22 +03:00
namespace GenerateEntryPoints {
bool generateEntryPointFiles ( const FilePath & dir )
{
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
bool generateMainCpp ( const FilePath & dir )
{
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 ) ;
2021-11-11 18:36:48 +02:00
bool cppOk = GenerateCmake : : queueFile ( cppFilePath , cppContent ) ;
QString modulesAsPlugins ;
for ( const QString & moduleName : GenerateCmakeLists : : moduleNames )
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 ) ;
2021-12-10 14:53:00 +02:00
bool pluginHeaderOk = GenerateCmake : : queueFile ( headerFilePath , headerContent ) ;
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 ) ;
envHeaderOk = GenerateCmake : : queueFile ( envHeaderPath , envHeaderContent ) ;
}
}
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
bool generateMainQml ( const FilePath & dir )
{
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 ) ;
2021-11-11 18:36:48 +02:00
return GenerateCmake : : queueFile ( filePath , content ) ;
2021-10-20 17:37:22 +03:00
}
2021-12-20 15:55:59 +02:00
const QStringList resourceFileLocations = { " qtquickcontrols2.conf " } ;
2021-12-21 19:50:21 +02:00
bool isFileResource ( const QString & relativeFilePath )
2021-12-20 15:55:59 +02:00
{
if ( resourceFileLocations . contains ( relativeFilePath ) )
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
}
2021-12-20 15:55:59 +02:00
} //GenerateEntryPoints
} //QmlDesigner