171 """ |
171 """ |
172 Private slot to (re)initialize the plugin. |
172 Private slot to (re)initialize the plugin. |
173 """ |
173 """ |
174 self.__projectRawMetricsAct = None |
174 self.__projectRawMetricsAct = None |
175 self.__projectRawMetricsDialog = None |
175 self.__projectRawMetricsDialog = None |
|
176 self.__projectMIAct = None |
|
177 self.__projectMIDialog = None |
176 self.__projectSeparatorActs = [] |
178 self.__projectSeparatorActs = [] |
177 |
179 |
178 self.__projectBrowserMenu = None |
180 self.__projectBrowserMenu = None |
179 self.__projectBrowserRawMetricsAct = None |
181 self.__projectBrowserRawMetricsAct = None |
180 self.__projectBrowserRawMetricsDialog = None |
182 self.__projectBrowserRawMetricsDialog = None |
|
183 self.__projectBrowserMIAct = None |
|
184 self.__projectBrowserMIDialog = None |
181 self.__projectBrowserSeparatorActs = [] |
185 self.__projectBrowserSeparatorActs = [] |
182 |
186 |
183 self.__editors = [] |
187 self.__editors = [] |
184 self.__editorRawMetricsAct = None |
188 self.__editorRawMetricsAct = None |
185 self.__editorRawMetricsDialog = None |
189 self.__editorRawMetricsDialog = None |
|
190 self.__editorMIAct = None |
|
191 self.__editorMIDialog = None |
186 self.__editorSeparatorActs = [] |
192 self.__editorSeparatorActs = [] |
187 |
193 |
188 def rawMetrics(self, lang, filename, source): |
194 def rawMetrics(self, lang, filename, source): |
189 """ |
195 """ |
190 Public method to prepare raw code metrics calculation on one Python |
196 Public method to prepare raw code metrics calculation on one Python |
238 """ |
244 """ |
239 Public method to cancel all batch jobs. |
245 Public method to cancel all batch jobs. |
240 """ |
246 """ |
241 for lang in ['Python2', 'Python3']: |
247 for lang in ['Python2', 'Python3']: |
242 self.backgroundService.requestCancel('batch_radon', lang) |
248 self.backgroundService.requestCancel('batch_radon', lang) |
|
249 |
|
250 def maintainabilityIndex(self, lang, filename, source): |
|
251 """ |
|
252 Public method to prepare maintainability index calculation on one |
|
253 Python source file. |
|
254 |
|
255 @param lang language of the file or None to determine by internal |
|
256 algorithm |
|
257 @type str or None |
|
258 @param filename source filename |
|
259 @type str |
|
260 @param source string containing the code |
|
261 @type str |
|
262 """ |
|
263 if lang is None: |
|
264 lang = 'Python{0}'.format(determinePythonVersion(filename, source)) |
|
265 if lang not in ['Python2', 'Python3']: |
|
266 return |
|
267 |
|
268 self.backgroundService.enqueueRequest( |
|
269 'radon', lang, filename, [source, 'mi']) |
|
270 |
|
271 def maintainabilityIndexBatch(self, argumentsList): |
|
272 """ |
|
273 Public method to prepare maintainability index calculation on multiple |
|
274 Python source files. |
|
275 |
|
276 @param argumentsList list of arguments tuples with each tuple |
|
277 containing filename and source |
|
278 @type (str, str) |
|
279 """ |
|
280 data = { |
|
281 "Python2": [], |
|
282 "Python3": [], |
|
283 } |
|
284 for filename, source in argumentsList: |
|
285 lang = 'Python{0}'.format(determinePythonVersion(filename, source)) |
|
286 if lang not in ['Python2', 'Python3']: |
|
287 continue |
|
288 else: |
|
289 data[lang].append((filename, source, 'mi')) |
|
290 |
|
291 self.queuedBatches = [] |
|
292 for lang in ['Python2', 'Python3']: |
|
293 if data[lang]: |
|
294 self.queuedBatches.append(lang) |
|
295 self.backgroundService.enqueueRequest('batch_radon', lang, "", |
|
296 data[lang]) |
|
297 self.batchesFinished = False |
|
298 |
|
299 def cancelMaintainabilityIndexBatch(self): |
|
300 """ |
|
301 Public method to cancel all batch jobs. |
|
302 """ |
|
303 for lang in ['Python2', 'Python3']: |
|
304 self.backgroundService.requestCancel('batch_radon', lang) |
243 |
305 |
244 def activate(self): |
306 def activate(self): |
245 """ |
307 """ |
246 Public method to activate this plug-in. |
308 Public method to activate this plug-in. |
247 |
309 |
255 if menu: |
317 if menu: |
256 if not menu.isEmpty(): |
318 if not menu.isEmpty(): |
257 act = menu.addSeparator() |
319 act = menu.addSeparator() |
258 act.setText(self.tr("Radon")) |
320 act.setText(self.tr("Radon")) |
259 self.__projectSeparatorActs.append(act) |
321 self.__projectSeparatorActs.append(act) |
|
322 |
260 self.__projectRawMetricsAct = E5Action( |
323 self.__projectRawMetricsAct = E5Action( |
261 self.tr('Code Metrics'), |
324 self.tr('Code Metrics'), |
262 self.tr('Code &Metrics...'), 0, 0, |
325 self.tr('Code &Metrics...'), 0, 0, |
263 self, 'project_show_radon_raw') |
326 self, 'project_show_radon_raw') |
264 self.__projectRawMetricsAct.setStatusTip( |
327 self.__projectRawMetricsAct.setStatusTip( |
271 """ multi-line strings and blank lines.</p>""" |
334 """ multi-line strings and blank lines.</p>""" |
272 )) |
335 )) |
273 self.__projectRawMetricsAct.triggered.connect( |
336 self.__projectRawMetricsAct.triggered.connect( |
274 self.__projectRawMetrics) |
337 self.__projectRawMetrics) |
275 menu.addAction(self.__projectRawMetricsAct) |
338 menu.addAction(self.__projectRawMetricsAct) |
|
339 |
|
340 self.__projectMIAct = E5Action( |
|
341 self.tr('Maintainability Index'), |
|
342 self.tr('Maintainability &Index...'), 0, 0, |
|
343 self, 'project_show_radon_mi') |
|
344 self.__projectMIAct.setStatusTip( |
|
345 self.tr('Show the maintainability index for Python files.')) |
|
346 self.__projectMIAct.setWhatsThis(self.tr( |
|
347 """<b>Maintainability Index...</b>""" |
|
348 """<p>This calculates the maintainability index of Python""" |
|
349 """ files and shows it together with a ranking.</p>""" |
|
350 )) |
|
351 self.__projectMIAct.triggered.connect( |
|
352 self.__projectMaintainabilityIndex) |
|
353 menu.addAction(self.__projectMIAct) |
|
354 |
276 act = menu.addSeparator() |
355 act = menu.addSeparator() |
277 self.__projectSeparatorActs.append(act) |
356 self.__projectSeparatorActs.append(act) |
278 |
357 |
279 e5App().getObject("Project").addE5Actions([ |
358 e5App().getObject("Project").addE5Actions([ |
280 self.__projectRawMetricsAct, |
359 self.__projectRawMetricsAct, |
|
360 self.__projectMIAct |
281 ]) |
361 ]) |
282 |
362 |
283 act = QAction("Radon", self) |
363 act = QAction("Radon", self) |
284 act.setSeparator(True) |
364 act.setSeparator(True) |
285 self.__editorSeparatorActs.append(act) |
365 self.__editorSeparatorActs.append(act) |
298 """ of code, source lines of code, comment lines,""" |
378 """ of code, source lines of code, comment lines,""" |
299 """ multi-line strings and blank lines.</p>""" |
379 """ multi-line strings and blank lines.</p>""" |
300 )) |
380 )) |
301 self.__editorRawMetricsAct.triggered.connect(self.__editorRawMetrics) |
381 self.__editorRawMetricsAct.triggered.connect(self.__editorRawMetrics) |
302 |
382 |
|
383 self.__editorMIAct = E5Action( |
|
384 self.tr('Maintainability Index'), |
|
385 self.tr('Maintainability &Index...'), 0, 0, |
|
386 self, "") |
|
387 self.__editorMIAct.setStatusTip( |
|
388 self.tr('Show the maintainability index for Python files.')) |
|
389 self.__projectMIAct.setWhatsThis(self.tr( |
|
390 """<b>Maintainability Index...</b>""" |
|
391 """<p>This calculates the maintainability index of Python""" |
|
392 """ files and shows it together with a ranking.</p>""" |
|
393 )) |
|
394 self.__editorMIAct.triggered.connect( |
|
395 self.__editorMaintainabilityIndex) |
|
396 |
303 e5App().getObject("Project").showMenu.connect(self.__projectShowMenu) |
397 e5App().getObject("Project").showMenu.connect(self.__projectShowMenu) |
304 e5App().getObject("ProjectBrowser").getProjectBrowser("sources")\ |
398 e5App().getObject("ProjectBrowser").getProjectBrowser("sources")\ |
305 .showMenu.connect(self.__projectBrowserShowMenu) |
399 .showMenu.connect(self.__projectBrowserShowMenu) |
306 e5App().getObject("ViewManager").editorOpenedEd.connect( |
400 e5App().getObject("ViewManager").editorOpenedEd.connect( |
307 self.__editorOpened) |
401 self.__editorOpened) |
329 menu = e5App().getObject("Project").getMenu("Show") |
423 menu = e5App().getObject("Project").getMenu("Show") |
330 if menu: |
424 if menu: |
331 for sep in self.__projectSeparatorActs: |
425 for sep in self.__projectSeparatorActs: |
332 menu.removeAction(sep) |
426 menu.removeAction(sep) |
333 menu.removeAction(self.__projectRawMetricsAct) |
427 menu.removeAction(self.__projectRawMetricsAct) |
334 e5App().getObject("Project").removeE5Actions( |
428 menu.removeAction(self.__projectMIAct) |
335 [self.__projectRawMetricsAct]) |
429 e5App().getObject("Project").removeE5Actions([ |
|
430 self.__projectRawMetricsAct, |
|
431 self.__projectMIAct |
|
432 ]) |
336 |
433 |
337 if self.__projectBrowserMenu: |
434 if self.__projectBrowserMenu: |
338 for sep in self.__projectBrowserSeparatorActs: |
435 for sep in self.__projectBrowserSeparatorActs: |
339 self.__projectBrowserMenu.removeAction(sep) |
436 self.__projectBrowserMenu.removeAction(sep) |
340 if self.__projectBrowserRawMetricsAct: |
437 if self.__projectBrowserRawMetricsAct: |
341 self.__projectBrowserMenu.removeAction( |
438 self.__projectBrowserMenu.removeAction( |
342 self.__projectBrowserRawMetricsAct) |
439 self.__projectBrowserRawMetricsAct) |
|
440 if self.__projectBrowserMIAct: |
|
441 self.__projectBrowserMenu.removeAction( |
|
442 self.__projectBrowserMIAct) |
343 |
443 |
344 for editor in self.__editors: |
444 for editor in self.__editors: |
345 editor.showMenu.disconnect(self.__editorShowMenu) |
445 editor.showMenu.disconnect(self.__editorShowMenu) |
346 menu = editor.getMenu("Show") |
446 menu = editor.getMenu("Show") |
347 if menu is not None: |
447 if menu is not None: |
348 for sep in self.__editorSeparatorActs: |
448 for sep in self.__editorSeparatorActs: |
349 menu.removeAction(sep) |
449 menu.removeAction(sep) |
350 menu.removeAction(self.__editorRawMetricsAct) |
450 menu.removeAction(self.__editorRawMetricsAct) |
|
451 menu.removeAction(self.__editorMIAct) |
351 |
452 |
352 self.__initialize() |
453 self.__initialize() |
353 |
454 |
354 def __loadTranslator(self): |
455 def __loadTranslator(self): |
355 """ |
456 """ |
380 @type str |
481 @type str |
381 @param menu reference to the menu |
482 @param menu reference to the menu |
382 @type QMenu |
483 @type QMenu |
383 """ |
484 """ |
384 if menuName == "Show": |
485 if menuName == "Show": |
385 for act in [self.__projectRawMetricsAct]: |
486 for act in [self.__projectRawMetricsAct, self.__projectMIAct]: |
386 if act is not None: |
487 if act is not None: |
387 act.setEnabled( |
488 act.setEnabled( |
388 e5App().getObject("Project").getProjectLanguage() in |
489 e5App().getObject("Project").getProjectLanguage() in |
389 ["Python3", "Python2", "Python"]) |
490 ["Python3", "Python2", "Python"]) |
390 |
491 |
419 """ multi-line strings and blank lines.</p>""" |
520 """ multi-line strings and blank lines.</p>""" |
420 )) |
521 )) |
421 self.__projectBrowserRawMetricsAct.triggered.connect( |
522 self.__projectBrowserRawMetricsAct.triggered.connect( |
422 self.__projectBrowserRawMetrics) |
523 self.__projectBrowserRawMetrics) |
423 menu.addAction(self.__projectBrowserRawMetricsAct) |
524 menu.addAction(self.__projectBrowserRawMetricsAct) |
|
525 |
|
526 self.__projectBrowserMIAct = E5Action( |
|
527 self.tr('Maintainability Index'), |
|
528 self.tr('Maintainability &Index...'), 0, 0, |
|
529 self, 'project_show_radon_mi') |
|
530 self.__projectBrowserMIAct.setStatusTip( |
|
531 self.tr('Show the maintainability index for Python' |
|
532 ' files.')) |
|
533 self.__projectBrowserMIAct.setWhatsThis(self.tr( |
|
534 """<b>Maintainability Index...</b>""" |
|
535 """<p>This calculates the maintainability index of""" |
|
536 """ Python files and shows it together with a ranking.""" |
|
537 """</p>""" |
|
538 )) |
|
539 self.__projectBrowserMIAct.triggered.connect( |
|
540 self.__projectBrowserMaintainabilityIndex) |
|
541 menu.addAction(self.__projectBrowserMIAct) |
|
542 |
|
543 def __editorOpened(self, editor): |
|
544 """ |
|
545 Private slot called, when a new editor was opened. |
|
546 |
|
547 @param editor reference to the new editor |
|
548 @type QScintilla.Editor |
|
549 """ |
|
550 menu = editor.getMenu("Show") |
|
551 if menu is not None: |
|
552 menu.addAction(self.__editorSeparatorActs[0]) |
|
553 menu.addAction(self.__editorRawMetricsAct) |
|
554 menu.addAction(self.__editorMIAct) |
|
555 menu.addAction(self.__editorSeparatorActs[1]) |
|
556 editor.showMenu.connect(self.__editorShowMenu) |
|
557 self.__editors.append(editor) |
|
558 |
|
559 def __editorClosed(self, editor): |
|
560 """ |
|
561 Private slot called, when an editor was closed. |
|
562 |
|
563 @param editor reference to the editor (QScintilla.Editor) |
|
564 """ |
|
565 try: |
|
566 self.__editors.remove(editor) |
|
567 except ValueError: |
|
568 pass |
|
569 |
|
570 def __editorShowMenu(self, menuName, menu, editor): |
|
571 """ |
|
572 Private slot called, when the the editor context menu or a submenu is |
|
573 about to be shown. |
|
574 |
|
575 @param menuName name of the menu to be shown (string) |
|
576 @param menu reference to the menu (QMenu) |
|
577 @param editor reference to the editor |
|
578 """ |
|
579 if menuName == "Show": |
|
580 enable = editor.isPyFile() |
|
581 self.__editorRawMetricsAct.setEnabled(enable) |
|
582 self.__editorMIAct.setEnabled(enable) |
|
583 |
|
584 ################################################################## |
|
585 ## Raw code metrics calculations |
|
586 ################################################################## |
424 |
587 |
425 def __projectRawMetrics(self): |
588 def __projectRawMetrics(self): |
426 """ |
589 """ |
427 Private slot used to calculate raw code metrics for the project. |
590 Private slot used to calculate raw code metrics for the project. |
428 """ |
591 """ |
440 self.__projectRawMetricsDialog.show() |
603 self.__projectRawMetricsDialog.show() |
441 self.__projectRawMetricsDialog.prepare(files, project) |
604 self.__projectRawMetricsDialog.prepare(files, project) |
442 |
605 |
443 def __projectBrowserRawMetrics(self): |
606 def __projectBrowserRawMetrics(self): |
444 """ |
607 """ |
445 Private method to handle the tabnanny context menu action of the |
608 Private method to handle the code metrics context menu action of the |
446 project sources browser. |
609 project sources browser. |
447 """ |
610 """ |
448 browser = e5App().getObject("ProjectBrowser").getProjectBrowser( |
611 browser = e5App().getObject("ProjectBrowser").getProjectBrowser( |
449 "sources") |
612 "sources") |
450 if browser.getSelectedItemsCount([ProjectBrowserFileItem]) > 1: |
613 if browser.getSelectedItemsCount([ProjectBrowserFileItem]) > 1: |
461 from RadonMetrics.RawMetricsDialog import RawMetricsDialog |
624 from RadonMetrics.RawMetricsDialog import RawMetricsDialog |
462 self.__projectBrowserRawMetricsDialog = RawMetricsDialog(self) |
625 self.__projectBrowserRawMetricsDialog = RawMetricsDialog(self) |
463 self.__projectBrowserRawMetricsDialog.show() |
626 self.__projectBrowserRawMetricsDialog.show() |
464 self.__projectBrowserRawMetricsDialog.start(fn) |
627 self.__projectBrowserRawMetricsDialog.start(fn) |
465 |
628 |
466 def __editorOpened(self, editor): |
|
467 """ |
|
468 Private slot called, when a new editor was opened. |
|
469 |
|
470 @param editor reference to the new editor |
|
471 @type QScintilla.Editor |
|
472 """ |
|
473 menu = editor.getMenu("Show") |
|
474 if menu is not None: |
|
475 menu.addAction(self.__editorSeparatorActs[0]) |
|
476 menu.addAction(self.__editorRawMetricsAct) |
|
477 menu.addAction(self.__editorSeparatorActs[1]) |
|
478 editor.showMenu.connect(self.__editorShowMenu) |
|
479 self.__editors.append(editor) |
|
480 |
|
481 def __editorClosed(self, editor): |
|
482 """ |
|
483 Private slot called, when an editor was closed. |
|
484 |
|
485 @param editor reference to the editor (QScintilla.Editor) |
|
486 """ |
|
487 try: |
|
488 self.__editors.remove(editor) |
|
489 except ValueError: |
|
490 pass |
|
491 |
|
492 def __editorShowMenu(self, menuName, menu, editor): |
|
493 """ |
|
494 Private slot called, when the the editor context menu or a submenu is |
|
495 about to be shown. |
|
496 |
|
497 @param menuName name of the menu to be shown (string) |
|
498 @param menu reference to the menu (QMenu) |
|
499 @param editor reference to the editor |
|
500 """ |
|
501 if menuName == "Show": |
|
502 self.__editorRawMetricsAct.setEnabled(editor.isPyFile()) |
|
503 |
|
504 def __editorRawMetrics(self): |
629 def __editorRawMetrics(self): |
505 """ |
630 """ |
506 Private slot to handle the raw code metrics action of the editor show |
631 Private slot to handle the raw code metrics action of the editor show |
507 menu. |
632 menu. |
508 """ |
633 """ |
511 if editor.checkDirty() and editor.getFileName() is not None: |
636 if editor.checkDirty() and editor.getFileName() is not None: |
512 from RadonMetrics.RawMetricsDialog import RawMetricsDialog |
637 from RadonMetrics.RawMetricsDialog import RawMetricsDialog |
513 self.__editorRawMetricsDialog = RawMetricsDialog(self) |
638 self.__editorRawMetricsDialog = RawMetricsDialog(self) |
514 self.__editorRawMetricsDialog.show() |
639 self.__editorRawMetricsDialog.show() |
515 self.__editorRawMetricsDialog.start(editor.getFileName()) |
640 self.__editorRawMetricsDialog.start(editor.getFileName()) |
|
641 |
|
642 ################################################################## |
|
643 ## Maintainability index calculations |
|
644 ################################################################## |
|
645 |
|
646 def __projectMaintainabilityIndex(self): |
|
647 """ |
|
648 Private slot used to calculate the maintainability indexes for the |
|
649 project. |
|
650 """ |
|
651 project = e5App().getObject("Project") |
|
652 project.saveAllScripts() |
|
653 ppath = project.getProjectPath() |
|
654 files = [os.path.join(ppath, file) |
|
655 for file in project.pdata["SOURCES"] |
|
656 if file.endswith( |
|
657 tuple(Preferences.getPython("Python3Extensions")) + |
|
658 tuple(Preferences.getPython("PythonExtensions")))] |
|
659 |
|
660 from RadonMetrics.MaintainabilityIndexDialog import \ |
|
661 MaintainabilityIndexDialog |
|
662 self.__projectMIDialog = MaintainabilityIndexDialog(self) |
|
663 self.__projectMIDialog.show() |
|
664 self.__projectMIDialog.prepare(files, project) |
|
665 |
|
666 def __projectBrowserMaintainabilityIndex(self): |
|
667 """ |
|
668 Private method to handle the maintainability index context menu action |
|
669 of the project sources browser. |
|
670 """ |
|
671 browser = e5App().getObject("ProjectBrowser").getProjectBrowser( |
|
672 "sources") |
|
673 if browser.getSelectedItemsCount([ProjectBrowserFileItem]) > 1: |
|
674 fn = [] |
|
675 for itm in browser.getSelectedItems([ProjectBrowserFileItem]): |
|
676 fn.append(itm.fileName()) |
|
677 else: |
|
678 itm = browser.model().item(browser.currentIndex()) |
|
679 try: |
|
680 fn = itm.fileName() |
|
681 except AttributeError: |
|
682 fn = itm.dirName() |
|
683 |
|
684 from RadonMetrics.MaintainabilityIndexDialog import \ |
|
685 MaintainabilityIndexDialog |
|
686 self.__projectBrowserMIDialog = MaintainabilityIndexDialog(self) |
|
687 self.__projectBrowserMIDialog.show() |
|
688 self.__projectBrowserMIDialog.start(fn) |
|
689 |
|
690 def __editorMaintainabilityIndex(self): |
|
691 """ |
|
692 Private slot to handle the maintainability index action of the editor |
|
693 show menu. |
|
694 """ |
|
695 editor = e5App().getObject("ViewManager").activeWindow() |
|
696 if editor is not None: |
|
697 if editor.checkDirty() and editor.getFileName() is not None: |
|
698 from RadonMetrics.MaintainabilityIndexDialog import \ |
|
699 MaintainabilityIndexDialog |
|
700 self.__editorMIDialog = MaintainabilityIndexDialog(self) |
|
701 self.__editorMIDialog.show() |
|
702 self.__editorMIDialog.start(editor.getFileName()) |