Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'sources/pyside-tools')
-rw-r--r--sources/pyside-tools/CMakeLists.txt3
-rw-r--r--sources/pyside-tools/project.py33
-rw-r--r--sources/pyside-tools/project.pyproject3
-rw-r--r--sources/pyside-tools/project_lib/newproject.py165
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