Tasks/TaskViewer.py

changeset 5117
1faa0780ae1d
parent 5114
ad158c12d744
child 5389
9b1c800daff3
equal deleted inserted replaced
5115:ed2f37c1f6b6 5117:1faa0780ae1d
13 13
14 from __future__ import unicode_literals 14 from __future__ import unicode_literals
15 15
16 import os 16 import os
17 import fnmatch 17 import fnmatch
18 18 import threading
19 from PyQt5.QtCore import pyqtSignal, Qt 19
20 from PyQt5.QtCore import pyqtSignal, Qt, QThread
20 from PyQt5.QtWidgets import QHeaderView, QLineEdit, QTreeWidget, QDialog, \ 21 from PyQt5.QtWidgets import QHeaderView, QLineEdit, QTreeWidget, QDialog, \
21 QInputDialog, QApplication, QMenu, QAbstractItemView, QTreeWidgetItem 22 QInputDialog, QApplication, QMenu, QAbstractItemView, QTreeWidgetItem
22 23
23 from E5Gui.E5Application import e5App 24 from E5Gui.E5Application import e5App
24 from E5Gui import E5MessageBox 25 from E5Gui import E5MessageBox
75 from .TaskFilter import TaskFilter 76 from .TaskFilter import TaskFilter
76 self.taskFilter = TaskFilter() 77 self.taskFilter = TaskFilter()
77 self.taskFilter.setActive(False) 78 self.taskFilter.setActive(False)
78 79
79 self.__projectTasksSaveTimer = AutoSaver(self, self.saveProjectTasks) 80 self.__projectTasksSaveTimer = AutoSaver(self, self.saveProjectTasks)
81 self.__projectTaskExtractionThread = ProjectTaskExtractionThread()
82 self.__projectTaskExtractionThread.taskFound.connect(self.addFileTask)
80 83
81 self.__projectTasksMenu = QMenu( 84 self.__projectTasksMenu = QMenu(
82 self.tr("P&roject Tasks"), self) 85 self.tr("P&roject Tasks"), self)
83 self.__projectTasksMenu.addAction( 86 self.__projectTasksMenu.addAction(
84 self.tr("&Regenerate project tasks"), 87 self.tr("&Regenerate project tasks"),
688 691
689 # remove all project tasks 692 # remove all project tasks
690 self.clearProjectTasks(fileOnly=True) 693 self.clearProjectTasks(fileOnly=True)
691 694
692 # now process them 695 # now process them
693 if not quiet: 696 if quiet:
697 ppath = self.project.getProjectPath()
698 self.__projectTaskExtractionThread.scan(
699 markers, [os.path.join(ppath, f) for f in files])
700 else:
694 progress = E5ProgressDialog( 701 progress = E5ProgressDialog(
695 self.tr("Extracting project tasks..."), 702 self.tr("Extracting project tasks..."),
696 self.tr("Abort"), 0, len(files), self.tr("%v/%m Files")) 703 self.tr("Abort"), 0, len(files), self.tr("%v/%m Files"))
697 progress.setMinimumDuration(0) 704 progress.setMinimumDuration(0)
698 progress.setWindowTitle(self.tr("Tasks")) 705 progress.setWindowTitle(self.tr("Tasks"))
699 count = 0 706 count = 0
700 707
701 for file in files: 708 ppath = self.project.getProjectPath()
702 if not quiet: 709 for file in files:
703 progress.setLabelText( 710 progress.setLabelText(
704 self.tr("Extracting project tasks...\n{0}").format(file)) 711 self.tr("Extracting project tasks...\n{0}").format(file))
705 progress.setValue(count) 712 progress.setValue(count)
706 QApplication.processEvents() 713 QApplication.processEvents()
707 if progress.wasCanceled(): 714 if progress.wasCanceled():
708 break 715 break
716
717 fn = os.path.join(ppath, file)
718 # read the file and split it into textlines
719 try:
720 text, encoding = Utilities.readEncodedFile(fn)
721 lines = text.splitlines()
722 except (UnicodeError, IOError):
723 count += 1
724 progress.setValue(count)
725 continue
726
727 # now search tasks and record them
728 lineIndex = 0
729 for line in lines:
730 lineIndex += 1
731 shouldBreak = False
732
733 for taskType, taskMarkers in markers.items():
734 for taskMarker in taskMarkers:
735 index = line.find(taskMarker)
736 if index > -1:
737 task = line[index:]
738 self.addFileTask(task, fn, lineIndex, taskType)
739 shouldBreak = True
740 break
741 if shouldBreak:
742 break
743
744 count += 1
709 745
710 QApplication.processEvents() 746 progress.setValue(len(files))
747
748 def __configure(self):
749 """
750 Private method to open the configuration dialog.
751 """
752 e5App().getObject("UserInterface").showPreferences("tasksPage")
753
754 def saveProjectTasks(self):
755 """
756 Public method to write the project tasks.
757 """
758 if self.projectOpen and Preferences.getProject("TasksProjectAutoSave"):
759 self.project.writeTasks()
760
761 def stopProjectTaskExtraction(self):
762 """
763 Public method to stop the project task extraction thread.
764 """
765 self.__projectTaskExtractionThread.requestInterrupt()
766 self.__projectTaskExtractionThread.wait()
767
768
769 class ProjectTaskExtractionThread(QThread):
770 """
771 Class implementing a thread to extract tasks related to a project.
772
773 @signal taskFound(str, str, int, int) emitted with the task description,
774 the file name, the line number and task type to signal the presence of
775 a task
776 """
777 taskFound = pyqtSignal(str, str, int, int)
778
779 def __init__(self, parent=None):
780 """
781 Constructor
782
783 @param parent reference to the parent object (QObject)
784 """
785 super(ProjectTaskExtractionThread, self).__init__()
786
787 self.__lock = threading.Lock()
788 self.__interrupt = False
789
790 def requestInterrupt(self):
791 """
792 Public method to request iterruption of the thread.
793 """
794 if self.isRunning():
795 self.__interrupt = True
796
797 def scan(self, markers, files):
798 """
799 Public method to scan the given list of files for tasks.
800
801 @param markers dictionary of defined task markers
802 @type dict of lists of str
803 @param files list of file names to be scanned
804 @type list of str
805 """
806 with self.__lock:
807 self.__interrupt = False
808 self.__files = files[:]
809 self.__markers = {}
810 for markerType in markers:
811 self.__markers[markerType] = markers[markerType][:]
711 812
712 fn = os.path.join(self.project.ppath, file) 813 if not self.isRunning():
814 self.start(QThread.LowPriority)
815
816 def run(self):
817 """
818 Public thread method to scan the given files.
819 """
820 with self.__lock:
821 files = self.__files[:]
822 markers = {}
823 for markerType in self.__markers:
824 markers[markerType] = self.__markers[markerType][:]
825
826 for fn in files:
827 if self.__interrupt:
828 break
829
713 # read the file and split it into textlines 830 # read the file and split it into textlines
714 try: 831 try:
715 text, encoding = Utilities.readEncodedFile(fn) 832 text, encoding = Utilities.readEncodedFile(fn)
716 lines = text.splitlines() 833 lines = text.splitlines()
717 except (UnicodeError, IOError): 834 except (UnicodeError, IOError):
718 count += 1
719 if not quiet:
720 progress.setValue(count)
721 continue 835 continue
722 836
723 # now search tasks and record them 837 # now search tasks and record them
724 lineIndex = 0 838 lineIndex = 0
725 for line in lines: 839 for line in lines:
840 if self.__interrupt:
841 break
842
726 lineIndex += 1 843 lineIndex += 1
727 shouldBreak = False 844 found = False
728 845
729 for taskType, taskMarkers in markers.items(): 846 for taskType, taskMarkers in markers.items():
730 for taskMarker in taskMarkers: 847 for taskMarker in taskMarkers:
731 index = line.find(taskMarker) 848 index = line.find(taskMarker)
732 if index > -1: 849 if index > -1:
733 task = line[index:] 850 task = line[index:]
734 self.addFileTask(task, fn, lineIndex, taskType) 851 with self.__lock:
735 shouldBreak = True 852 self.taskFound.emit(task, fn, lineIndex,
853 taskType)
854 found = True
736 break 855 break
737 if shouldBreak: 856 if found:
738 break 857 break
739
740 count += 1
741
742 if not quiet:
743 progress.setValue(len(files))
744
745 def __configure(self):
746 """
747 Private method to open the configuration dialog.
748 """
749 e5App().getObject("UserInterface").showPreferences("tasksPage")
750
751 def saveProjectTasks(self):
752 """
753 Public method to write the project tasks.
754 """
755 if self.projectOpen and Preferences.getProject("TasksProjectAutoSave"):
756 self.project.writeTasks()

eric ide

mercurial