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