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 |
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)) |