1#!/usr/bin/env python 2 3 4############################################################################# 5## 6## Copyright (C) 2013 Riverbank Computing Limited. 7## Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). 8## All rights reserved. 9## 10## This file is part of the examples of PyQt. 11## 12## $QT_BEGIN_LICENSE:BSD$ 13## You may use this file under the terms of the BSD license as follows: 14## 15## "Redistribution and use in source and binary forms, with or without 16## modification, are permitted provided that the following conditions are 17## met: 18## * Redistributions of source code must retain the above copyright 19## notice, this list of conditions and the following disclaimer. 20## * Redistributions in binary form must reproduce the above copyright 21## notice, this list of conditions and the following disclaimer in 22## the documentation and/or other materials provided with the 23## distribution. 24## * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor 25## the names of its contributors may be used to endorse or promote 26## products derived from this software without specific prior written 27## permission. 28## 29## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 31## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 32## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 33## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 34## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 35## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 36## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 37## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 39## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 40## $QT_END_LICENSE$ 41## 42############################################################################# 43 44 45from PyQt5.QtCore import QDir, QFile, QRegExp 46from PyQt5.QtGui import QPixmap 47from PyQt5.QtWidgets import (QApplication, QCheckBox, QGridLayout, QGroupBox, 48 QLabel, QLineEdit, QMessageBox, QRadioButton, QVBoxLayout, QWizard, 49 QWizardPage) 50 51import classwizard_rc 52 53 54class ClassWizard(QWizard): 55 def __init__(self, parent=None): 56 super(ClassWizard, self).__init__(parent) 57 58 self.addPage(IntroPage()) 59 self.addPage(ClassInfoPage()) 60 self.addPage(CodeStylePage()) 61 self.addPage(OutputFilesPage()) 62 self.addPage(ConclusionPage()) 63 64 self.setPixmap(QWizard.BannerPixmap, QPixmap(':/images/banner.png')) 65 self.setPixmap(QWizard.BackgroundPixmap, 66 QPixmap(':/images/background.png')) 67 68 self.setWindowTitle("Class Wizard") 69 70 def accept(self): 71 className = self.field('className') 72 baseClass = self.field('baseClass') 73 macroName = self.field('macroName') 74 baseInclude = self.field('baseInclude') 75 76 outputDir = self.field('outputDir') 77 header = self.field('header') 78 implementation = self.field('implementation') 79 80 block = '' 81 82 if self.field('comment'): 83 block += '/*\n' 84 block += ' ' + header + '\n' 85 block += '*/\n' 86 block += '\n' 87 88 if self.field('protect'): 89 block += '#ifndef ' + macroName + '\n' 90 block += '#define ' + macroName + '\n' 91 block += '\n' 92 93 if self.field('includeBase'): 94 block += '#include ' + baseInclude + '\n' 95 block += '\n' 96 97 block += 'class ' + className 98 if baseClass: 99 block += ' : public ' + baseClass 100 101 block += '\n' 102 block += '{\n' 103 104 if self.field('qobjectMacro'): 105 block += ' Q_OBJECT\n' 106 block += '\n' 107 108 block += 'public:\n' 109 110 if self.field('qobjectCtor'): 111 block += ' ' + className + '(QObject *parent = 0);\n' 112 elif self.field('qwidgetCtor'): 113 block += ' ' + className + '(QWidget *parent = 0);\n' 114 elif self.field('defaultCtor'): 115 block += ' ' + className + '();\n' 116 117 if self.field('copyCtor'): 118 block += ' ' + className + '(const ' + className + ' &other);\n' 119 block += '\n' 120 block += ' ' + className + ' &operator=' + '(const ' + className + ' &other);\n' 121 122 block += '};\n' 123 124 if self.field('protect'): 125 block += '\n' 126 block += '#endif\n' 127 128 headerFile = QFile(outputDir + '/' + header) 129 130 if not headerFile.open(QFile.WriteOnly | QFile.Text): 131 QMessageBox.warning(None, "Class Wizard", 132 "Cannot write file %s:\n%s" % (headerFile.fileName(), headerFile.errorString())) 133 return 134 135 headerFile.write(block) 136 137 block = '' 138 139 if self.field('comment'): 140 block += '/*\n' 141 block += ' ' + implementation + '\n' 142 block += '*/\n' 143 block += '\n' 144 145 block += '#include "' + header + '"\n' 146 block += '\n' 147 148 if self.field('qobjectCtor'): 149 block += className + '::' + className + '(QObject *parent)\n' 150 block += ' : ' + baseClass + '(parent)\n' 151 block += '{\n' 152 block += '}\n' 153 elif self.field('qwidgetCtor'): 154 block += className + '::' + className + '(QWidget *parent)\n' 155 block += ' : ' + baseClass + '(parent)\n' 156 block += '{\n' 157 block += '}\n' 158 elif self.field('defaultCtor'): 159 block += className + '::' + className + '()\n' 160 block += '{\n' 161 block += ' // missing code\n' 162 block += '}\n' 163 164 if self.field('copyCtor'): 165 block += '\n' 166 block += className + '::' + className + '(const ' + className + ' &other)\n' 167 block += '{\n' 168 block += ' *this = other;\n' 169 block += '}\n' 170 block += '\n' 171 block += className + ' &' + className + '::operator=(const ' + className + ' &other)\n' 172 block += '{\n' 173 174 if baseClass: 175 block += ' ' + baseClass + '::operator=(other);\n' 176 177 block += ' // missing code\n' 178 block += ' return *this;\n' 179 block += '}\n' 180 181 implementationFile = QFile(outputDir + '/' + implementation) 182 183 if not implementationFile.open(QFile.WriteOnly | QFile.Text): 184 QMessageBox.warning(None, "Class Wizard", 185 "Cannot write file %s:\n%s" % (implementationFile.fileName(), implementationFile.errorString())) 186 return 187 188 implementationFile.write(block) 189 190 super(ClassWizard, self).accept() 191 192 193class IntroPage(QWizardPage): 194 def __init__(self, parent=None): 195 super(IntroPage, self).__init__(parent) 196 197 self.setTitle("Introduction") 198 self.setPixmap(QWizard.WatermarkPixmap, 199 QPixmap(':/images/watermark1.png')) 200 201 label = QLabel("This wizard will generate a skeleton C++ class " 202 "definition, including a few functions. You simply need to " 203 "specify the class name and set a few options to produce a " 204 "header file and an implementation file for your new C++ " 205 "class.") 206 label.setWordWrap(True) 207 208 layout = QVBoxLayout() 209 layout.addWidget(label) 210 self.setLayout(layout) 211 212 213class ClassInfoPage(QWizardPage): 214 def __init__(self, parent=None): 215 super(ClassInfoPage, self).__init__(parent) 216 217 self.setTitle("Class Information") 218 self.setSubTitle("Specify basic information about the class for " 219 "which you want to generate skeleton source code files.") 220 self.setPixmap(QWizard.LogoPixmap, QPixmap(':/images/logo1.png')) 221 222 classNameLabel = QLabel("&Class name:") 223 classNameLineEdit = QLineEdit() 224 classNameLabel.setBuddy(classNameLineEdit) 225 226 baseClassLabel = QLabel("B&ase class:") 227 baseClassLineEdit = QLineEdit() 228 baseClassLabel.setBuddy(baseClassLineEdit) 229 230 qobjectMacroCheckBox = QCheckBox("Generate Q_OBJECT ¯o") 231 232 groupBox = QGroupBox("C&onstructor") 233 234 qobjectCtorRadioButton = QRadioButton("&QObject-style constructor") 235 qwidgetCtorRadioButton = QRadioButton("Q&Widget-style constructor") 236 defaultCtorRadioButton = QRadioButton("&Default constructor") 237 copyCtorCheckBox = QCheckBox("&Generate copy constructor and operator=") 238 239 defaultCtorRadioButton.setChecked(True) 240 241 defaultCtorRadioButton.toggled.connect(copyCtorCheckBox.setEnabled) 242 243 self.registerField('className*', classNameLineEdit) 244 self.registerField('baseClass', baseClassLineEdit) 245 self.registerField('qobjectMacro', qobjectMacroCheckBox) 246 self.registerField('qobjectCtor', qobjectCtorRadioButton) 247 self.registerField('qwidgetCtor', qwidgetCtorRadioButton) 248 self.registerField('defaultCtor', defaultCtorRadioButton) 249 self.registerField('copyCtor', copyCtorCheckBox) 250 251 groupBoxLayout = QVBoxLayout() 252 groupBoxLayout.addWidget(qobjectCtorRadioButton) 253 groupBoxLayout.addWidget(qwidgetCtorRadioButton) 254 groupBoxLayout.addWidget(defaultCtorRadioButton) 255 groupBoxLayout.addWidget(copyCtorCheckBox) 256 groupBox.setLayout(groupBoxLayout) 257 258 layout = QGridLayout() 259 layout.addWidget(classNameLabel, 0, 0) 260 layout.addWidget(classNameLineEdit, 0, 1) 261 layout.addWidget(baseClassLabel, 1, 0) 262 layout.addWidget(baseClassLineEdit, 1, 1) 263 layout.addWidget(qobjectMacroCheckBox, 2, 0, 1, 2) 264 layout.addWidget(groupBox, 3, 0, 1, 2) 265 self.setLayout(layout) 266 267 268class CodeStylePage(QWizardPage): 269 def __init__(self, parent=None): 270 super(CodeStylePage, self).__init__(parent) 271 272 self.setTitle("Code Style Options") 273 self.setSubTitle("Choose the formatting of the generated code.") 274 self.setPixmap(QWizard.LogoPixmap, QPixmap(':/images/logo2.png')) 275 276 commentCheckBox = QCheckBox("&Start generated files with a comment") 277 commentCheckBox.setChecked(True) 278 279 protectCheckBox = QCheckBox("&Protect header file against multiple " 280 "inclusions") 281 protectCheckBox.setChecked(True) 282 283 macroNameLabel = QLabel("&Macro name:") 284 self.macroNameLineEdit = QLineEdit() 285 macroNameLabel.setBuddy(self.macroNameLineEdit) 286 287 self.includeBaseCheckBox = QCheckBox("&Include base class definition") 288 self.baseIncludeLabel = QLabel("Base class include:") 289 self.baseIncludeLineEdit = QLineEdit() 290 self.baseIncludeLabel.setBuddy(self.baseIncludeLineEdit) 291 292 protectCheckBox.toggled.connect(macroNameLabel.setEnabled) 293 protectCheckBox.toggled.connect(self.macroNameLineEdit.setEnabled) 294 self.includeBaseCheckBox.toggled.connect(self.baseIncludeLabel.setEnabled) 295 self.includeBaseCheckBox.toggled.connect(self.baseIncludeLineEdit.setEnabled) 296 297 self.registerField('comment', commentCheckBox) 298 self.registerField('protect', protectCheckBox) 299 self.registerField('macroName', self.macroNameLineEdit) 300 self.registerField('includeBase', self.includeBaseCheckBox) 301 self.registerField('baseInclude', self.baseIncludeLineEdit) 302 303 layout = QGridLayout() 304 layout.setColumnMinimumWidth(0, 20) 305 layout.addWidget(commentCheckBox, 0, 0, 1, 3) 306 layout.addWidget(protectCheckBox, 1, 0, 1, 3) 307 layout.addWidget(macroNameLabel, 2, 1) 308 layout.addWidget(self.macroNameLineEdit, 2, 2) 309 layout.addWidget(self.includeBaseCheckBox, 3, 0, 1, 3) 310 layout.addWidget(self.baseIncludeLabel, 4, 1) 311 layout.addWidget(self.baseIncludeLineEdit, 4, 2) 312 self.setLayout(layout) 313 314 def initializePage(self): 315 className = self.field('className') 316 self.macroNameLineEdit.setText(className.upper() + "_H") 317 318 baseClass = self.field('baseClass') 319 is_baseClass = bool(baseClass) 320 321 self.includeBaseCheckBox.setChecked(is_baseClass) 322 self.includeBaseCheckBox.setEnabled(is_baseClass) 323 self.baseIncludeLabel.setEnabled(is_baseClass) 324 self.baseIncludeLineEdit.setEnabled(is_baseClass) 325 326 if not is_baseClass: 327 self.baseIncludeLineEdit.clear() 328 elif QRegExp('Q[A-Z].*').exactMatch(baseClass): 329 self.baseIncludeLineEdit.setText('<' + baseClass + '>') 330 else: 331 self.baseIncludeLineEdit.setText('"' + baseClass.lower() + '.h"') 332 333 334class OutputFilesPage(QWizardPage): 335 def __init__(self, parent=None): 336 super(OutputFilesPage, self).__init__(parent) 337 338 self.setTitle("Output Files") 339 self.setSubTitle("Specify where you want the wizard to put the " 340 "generated skeleton code.") 341 self.setPixmap(QWizard.LogoPixmap, QPixmap(':/images/logo3.png')) 342 343 outputDirLabel = QLabel("&Output directory:") 344 self.outputDirLineEdit = QLineEdit() 345 outputDirLabel.setBuddy(self.outputDirLineEdit) 346 347 headerLabel = QLabel("&Header file name:") 348 self.headerLineEdit = QLineEdit() 349 headerLabel.setBuddy(self.headerLineEdit) 350 351 implementationLabel = QLabel("&Implementation file name:") 352 self.implementationLineEdit = QLineEdit() 353 implementationLabel.setBuddy(self.implementationLineEdit) 354 355 self.registerField('outputDir*', self.outputDirLineEdit) 356 self.registerField('header*', self.headerLineEdit) 357 self.registerField('implementation*', self.implementationLineEdit) 358 359 layout = QGridLayout() 360 layout.addWidget(outputDirLabel, 0, 0) 361 layout.addWidget(self.outputDirLineEdit, 0, 1) 362 layout.addWidget(headerLabel, 1, 0) 363 layout.addWidget(self.headerLineEdit, 1, 1) 364 layout.addWidget(implementationLabel, 2, 0) 365 layout.addWidget(self.implementationLineEdit, 2, 1) 366 self.setLayout(layout) 367 368 def initializePage(self): 369 className = self.field('className') 370 self.headerLineEdit.setText(className.lower() + '.h') 371 self.implementationLineEdit.setText(className.lower() + '.cpp') 372 self.outputDirLineEdit.setText(QDir.toNativeSeparators(QDir.tempPath())) 373 374 375class ConclusionPage(QWizardPage): 376 def __init__(self, parent=None): 377 super(ConclusionPage, self).__init__(parent) 378 379 self.setTitle("Conclusion") 380 self.setPixmap(QWizard.WatermarkPixmap, 381 QPixmap(':/images/watermark2.png')) 382 383 self.label = QLabel() 384 self.label.setWordWrap(True) 385 386 layout = QVBoxLayout() 387 layout.addWidget(self.label) 388 self.setLayout(layout) 389 390 def initializePage(self): 391 finishText = self.wizard().buttonText(QWizard.FinishButton) 392 finishText.replace('&', '') 393 self.label.setText("Click %s to generate the class skeleton." % finishText) 394 395 396if __name__ == '__main__': 397 398 import sys 399 400 app = QApplication(sys.argv) 401 wizard = ClassWizard() 402 wizard.show() 403 sys.exit(app.exec_()) 404