Project/CreateDialogCodeDialog.py

branch
Py2 comp.
changeset 3057
10516539f238
parent 2791
a9577f248f04
parent 2995
63d874899b8b
child 3058
0a02c433f52d
equal deleted inserted replaced
3056:9986ec0e559a 3057:10516539f238
9 9
10 from __future__ import unicode_literals # __IGNORE_WARNING__ 10 from __future__ import unicode_literals # __IGNORE_WARNING__
11 11
12 import os 12 import os
13 13
14 from PyQt4.QtCore import QMetaObject, QByteArray, QRegExp, Qt, pyqtSlot, QMetaMethod, \ 14 from PyQt4.QtCore import QMetaObject, QByteArray, QRegExp, Qt, pyqtSlot, \
15 qVersion 15 QMetaMethod, qVersion
16 from PyQt4.QtGui import QWidget, QSortFilterProxyModel, QStandardItemModel, QDialog, \ 16 from PyQt4.QtGui import QWidget, QSortFilterProxyModel, QStandardItemModel, \
17 QBrush, QStandardItem, QDialogButtonBox, QAction 17 QDialog, QBrush, QStandardItem, QDialogButtonBox, QAction
18 from PyQt4 import uic 18 from PyQt4 import uic
19 19
20 from E5Gui.E5Application import e5App 20 from E5Gui.E5Application import e5App
21 from E5Gui import E5MessageBox 21 from E5Gui import E5MessageBox
22 22
31 31
32 class CreateDialogCodeDialog(QDialog, Ui_CreateDialogCodeDialog): 32 class CreateDialogCodeDialog(QDialog, Ui_CreateDialogCodeDialog):
33 """ 33 """
34 Class implementing a dialog to generate code for a Qt4/Qt5 dialog. 34 Class implementing a dialog to generate code for a Qt4/Qt5 dialog.
35 """ 35 """
36 DialogClasses = {"QDialog", "QWidget", "QMainWindow", "QWizard", "QWizardPage", 36 DialogClasses = {
37 "QDialog", "QWidget", "QMainWindow", "QWizard", "QWizardPage",
37 "QDockWidget", "QFrame", "QGroupBox", "QScrollArea", "QMdiArea", 38 "QDockWidget", "QFrame", "QGroupBox", "QScrollArea", "QMdiArea",
38 "QTabWidget", "QToolBox", "QStackedWidget"} 39 "QTabWidget", "QToolBox", "QStackedWidget"
40 }
39 Separator = 25 * "=" 41 Separator = 25 * "="
40 42
41 def __init__(self, formName, project, parent=None): 43 def __init__(self, formName, project, parent=None):
42 """ 44 """
43 Constructor 45 Constructor
55 57
56 self.project = project 58 self.project = project
57 59
58 self.formFile = formName 60 self.formFile = formName
59 filename, ext = os.path.splitext(self.formFile) 61 filename, ext = os.path.splitext(self.formFile)
60 self.srcFile = '{0}{1}'.format(filename, self.project.getDefaultSourceExtension()) 62 self.srcFile = '{0}{1}'.format(
63 filename, self.project.getDefaultSourceExtension())
61 64
62 self.slotsModel = QStandardItemModel() 65 self.slotsModel = QStandardItemModel()
63 self.proxyModel = QSortFilterProxyModel() 66 self.proxyModel = QSortFilterProxyModel()
64 self.proxyModel.setDynamicSortFilter(True) 67 self.proxyModel.setDynamicSortFilter(True)
65 self.proxyModel.setSourceModel(self.slotsModel) 68 self.proxyModel.setSourceModel(self.slotsModel)
81 if len(splitExt) == 2: 84 if len(splitExt) == 2:
82 exts = [splitExt[1]] 85 exts = [splitExt[1]]
83 else: 86 else:
84 exts = None 87 exts = None
85 from Utilities import ModuleParser 88 from Utilities import ModuleParser
86 self.__module = ModuleParser.readModule(self.srcFile, extensions=exts, 89 self.__module = ModuleParser.readModule(
87 caching=False) 90 self.srcFile, extensions=exts, caching=False)
88 except ImportError: 91 except ImportError:
89 pass 92 pass
90 93
91 if self.__module is not None: 94 if self.__module is not None:
92 self.filenameEdit.setText(self.srcFile) 95 self.filenameEdit.setText(self.srcFile)
93 96
94 classesList = [] 97 classesList = []
95 vagueClassesList = [] 98 vagueClassesList = []
96 for cls in list(self.__module.classes.values()): 99 for cls in list(self.__module.classes.values()):
97 if not set(cls.super).isdisjoint(CreateDialogCodeDialog.DialogClasses): 100 if not set(cls.super).isdisjoint(
101 CreateDialogCodeDialog.DialogClasses):
98 classesList.append(cls.name) 102 classesList.append(cls.name)
99 else: 103 else:
100 vagueClassesList.append(cls.name) 104 vagueClassesList.append(cls.name)
101 classesList.sort() 105 classesList.sort()
102 self.classNameCombo.addItems(classesList) 106 self.classNameCombo.addItems(classesList)
103 if vagueClassesList: 107 if vagueClassesList:
104 if classesList: 108 if classesList:
105 self.classNameCombo.addItem(CreateDialogCodeDialog.Separator) 109 self.classNameCombo.addItem(
110 CreateDialogCodeDialog.Separator)
106 self.classNameCombo.addItems(sorted(vagueClassesList)) 111 self.classNameCombo.addItems(sorted(vagueClassesList))
107 112
108 if os.path.exists(self.srcFile) and \ 113 if os.path.exists(self.srcFile) and \
109 self.__module is not None and \ 114 self.__module is not None and \
110 self.classNameCombo.count() == 0: 115 self.classNameCombo.count() == 0:
111 self.__initError = True 116 self.__initError = True
112 E5MessageBox.critical(self, 117 E5MessageBox.critical(self,
113 self.trUtf8("Create Dialog Code"), 118 self.trUtf8("Create Dialog Code"),
114 self.trUtf8("""The file <b>{0}</b> exists but does not contain""" 119 self.trUtf8(
115 """ any classes.""").format(self.srcFile)) 120 """The file <b>{0}</b> exists but does not contain"""
121 """ any classes.""").format(self.srcFile))
116 122
117 self.okButton.setEnabled(self.classNameCombo.count() > 0) 123 self.okButton.setEnabled(self.classNameCombo.count() > 0)
118 124
119 self.__updateSlotsModel() 125 self.__updateSlotsModel()
120 126
136 dlg = uic.loadUi(self.formFile) 142 dlg = uic.loadUi(self.formFile)
137 return dlg.objectName() 143 return dlg.objectName()
138 except (AttributeError, ImportError) as err: 144 except (AttributeError, ImportError) as err:
139 E5MessageBox.critical(self, 145 E5MessageBox.critical(self,
140 self.trUtf8("uic error"), 146 self.trUtf8("uic error"),
141 self.trUtf8("""<p>There was an error loading the form <b>{0}</b>.</p>""" 147 self.trUtf8(
142 """<p>{1}</p>""").format(self.formFile, str(err))) 148 """<p>There was an error loading the form <b>{0}</b>"""
149 """.</p><p>{1}</p>""").format(self.formFile, str(err)))
143 return "" 150 return ""
144 151
145 def __className(self): 152 def __className(self):
146 """ 153 """
147 Private method to get the class name of the dialog. 154 Private method to get the class name of the dialog.
152 dlg = uic.loadUi(self.formFile) 159 dlg = uic.loadUi(self.formFile)
153 return dlg.metaObject().className() 160 return dlg.metaObject().className()
154 except (AttributeError, ImportError) as err: 161 except (AttributeError, ImportError) as err:
155 E5MessageBox.critical(self, 162 E5MessageBox.critical(self,
156 self.trUtf8("uic error"), 163 self.trUtf8("uic error"),
157 self.trUtf8("""<p>There was an error loading the form <b>{0}</b>.</p>""" 164 self.trUtf8(
158 """<p>{1}</p>""").format(self.formFile, str(err))) 165 """<p>There was an error loading the form <b>{0}</b>"""
166 """.</p><p>{1}</p>""").format(self.formFile, str(err)))
159 return "" 167 return ""
160 168
161 def __signatures(self): 169 def __signatures(self):
162 """ 170 """
163 Private slot to get the signatures. 171 Private slot to get the signatures.
172 if clsName: 180 if clsName:
173 cls = self.__module.classes[clsName] 181 cls = self.__module.classes[clsName]
174 for meth in list(cls.methods.values()): 182 for meth in list(cls.methods.values()):
175 if meth.name.startswith("on_"): 183 if meth.name.startswith("on_"):
176 if meth.pyqtSignature is not None: 184 if meth.pyqtSignature is not None:
177 sig = ", ".join([bytes(QMetaObject.normalizedType(t)).decode() \ 185 sig = ", ".join(
178 for t in meth.pyqtSignature.split(",")]) 186 [bytes(QMetaObject.normalizedType(t)).decode()
187 for t in meth.pyqtSignature.split(",")])
179 signatures.append("{0}({1})".format(meth.name, sig)) 188 signatures.append("{0}({1})".format(meth.name, sig))
180 else: 189 else:
181 signatures.append(meth.name) 190 signatures.append(meth.name)
182 return signatures 191 return signatures
183 192
198 207
199 # 2. check fpr * 208 # 2. check fpr *
200 mapped = mapped.replace("*", "") 209 mapped = mapped.replace("*", "")
201 210
202 # 3. replace QString and QStringList 211 # 3. replace QString and QStringList
203 mapped = mapped.replace("QStringList", "list").replace("QString", "str") 212 mapped = mapped.replace("QStringList", "list")\
213 .replace("QString", "str")
204 214
205 # 4. replace double by float 215 # 4. replace double by float
206 mapped = mapped.replace("double", "float") 216 mapped = mapped.replace("double", "float")
207 217
208 return mapped 218 return mapped
233 for index in range(metaObject.methodCount()): 243 for index in range(metaObject.methodCount()):
234 metaMethod = metaObject.method(index) 244 metaMethod = metaObject.method(index)
235 if metaMethod.methodType() == QMetaMethod.Signal: 245 if metaMethod.methodType() == QMetaMethod.Signal:
236 if qVersion() >= "5.0.0": 246 if qVersion() >= "5.0.0":
237 itm2 = QStandardItem("on_{0}_{1}".format( 247 itm2 = QStandardItem("on_{0}_{1}".format(
238 name, bytes(metaMethod.methodSignature()).decode())) 248 name,
249 bytes(metaMethod.methodSignature()).decode()))
239 else: 250 else:
240 itm2 = QStandardItem("on_{0}_{1}".format( 251 itm2 = QStandardItem("on_{0}_{1}".format(
241 name, metaMethod.signature())) 252 name, metaMethod.signature()))
242 itm.appendRow(itm2) 253 itm.appendRow(itm2)
243 if self.__module is not None: 254 if self.__module is not None:
244 if qVersion() >= "5.0.0": 255 if qVersion() >= "5.0.0":
245 method = "on_{0}_{1}".format( 256 method = "on_{0}_{1}".format(
246 name, bytes(metaMethod.methodSignature()).decode()\ 257 name,
247 .split("(")[0]) 258 bytes(metaMethod.methodSignature())\
259 .decode().split("(")[0])
248 else: 260 else:
249 method = "on_{0}_{1}".format( 261 method = "on_{0}_{1}".format(
250 name, metaMethod.signature().split("(")[0]) 262 name, metaMethod.signature().split("(")[0])
251 method2 = "{0}({1})".format(method, 263 method2 = "{0}({1})".format(method,
252 ", ".join([self.__mapType(t) 264 ", ".join(
253 for t in metaMethod.parameterTypes()])) 265 [self.__mapType(t)
266 for t in metaMethod.parameterTypes()]))
254 267
255 if method2 in signatureList or method in signatureList: 268 if method2 in signatureList or \
269 method in signatureList:
256 itm2.setFlags(Qt.ItemFlags(Qt.ItemIsEnabled)) 270 itm2.setFlags(Qt.ItemFlags(Qt.ItemIsEnabled))
257 itm2.setCheckState(Qt.Checked) 271 itm2.setCheckState(Qt.Checked)
258 itm2.setForeground(QBrush(Qt.blue)) 272 itm2.setForeground(QBrush(Qt.blue))
259 continue 273 continue
260 274
267 for index in range(len(parameterNames)): 281 for index in range(len(parameterNames)):
268 if not parameterNames[index]: 282 if not parameterNames[index]:
269 parameterNames[index] = \ 283 parameterNames[index] = \
270 QByteArray("p{0:d}".format(index)) 284 QByteArray("p{0:d}".format(index))
271 methNamesSig = \ 285 methNamesSig = \
272 ", ".join([bytes(n).decode() for n in parameterNames]) 286 ", ".join(
287 [bytes(n).decode() for n in parameterNames])
273 288
274 if methNamesSig: 289 if methNamesSig:
275 if qVersion() >= "5.0.0": 290 if qVersion() >= "5.0.0":
276 pythonSignature = "on_{0}_{1}(self, {2})".format( 291 pythonSignature = \
277 name, 292 "on_{0}_{1}(self, {2})".format(
278 bytes(metaMethod.methodSignature()).decode()\ 293 name,
279 .split("(")[0], 294 bytes(metaMethod.methodSignature())\
280 methNamesSig) 295 .decode().split("(")[0],
296 methNamesSig)
281 else: 297 else:
282 pythonSignature = "on_{0}_{1}(self, {2})".format( 298 pythonSignature = \
283 name, 299 "on_{0}_{1}(self, {2})".format(
284 metaMethod.signature().split("(")[0], 300 name,
285 methNamesSig) 301 metaMethod.signature().split("(")[0],
302 methNamesSig)
286 else: 303 else:
287 if qVersion() >= "5.0.0": 304 if qVersion() >= "5.0.0":
288 pythonSignature = "on_{0}_{1}(self)".format( 305 pythonSignature = "on_{0}_{1}(self)".format(
289 name, 306 name,
290 bytes(metaMethod.methodSignature()).decode()\ 307 bytes(metaMethod.methodSignature())\
291 .split("(")[0]) 308 .decode().split("(")[0])
292 else: 309 else:
293 pythonSignature = "on_{0}_{1}(self)".format( 310 pythonSignature = "on_{0}_{1}(self)".format(
294 name, 311 name,
295 metaMethod.signature().split("(")[0]) 312 metaMethod.signature().split("(")[0])
296 itm2.setData(pyqtSignature, pyqtSignatureRole) 313 itm2.setData(pyqtSignature, pyqtSignatureRole)
305 322
306 self.slotsView.sortByColumn(0, Qt.AscendingOrder) 323 self.slotsView.sortByColumn(0, Qt.AscendingOrder)
307 except (AttributeError, ImportError) as err: 324 except (AttributeError, ImportError) as err:
308 E5MessageBox.critical(self, 325 E5MessageBox.critical(self,
309 self.trUtf8("uic error"), 326 self.trUtf8("uic error"),
310 self.trUtf8("""<p>There was an error loading the form <b>{0}</b>.</p>""" 327 self.trUtf8(
311 """<p>{1}</p>""").format(self.formFile, str(err))) 328 """<p>There was an error loading the form <b>{0}</b>"""
329 """.</p><p>{1}</p>""").format(self.formFile, str(err)))
312 330
313 def __generateCode(self): 331 def __generateCode(self):
314 """ 332 """
315 Private slot to generate the code as requested by the user. 333 Private slot to generate the code as requested by the user.
316 """ 334 """
342 if self.__module is None: 360 if self.__module is None:
343 # new file 361 # new file
344 try: 362 try:
345 if self.project.getProjectLanguage() == "Python2": 363 if self.project.getProjectLanguage() == "Python2":
346 if self.project.getProjectType() == "PySide": 364 if self.project.getProjectType() == "PySide":
347 tmplName = os.path.join(getConfig('ericCodeTemplatesDir'), 365 tmplName = os.path.join(
348 "impl_pyside.py2.tmpl") 366 getConfig('ericCodeTemplatesDir'),
367 "impl_pyside.py2.tmpl")
349 elif self.project.getProjectType() == "PyQt5": 368 elif self.project.getProjectType() == "PyQt5":
350 tmplName = os.path.join(getConfig('ericCodeTemplatesDir'), 369 tmplName = os.path.join(
351 "impl_pyqt5.py2.tmpl") 370 getConfig('ericCodeTemplatesDir'),
371 "impl_pyqt5.py2.tmpl")
352 else: 372 else:
353 tmplName = os.path.join(getConfig('ericCodeTemplatesDir'), 373 tmplName = os.path.join(
354 "impl_pyqt.py2.tmpl") 374 getConfig('ericCodeTemplatesDir'),
375 "impl_pyqt.py2.tmpl")
355 else: 376 else:
356 if self.project.getProjectType() == "PySide": 377 if self.project.getProjectType() == "PySide":
357 tmplName = os.path.join(getConfig('ericCodeTemplatesDir'), 378 tmplName = os.path.join(
358 "impl_pyside.py.tmpl") 379 getConfig('ericCodeTemplatesDir'),
380 "impl_pyside.py.tmpl")
359 elif self.project.getProjectType() == "PyQt5": 381 elif self.project.getProjectType() == "PyQt5":
360 tmplName = os.path.join(getConfig('ericCodeTemplatesDir'), 382 tmplName = os.path.join(
361 "impl_pyqt5.py.tmpl") 383 getConfig('ericCodeTemplatesDir'),
384 "impl_pyqt5.py.tmpl")
362 else: 385 else:
363 tmplName = os.path.join(getConfig('ericCodeTemplatesDir'), 386 tmplName = os.path.join(
364 "impl_pyqt.py.tmpl") 387 getConfig('ericCodeTemplatesDir'),
388 "impl_pyqt.py.tmpl")
365 tmplFile = open(tmplName, 'r', encoding="utf-8") 389 tmplFile = open(tmplName, 'r', encoding="utf-8")
366 template = tmplFile.read() 390 template = tmplFile.read()
367 tmplFile.close() 391 tmplFile.close()
368 except IOError as why: 392 except IOError as why:
369 E5MessageBox.critical(self, 393 E5MessageBox.critical(self,
370 self.trUtf8("Code Generation"), 394 self.trUtf8("Code Generation"),
371 self.trUtf8("""<p>Could not open the code template file "{0}".</p>""" 395 self.trUtf8(
372 """<p>Reason: {1}</p>""")\ 396 """<p>Could not open the code template file"""
397 """ "{0}".</p><p>Reason: {1}</p>""")\
373 .format(tmplName, str(why))) 398 .format(tmplName, str(why)))
374 return 399 return
375 400
376 objName = self.__objectName() 401 objName = self.__objectName()
377 if objName: 402 if objName:
378 template = template\ 403 template = template\
379 .replace("$FORMFILE$", 404 .replace(
380 os.path.splitext(os.path.basename(self.formFile))[0])\ 405 "$FORMFILE$",
406 os.path.splitext(os.path.basename(self.formFile))[0])\
381 .replace("$FORMCLASS$", objName)\ 407 .replace("$FORMCLASS$", objName)\
382 .replace("$CLASSNAME$", self.classNameCombo.currentText())\ 408 .replace("$CLASSNAME$", self.classNameCombo.currentText())\
383 .replace("$SUPERCLASS$", self.__className()) 409 .replace("$SUPERCLASS$", self.__className())
384 410
385 sourceImpl = template.splitlines(True) 411 sourceImpl = template.splitlines(True)
399 if not sourceImpl[-1].endswith("\n"): 425 if not sourceImpl[-1].endswith("\n"):
400 sourceImpl[-1] = "{0}{1}".format(sourceImpl[-1], "\n") 426 sourceImpl[-1] = "{0}{1}".format(sourceImpl[-1], "\n")
401 except IOError as why: 427 except IOError as why:
402 E5MessageBox.critical(self, 428 E5MessageBox.critical(self,
403 self.trUtf8("Code Generation"), 429 self.trUtf8("Code Generation"),
404 self.trUtf8("""<p>Could not open the source file "{0}".</p>""" 430 self.trUtf8(
405 """<p>Reason: {1}</p>""")\ 431 """<p>Could not open the source file "{0}".</p>"""
432 """<p>Reason: {1}</p>""")\
406 .format(self.srcFile, str(why))) 433 .format(self.srcFile, str(why)))
407 return 434 return
408 435
409 cls = self.__module.classes[self.classNameCombo.currentText()] 436 cls = self.__module.classes[self.classNameCombo.currentText()]
410 if cls.endlineno == len(sourceImpl) or cls.endlineno == -1: 437 if cls.endlineno == len(sourceImpl) or cls.endlineno == -1:
444 if child.checkState() and \ 471 if child.checkState() and \
445 child.flags() & Qt.ItemFlags(Qt.ItemIsUserCheckable): 472 child.flags() & Qt.ItemFlags(Qt.ItemIsUserCheckable):
446 slotsCode.append('{0}\n'.format(indentStr)) 473 slotsCode.append('{0}\n'.format(indentStr))
447 slotsCode.append('{0}{1}\n'.format( 474 slotsCode.append('{0}{1}\n'.format(
448 indentStr, 475 indentStr,
449 pyqtSignatureFormat.format(child.data(pyqtSignatureRole)))) 476 pyqtSignatureFormat.format(
477 child.data(pyqtSignatureRole))))
450 slotsCode.append('{0}def {1}:\n'.format( 478 slotsCode.append('{0}def {1}:\n'.format(
451 indentStr, child.data(pythonSignatureRole))) 479 indentStr, child.data(pythonSignatureRole)))
452 slotsCode.append('{0}"""\n'.format(indentStr * 2)) 480 slotsCode.append('{0}"""\n'.format(indentStr * 2))
453 slotsCode.append('{0}Slot documentation goes here.\n'.format( 481 slotsCode.append(
454 indentStr * 2)) 482 '{0}Slot documentation goes here.\n'.format(
483 indentStr * 2))
455 slotsCode.append('{0}"""\n'.format(indentStr * 2)) 484 slotsCode.append('{0}"""\n'.format(indentStr * 2))
456 slotsCode.append('{0}# {1}: not implemented yet\n'.format( 485 slotsCode.append('{0}# {1}: not implemented yet\n'.format(
457 indentStr * 2, "TODO")) 486 indentStr * 2, "TODO"))
458 slotsCode.append('{0}raise NotImplementedError\n'.format( 487 slotsCode.append('{0}raise NotImplementedError\n'.format(
459 indentStr * 2)) 488 indentStr * 2))
488 """ 517 """
489 Private slot to handle the activated signal of the classname combo. 518 Private slot to handle the activated signal of the classname combo.
490 519
491 @param index index of the activated item (integer) 520 @param index index of the activated item (integer)
492 """ 521 """
493 if self.classNameCombo.currentText() == CreateDialogCodeDialog.Separator: 522 if (self.classNameCombo.currentText() ==
523 CreateDialogCodeDialog.Separator):
494 self.okButton.setEnabled(False) 524 self.okButton.setEnabled(False)
495 self.filterEdit.clear() 525 self.filterEdit.clear()
496 self.slotsModel.clear() 526 self.slotsModel.clear()
497 self.slotsModel.setHorizontalHeaderLabels([""]) 527 self.slotsModel.setHorizontalHeaderLabels([""])
498 else: 528 else:
531 561
532 def on_buttonBox_clicked(self, button): 562 def on_buttonBox_clicked(self, button):
533 """ 563 """
534 Private slot to handle the buttonBox clicked signal. 564 Private slot to handle the buttonBox clicked signal.
535 565
536 @param button reference to the button that was clicked (QAbstractButton) 566 @param button reference to the button that was clicked
567 (QAbstractButton)
537 """ 568 """
538 if button == self.okButton: 569 if button == self.okButton:
539 self.__generateCode() 570 self.__generateCode()
540 self.accept() 571 self.accept()

eric ide

mercurial