Project/CreateDialogCodeDialog.py

changeset 6547
77c817301ca1
parent 6544
51996454f89f
child 6548
21f8260753b5
equal deleted inserted replaced
6546:30829a28e969 6547:77c817301ca1
6 """ 6 """
7 Module implementing a dialog to generate code for a Qt4/Qt5 dialog. 7 Module implementing a dialog to generate code for a Qt4/Qt5 dialog.
8 """ 8 """
9 9
10 from __future__ import unicode_literals 10 from __future__ import unicode_literals
11 try:
12 str = unicode # __IGNORE_EXCEPTION__
13 except NameError:
14 pass
11 15
12 import os 16 import os
13 import sys 17 import json
14 import xml.etree.ElementTree 18 import xml.etree.ElementTree
15 19
16 from PyQt5.QtCore import QMetaObject, QByteArray, QRegExp, Qt, pyqtSlot, \ 20 from PyQt5.QtCore import QMetaObject, QByteArray, QRegExp, Qt, pyqtSlot, \
17 QMetaMethod, QSortFilterProxyModel 21 QMetaMethod, QSortFilterProxyModel, QProcess
18 from PyQt5.QtGui import QStandardItemModel, QBrush, QStandardItem 22 from PyQt5.QtGui import QStandardItemModel, QBrush, QStandardItem
19 from PyQt5.QtWidgets import QWidget, QDialog, QDialogButtonBox, QAction 23 from PyQt5.QtWidgets import QWidget, QDialog, QDialogButtonBox, QAction
20 from PyQt5 import uic 24 from PyQt5 import uic
21 25
22 26
27 from .NewDialogClassDialog import NewDialogClassDialog 31 from .NewDialogClassDialog import NewDialogClassDialog
28 32
29 from eric6config import getConfig 33 from eric6config import getConfig
30 34
31 from Globals import qVersionTuple 35 from Globals import qVersionTuple
32
33 import Utilities
34 36
35 37
36 pyqtSignatureRole = Qt.UserRole + 1 38 pyqtSignatureRole = Qt.UserRole + 1
37 pythonSignatureRole = Qt.UserRole + 2 39 pythonSignatureRole = Qt.UserRole + 2
38 rubySignatureRole = Qt.UserRole + 3 40 rubySignatureRole = Qt.UserRole + 3
143 145
144 @return flag indicating an initialzation error (boolean) 146 @return flag indicating an initialzation error (boolean)
145 """ 147 """
146 return self.__initError 148 return self.__initError
147 149
148 def __loadUi(self, formFile, package=""): 150 def __objectNameExternal(self):
149 """ 151 """
150 Private method to load a form file and instantiate the defined form. 152 Private method to get the object name of a form via an external
151 153 interpreter.
152 @param formFile path of the form file to be loaded 154
153 @type str 155 @return object name
154 @param package base path to be used for relative imports 156 @rtype str
155 @type str 157 """
156 @return instantiated form
157 @rtype QWidget
158 """
159 oldSysPath = []
160 interpreter = self.project.getDebugProperty("INTERPRETER") 158 interpreter = self.project.getDebugProperty("INTERPRETER")
161 if interpreter: 159 objectName = ""
162 oldSysPath = sys.path[:] 160
163 sys.path = oldSysPath + Utilities.getSysPath(interpreter) 161 loadUi = os.path.join(os.path.dirname(__file__), "UicLoadUi.py")
164 162 args = [
165 dlg = uic.loadUi(formFile, package=package) 163 loadUi,
166 164 "object_name",
167 if oldSysPath: 165 self.formFile,
168 sys.path = oldSysPath 166 self.project.getProjectPath(),
169 167 ]
170 return dlg 168
169 proc = QProcess()
170 proc.start(interpreter, args)
171 finished = proc.waitForFinished(30000)
172 if finished:
173 text = proc.readAllStandardOutput()
174 if proc.exitCode() == 0:
175 objectName = str(text, "utf-8", "replace").strip()
176 else:
177 errorText = str(text, "utf-8", "replace")
178 E5MessageBox.critical(
179 self,
180 self.tr("uic error"),
181 self.tr(
182 """<p>There was an error loading the form <b>{0}</b>"""
183 """.</p><p>{1}</p>""").format(
184 self.formFile, errorText))
185
186 return objectName
171 187
172 def __objectName(self): 188 def __objectName(self):
173 """ 189 """
174 Private method to get the object name of the dialog. 190 Private method to get the object name of a form.
175 191
176 @return object name (string) 192 @return object name
177 """ 193 @rtype str
178 try: 194 """
179 dlg = self.__loadUi( 195 if self.project.getDebugProperty("INTERPRETER"):
180 self.formFile, package=self.project.getProjectPath()) 196 return self.__objectNameExternal()
181 return dlg.objectName() 197 else:
182 except (AttributeError, ImportError, 198 try:
183 xml.etree.ElementTree.ParseError) as err: 199 dlg = uic.loadUi(
184 E5MessageBox.critical( 200 self.formFile, package=self.project.getProjectPath())
185 self, 201 return dlg.objectName()
186 self.tr("uic error"), 202 except (AttributeError, ImportError,
187 self.tr( 203 xml.etree.ElementTree.ParseError) as err:
188 """<p>There was an error loading the form <b>{0}</b>""" 204 E5MessageBox.critical(
189 """.</p><p>{1}</p>""").format(self.formFile, str(err))) 205 self,
190 return "" 206 self.tr("uic error"),
191 207 self.tr(
208 """<p>There was an error loading the form <b>{0}</b>"""
209 """.</p><p>{1}</p>""").format(self.formFile, str(err)))
210 return ""
211
212 def __classNameExternal(self):
213 """
214 Private method to get the class name of a form via an external
215 interpreter.
216
217 @return class name
218 @rtype str
219 """
220 interpreter = self.project.getDebugProperty("INTERPRETER")
221 className = ""
222
223 loadUi = os.path.join(os.path.dirname(__file__), "UicLoadUi.py")
224 args = [
225 loadUi,
226 "class_name",
227 self.formFile,
228 self.project.getProjectPath(),
229 ]
230
231 proc = QProcess()
232 proc.start(interpreter, args)
233 finished = proc.waitForFinished(30000)
234 if finished:
235 text = proc.readAllStandardOutput()
236 if proc.exitCode() == 0:
237 className = str(text, "utf-8", "replace").strip()
238 else:
239 errorText = str(text, "utf-8", "replace")
240 E5MessageBox.critical(
241 self,
242 self.tr("uic error"),
243 self.tr(
244 """<p>There was an error loading the form <b>{0}</b>"""
245 """.</p><p>{1}</p>""").format(
246 self.formFile, errorText))
247
248 return className
249
192 def __className(self): 250 def __className(self):
193 """ 251 """
194 Private method to get the class name of the dialog. 252 Private method to get the class name of a form.
195 253
196 @return class name (sting) 254 @return class name
197 """ 255 @rtype str
198 try: 256 """
199 dlg = self.__loadUi( 257 if self.project.getDebugProperty("INTERPRETER"):
200 self.formFile, package=self.project.getProjectPath()) 258 return self.__objectNameExternal()
201 return dlg.metaObject().className() 259 else:
202 except (AttributeError, ImportError, 260 try:
203 xml.etree.ElementTree.ParseError) as err: 261 dlg = uic.loadUi(
204 E5MessageBox.critical( 262 self.formFile, package=self.project.getProjectPath())
205 self, 263 return dlg.metaObject().className()
206 self.tr("uic error"), 264 except (AttributeError, ImportError,
207 self.tr( 265 xml.etree.ElementTree.ParseError) as err:
208 """<p>There was an error loading the form <b>{0}</b>""" 266 E5MessageBox.critical(
209 """.</p><p>{1}</p>""").format(self.formFile, str(err))) 267 self,
210 return "" 268 self.tr("uic error"),
211 269 self.tr(
270 """<p>There was an error loading the form <b>{0}</b>"""
271 """.</p><p>{1}</p>""").format(self.formFile, str(err)))
272 return ""
273
212 def __signatures(self): 274 def __signatures(self):
213 """ 275 """
214 Private slot to get the signatures. 276 Private slot to get the signatures.
215 277
216 @return list of signatures (list of strings) 278 @return list of signatures (list of strings)
241 @param type_ type as reported by Qt (QByteArray) 303 @param type_ type as reported by Qt (QByteArray)
242 @return mapped Python type (string) 304 @return mapped Python type (string)
243 """ 305 """
244 mapped = bytes(type_).decode() 306 mapped = bytes(type_).decode()
245 307
308 # I. always check for *
309 mapped = mapped.replace("*", "")
310
246 if self.project.getProjectLanguage() != "Python2" or \ 311 if self.project.getProjectLanguage() != "Python2" or \
247 self.project.getProjectType in ("PySide", "PySide2"): 312 self.project.getProjectType in ("PySide", "PySide2"):
248 # 1. check for const 313 # 1. check for const
249 mapped = mapped.replace("const ", "") 314 mapped = mapped.replace("const ", "")
250 315
251 # 2. check for * 316 # 2. replace QString and QStringList
252 mapped = mapped.replace("*", "")
253
254 # 3. replace QString and QStringList
255 mapped = mapped.replace("QStringList", "list")\ 317 mapped = mapped.replace("QStringList", "list")\
256 .replace("QString", "str") 318 .replace("QString", "str")
257 319
258 # 4. replace double by float 320 # 3. replace double by float
259 mapped = mapped.replace("double", "float") 321 mapped = mapped.replace("double", "float")
260 322
261 return mapped 323 return mapped
262 324
263 def __updateSlotsModel(self): 325 def __updateSlotsModelExternal(self):
264 """ 326 """
265 Private slot to update the slots tree display. 327 Private slot to update the slots tree display getting the data via an
266 """ 328 external interpreter.
267 self.filterEdit.clear() 329 """
268 330 interpreter = self.project.getDebugProperty("INTERPRETER")
269 try: 331 objectsList = []
270 dlg = self.__loadUi( 332
271 self.formFile, package=self.project.getProjectPath()) 333 loadUi = os.path.join(os.path.dirname(__file__), "UicLoadUi.py")
272 objects = dlg.findChildren(QWidget) + dlg.findChildren(QAction) 334 args = [
273 335 loadUi,
274 signatureList = self.__signatures() 336 "signatures",
275 337 self.formFile,
276 self.slotsModel.clear() 338 self.project.getProjectPath(),
277 self.slotsModel.setHorizontalHeaderLabels([""]) 339 ]
278 for obj in objects: 340
279 name = obj.objectName() 341 proc = QProcess()
280 if not name or name.startswith("qt_"): 342 proc.start(interpreter, args)
281 # ignore un-named or internal objects 343 finished = proc.waitForFinished(30000)
282 continue 344 if not finished:
283 345 return
284 metaObject = obj.metaObject() 346
285 className = metaObject.className() 347 text = proc.readAllStandardOutput()
286 itm = QStandardItem("{0} ({1})".format(name, className)) 348 if proc.exitCode() != 0:
287 self.slotsModel.appendRow(itm) 349 errorText = str(text, "utf-8", "replace")
288 for index in range(metaObject.methodCount()):
289 metaMethod = metaObject.method(index)
290 if metaMethod.methodType() == QMetaMethod.Signal:
291 if qVersionTuple() >= (5, 0, 0):
292 itm2 = QStandardItem("on_{0}_{1}".format(
293 name,
294 bytes(metaMethod.methodSignature()).decode()))
295 else:
296 itm2 = QStandardItem("on_{0}_{1}".format(
297 name, metaMethod.signature()))
298 itm.appendRow(itm2)
299 if self.__module is not None:
300 if qVersionTuple() >= (5, 0, 0):
301 method = "on_{0}_{1}".format(
302 name,
303 bytes(metaMethod.methodSignature())
304 .decode().split("(")[0])
305 else:
306 method = "on_{0}_{1}".format(
307 name, metaMethod.signature().split("(")[0])
308 method2 = "{0}({1})".format(
309 method, ", ".join(
310 [self.__mapType(t)
311 for t in metaMethod.parameterTypes()]))
312
313 if method2 in signatureList or \
314 method in signatureList:
315 itm2.setFlags(Qt.ItemFlags(Qt.ItemIsEnabled))
316 itm2.setCheckState(Qt.Checked)
317 itm2.setForeground(QBrush(Qt.blue))
318 continue
319
320 returnType = self.__mapType(
321 metaMethod.typeName().encode())
322 if returnType == 'void':
323 returnType = ""
324 parameterTypesList = [
325 self.__mapType(t)
326 for t in metaMethod.parameterTypes()]
327 pyqtSignature = ", ".join(parameterTypesList)
328
329 parameterNames = metaMethod.parameterNames()
330 if parameterNames:
331 for index in range(len(parameterNames)):
332 if not parameterNames[index]:
333 parameterNames[index] = \
334 QByteArray("p{0:d}".format(index)
335 .encode("utf-8"))
336 parameterNamesList = [bytes(n).decode()
337 for n in parameterNames]
338 methNamesSig = ", ".join(parameterNamesList)
339
340 if methNamesSig:
341 if qVersionTuple() >= (5, 0, 0):
342 pythonSignature = \
343 "on_{0}_{1}(self, {2})".format(
344 name,
345 bytes(metaMethod.methodSignature())
346 .decode().split("(")[0],
347 methNamesSig)
348 else:
349 pythonSignature = \
350 "on_{0}_{1}(self, {2})".format(
351 name,
352 metaMethod.signature().split("(")[0],
353 methNamesSig)
354 else:
355 if qVersionTuple() >= (5, 0, 0):
356 pythonSignature = "on_{0}_{1}(self)".format(
357 name,
358 bytes(metaMethod.methodSignature())
359 .decode().split("(")[0])
360 else:
361 pythonSignature = "on_{0}_{1}(self)".format(
362 name,
363 metaMethod.signature().split("(")[0])
364 itm2.setData(pyqtSignature, pyqtSignatureRole)
365 itm2.setData(pythonSignature, pythonSignatureRole)
366 itm2.setData(returnType, returnTypeRole)
367 itm2.setData(parameterTypesList,
368 parameterTypesListRole)
369 itm2.setData(parameterNamesList,
370 parameterNamesListRole)
371
372 itm2.setFlags(Qt.ItemFlags(
373 Qt.ItemIsUserCheckable |
374 Qt.ItemIsEnabled |
375 Qt.ItemIsSelectable)
376 )
377 itm2.setCheckState(Qt.Unchecked)
378
379 self.slotsView.sortByColumn(0, Qt.AscendingOrder)
380 except (AttributeError, ImportError,
381 xml.etree.ElementTree.ParseError) as err:
382 E5MessageBox.critical( 350 E5MessageBox.critical(
383 self, 351 self,
384 self.tr("uic error"), 352 self.tr("uic error"),
385 self.tr( 353 self.tr(
386 """<p>There was an error loading the form <b>{0}</b>""" 354 """<p>There was an error loading the form <b>{0}</b>"""
387 """.</p><p>{1}</p>""").format(self.formFile, str(err))) 355 """.</p><p>{1}</p>""").format(
356 self.formFile, errorText))
357 else:
358 objectsListStr = str(text, "utf-8", "replace").strip()
359 objectsList = json.loads(objectsListStr)
360
361 signatureList = self.__signatures()
362
363 for objectDict in objectsList:
364 itm = QStandardItem("{0} ({1})".format(
365 objectDict["name"],
366 objectDict["class_name"]))
367 self.slotsModel.appendRow(itm)
368 for methodDict in objectDict["methods"]:
369 itm2 = QStandardItem(methodDict["signature"])
370 itm.appendRow(itm2)
371
372 if self.__module is not None:
373 if methodDict["methods"][0] in signatureList or \
374 methodDict["methods"][1] in signatureList:
375 itm2.setFlags(
376 Qt.ItemFlags(Qt.ItemIsEnabled))
377 itm2.setCheckState(Qt.Checked)
378 itm2.setForeground(QBrush(Qt.blue))
379 continue
380
381 itm2.setData(methodDict["pyqt_signature"],
382 pyqtSignatureRole)
383 itm2.setData(methodDict["python_signature"],
384 pythonSignatureRole)
385 itm2.setData(methodDict["return_type"],
386 returnTypeRole)
387 itm2.setData(methodDict["parameter_types"],
388 parameterTypesListRole)
389 itm2.setData(methodDict["parameter_names"],
390 parameterNamesListRole)
391
392 itm2.setFlags(Qt.ItemFlags(
393 Qt.ItemIsUserCheckable |
394 Qt.ItemIsEnabled |
395 Qt.ItemIsSelectable)
396 )
397 itm2.setCheckState(Qt.Unchecked)
398
399 self.slotsView.sortByColumn(0, Qt.AscendingOrder)
400
401 def __updateSlotsModel(self):
402 """
403 Private slot to update the slots tree display.
404 """
405 self.filterEdit.clear()
406
407 if self.project.getDebugProperty("INTERPRETER"):
408 self.__updateSlotsModelExternal()
409 else:
410 try:
411 dlg = uic.loadUi(
412 self.formFile, package=self.project.getProjectPath())
413 objects = dlg.findChildren(QWidget) + dlg.findChildren(QAction)
414
415 signatureList = self.__signatures()
416
417 self.slotsModel.clear()
418 self.slotsModel.setHorizontalHeaderLabels([""])
419 for obj in objects:
420 name = obj.objectName()
421 if not name or name.startswith("qt_"):
422 # ignore un-named or internal objects
423 continue
424
425 metaObject = obj.metaObject()
426 className = metaObject.className()
427 itm = QStandardItem("{0} ({1})".format(name, className))
428 self.slotsModel.appendRow(itm)
429 for index in range(metaObject.methodCount()):
430 metaMethod = metaObject.method(index)
431 if metaMethod.methodType() == QMetaMethod.Signal:
432 if qVersionTuple() >= (5, 0, 0):
433 itm2 = QStandardItem("on_{0}_{1}".format(
434 name,
435 bytes(metaMethod.methodSignature())
436 .decode()
437 ))
438 else:
439 itm2 = QStandardItem("on_{0}_{1}".format(
440 name, metaMethod.signature()
441 ))
442 itm.appendRow(itm2)
443 if self.__module is not None:
444 if qVersionTuple() >= (5, 0, 0):
445 method = "on_{0}_{1}".format(
446 name,
447 bytes(metaMethod.methodSignature())
448 .decode().split("(")[0])
449 else:
450 method = "on_{0}_{1}".format(
451 name,
452 metaMethod.signature().split("(")[0])
453 method2 = "{0}({1})".format(
454 method,
455 ", ".join([
456 self.__mapType(t)
457 for t in metaMethod.parameterTypes()
458 ])
459 )
460
461 if method2 in signatureList or \
462 method in signatureList:
463 itm2.setFlags(
464 Qt.ItemFlags(Qt.ItemIsEnabled))
465 itm2.setCheckState(Qt.Checked)
466 itm2.setForeground(QBrush(Qt.blue))
467 continue
468
469 returnType = self.__mapType(
470 metaMethod.typeName().encode())
471 if returnType == 'void':
472 returnType = ""
473 parameterTypesList = [
474 self.__mapType(t)
475 for t in metaMethod.parameterTypes()]
476 pyqtSignature = ", ".join(parameterTypesList)
477
478 parameterNames = metaMethod.parameterNames()
479 if parameterNames:
480 for index in range(len(parameterNames)):
481 if not parameterNames[index]:
482 parameterNames[index] = \
483 QByteArray("p{0:d}".format(index)
484 .encode("utf-8"))
485 parameterNamesList = [bytes(n).decode()
486 for n in parameterNames]
487 methNamesSig = ", ".join(parameterNamesList)
488
489 if methNamesSig:
490 if qVersionTuple() >= (5, 0, 0):
491 pythonSignature = \
492 "on_{0}_{1}(self, {2})".format(
493 name,
494 bytes(metaMethod.methodSignature())
495 .decode().split("(")[0],
496 methNamesSig)
497 else:
498 pythonSignature = \
499 "on_{0}_{1}(self, {2})".format(
500 name,
501 metaMethod.signature()
502 .split("(")[0],
503 methNamesSig)
504 else:
505 if qVersionTuple() >= (5, 0, 0):
506 pythonSignature = "on_{0}_{1}(self)"\
507 .format(
508 name,
509 bytes(metaMethod.methodSignature())
510 .decode().split("(")[0])
511 else:
512 pythonSignature = "on_{0}_{1}(self)"\
513 .format(
514 name,
515 metaMethod.signature().split(
516 "(")[0])
517 itm2.setData(pyqtSignature, pyqtSignatureRole)
518 itm2.setData(pythonSignature, pythonSignatureRole)
519 itm2.setData(returnType, returnTypeRole)
520 itm2.setData(parameterTypesList,
521 parameterTypesListRole)
522 itm2.setData(parameterNamesList,
523 parameterNamesListRole)
524
525 itm2.setFlags(Qt.ItemFlags(
526 Qt.ItemIsUserCheckable |
527 Qt.ItemIsEnabled |
528 Qt.ItemIsSelectable)
529 )
530 itm2.setCheckState(Qt.Unchecked)
531
532 self.slotsView.sortByColumn(0, Qt.AscendingOrder)
533 except (AttributeError, ImportError,
534 xml.etree.ElementTree.ParseError) as err:
535 E5MessageBox.critical(
536 self,
537 self.tr("uic error"),
538 self.tr(
539 """<p>There was an error loading the form <b>{0}</b>"""
540 """.</p><p>{1}</p>""").format(self.formFile, str(err)))
388 541
389 def __generateCode(self): 542 def __generateCode(self):
390 """ 543 """
391 Private slot to generate the code as requested by the user. 544 Private slot to generate the code as requested by the user.
392 """ 545 """

eric ide

mercurial