diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/boilerplate.qrc b/src/plugins/qmlprojectmanager/qmlprojectexporter/boilerplate.qrc index 4960324ab74..50e9909a17c 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/boilerplate.qrc +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/boilerplate.qrc @@ -11,5 +11,8 @@ templates/import_qml_components_h.tpl templates/qtquickcontrols2_conf.tpl templates/cmakelists_txt_shared.tpl + templates/python_generator_main.tpl + templates/python_generator_settings.tpl + templates/python_pyproject_toml.tpl diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/exporter.cpp b/src/plugins/qmlprojectmanager/qmlprojectexporter/exporter.cpp index e228b53703a..40de901c4fe 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/exporter.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/exporter.cpp @@ -30,6 +30,7 @@ void Exporter::updateProject(QmlProject *project) void Exporter::updateProjectItem(QmlProjectItem *item, bool updateEnabled) { connect(item, &QmlProjectItem::filesChanged, m_cmakeGen, &CMakeGenerator::update); + connect(item, &QmlProjectItem::filesChanged, m_pythonGen, &PythonGenerator::update); connect(item, &QmlProjectItem::fileModified, m_cmakeGen, &CMakeGenerator::updateModifiedFile); if (updateEnabled) { diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/pythongenerator.cpp b/src/plugins/qmlprojectmanager/qmlprojectexporter/pythongenerator.cpp index 11ae25fd2ce..636f47fa7d9 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/pythongenerator.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/pythongenerator.cpp @@ -3,41 +3,14 @@ #include "pythongenerator.h" #include "cmakewriter.h" +#include "resourcegenerator.h" #include "projectexplorer/projectmanager.h" #include "qmlprojectmanager/qmlproject.h" #include -namespace QmlProjectManager { - -namespace QmlProjectExporter { - -const char *PYTHON_MAIN_FILE_TEMPLATE = R"( -import os -import sys -from pathlib import Path - -from PySide6.QtGui import QGuiApplication -from PySide6.QtQml import QQmlApplicationEngine - -from autogen.settings import url, import_paths - -if __name__ == '__main__': - app = QGuiApplication(sys.argv) - engine = QQmlApplicationEngine() - - app_dir = Path(__file__).parent.parent - - engine.addImportPath(os.fspath(app_dir)) - for path in import_paths: - engine.addImportPath(os.fspath(app_dir / path)) - - engine.load(os.fspath(app_dir/url)) - if not engine.rootObjects(): - sys.exit(-1) - sys.exit(app.exec()) -)"; +namespace QmlProjectManager::QmlProjectExporter { void PythonGenerator::createMenuAction(QObject *parent) { @@ -66,9 +39,8 @@ PythonGenerator::PythonGenerator(QmlBuildSystem *bs) void PythonGenerator::updateMenuAction() { - FileGenerator::updateMenuAction( - "QmlProject.EnablePythonGenerator", - [this]() { return buildSystem()->enablePythonGeneration(); }); + FileGenerator::updateMenuAction("QmlProject.EnablePythonGenerator", + [this]() { return buildSystem()->enablePythonGeneration(); }); } void PythonGenerator::updateProject(QmlProject *project) @@ -77,38 +49,47 @@ void PythonGenerator::updateProject(QmlProject *project) return; Utils::FilePath projectPath = project->rootProjectDirectory(); - Utils::FilePath pythonPath = projectPath.pathAppended("Python"); - if (!pythonPath.exists()) - pythonPath.createDir(); + Utils::FilePath pythonFolderPath = projectPath.pathAppended("Python"); + if (!pythonFolderPath.exists()) + pythonFolderPath.createDir(); - Utils::FilePath mainFile = pythonPath.pathAppended("main.py"); - if (!mainFile.exists()) { - const QString mainContent = QString::fromUtf8(PYTHON_MAIN_FILE_TEMPLATE); - CMakeWriter::writeFile(mainFile, mainContent); + Utils::FilePath mainFilePath = pythonFolderPath.pathAppended("main.py"); + if (!mainFilePath.exists()) { + const QString mainFileTemplate = CMakeWriter::readTemplate( + ":/templates/python_generator_main"); + CMakeWriter::writeFile(mainFilePath, mainFileTemplate); } - Utils::FilePath autogenPath = pythonPath.pathAppended("autogen"); - if (!autogenPath.exists()) - autogenPath.createDir(); + Utils::FilePath pyprojectFilePath = pythonFolderPath.pathAppended("pyproject.toml"); + if (!pyprojectFilePath.exists()) { + const QString pyprojectFileTemplate = CMakeWriter::readTemplate( + ":/templates/python_pyproject_toml"); + const QString pyprojectFileContent = pyprojectFileTemplate.arg(project->displayName()); + CMakeWriter::writeFile(pyprojectFilePath, pyprojectFileContent); + } - Utils::FilePath settingsPath = autogenPath.pathAppended("settings.py"); - CMakeWriter::writeFile(settingsPath, settingsFileContent()); + Utils::FilePath autogenFolderPath = pythonFolderPath.pathAppended("autogen"); + if (!autogenFolderPath.exists()) + autogenFolderPath.createDir(); + + Utils::FilePath settingsFilePath = autogenFolderPath.pathAppended("settings.py"); + const QString settingsFileTemplate = CMakeWriter::readTemplate( + ":/templates/python_generator_settings"); + const QString settingsFileContent = settingsFileTemplate.arg(buildSystem()->mainFile()); + CMakeWriter::writeFile(settingsFilePath, settingsFileContent); + + // Python code uses the Qt resources collection file (.qrc) + ResourceGenerator::createQrc(project); } -QString PythonGenerator::settingsFileContent() const -{ - QTC_ASSERT(buildSystem(), return {}); +/*! + Regenerates the .qrc resources file +*/ +void PythonGenerator::update(const QSet &added, const QSet &removed) { + Q_UNUSED(added); + Q_UNUSED(removed); + ResourceGenerator::createQrc(qmlProject()); + // Generated Python code does not need to be updated +}; - QString content("\n"); - content.append("url = \"" + buildSystem()->mainFile() + "\"\n"); - - content.append("import_paths = [\n"); - for (const QString &path : buildSystem()->importPaths()) - content.append("\t\"" + path + "\",\n"); - content.append("]\n"); - - return content; -} - -} // namespace QmlProjectExporter. -} // namespace QmlProjectManager. +} // namespace QmlProjectExporter::QmlProjectManager. diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/pythongenerator.h b/src/plugins/qmlprojectmanager/qmlprojectexporter/pythongenerator.h index 7c0a5810df5..34f8c2be38d 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/pythongenerator.h +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/pythongenerator.h @@ -21,11 +21,10 @@ public: static void createMenuAction(QObject *parent); PythonGenerator(QmlBuildSystem *bs); + + void update(const QSet &added, const QSet &removed); void updateMenuAction() override; void updateProject(QmlProject *project) override; - -private: - QString settingsFileContent() const; }; } // namespace QmlProjectExporter. diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/templates/python_generator_main.tpl b/src/plugins/qmlprojectmanager/qmlprojectexporter/templates/python_generator_main.tpl new file mode 100644 index 00000000000..c768aa799bf --- /dev/null +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/templates/python_generator_main.tpl @@ -0,0 +1,26 @@ +import sys + +from PySide6.QtGui import QGuiApplication +from PySide6.QtQml import QQmlApplicationEngine + +from autogen.settings import setup_qt_environment + +# Import here the Python files that define QML elements + + +def main(): + app = QGuiApplication(sys.argv) + engine = QQmlApplicationEngine() + + setup_qt_environment(engine) + + if not engine.rootObjects(): + sys.exit(-1) + + ex = app.exec() + del engine + return ex + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/templates/python_generator_settings.tpl b/src/plugins/qmlprojectmanager/qmlprojectexporter/templates/python_generator_settings.tpl new file mode 100644 index 00000000000..435ee55aac4 --- /dev/null +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/templates/python_generator_settings.tpl @@ -0,0 +1,36 @@ +# This file is automatically generated by Qt Design Studio. +import os +import sys +from pathlib import Path + +from PySide6.QtQml import QQmlApplicationEngine + +project_root = Path(__file__).parent.parent.parent + + +def setup_qt_environment(qml_engine: QQmlApplicationEngine): + """ + Load the QML application. Import the compiled resources when the application is deployed. + """ + qml_app_url = "%1" + + if "__compiled__" in globals(): + # Application has been deployed using pyside6-deploy + try: + import autogen.resources # noqa: F401 + except ImportError: + resource_file = Path(__file__).parent / "resources.py" + print( + f"Error: No compiled resources found in {resource_file.absolute()}\n" + f"Please compile the resources using pyside6-rcc or pyside6-project build", + file=sys.stderr, + ) + sys.exit(1) + + qml_engine.addImportPath(":/") + qml_engine.load(f":/{qml_app_url}") + return + + qml_engine.addImportPath(str(project_root.absolute())) + os.environ["QT_QUICK_CONTROLS_CONF"] = str(project_root / "qtquickcontrols2.conf") + qml_engine.load(str(project_root / qml_app_url)) diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/templates/python_pyproject_toml.tpl b/src/plugins/qmlprojectmanager/qmlprojectexporter/templates/python_pyproject_toml.tpl new file mode 100644 index 00000000000..21c00189295 --- /dev/null +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/templates/python_pyproject_toml.tpl @@ -0,0 +1,5 @@ +[project] +name = "%1" + +[tool.pyside6-project] +files = ["main.py", "autogen/settings.py"]