diff options
Diffstat (limited to 'examples/widgets/dialogs/classwizard/classwizard.py')
-rw-r--r-- | examples/widgets/dialogs/classwizard/classwizard.py | 628 |
1 files changed, 302 insertions, 326 deletions
diff --git a/examples/widgets/dialogs/classwizard/classwizard.py b/examples/widgets/dialogs/classwizard/classwizard.py index fc2feb498..0efbde69f 100644 --- a/examples/widgets/dialogs/classwizard/classwizard.py +++ b/examples/widgets/dialogs/classwizard/classwizard.py @@ -1,404 +1,380 @@ -# -*- coding: utf-8 -*- -############################################################################# -## -## Copyright (C) 2013 Riverbank Computing Limited. -## Copyright (C) 2016 The Qt Company Ltd. -## Contact: http://www.qt.io/licensing/ -## -## This file is part of the Qt for Python examples of the Qt Toolkit. -## -## $QT_BEGIN_LICENSE:BSD$ -## You may use this file under the terms of the BSD license as follows: -## -## "Redistribution and use in source and binary forms, with or without -## modification, are permitted provided that the following conditions are -## met: -## * Redistributions of source code must retain the above copyright -## notice, this list of conditions and the following disclaimer. -## * Redistributions in binary form must reproduce the above copyright -## notice, this list of conditions and the following disclaimer in -## the documentation and/or other materials provided with the -## distribution. -## * Neither the name of The Qt Company Ltd nor the names of its -## contributors may be used to endorse or promote products derived -## from this software without specific prior written permission. -## -## -## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -## -## $QT_END_LICENSE$ -## -############################################################################# - -from __future__ import unicode_literals -from PySide2 import QtCore, QtGui, QtWidgets - -import classwizard_rc - - -class ClassWizard(QtWidgets.QWizard): - def __init__(self, parent=None): - super(ClassWizard, self).__init__(parent) +# Copyright (C) 2013 Riverbank Computing Limited. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause - self.addPage(IntroPage()) - self.addPage(ClassInfoPage()) - self.addPage(CodeStylePage()) - self.addPage(OutputFilesPage()) - self.addPage(ConclusionPage()) +import os +from pathlib import Path +import sys - self.setPixmap(QtWidgets.QWizard.BannerPixmap, - QtGui.QPixmap(':/images/banner.png')) - self.setPixmap(QtWidgets.QWizard.BackgroundPixmap, - QtGui.QPixmap(':/images/background.png')) +from PySide6.QtCore import QDir, QFileInfo, QUrl, Slot +from PySide6.QtGui import QDesktopServices, QPixmap +from PySide6.QtWidgets import (QApplication, QComboBox, QCheckBox, QFormLayout, + QFileDialog, QHBoxLayout, QLabel, QLineEdit, + QMessageBox, QToolButton, QVBoxLayout, QWizard, + QWizardPage) - self.setWindowTitle("Class Wizard") +from listchooser import PropertyChooser, SignalChooser - def accept(self): - className = self.field('className') - baseClass = self.field('baseClass') - macroName = self.field('macroName') - baseInclude = self.field('baseInclude') +import classwizard_rc # noqa: F401 - outputDir = self.field('outputDir') - header = self.field('header') - implementation = self.field('implementation') - block = '' +BASE_CLASSES = ['<None>', 'PySide6.QtCore.QObject', + 'PySide6.QtWidgets.QDialog', 'PySide6.QtWidgets.QMainWindow', + 'PySide6.QtWidgets.QWidget'] - if self.field('comment'): - block += '/*\n' - block += ' ' + header + '\n' - block += '*/\n' - block += '\n' - if self.field('protect'): - block += '#ifndef ' + macroName + '\n' - block += '#define ' + macroName + '\n' - block += '\n' +PYTHON_TYPES = ['int', 'list', 'str'] - if self.field('includeBase'): - block += '#include ' + baseInclude + '\n' - block += '\n' - block += 'class ' + className - if baseClass: - block += ' : public ' + baseClass +INTRODUCTION = ("This wizard will generate a skeleton Python class definition, " + "including a few functions. You simply need to specify the class name and set " + "a few options to produce a Python file.") - block += '\n' - block += '{\n' - if self.field('qobjectMacro'): - block += ' Q_OBJECT\n' - block += '\n' +def property_accessors(property_type, name): + """Generate the property accessor functions.""" + return (f' @Property({property_type})\n' + f' def {name}(self):\n' + f' return self._{name}\n\n' + f' @{name}.setter\n' + f' def {name}(self, value):\n' + f' self._{name} = value\n') - block += 'public:\n' - if self.field('qobjectCtor'): - block += ' ' + className + '(QObject *parent = 0);\n' - elif self.field('qwidgetCtor'): - block += ' ' + className + '(QWidget *parent = 0);\n' - elif self.field('defaultCtor'): - block += ' ' + className + '();\n' +def property_initialization(property_type, name): + """Generate the property initialization for __init__().""" + return f' self._{name} = {property_type}()\n' - if self.field('copyCtor'): - block += ' ' + className + '(const ' + className + ' &other);\n' - block += '\n' - block += ' ' + className + ' &operator=' + '(const ' + className + ' &other);\n' - block += '};\n' +def signal_initialization(signature): + """Generate the Signal initialization from the function signature.""" + paren_pos = signature.find('(') + name = signature[:paren_pos] + parameters = signature[paren_pos:] + return f' {name} = Signal{parameters}\n' - if self.field('protect'): - block += '\n' - block += '#endif\n' - headerFile = QtCore.QFile(outputDir + '/' + header) +class ClassWizard(QWizard): + def __init__(self, parent=None): + super().__init__(parent) - if not headerFile.open(QtCore.QFile.WriteOnly | QtCore.QFile.Text): - QtWidgets.QMessageBox.warning(None, "Class Wizard", - "Cannot write file %s:\n%s" % (headerFile.fileName(), headerFile.errorString())) - return + self.addPage(IntroPage()) + self._class_info_index = self.addPage(ClassInfoPage()) + self._qobject_index = self.addPage(QObjectPage()) + self._output_index = self.addPage(OutputFilesPage()) + self.addPage(ConclusionPage()) - headerFile.write(QtCore.QByteArray(block.encode("utf-8"))) + self.setPixmap(QWizard.BannerPixmap, + QPixmap(':/images/banner.png')) + self.setPixmap(QWizard.BackgroundPixmap, + QPixmap(':/images/background.png')) - block = '' + self.setWindowTitle("Class Wizard") - if self.field('comment'): - block += '/*\n' - block += ' ' + implementation + '\n' - block += '*/\n' + def nextId(self): + """Overrides QWizard.nextId() to insert the property/signal + page in case the class is a QObject.""" + idx = self.currentId() + if idx == self._class_info_index: + qobject = self.field('qobject') + return self._qobject_index if qobject else self._output_index + return super(ClassWizard, self).nextId() + + def generate_code(self): + imports = [] # Classes to be imported + module_imports = {} # Module->class list + + def add_import(class_str): + """Add a class to the import list or module hash depending on + whether it is 'class' or 'module.class'. Returns the + class name.""" + dot = class_str.rfind('.') + if dot < 0: + imports.append(class_str) + return class_str + module = class_str[0:dot] + class_name = class_str[dot + 1:] + class_list = module_imports.get(module) + if class_list: + if class_name not in class_list: + class_list.append(class_name) + else: + module_imports[module] = [class_name] + return class_name + + class_name = self.field('className') + qobject = self.field('qobject') + base_class = self.field('baseClass') + if base_class.startswith('<'): # <None> + base_class = '' + if qobject and not base_class: + base_class = 'PySide6.QtCore.QObject' + + if base_class: + base_class = add_import(base_class) + + signals = self.field('signals') + if signals: + add_import('PySide6.QtCore.Signal') + + property_types = [] + property_names = [] + for p in self.field('properties'): + property_type, property_name = str(p).split(' ') + if property_type not in PYTHON_TYPES: + property_type = add_import(property_type) + property_types.append(property_type) + property_names.append(property_name) + + if property_names: + add_import('PySide6.QtCore.Property') + + signals = self.field('signals') + if signals: + add_import('PySide6.QtCore.Signal') + + property_types = [] + property_names = [] + for p in self.field('properties'): + property_type, property_name = str(p).split(' ') + if property_type not in PYTHON_TYPES: + property_type = add_import(property_type) + property_types.append(property_type) + property_names.append(property_name) + + if property_names: + add_import('PySide6.QtCore.Property') + + # Generate imports + block = '# This Python file uses the following encoding: utf-8\n\n' + for module, class_list in module_imports.items(): + class_list.sort() + class_list_str = ', '.join(class_list) + block += f'from {module} import {class_list_str}\n' + for klass in imports: + block += f'import {klass}\n' + + # Generate class definition + block += f'\n\nclass {class_name}' + if base_class: + block += f'({base_class})' + block += ':\n' + description = self.field('description') + if description: + block += f' """{description}"""\n' + + if signals: block += '\n' + for s in signals: + block += signal_initialization(str(s)) + + # Generate __init__ function + block += '\n def __init__(self' + if qobject: + block += ', parent=None' + block += '):\n' + + if base_class: + block += ' super().__init__(' + if qobject: + block += 'parent' + block += ')\n' + + for i, name in enumerate(property_names): + block += property_initialization(property_types[i], name) + + if not base_class and not property_names: + block += ' pass\n' - block += '#include "' + header + '"\n' - block += '\n' - - if self.field('qobjectCtor'): - block += className + '::' + className + '(QObject *parent)\n' - block += ' : ' + baseClass + '(parent)\n' - block += '{\n' - block += '}\n' - elif self.field('qwidgetCtor'): - block += className + '::' + className + '(QWidget *parent)\n' - block += ' : ' + baseClass + '(parent)\n' - block += '{\n' - block += '}\n' - elif self.field('defaultCtor'): - block += className + '::' + className + '()\n' - block += '{\n' - block += ' // missing code\n' - block += '}\n' - - if self.field('copyCtor'): - block += '\n' - block += className + '::' + className + '(const ' + className + ' &other)\n' - block += '{\n' - block += ' *this = other;\n' - block += '}\n' - block += '\n' - block += className + ' &' + className + '::operator=(const ' + className + ' &other)\n' - block += '{\n' - - if baseClass: - block += ' ' + baseClass + '::operator=(other);\n' - - block += ' // missing code\n' - block += ' return *this;\n' - block += '}\n' - - implementationFile = QtCore.QFile(outputDir + '/' + implementation) - - if not implementationFile.open(QtCore.QFile.WriteOnly | QtCore.QFile.Text): - QtWidgets.QMessageBox.warning(None, "Class Wizard", - "Cannot write file %s:\n%s" % (implementationFile.fileName(), implementationFile.errorString())) + # Generate property accessors + for i, name in enumerate(property_names): + block += '\n' + property_accessors(property_types[i], name) + + return block + + def accept(self): + file_name = self.field('file') + output_dir = self.field('outputDir') + python_file = Path(output_dir) / file_name + name = os.fspath(python_file) + try: + python_file.write_text(self.generate_code()) + except (OSError, PermissionError) as e: + reason = str(e) + QMessageBox.warning(None, "Class Wizard", + f"Cannot write file {name}:\n{reason}") return - implementationFile.write(QtCore.QByteArray(block.encode("utf-8"))) + if self.field('launch'): + url = QUrl.fromLocalFile(QDir.fromNativeSeparators(name)) + QDesktopServices.openUrl(url) super(ClassWizard, self).accept() -class IntroPage(QtWidgets.QWizardPage): +class IntroPage(QWizardPage): def __init__(self, parent=None): - super(IntroPage, self).__init__(parent) + super().__init__(parent) self.setTitle("Introduction") - self.setPixmap(QtWidgets.QWizard.WatermarkPixmap, - QtGui.QPixmap(':/images/watermark1.png')) - - label = QtWidgets.QLabel("This wizard will generate a skeleton C++ class " - "definition, including a few functions. You simply need to " - "specify the class name and set a few options to produce a " - "header file and an implementation file for your new C++ " - "class.") + self.setPixmap(QWizard.WatermarkPixmap, + QPixmap(':/images/watermark1.png')) + + label = QLabel(INTRODUCTION) label.setWordWrap(True) - layout = QtWidgets.QVBoxLayout() + layout = QVBoxLayout(self) layout.addWidget(label) - self.setLayout(layout) -class ClassInfoPage(QtWidgets.QWizardPage): +class ClassInfoPage(QWizardPage): def __init__(self, parent=None): - super(ClassInfoPage, self).__init__(parent) + super().__init__(parent) self.setTitle("Class Information") self.setSubTitle("Specify basic information about the class for " - "which you want to generate skeleton source code files.") - self.setPixmap(QtWidgets.QWizard.LogoPixmap, - QtGui.QPixmap(':/images/logo1.png')) + "which you want to generate a skeleton source code file.") + self.setPixmap(QWizard.LogoPixmap, + QPixmap(':/qt-project.org/logos/pysidelogo.png')) - classNameLabel = QtWidgets.QLabel("&Class name:") - classNameLineEdit = QtWidgets.QLineEdit() - classNameLabel.setBuddy(classNameLineEdit) + class_name_line_edit = QLineEdit() + class_name_line_edit.setClearButtonEnabled(True) - baseClassLabel = QtWidgets.QLabel("B&ase class:") - baseClassLineEdit = QtWidgets.QLineEdit() - baseClassLabel.setBuddy(baseClassLineEdit) + self._base_class_combo = QComboBox() + self._base_class_combo.addItems(BASE_CLASSES) + self._base_class_combo.setEditable(True) - qobjectMacroCheckBox = QtWidgets.QCheckBox("Generate Q_OBJECT ¯o") + base_class_line_edit = self._base_class_combo.lineEdit() + base_class_line_edit.setPlaceholderText('Module.Class') + self._base_class_combo.currentTextChanged.connect(self._base_class_changed) - groupBox = QtWidgets.QGroupBox("C&onstructor") + description_line_edit = QLineEdit() + description_line_edit.setClearButtonEnabled(True) - qobjectCtorRadioButton = QtWidgets.QRadioButton("&QObject-style constructor") - qwidgetCtorRadioButton = QtWidgets.QRadioButton("Q&Widget-style constructor") - defaultCtorRadioButton = QtWidgets.QRadioButton("&Default constructor") - copyCtorCheckBox = QtWidgets.QCheckBox("&Generate copy constructor and operator=") + self._qobject_check_box = QCheckBox("Inherits QObject") - defaultCtorRadioButton.setChecked(True) + self.registerField('className*', class_name_line_edit) + self.registerField('baseClass', base_class_line_edit) + self.registerField('description', description_line_edit) + self.registerField('qobject', self._qobject_check_box) - defaultCtorRadioButton.toggled.connect(copyCtorCheckBox.setEnabled) + layout = QFormLayout(self) + layout.addRow("&Class name:", class_name_line_edit) + layout.addRow("B&ase class:", self._base_class_combo) + layout.addRow("&Description:", description_line_edit) + layout.addRow(self._qobject_check_box) - self.registerField('className*', classNameLineEdit) - self.registerField('baseClass', baseClassLineEdit) - self.registerField('qobjectMacro', qobjectMacroCheckBox) - self.registerField('qobjectCtor', qobjectCtorRadioButton) - self.registerField('qwidgetCtor', qwidgetCtorRadioButton) - self.registerField('defaultCtor', defaultCtorRadioButton) - self.registerField('copyCtor', copyCtorCheckBox) + @Slot(str) + def _base_class_changed(self, text): + is_qobject = text.startswith('PySide') + self._qobject_check_box.setChecked(is_qobject) - groupBoxLayout = QtWidgets.QVBoxLayout() - groupBoxLayout.addWidget(qobjectCtorRadioButton) - groupBoxLayout.addWidget(qwidgetCtorRadioButton) - groupBoxLayout.addWidget(defaultCtorRadioButton) - groupBoxLayout.addWidget(copyCtorCheckBox) - groupBox.setLayout(groupBoxLayout) - layout = QtWidgets.QGridLayout() - layout.addWidget(classNameLabel, 0, 0) - layout.addWidget(classNameLineEdit, 0, 1) - layout.addWidget(baseClassLabel, 1, 0) - layout.addWidget(baseClassLineEdit, 1, 1) - layout.addWidget(qobjectMacroCheckBox, 2, 0, 1, 2) - layout.addWidget(groupBox, 3, 0, 1, 2) - self.setLayout(layout) +class QObjectPage(QWizardPage): + """Allows for adding properties and signals to a QObject.""" + def __init__(self, parent=None): + super().__init__(parent) + + self.setTitle("QObject parameters") + self.setSubTitle("Specify the signals, slots and properties.") + self.setPixmap(QWizard.LogoPixmap, + QPixmap(':/qt-project.org/logos/pysidelogo.png')) + layout = QVBoxLayout(self) + self._properties_chooser = PropertyChooser() + self.registerField('properties', self._properties_chooser, 'items') + layout.addWidget(self._properties_chooser) + self._signals_chooser = SignalChooser() + self.registerField('signals', self._signals_chooser, 'items') + layout.addWidget(self._signals_chooser) + + +class OutputFilesPage(QWizardPage): + def __init__(self, parent=None): + super().__init__(parent) + self.setTitle("Output Files") + self.setSubTitle("Specify where you want the wizard to put the " + "generated skeleton code.") + self.setPixmap(QWizard.LogoPixmap, + QPixmap(':/qt-project.org/logos/pysidelogo.png')) -class CodeStylePage(QtWidgets.QWizardPage): - def __init__(self, parent=None): - super(CodeStylePage, self).__init__(parent) - - self.setTitle("Code Style Options") - self.setSubTitle("Choose the formatting of the generated code.") - self.setPixmap(QtWidgets.QWizard.LogoPixmap, - QtGui.QPixmap(':/images/logo2.png')) - - commentCheckBox = QtWidgets.QCheckBox("&Start generated files with a " - "comment") - commentCheckBox.setChecked(True) - - protectCheckBox = QtWidgets.QCheckBox("&Protect header file against " - "multiple inclusions") - protectCheckBox.setChecked(True) - - macroNameLabel = QtWidgets.QLabel("&Macro name:") - self.macroNameLineEdit = QtWidgets.QLineEdit() - macroNameLabel.setBuddy(self.macroNameLineEdit) - - self.includeBaseCheckBox = QtWidgets.QCheckBox("&Include base class " - "definition") - self.baseIncludeLabel = QtWidgets.QLabel("Base class include:") - self.baseIncludeLineEdit = QtWidgets.QLineEdit() - self.baseIncludeLabel.setBuddy(self.baseIncludeLineEdit) - - protectCheckBox.toggled.connect(macroNameLabel.setEnabled) - protectCheckBox.toggled.connect(self.macroNameLineEdit.setEnabled) - self.includeBaseCheckBox.toggled.connect(self.baseIncludeLabel.setEnabled) - self.includeBaseCheckBox.toggled.connect(self.baseIncludeLineEdit.setEnabled) - - self.registerField('comment', commentCheckBox) - self.registerField('protect', protectCheckBox) - self.registerField('macroName', self.macroNameLineEdit) - self.registerField('includeBase', self.includeBaseCheckBox) - self.registerField('baseInclude', self.baseIncludeLineEdit) - - layout = QtWidgets.QGridLayout() - layout.setColumnMinimumWidth(0, 20) - layout.addWidget(commentCheckBox, 0, 0, 1, 3) - layout.addWidget(protectCheckBox, 1, 0, 1, 3) - layout.addWidget(macroNameLabel, 2, 1) - layout.addWidget(self.macroNameLineEdit, 2, 2) - layout.addWidget(self.includeBaseCheckBox, 3, 0, 1, 3) - layout.addWidget(self.baseIncludeLabel, 4, 1) - layout.addWidget(self.baseIncludeLineEdit, 4, 2) - self.setLayout(layout) + output_dir_label = QLabel("&Output directory:") + output_dir_layout = QHBoxLayout() + self._output_dir_line_edit = QLineEdit() + output_dir_layout.addWidget(self._output_dir_line_edit) + output_dir_label.setBuddy(self._output_dir_line_edit) + output_dir_button = QToolButton() + output_dir_button.setText('...') + output_dir_button.clicked.connect(self._choose_output_dir) + output_dir_layout.addWidget(output_dir_button) - def initializePage(self): - className = self.field('className') - self.macroNameLineEdit.setText(className.upper() + "_H") + self._file_line_edit = QLineEdit() - baseClass = self.field('baseClass') - is_baseClass = bool(baseClass) + self.registerField('outputDir*', self._output_dir_line_edit) + self.registerField('file*', self._file_line_edit) - self.includeBaseCheckBox.setChecked(is_baseClass) - self.includeBaseCheckBox.setEnabled(is_baseClass) - self.baseIncludeLabel.setEnabled(is_baseClass) - self.baseIncludeLineEdit.setEnabled(is_baseClass) + layout = QFormLayout(self) + layout.addRow(output_dir_label, output_dir_layout) + layout.addRow("&File name:", self._file_line_edit) - if not is_baseClass: - self.baseIncludeLineEdit.clear() - elif QtCore.QRegExp('Q[A-Z].*').exactMatch(baseClass): - self.baseIncludeLineEdit.setText('<' + baseClass + '>') - else: - self.baseIncludeLineEdit.setText('"' + baseClass.lower() + '.h"') + def initializePage(self): + class_name = self.field('className') + self._file_line_edit.setText(class_name.lower() + '.py') + self.set_output_dir(QDir.tempPath()) + def set_output_dir(self, directory): + self._output_dir_line_edit.setText(QDir.toNativeSeparators(directory)) -class OutputFilesPage(QtWidgets.QWizardPage): - def __init__(self, parent=None): - super(OutputFilesPage, self).__init__(parent) + def output_dir(self): + return QDir.fromNativeSeparators(self._output_dir_line_edit.text()) - self.setTitle("Output Files") - self.setSubTitle("Specify where you want the wizard to put the " - "generated skeleton code.") - self.setPixmap(QtWidgets.QWizard.LogoPixmap, - QtGui.QPixmap(':/images/logo3.png')) - - outputDirLabel = QtWidgets.QLabel("&Output directory:") - self.outputDirLineEdit = QtWidgets.QLineEdit() - outputDirLabel.setBuddy(self.outputDirLineEdit) - - headerLabel = QtWidgets.QLabel("&Header file name:") - self.headerLineEdit = QtWidgets.QLineEdit() - headerLabel.setBuddy(self.headerLineEdit) - - implementationLabel = QtWidgets.QLabel("&Implementation file name:") - self.implementationLineEdit = QtWidgets.QLineEdit() - implementationLabel.setBuddy(self.implementationLineEdit) - - self.registerField('outputDir*', self.outputDirLineEdit) - self.registerField('header*', self.headerLineEdit) - self.registerField('implementation*', self.implementationLineEdit) - - layout = QtWidgets.QGridLayout() - layout.addWidget(outputDirLabel, 0, 0) - layout.addWidget(self.outputDirLineEdit, 0, 1) - layout.addWidget(headerLabel, 1, 0) - layout.addWidget(self.headerLineEdit, 1, 1) - layout.addWidget(implementationLabel, 2, 0) - layout.addWidget(self.implementationLineEdit, 2, 1) - self.setLayout(layout) + def file_name(self): + return f"{self.output_dir()}/{self._file_line_edit.text()}" - def initializePage(self): - className = self.field('className') - self.headerLineEdit.setText(className.lower() + '.h') - self.implementationLineEdit.setText(className.lower() + '.cpp') - self.outputDirLineEdit.setText(QtCore.QDir.toNativeSeparators(QtCore.QDir.tempPath())) + def _choose_output_dir(self): + directory = QFileDialog.getExistingDirectory(self, "Output Directory", + self.output_dir()) + if directory: + self.set_output_dir(directory) + def validatePage(self): + """Ensure we do not overwrite existing files.""" + name = self.file_name() + if QFileInfo.exists(name): + question = f'{name} already exists. Would you like to overwrite it?' + r = QMessageBox.question(self, 'File Exists', question) + if r != QMessageBox.Yes: + return False + return True -class ConclusionPage(QtWidgets.QWizardPage): + +class ConclusionPage(QWizardPage): def __init__(self, parent=None): - super(ConclusionPage, self).__init__(parent) + super().__init__(parent) self.setTitle("Conclusion") - self.setPixmap(QtWidgets.QWizard.WatermarkPixmap, - QtGui.QPixmap(':/images/watermark2.png')) + self.setPixmap(QWizard.WatermarkPixmap, + QPixmap(':/images/watermark1.png')) - self.label = QtWidgets.QLabel() + self.label = QLabel() self.label.setWordWrap(True) - layout = QtWidgets.QVBoxLayout() + self._launch_check_box = QCheckBox("Launch") + self.registerField('launch', self._launch_check_box) + + layout = QVBoxLayout(self) layout.addWidget(self.label) - self.setLayout(layout) + layout.addWidget(self._launch_check_box) def initializePage(self): - finishText = self.wizard().buttonText(QtWidgets.QWizard.FinishButton) - finishText.replace('&', '') - self.label.setText("Click %s to generate the class skeleton." % finishText) + finish_text = self.wizard().buttonText(QWizard.FinishButton) + finish_text = finish_text.replace('&', '') + self.label.setText(f"Click {finish_text} to generate the class skeleton.") + self._launch_check_box.setChecked(True) if __name__ == '__main__': - - import sys - - app = QtWidgets.QApplication(sys.argv) + app = QApplication(sys.argv) wizard = ClassWizard() wizard.show() - sys.exit(app.exec_()) + sys.exit(app.exec()) |