Plugins/CheckerPlugins/Pep8/Pep8Dialog.py

changeset 2876
bfa39cf40277
parent 2874
0d754c68e1db
child 2878
61042247f793
equal deleted inserted replaced
2875:1267f0663801 2876:bfa39cf40277
65 """ 65 """
66 filenameRole = Qt.UserRole + 1 66 filenameRole = Qt.UserRole + 1
67 lineRole = Qt.UserRole + 2 67 lineRole = Qt.UserRole + 2
68 positionRole = Qt.UserRole + 3 68 positionRole = Qt.UserRole + 3
69 messageRole = Qt.UserRole + 4 69 messageRole = Qt.UserRole + 4
70 70 fixableRole = Qt.UserRole + 5
71 settingsKey = "PEP8/" 71 codeRole = Qt.UserRole + 6
72 72
73 def __init__(self, parent=None): 73 def __init__(self, parent=None):
74 """ 74 """
75 Constructor 75 Constructor
76 76
132 self.__lastFileItem = QTreeWidgetItem(self.resultList, [file]) 132 self.__lastFileItem = QTreeWidgetItem(self.resultList, [file])
133 self.__lastFileItem.setFirstColumnSpanned(True) 133 self.__lastFileItem.setFirstColumnSpanned(True)
134 self.__lastFileItem.setExpanded(True) 134 self.__lastFileItem.setExpanded(True)
135 self.__lastFileItem.setData(0, self.filenameRole, file) 135 self.__lastFileItem.setData(0, self.filenameRole, file)
136 136
137 fixable = False
137 code, message = message.split(None, 1) 138 code, message = message.split(None, 1)
138 itm = QTreeWidgetItem(self.__lastFileItem, 139 itm = QTreeWidgetItem(self.__lastFileItem,
139 ["{0:6}".format(line), code, message]) 140 ["{0:6}".format(line), code, message])
140 if code.startswith("W"): 141 if code.startswith("W"):
141 itm.setIcon(1, UI.PixmapCache.getIcon("warning.png")) 142 itm.setIcon(1, UI.PixmapCache.getIcon("warning.png"))
143 itm.setIcon(1, UI.PixmapCache.getIcon("syntaxError.png")) 144 itm.setIcon(1, UI.PixmapCache.getIcon("syntaxError.png"))
144 if fixed: 145 if fixed:
145 itm.setIcon(0, UI.PixmapCache.getIcon("issueFixed.png")) 146 itm.setIcon(0, UI.PixmapCache.getIcon("issueFixed.png"))
146 elif code in Pep8FixableIssues: 147 elif code in Pep8FixableIssues:
147 itm.setIcon(0, UI.PixmapCache.getIcon("issueFixable.png")) 148 itm.setIcon(0, UI.PixmapCache.getIcon("issueFixable.png"))
149 fixable = True
148 150
149 itm.setTextAlignment(0, Qt.AlignRight) 151 itm.setTextAlignment(0, Qt.AlignRight)
150 itm.setTextAlignment(1, Qt.AlignHCenter) 152 itm.setTextAlignment(1, Qt.AlignHCenter)
151 153
152 itm.setTextAlignment(0, Qt.AlignVCenter) 154 itm.setTextAlignment(0, Qt.AlignVCenter)
155 157
156 itm.setData(0, self.filenameRole, file) 158 itm.setData(0, self.filenameRole, file)
157 itm.setData(0, self.lineRole, int(line)) 159 itm.setData(0, self.lineRole, int(line))
158 itm.setData(0, self.positionRole, int(pos)) 160 itm.setData(0, self.positionRole, int(pos))
159 itm.setData(0, self.messageRole, message) 161 itm.setData(0, self.messageRole, message)
162 itm.setData(0, self.fixableRole, fixable)
163 itm.setData(0, self.codeRole, code)
164
165 def __modifyFixedResultItem(self, itm, text):
166 """
167 Private method to modify a result list entry to show its
168 positive fixed state.
169
170 @param itm reference to the item to modify (QTreeWidgetItem)
171 @param text text to be appended (string)
172 """
173 message = itm.data(0, self.messageRole) + text
174 itm.setText(2, message)
175 itm.setIcon(0, UI.PixmapCache.getIcon("issueFixed.png"))
176
177 itm.setData(0, self.messageRole, message)
178 itm.setData(0, self.fixableRole, False)
160 179
161 def __updateStatistics(self, statistics, fixer): 180 def __updateStatistics(self, statistics, fixer):
162 """ 181 """
163 Private method to update the collected statistics. 182 Private method to update the collected statistics.
164 183
174 self.__statistics[key] += statistics[key] 193 self.__statistics[key] += statistics[key]
175 else: 194 else:
176 self.__statistics[key] = statistics[key] 195 self.__statistics[key] = statistics[key]
177 if fixer: 196 if fixer:
178 self.__statistics["_IssuesFixed"] += fixer.fixed 197 self.__statistics["_IssuesFixed"] += fixer.fixed
198
199 def __updateFixerStatistics(self, fixer):
200 """
201 Private method to update the collected fixer related statistics.
202
203 @param fixer reference to the PEP 8 fixer (Pep8Fixer)
204 """
205 self.__statistics["_IssuesFixed"] += fixer.fixed
179 206
180 def __resetStatistics(self): 207 def __resetStatistics(self):
181 """ 208 """
182 Private slot to reset the statistics data. 209 Private slot to reset the statistics data.
183 """ 210 """
215 } 242 }
216 if "MaxLineLength" not in self.__data: 243 if "MaxLineLength" not in self.__data:
217 self.__data["MaxLineLength"] = pep8.MAX_LINE_LENGTH, 244 self.__data["MaxLineLength"] = pep8.MAX_LINE_LENGTH,
218 if "HangClosing" not in self.__data: 245 if "HangClosing" not in self.__data:
219 self.__data["HangClosing"] = False 246 self.__data["HangClosing"] = False
247 if "NoFixCodes" not in self.__data:
248 self.__data["NoFixCodes"] = "E501"
220 249
221 self.excludeFilesEdit.setText(self.__data["ExcludeFiles"]) 250 self.excludeFilesEdit.setText(self.__data["ExcludeFiles"])
222 self.excludeMessagesEdit.setText(self.__data["ExcludeMessages"]) 251 self.excludeMessagesEdit.setText(self.__data["ExcludeMessages"])
223 self.includeMessagesEdit.setText(self.__data["IncludeMessages"]) 252 self.includeMessagesEdit.setText(self.__data["IncludeMessages"])
224 self.repeatCheckBox.setChecked(self.__data["RepeatMessages"]) 253 self.repeatCheckBox.setChecked(self.__data["RepeatMessages"])
225 self.fixIssuesEdit.setText(self.__data["FixCodes"]) 254 self.fixIssuesEdit.setText(self.__data["FixCodes"])
255 self.noFixIssuesEdit.setText(self.__data["NoFixCodes"])
226 self.fixIssuesCheckBox.setChecked(self.__data["FixIssues"]) 256 self.fixIssuesCheckBox.setChecked(self.__data["FixIssues"])
227 self.lineLengthSpinBox.setValue(self.__data["MaxLineLength"]) 257 self.lineLengthSpinBox.setValue(self.__data["MaxLineLength"])
228 self.hangClosingCheckBox.setChecked(self.__data["HangClosing"]) 258 self.hangClosingCheckBox.setChecked(self.__data["HangClosing"])
229 259
230 def start(self, fn, save=False, repeat=None): 260 def start(self, fn, save=False, repeat=None):
245 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False) 275 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False)
246 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(True) 276 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(True)
247 self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True) 277 self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True)
248 self.statisticsButton.setEnabled(False) 278 self.statisticsButton.setEnabled(False)
249 self.showButton.setEnabled(False) 279 self.showButton.setEnabled(False)
280 self.fixButton.setEnabled(False)
250 if repeat is not None: 281 if repeat is not None:
251 self.repeatCheckBox.setChecked(repeat) 282 self.repeatCheckBox.setChecked(repeat)
252 QApplication.processEvents() 283 QApplication.processEvents()
253 284
254 self.__resetStatistics() 285 self.__resetStatistics()
293 # extract the configuration values 324 # extract the configuration values
294 excludeMessages = self.excludeMessagesEdit.text() 325 excludeMessages = self.excludeMessagesEdit.text()
295 includeMessages = self.includeMessagesEdit.text() 326 includeMessages = self.includeMessagesEdit.text()
296 repeatMessages = self.repeatCheckBox.isChecked() 327 repeatMessages = self.repeatCheckBox.isChecked()
297 fixCodes = self.fixIssuesEdit.text() 328 fixCodes = self.fixIssuesEdit.text()
329 noFixCodes = self.noFixIssuesEdit.text()
298 fixIssues = self.fixIssuesCheckBox.isChecked() and repeatMessages 330 fixIssues = self.fixIssuesCheckBox.isChecked() and repeatMessages
299 maxLineLength = self.lineLengthSpinBox.value() 331 maxLineLength = self.lineLengthSpinBox.value()
300 hangClosing = self.hangClosingCheckBox.isChecked() 332 hangClosing = self.hangClosingCheckBox.isChecked()
301 333
302 try: 334 try:
330 flags = Utilities.extractFlags(source) 362 flags = Utilities.extractFlags(source)
331 ext = os.path.splitext(file)[1] 363 ext = os.path.splitext(file)[1]
332 if fixIssues: 364 if fixIssues:
333 from .Pep8Fixer import Pep8Fixer 365 from .Pep8Fixer import Pep8Fixer
334 fixer = Pep8Fixer(self.__project, file, source, 366 fixer = Pep8Fixer(self.__project, file, source,
335 fixCodes, True) # always fix in place 367 fixCodes, noFixCodes, maxLineLength,
368 True) # always fix in place
336 else: 369 else:
337 fixer = None 370 fixer = None
338 if ("FileType" in flags and 371 if ("FileType" in flags and
339 flags["FileType"] in ["Python", "Python2"]) or \ 372 flags["FileType"] in ["Python", "Python2"]) or \
340 file in py2files or \ 373 file in py2files or \
438 "ExcludeFiles": self.excludeFilesEdit.text(), 471 "ExcludeFiles": self.excludeFilesEdit.text(),
439 "ExcludeMessages": self.excludeMessagesEdit.text(), 472 "ExcludeMessages": self.excludeMessagesEdit.text(),
440 "IncludeMessages": self.includeMessagesEdit.text(), 473 "IncludeMessages": self.includeMessagesEdit.text(),
441 "RepeatMessages": self.repeatCheckBox.isChecked(), 474 "RepeatMessages": self.repeatCheckBox.isChecked(),
442 "FixCodes": self.fixIssuesEdit.text(), 475 "FixCodes": self.fixIssuesEdit.text(),
476 "NoFixCodes": self.noFixIssuesEdit.text(),
443 "FixIssues": self.fixIssuesCheckBox.isChecked(), 477 "FixIssues": self.fixIssuesCheckBox.isChecked(),
444 "MaxLineLength": self.lineLengthSpinBox.value(), 478 "MaxLineLength": self.lineLengthSpinBox.value(),
445 "HangClosing": self.hangClosingCheckBox.isChecked(), 479 "HangClosing": self.hangClosingCheckBox.isChecked(),
446 } 480 }
447 if data != self.__data: 481 if data != self.__data:
452 self.resultList.clear() 486 self.resultList.clear()
453 self.noResults = True 487 self.noResults = True
454 self.cancelled = False 488 self.cancelled = False
455 self.start(self.__fileOrFileList) 489 self.start(self.__fileOrFileList)
456 490
491 def __selectCodes(self, edit, showFixCodes):
492 """
493 Private method to select message codes via a selection dialog.
494
495 @param edit reference of the line edit to be populated (QLineEdit)
496 @param showFixCodes flag indicating to show a list of fixable
497 issues (boolean)
498 """
499 from .Pep8CodeSelectionDialog import Pep8CodeSelectionDialog
500 dlg = Pep8CodeSelectionDialog(edit.text(), showFixCodes, self)
501 if dlg.exec_() == QDialog.Accepted:
502 edit.setText(dlg.getSelectedCodes())
503
457 @pyqtSlot() 504 @pyqtSlot()
458 def on_excludeMessagesSelectButton_clicked(self): 505 def on_excludeMessagesSelectButton_clicked(self):
459 """ 506 """
460 Private slot to select the message codes to be excluded via a 507 Private slot to select the message codes to be excluded via a
461 selection dialog. 508 selection dialog.
462 """ 509 """
463 from .Pep8CodeSelectionDialog import Pep8CodeSelectionDialog 510 self.__selectCodes(self.excludeMessagesEdit, False)
464 dlg = Pep8CodeSelectionDialog(
465 self.excludeMessagesEdit.text(), False, self)
466 if dlg.exec_() == QDialog.Accepted:
467 self.excludeMessagesEdit.setText(dlg.getSelectedCodes())
468 511
469 @pyqtSlot() 512 @pyqtSlot()
470 def on_includeMessagesSelectButton_clicked(self): 513 def on_includeMessagesSelectButton_clicked(self):
471 """ 514 """
472 Private slot to select the message codes to be included via a 515 Private slot to select the message codes to be included via a
473 selection dialog. 516 selection dialog.
474 """ 517 """
475 from .Pep8CodeSelectionDialog import Pep8CodeSelectionDialog 518 self.__selectCodes(self.includeMessagesEdit, False)
476 dlg = Pep8CodeSelectionDialog(
477 self.includeMessagesEdit.text(), False, self)
478 if dlg.exec_() == QDialog.Accepted:
479 self.includeMessagesEdit.setText(dlg.getSelectedCodes())
480 519
481 @pyqtSlot() 520 @pyqtSlot()
482 def on_fixIssuesSelectButton_clicked(self): 521 def on_fixIssuesSelectButton_clicked(self):
483 """ 522 """
484 Private slot to select the issue codes to be fixed via a 523 Private slot to select the issue codes to be fixed via a
485 selection dialog. 524 selection dialog.
486 """ 525 """
487 from .Pep8CodeSelectionDialog import Pep8CodeSelectionDialog 526 self.__selectCodes(self.fixIssuesEdit, True)
488 dlg = Pep8CodeSelectionDialog( 527
489 self.fixIssuesEdit.text(), True, self) 528 @pyqtSlot()
490 if dlg.exec_() == QDialog.Accepted: 529 def on_noFixIssuesSelectButton_clicked(self):
491 self.fixIssuesEdit.setText(dlg.getSelectedCodes()) 530 """
531 Private slot to select the issue codes not to be fixed via a
532 selection dialog.
533 """
534 self.__selectCodes(self.noFixIssuesEdit, True)
492 535
493 @pyqtSlot(QTreeWidgetItem, int) 536 @pyqtSlot(QTreeWidgetItem, int)
494 def on_resultList_itemActivated(self, item, column): 537 def on_resultList_itemActivated(self, item, column):
495 """ 538 """
496 Private slot to handle the activation of an item. 539 Private slot to handle the activation of an item.
510 vm = e5App().getObject("ViewManager") 553 vm = e5App().getObject("ViewManager")
511 vm.openSourceFile(fn, lineno=lineno, pos=position + 1) 554 vm.openSourceFile(fn, lineno=lineno, pos=position + 1)
512 editor = vm.getOpenEditor(fn) 555 editor = vm.getOpenEditor(fn)
513 556
514 editor.toggleFlakesWarning(lineno, True, message) 557 editor.toggleFlakesWarning(lineno, True, message)
558
559 @pyqtSlot()
560 def on_resultList_itemSelectionChanged(self):
561 """
562 Private slot to change the dialog state depending on the selection.
563 """
564 self.fixButton.setEnabled(len(self.__getSelectedFixableItems()) > 0)
515 565
516 @pyqtSlot() 566 @pyqtSlot()
517 def on_showButton_clicked(self): 567 def on_showButton_clicked(self):
518 """ 568 """
519 Private slot to handle the "Show" button press. 569 Private slot to handle the "Show" button press.
571 "PEP8/ExcludeMessages", pep8.DEFAULT_IGNORE)) 621 "PEP8/ExcludeMessages", pep8.DEFAULT_IGNORE))
572 self.includeMessagesEdit.setText(Preferences.Prefs.settings.value( 622 self.includeMessagesEdit.setText(Preferences.Prefs.settings.value(
573 "PEP8/IncludeMessages")) 623 "PEP8/IncludeMessages"))
574 self.fixIssuesEdit.setText(Preferences.Prefs.settings.value( 624 self.fixIssuesEdit.setText(Preferences.Prefs.settings.value(
575 "PEP8/FixCodes")) 625 "PEP8/FixCodes"))
626 self.noFixIssuesEdit.setText(Preferences.Prefs.settings.value(
627 "PEP8/NoFixCodes"))
576 self.fixIssuesCheckBox.setChecked(Preferences.toBool( 628 self.fixIssuesCheckBox.setChecked(Preferences.toBool(
577 Preferences.Prefs.settings.value("PEP8/FixIssues"))) 629 Preferences.Prefs.settings.value("PEP8/FixIssues")))
578 self.lineLengthSpinBox.setValue(int(Preferences.Prefs.settings.value( 630 self.lineLengthSpinBox.setValue(int(Preferences.Prefs.settings.value(
579 "PEP8/MaxLineLength", pep8.MAX_LINE_LENGTH))) 631 "PEP8/MaxLineLength", pep8.MAX_LINE_LENGTH)))
580 self.hangClosingCheckBox.setChecked(Preferences.toBool( 632 self.hangClosingCheckBox.setChecked(Preferences.toBool(
592 self.excludeMessagesEdit.text()) 644 self.excludeMessagesEdit.text())
593 Preferences.Prefs.settings.setValue("PEP8/IncludeMessages", 645 Preferences.Prefs.settings.setValue("PEP8/IncludeMessages",
594 self.includeMessagesEdit.text()) 646 self.includeMessagesEdit.text())
595 Preferences.Prefs.settings.setValue("PEP8/FixCodes", 647 Preferences.Prefs.settings.setValue("PEP8/FixCodes",
596 self.fixIssuesEdit.text()) 648 self.fixIssuesEdit.text())
649 Preferences.Prefs.settings.setValue("PEP8/NoFixCodes",
650 self.noFixIssuesEdit.text())
597 Preferences.Prefs.settings.setValue("PEP8/FixIssues", 651 Preferences.Prefs.settings.setValue("PEP8/FixIssues",
598 self.fixIssuesCheckBox.isChecked()) 652 self.fixIssuesCheckBox.isChecked())
599 Preferences.Prefs.settings.setValue("PEP8/MaxLineLength", 653 Preferences.Prefs.settings.setValue("PEP8/MaxLineLength",
600 self.lineLengthSpinBox.value()) 654 self.lineLengthSpinBox.value())
601 Preferences.Prefs.settings.setValue("PEP8/HangClosing", 655 Preferences.Prefs.settings.setValue("PEP8/HangClosing",
624 vm = e5App().getObject("ViewManager") 678 vm = e5App().getObject("ViewManager")
625 openFiles = vm.getOpenFilenames() 679 openFiles = vm.getOpenFilenames()
626 for file in openFiles: 680 for file in openFiles:
627 editor = vm.getOpenEditor(file) 681 editor = vm.getOpenEditor(file)
628 editor.clearFlakesWarnings() 682 editor.clearFlakesWarnings()
683
684 @pyqtSlot()
685 def on_fixButton_clicked(self):
686 """
687 Private slot to fix selected issues.
688 """
689 # TODO: test this
690 from .Pep8Fixer import Pep8Fixer
691
692 # build a dictionary of issues to fix
693 fixableItems = self.__getSelectedFixableItems()
694 fixesDict = {} # dictionary of lists of tuples containing
695 # the issue and the item
696 for itm in fixableItems:
697 filename = itm.data(0, self.filenameRole)
698 if filename not in fixesDict:
699 fixesDict[filename] = []
700 fixesDict[filename].append((
701 (itm.data(0, self.lineRole),
702 itm.data(0, self.positionRole),
703 "{0} {1}".format(itm.data(0, self.codeRole),
704 itm.data(0, self.messageRole))),
705 itm
706 ))
707
708 # extract the configuration values
709 fixCodes = self.fixIssuesEdit.text()
710 noFixCodes = self.noFixIssuesEdit.text()
711 maxLineLength = self.lineLengthSpinBox.value()
712
713 # now go through all the files
714 if fixesDict:
715 self.checkProgress.setMaximum(len(fixesDict))
716 progress = 0
717 for file in fixesDict:
718 self.checkProgress.setValue(progress)
719 QApplication.processEvents()
720
721 try:
722 source, encoding = Utilities.readEncodedFile(file)
723 source = source.splitlines(True)
724 except (UnicodeError, IOError) as msg:
725 # skip silently because that should not happen
726 progress += 1
727 continue
728
729 fixer = Pep8Fixer(self.__project, file, source,
730 fixCodes, noFixCodes, maxLineLength,
731 True) # always fix in place
732 errors = fixesDict[file]
733 errors.sort(key=lambda a: a[0][0])
734 for error in errors:
735 (lineno, position, text), itm = error
736 if lineno > len(source):
737 lineno = len(source)
738 fixed, msg = fixer.fixIssue(lineno, position, text)
739 if fixed:
740 text = "\n" + self.trUtf8("Fix: {0}").format(msg)
741 self.__modifyFixedResultItem(itm, text)
742 fixer.saveFile(encoding)
743
744 self.__updateFixerStatistics(fixer)
745 progress += 1
746
747 self.checkProgress.setValue(progress)
748 QApplication.processEvents()
749
750 def __getSelectedFixableItems(self):
751 """
752 Private method to extract all selected items for fixable issues.
753
754 @return selected items for fixable issues (list of QTreeWidgetItem)
755 """
756 fixableItems = []
757 for itm in self.resultList.selectedItems():
758 if itm.childCount() > 0:
759 for index in range(itm.childCount()):
760 citm = itm.child(index)
761 if self.__itemFixable(citm) and not citm in fixableItems:
762 fixableItems.append(citm)
763 elif self.__itemFixable(itm) and not itm in fixableItems:
764 fixableItems.append(itm)
765
766 return fixableItems
767
768 def __itemFixable(self, itm):
769 """
770 Private method to check, if an item has a fixable issue.
771
772 @param itm item to be checked (QTreeWidgetItem)
773 @return flag indicating a fixable issue (boolean)
774 """
775 return itm.data(0, self.fixableRole)

eric ide

mercurial