diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2022-09-19 16:40:00 +0200 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2022-10-14 10:15:59 +0200 |
commit | a68fb1816d3fa67b322bb30f6bdd5347a149aaea (patch) | |
tree | c6a8f50121f74418bc031f8157e0b4c568140797 /sources/pyside-tools | |
parent | 7147b48ed466409fda818b2e26f46a36f624c4d3 (diff) |
Add project generation to pyside6-project
Add mode keywords "new-quick", "new-ui" and "new-widget" that create
simple applications.
[ChangeLog][PySide6] pyside6-project can now generate simple project
templates.
Change-Id: Id4e457ab3592bd9ac4c8c7f45667e8c166ec4754
Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io>
Diffstat (limited to 'sources/pyside-tools')
-rw-r--r-- | sources/pyside-tools/CMakeLists.txt | 3 | ||||
-rw-r--r-- | sources/pyside-tools/project.py | 33 | ||||
-rw-r--r-- | sources/pyside-tools/project.pyproject | 3 | ||||
-rw-r--r-- | sources/pyside-tools/project_lib/newproject.py | 165 |
4 files changed, 196 insertions, 8 deletions
diff --git a/sources/pyside-tools/CMakeLists.txt b/sources/pyside-tools/CMakeLists.txt index 2afdad52c..00f127ac4 100644 --- a/sources/pyside-tools/CMakeLists.txt +++ b/sources/pyside-tools/CMakeLists.txt @@ -36,7 +36,8 @@ if(NOT NO_QT_TOOLS STREQUAL "yes") endif() endif() -list(APPEND directories ${CMAKE_CURRENT_SOURCE_DIR}/qtpy2cpp_lib) +list(APPEND directories ${CMAKE_CURRENT_SOURCE_DIR}/qtpy2cpp_lib + ${CMAKE_CURRENT_SOURCE_DIR}/project_lib) # pyside6-rcc, pyside6-uic, pyside6-designer, shiboken and pyside6-lupdate entrypoints diff --git a/sources/pyside-tools/project.py b/sources/pyside-tools/project.py index 0322c3c78..d6ec804d6 100644 --- a/sources/pyside-tools/project.py +++ b/sources/pyside-tools/project.py @@ -29,12 +29,17 @@ from argparse import ArgumentParser, RawTextHelpFormatter from pathlib import Path from typing import Dict, List, Optional, Tuple +from project_lib.newproject import new_project, ProjectType MODE_HELP = """build Builds the project -run Builds the project and runs the first file") -clean Cleans the build artifacts") -qmllint Runs the qmllint tool -deploy Deploys the application""" +run Builds the project and runs the first file") +clean Cleans the build artifacts") +qmllint Runs the qmllint tool +deploy Deploys the application +new-ui Creates a new QtWidgets project with a Qt Designer-based main window +new-widget Creates a new QtWidgets project with a main window +new-quick Creates a new QtQuick project +""" opt_quiet = False @@ -65,6 +70,11 @@ QT_MODULES = "QT_MODULES" METATYPES_JSON_SUFFIX = "_metatypes.json" +NEW_PROJECT_TYPES = {"new-quick": ProjectType.QUICK, + "new-ui": ProjectType.WIDGET_FORM, + "new-widget": ProjectType.WIDGET} + + def run_command(command: List[str], cwd: str = None, ignore_fail: bool = False): """Run a command observing quiet/dry run""" if not opt_quiet or opt_dry_run: @@ -493,9 +503,10 @@ if __name__ == "__main__": parser.add_argument("--force", "-f", action="store_true", help="Force rebuild") parser.add_argument("--qml-module", "-Q", action="store_true", help="Perform check for QML module") - parser.add_argument("mode", - choices=["build", "run", "clean", "qmllint", "deploy"], - default="build", type=str, help=MODE_HELP) + mode_choices = ["build", "run", "clean", "qmllint", "deploy"] + mode_choices.extend(NEW_PROJECT_TYPES.keys()) + parser.add_argument("mode", choices=mode_choices, default="build", + type=str, help=MODE_HELP) parser.add_argument("file", help="Project file", nargs="?", type=str) options = parser.parse_args() @@ -504,6 +515,14 @@ if __name__ == "__main__": opt_force = options.force opt_qml_module = options.qml_module mode = options.mode + + new_project_type = NEW_PROJECT_TYPES.get(mode) + if new_project_type: + if not options.file: + print(f"{mode} requires a directory name.", file=sys.stderr) + sys.exit(1) + sys.exit(new_project(options.file, new_project_type)) + project_file = resolve_project_file(options.file) if not project_file: print(f"Cannot determine project_file {options.file}", file=sys.stderr) diff --git a/sources/pyside-tools/project.pyproject b/sources/pyside-tools/project.pyproject new file mode 100644 index 000000000..f460d5739 --- /dev/null +++ b/sources/pyside-tools/project.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["project.py", "project_lib/newproject.py"] +} diff --git a/sources/pyside-tools/project_lib/newproject.py b/sources/pyside-tools/project_lib/newproject.py new file mode 100644 index 000000000..02164ffc6 --- /dev/null +++ b/sources/pyside-tools/project_lib/newproject.py @@ -0,0 +1,165 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import json +import os +import sys +from enum import Enum +from pathlib import Path +from typing import Optional + +"""New project generation code.""" + + +Project = list[tuple[str, str]] # tuple of (filename, contents). + + +class ProjectType(Enum): + WIDGET_FORM = 1 + WIDGET = 2 + QUICK = 3 + + +_WIDGET_MAIN = """if __name__ == '__main__': + app = QApplication(sys.argv) + window = MainWindow() + window.show() + sys.exit(app.exec()) +""" + + +_WIDGET_IMPORTS = """import sys +from PySide6.QtWidgets import QApplication, QMainWindow +""" + + +_WIDGET_CLASS_DEFINITION = """class MainWindow(QMainWindow): + def __init__(self): + super().__init__() +""" + + +_WIDGET_SETUP_UI_CODE = """ self._ui = Ui_MainWindow() + self._ui.setupUi(self) +""" + + +_MAINWINDOW_FORM = """<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>800</width> + <height>600</height> + </rect> + </property> + <property name="windowTitle"> + <string>MainWindow</string> + </property> + <widget class="QWidget" name="centralwidget"/> + <widget class="QMenuBar" name="menubar"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>800</width> + <height>22</height> + </rect> + </property> + </widget> + <widget class="QStatusBar" name="statusbar"/> + </widget> +</ui> +""" + + +_QUICK_FORM = """import QtQuick +import QtQuick.Controls + +ApplicationWindow { + id: window + width: 1024 + height: 600 + visible: true +} +""" + +_QUICK_MAIN = """import sys +from pathlib import Path + +from PySide6.QtGui import QGuiApplication +from PySide6.QtCore import QUrl +from PySide6.QtQml import QQmlApplicationEngine + + +if __name__ == "__main__": + app = QGuiApplication() + engine = QQmlApplicationEngine() + qml_file = Path(__file__).parent / 'main.qml' + engine.load(QUrl.fromLocalFile(qml_file)) + if not engine.rootObjects(): + sys.exit(-1) + exit_code = app.exec() + del engine + sys.exit(exit_code) +""" + + +def _write_project(directory: Path, files: Project): + """Write out the project.""" + file_list = [] + for file, contents in files: + (directory / file).write_text(contents) + print(f"Wrote {directory.name}{os.sep}{file}.") + file_list.append(file) + pyproject = {"files": file_list} + pyproject_file = f"{directory}.pyproject" + (directory / pyproject_file).write_text(json.dumps(pyproject)) + print(f"Wrote {directory.name}{os.sep}{pyproject_file}.") + + +def _widget_project() -> Project: + """Create a (form-less) widgets project.""" + main_py = (_WIDGET_IMPORTS + "\n\n" + _WIDGET_CLASS_DEFINITION + "\n\n" + + _WIDGET_MAIN) + return [("main.py", main_py)] + + +def _ui_form_project() -> Project: + """Create a Qt Designer .ui form based widgets project.""" + main_py = (_WIDGET_IMPORTS + + "\nfrom ui_mainwindow import Ui_MainWindow\n\n\n" + + _WIDGET_CLASS_DEFINITION + _WIDGET_SETUP_UI_CODE + + "\n\n" + _WIDGET_MAIN) + return [("main.py", main_py), + ("mainwindow.ui", _MAINWINDOW_FORM)] + + +def _qml_project() -> Project: + """Create a QML project.""" + return [("main.py", _QUICK_MAIN), + ("main.qml", _QUICK_FORM)] + + +def new_project(directory_s: str, + project_type: ProjectType=ProjectType.WIDGET_FORM) -> int: + directory = Path(directory_s) + if directory.exists(): + print(f"{directory_s} already exists.", file=sys.stderr) + return -1 + directory.mkdir(parents=True) + + if project_type == ProjectType.WIDGET_FORM: + project = _ui_form_project() + elif project_type == ProjectType.QUICK: + project = _qml_project() + else: + project = _widget_project() + _write_project(directory, project) + if project_type == ProjectType.WIDGET_FORM: + print(f'Run "pyside6-project build {directory_s}" to build the project') + print(f'Run "python {directory.name}{os.sep}main.py" to run the project') + return 0 |