diff -r d02708288a22 -r 7f6e04213998 RadonMetrics/MaintainabilityIndexDialog.py --- a/RadonMetrics/MaintainabilityIndexDialog.py Wed Sep 16 20:07:48 2015 +0200 +++ b/RadonMetrics/MaintainabilityIndexDialog.py Thu Sep 17 19:57:14 2015 +0200 @@ -53,14 +53,16 @@ self.resultList.headerItem().setText(self.resultList.columnCount(), "") self.radonService = radonService - self.radonService.metricsDone.connect(self.__processResult) - self.radonService.metricsError.connect(self.__processError) + self.radonService.maintainabilityIndexDone.connect( + self.__processResult) + self.radonService.error.connect(self.__processError) self.radonService.batchFinished.connect(self.__batchFinished) self.cancelled = False self.__project = e5App().getObject("Project") self.__locale = QLocale() + self.__finished = True self.__fileList = [] self.filterFrame.setVisible(False) @@ -90,6 +92,7 @@ @param values values to be displayed @type dict """ + # TODO: colorize the rank column according to rank (green, orange, red) data = [self.__project.getRelativePath(filename)] try: data.append(self.__locale.toString(float(values["mi"]), "f", 2)) @@ -99,6 +102,9 @@ itm = QTreeWidgetItem(self.resultList, data) itm.setTextAlignment(1, Qt.Alignment(Qt.AlignRight)) itm.setTextAlignment(2, Qt.Alignment(Qt.AlignHCenter)) + + if values["rank"] in ["A", "B", "C"]: + self.__summary[values["rank"]] += 1 def __createErrorItem(self, filename, message): """ @@ -172,9 +178,11 @@ if not os.path.exists(f): self.files.remove(f) - self.__summary = {"files": 0} - for key in ['loc', 'sloc', 'lloc', 'comments', 'multi', 'blank']: - self.__summary[key] = 0 + self.__summary = { + "A": 0, + "B": 0, + "C": 0, + } if len(self.files) > 0: # disable updates of the list for speed @@ -194,3 +202,208 @@ else: self.__batch = True self.maintainabilityIndexBatch() + + def maintainabilityIndex(self, codestring=''): + """ + Public method to start a maintainability index calculation for one + Python file. + + The results are reported to the __processResult slot. + + @keyparam codestring optional sourcestring + @type str + """ + if not self.files: + self.checkProgressLabel.setPath("") + self.checkProgress.setMaximum(1) + self.checkProgress.setValue(1) + self.__finish() + return + + self.filename = self.files.pop(0) + self.checkProgress.setValue(self.progress) + self.checkProgressLabel.setPath(self.filename) + QApplication.processEvents() + + if self.cancelled: + return + + try: + self.source = Utilities.readEncodedFile(self.filename)[0] + self.source = Utilities.normalizeCode(self.source) + except (UnicodeError, IOError) as msg: + self.__createErrorItem(self.filename, str(msg).rstrip()) + self.progress += 1 + # Continue with next file + self.rawMetrics() + return + + self.__finished = False + self.radonService.maintainabilityIndex( + None, self.filename, self.source) + + def maintainabilityIndexBatch(self): + """ + Public method to start a maintainability index calculation batch job. + + The results are reported to the __processResult slot. + """ + self.__lastFileItem = None + + self.checkProgressLabel.setPath(self.tr("Preparing files...")) + progress = 0 + + argumentsList = [] + for filename in self.files: + progress += 1 + self.checkProgress.setValue(progress) + QApplication.processEvents() + + try: + source = Utilities.readEncodedFile(filename)[0] + source = Utilities.normalizeCode(source) + except (UnicodeError, IOError) as msg: + self.__createErrorItem(filename, str(msg).rstrip()) + continue + + argumentsList.append((filename, source)) + + # reset the progress bar to the checked files + self.checkProgress.setValue(self.progress) + QApplication.processEvents() + + self.__finished = False + self.radonService.maintainabilityIndexBatch(argumentsList) + + def __batchFinished(self): + """ + Private slot handling the completion of a batch job. + """ + self.checkProgressLabel.setPath("") + self.checkProgress.setMaximum(1) + self.checkProgress.setValue(1) + self.__finish() + + def __processError(self, fn, msg): + """ + Private slot to process an error indication from the service. + + @param fn filename of the file + @type str + @param msg error message + @type str + """ + self.__createErrorItem(fn, msg) + + def __processResult(self, fn, result): + """ + Private slot called after perfoming a maintainability index calculation + on one file. + + @param fn filename of the file + @type str + @param result result dict + @type dict + """ + if self.__finished: + return + + # Check if it's the requested file, otherwise ignore signal if not + # in batch mode + if not self.__batch and fn != self.filename: + return + + if "error" in result: + self.__createErrorItem(fn, result["error"]) + else: + self.__createResultItem(fn, result) + + self.progress += 1 + + self.checkProgress.setValue(self.progress) + self.checkProgressLabel.setPath(fn) + QApplication.processEvents() + + if not self.__batch: + self.maintainabilityIndex() + + def __finish(self): + """ + Private slot called when the action or the user pressed the button. + """ + if not self.__finished: + self.__finished = True + + # reenable updates of the list + self.resultList.setSortingEnabled(True) + self.resultList.setUpdatesEnabled(True) + + self.cancelled = True + self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True) + self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False) + self.buttonBox.button(QDialogButtonBox.Close).setDefault(True) + + self.resultList.header().resizeSections( + QHeaderView.ResizeToContents) + self.resultList.header().setStretchLastSection(True) + if qVersion() >= "5.0.0": + self.resultList.header().setSectionResizeMode( + QHeaderView.Interactive) + else: + self.resultList.header().setResizeMode(QHeaderView.Interactive) + + self.summaryLabel.setText(self.tr( + "<table>" + "<tr><td colspan=2><b>Summary:</b></td></tr>" + "<tr><td><b>A</b></td><td>{0} files</td></tr>" + "<tr><td><b>B</b></td><td>{1} files</td></tr>" + "<tr><td><b>C</b></td><td>{2} files</td></tr>" + "</table>" + ).format(self.__summary["A"], + self.__summary["B"], + self.__summary["C"]) + ) + + self.checkProgress.setVisible(False) + self.checkProgressLabel.setVisible(False) + + @pyqtSlot(QAbstractButton) + def on_buttonBox_clicked(self, button): + """ + Private slot called by a button of the button box clicked. + + @param button button that was clicked + @type QAbstractButton + """ + if button == self.buttonBox.button(QDialogButtonBox.Close): + self.close() + elif button == self.buttonBox.button(QDialogButtonBox.Cancel): + if self.__batch: + self.radonService.cancelMaintainabilityIndexBatch() + QTimer.singleShot(1000, self.__finish) + else: + self.__finish() + + @pyqtSlot() + def on_startButton_clicked(self): + """ + Private slot to start a maintainability index run. + """ + fileList = self.__fileList[:] + + filterString = self.excludeFilesEdit.text() + if "ExcludeFiles" not in self.__data or \ + filterString != self.__data["ExcludeFiles"]: + self.__data["ExcludeFiles"] = filterString + self.__project.setData( + "OTHERTOOLSPARMS", "RadonCodeMetrics", self.__data) + filterList = [f.strip() for f in filterString.split(",") + if f.strip()] + if filterList: + for filter in filterList: + fileList = \ + [f for f in fileList if not fnmatch.fnmatch(f, filter)] + + self.resultList.clear() + self.cancelled = False + self.start(fileList)