--- a/src/eric7/Tasks/TaskViewer.py Wed Jul 13 11:16:20 2022 +0200 +++ b/src/eric7/Tasks/TaskViewer.py Wed Jul 13 14:55:47 2022 +0200 @@ -18,8 +18,15 @@ from PyQt6.QtCore import pyqtSignal, Qt, QThread from PyQt6.QtWidgets import ( - QHeaderView, QLineEdit, QTreeWidget, QDialog, QInputDialog, QApplication, - QMenu, QAbstractItemView, QTreeWidgetItem + QHeaderView, + QLineEdit, + QTreeWidget, + QDialog, + QInputDialog, + QApplication, + QMenu, + QAbstractItemView, + QTreeWidgetItem, ) from EricWidgets.EricApplication import ericApp @@ -34,152 +41,147 @@ import Utilities from Utilities.AutoSaver import AutoSaver - + class TaskViewer(QTreeWidget): """ Class implementing the task viewer. - + @signal displayFile(str, int) emitted to go to a file task """ + displayFile = pyqtSignal(str, int) - + def __init__(self, parent, project): """ Constructor - + @param parent the parent (QWidget) @param project reference to the project object """ super().__init__(parent) - + self.setSortingEnabled(True) self.setExpandsOnDoubleClick(False) - + self.__headerItem = QTreeWidgetItem( - ["", "", self.tr("Summary"), self.tr("Filename"), - self.tr("Line"), ""]) - self.__headerItem.setIcon( - 0, UI.PixmapCache.getIcon("taskCompleted")) - self.__headerItem.setIcon( - 1, UI.PixmapCache.getIcon("taskPriority")) + ["", "", self.tr("Summary"), self.tr("Filename"), self.tr("Line"), ""] + ) + self.__headerItem.setIcon(0, UI.PixmapCache.getIcon("taskCompleted")) + self.__headerItem.setIcon(1, UI.PixmapCache.getIcon("taskPriority")) self.setHeaderItem(self.__headerItem) - + self.header().setSortIndicator(2, Qt.SortOrder.AscendingOrder) self.__resizeColumns() - + self.tasks = [] self.copyTask = None self.projectOpen = False self.project = project self.__projectTasksScanFilter = "" - + from .TaskFilter import TaskFilter + self.taskFilter = TaskFilter() self.taskFilter.setActive(False) - + self.__projectTasksSaveTimer = AutoSaver(self, self.saveProjectTasks) self.__projectTaskExtractionThread = ProjectTaskExtractionThread() self.__projectTaskExtractionThread.taskFound.connect(self.addFileTask) - - self.__projectTasksMenu = QMenu( - self.tr("P&roject Tasks"), self) + + self.__projectTasksMenu = QMenu(self.tr("P&roject Tasks"), self) self.__projectTasksMenu.addAction( - self.tr("&Regenerate project tasks"), - self.regenerateProjectTasks) + self.tr("&Regenerate project tasks"), self.regenerateProjectTasks + ) self.__projectTasksMenu.addSeparator() self.__projectTasksMenu.addAction( - self.tr("&Configure scan options"), - self.__configureProjectTasksScanOptions) - + self.tr("&Configure scan options"), self.__configureProjectTasksScanOptions + ) + self.__menu = QMenu(self) self.__menu.addAction(self.tr("&New Task..."), self.__newTask) self.subtaskItem = self.__menu.addAction( - self.tr("New &Sub-Task..."), self.__newSubTask) + self.tr("New &Sub-Task..."), self.__newSubTask + ) self.__menu.addSeparator() - self.projectTasksMenuItem = self.__menu.addMenu( - self.__projectTasksMenu) + self.projectTasksMenuItem = self.__menu.addMenu(self.__projectTasksMenu) self.__menu.addSeparator() - self.gotoItem = self.__menu.addAction( - self.tr("&Go To"), self.__goToTask) + self.gotoItem = self.__menu.addAction(self.tr("&Go To"), self.__goToTask) self.__menu.addSeparator() - self.copyItem = self.__menu.addAction( - self.tr("&Copy"), self.__copyTask) - self.pasteItem = self.__menu.addAction( - self.tr("&Paste"), self.__pasteTask) + self.copyItem = self.__menu.addAction(self.tr("&Copy"), self.__copyTask) + self.pasteItem = self.__menu.addAction(self.tr("&Paste"), self.__pasteTask) self.pasteMainItem = self.__menu.addAction( - self.tr("Paste as &Main Task"), self.__pasteMainTask) - self.deleteItem = self.__menu.addAction( - self.tr("&Delete"), self.__deleteTask) + self.tr("Paste as &Main Task"), self.__pasteMainTask + ) + self.deleteItem = self.__menu.addAction(self.tr("&Delete"), self.__deleteTask) self.__menu.addSeparator() self.markCompletedItem = self.__menu.addAction( - self.tr("&Mark Completed"), self.__markCompleted) - self.__menu.addAction( - self.tr("Delete Completed &Tasks"), self.__deleteCompleted) - self.__menu.addSeparator() + self.tr("&Mark Completed"), self.__markCompleted + ) self.__menu.addAction( - self.tr("P&roperties..."), self.__editTaskProperties) + self.tr("Delete Completed &Tasks"), self.__deleteCompleted + ) self.__menu.addSeparator() - self.__menuFilteredAct = self.__menu.addAction( - self.tr("&Filtered display")) + self.__menu.addAction(self.tr("P&roperties..."), self.__editTaskProperties) + self.__menu.addSeparator() + self.__menuFilteredAct = self.__menu.addAction(self.tr("&Filtered display")) self.__menuFilteredAct.setCheckable(True) self.__menuFilteredAct.setChecked(False) self.__menuFilteredAct.triggered[bool].connect(self.__activateFilter) self.__menu.addAction( - self.tr("Filter c&onfiguration..."), self.__configureFilter) + self.tr("Filter c&onfiguration..."), self.__configureFilter + ) self.__menu.addSeparator() - self.__menu.addAction( - self.tr("Resi&ze columns"), self.__resizeColumns) + self.__menu.addAction(self.tr("Resi&ze columns"), self.__resizeColumns) self.__menu.addSeparator() self.__menu.addAction(self.tr("Configure..."), self.__configure) - + self.__backMenu = QMenu(self) self.__backMenu.addAction(self.tr("&New Task..."), self.__newTask) self.__backMenu.addSeparator() - self.backProjectTasksMenuItem = self.__backMenu.addMenu( - self.__projectTasksMenu) + self.backProjectTasksMenuItem = self.__backMenu.addMenu(self.__projectTasksMenu) self.__backMenu.addSeparator() self.backPasteItem = self.__backMenu.addAction( - self.tr("&Paste"), self.__pasteTask) + self.tr("&Paste"), self.__pasteTask + ) self.backPasteMainItem = self.__backMenu.addAction( - self.tr("Paste as &Main Task"), self.__pasteMainTask) + self.tr("Paste as &Main Task"), self.__pasteMainTask + ) self.__backMenu.addSeparator() self.backDeleteCompletedItem = self.__backMenu.addAction( - self.tr("Delete Completed &Tasks"), self.__deleteCompleted) + self.tr("Delete Completed &Tasks"), self.__deleteCompleted + ) self.__backMenu.addSeparator() self.__backMenuFilteredAct = self.__backMenu.addAction( - self.tr("&Filtered display")) + self.tr("&Filtered display") + ) self.__backMenuFilteredAct.setCheckable(True) self.__backMenuFilteredAct.setChecked(False) - self.__backMenuFilteredAct.triggered[bool].connect( - self.__activateFilter) - self.__backMenu.addAction( - self.tr("Filter c&onfiguration..."), self.__configureFilter) - self.__backMenu.addSeparator() + self.__backMenuFilteredAct.triggered[bool].connect(self.__activateFilter) self.__backMenu.addAction( - self.tr("Resi&ze columns"), self.__resizeColumns) + self.tr("Filter c&onfiguration..."), self.__configureFilter + ) + self.__backMenu.addSeparator() + self.__backMenu.addAction(self.tr("Resi&ze columns"), self.__resizeColumns) self.__backMenu.addSeparator() - self.__backMenu.addAction( - self.tr("Configure..."), self.__configure) - + self.__backMenu.addAction(self.tr("Configure..."), self.__configure) + self.__activating = False - + self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) self.customContextMenuRequested.connect(self.__showContextMenu) self.itemActivated.connect(self.__taskItemActivated) - + self.setWindowIcon(UI.PixmapCache.getIcon("eric")) - + self.__generateTopLevelItems() - + def __generateTopLevelItems(self): """ Private method to generate the 'Extracted Tasks' item. """ - self.__extractedItem = QTreeWidgetItem(self, - [self.tr("Extracted Tasks")]) - self.__manualItem = QTreeWidgetItem(self, - [self.tr("Manual Tasks")]) + self.__extractedItem = QTreeWidgetItem(self, [self.tr("Extracted Tasks")]) + self.__manualItem = QTreeWidgetItem(self, [self.tr("Manual Tasks")]) for itm in [self.__extractedItem, self.__manualItem]: itm.setFirstColumnSpanned(True) itm.setExpanded(True) @@ -187,7 +189,7 @@ font = itm.font(0) font.setUnderline(True) itm.setFont(0, font) - + def __checkTopLevelItems(self): """ Private slot to check the 'Extracted Tasks' item for children. @@ -198,42 +200,42 @@ if itm.child(index).isHidden(): visibleCount -= 1 itm.setHidden(visibleCount == 0) - + def __resort(self): """ Private method to resort the tree. """ self.sortItems(self.sortColumn(), self.header().sortIndicatorOrder()) - + def __resizeColumns(self): """ Private method to resize the list columns. """ self.header().resizeSections(QHeaderView.ResizeMode.ResizeToContents) self.header().setStretchLastSection(True) - + def findParentTask(self, parentUid): """ Public method to find a parent task by its ID. - + @param parentUid uid of the parent task (string) @return reference to the task (Task) """ if not parentUid: return None - + parentTask = None for task in self.tasks: if task.getUuid() == parentUid: parentTask = task break - + return parentTask - + def containsTask(self, taskToTest): """ Public method to test, if a task is already in the tasks list. - + @param taskToTest task to look for @type Task @return flag indicating the existence of the task @@ -242,36 +244,36 @@ if taskToTest is None: # play it safe return False - + return any( - (task.summary == taskToTest.summary) and - (task.filename == taskToTest.filename) and - (task.lineno == taskToTest.lineno) + (task.summary == taskToTest.summary) + and (task.filename == taskToTest.filename) + and (task.lineno == taskToTest.lineno) for task in self.tasks ) - + def __refreshDisplay(self): """ Private method to refresh the display. """ for task in self.tasks: task.setHidden(not self.taskFilter.showTask(task)) - + self.__checkTopLevelItems() self.__resort() self.__resizeColumns() - + def __taskItemActivated(self, itm, col): """ Private slot to handle the activation of an item. - + @param itm reference to the activated item (QTreeWidgetItem) @param col column the item was activated in (integer) """ if ( - not self.__activating and - itm is not self.__extractedItem and - itm is not self.__manualItem + not self.__activating + and itm is not self.__extractedItem + and itm is not self.__manualItem ): self.__activating = True fn = itm.getFilename() @@ -288,16 +290,12 @@ def __showContextMenu(self, coord): """ Private slot to show the context menu of the list. - + @param coord the position of the mouse pointer (QPoint) """ itm = self.itemAt(coord) coord = self.mapToGlobal(coord) - if ( - itm is None or - itm is self.__extractedItem or - itm is self.__manualItem - ): + if itm is None or itm is self.__extractedItem or itm is self.__manualItem: self.backProjectTasksMenuItem.setEnabled(self.projectOpen) if self.copyTask: self.backPasteItem.setEnabled(True) @@ -305,8 +303,7 @@ else: self.backPasteItem.setEnabled(False) self.backPasteMainItem.setEnabled(False) - self.backDeleteCompletedItem.setEnabled( - bool(self.tasks)) + self.backDeleteCompletedItem.setEnabled(bool(self.tasks)) self.__backMenu.popup(coord) else: self.projectTasksMenuItem.setEnabled(self.projectOpen) @@ -328,24 +325,34 @@ else: self.pasteItem.setEnabled(False) self.pasteMainItem.setEnabled(False) - + self.__menu.popup(coord) - + def setProjectOpen(self, o=False): """ Public slot to set the project status. - + @param o flag indicating the project status """ self.projectOpen = o - - def addTask(self, summary, priority=TaskPriority.NORMAL, filename="", - lineno=0, completed=False, _time=0, isProjectTask=False, - taskType=TaskType.TODO, description="", uid="", - parentTask=None): + + def addTask( + self, + summary, + priority=TaskPriority.NORMAL, + filename="", + lineno=0, + completed=False, + _time=0, + isProjectTask=False, + taskType=TaskType.TODO, + description="", + uid="", + parentTask=None, + ): """ Public slot to add a task. - + @param summary summary text of the task @type str @param priority priority of the task @@ -387,9 +394,20 @@ parentUid = parentTask.getUuid() else: parentUid = "" - task = Task(summary, priority, filename, lineno, completed, - _time, isProjectTask, taskType, - self.project, description, uid, parentUid) + task = Task( + summary, + priority, + filename, + lineno, + completed, + _time, + isProjectTask, + taskType, + self.project, + description, + uid, + parentUid, + ) if not self.containsTask(task): self.tasks.append(task) if parentTask: @@ -400,23 +418,24 @@ else: self.__manualItem.addChild(task) task.setHidden(not self.taskFilter.showTask(task)) - + self.__checkTopLevelItems() self.__resort() self.__resizeColumns() - + if isProjectTask: self.__projectTasksSaveTimer.changeOccurred() - + return task else: return None - - def addFileTask(self, summary, filename, lineno, taskType=TaskType.TODO, - description=""): + + def addFileTask( + self, summary, filename, lineno, taskType=TaskType.TODO, description="" + ): """ Public slot to add a file related task. - + @param summary summary text of the task @type str @param filename filename containing the task @@ -428,30 +447,33 @@ @param description explanatory text of the task @type str """ - self.addTask(summary, filename=filename, lineno=lineno, - isProjectTask=( - self.project and - self.project.isProjectSource(filename)), - taskType=TaskType(taskType), description=description) - + self.addTask( + summary, + filename=filename, + lineno=lineno, + isProjectTask=(self.project and self.project.isProjectSource(filename)), + taskType=TaskType(taskType), + description=description, + ) + def getProjectTasks(self): """ Public method to retrieve all project related tasks. - + @return copy of tasks (list of Task) """ tasks = [task for task in self.tasks if task.isProjectTask()] return tasks[:] - + def getGlobalTasks(self): """ Public method to retrieve all non project related tasks. - + @return copy of tasks (list of Task) """ tasks = [task for task in self.tasks if not task.isProjectTask()] return tasks[:] - + def clearTasks(self): """ Public slot to clear all tasks from display. @@ -459,18 +481,17 @@ self.tasks = [] self.clear() self.__generateTopLevelItems() - + def clearProjectTasks(self, fileOnly=False): """ Public slot to clear project related tasks. - + @param fileOnly flag indicating to clear only file related project tasks (boolean) """ for task in reversed(self.tasks[:]): - if ( - (fileOnly and task.isProjectFileTask()) or - (not fileOnly and task.isProjectTask()) + if (fileOnly and task.isProjectFileTask()) or ( + not fileOnly and task.isProjectTask() ): if self.copyTask == task: self.copyTask = None @@ -478,15 +499,15 @@ parent.removeChild(task) self.tasks.remove(task) del task - + self.__checkTopLevelItems() self.__resort() self.__resizeColumns() - + def clearFileTasks(self, filename, conditionally=False): """ Public slot to clear all tasks related to a file. - + @param filename name of the file (string) @param conditionally flag indicating to clear the tasks of the file checking some conditions (boolean) @@ -506,25 +527,28 @@ if task.isProjectTask: self.__projectTasksSaveTimer.changeOccurred() del task - + self.__checkTopLevelItems() self.__resort() self.__resizeColumns() - + def __editTaskProperties(self): """ Private slot to handle the "Properties" context menu entry. """ from .TaskPropertiesDialog import TaskPropertiesDialog + task = self.currentItem() - dlg = TaskPropertiesDialog(task, parent=self, - projectOpen=self.projectOpen) - if ( - dlg.exec() == QDialog.DialogCode.Accepted and - dlg.isManualTaskMode() - ): - (summary, priority, taskType, completed, isProjectTask, - description) = dlg.getData() + dlg = TaskPropertiesDialog(task, parent=self, projectOpen=self.projectOpen) + if dlg.exec() == QDialog.DialogCode.Accepted and dlg.isManualTaskMode(): + ( + summary, + priority, + taskType, + completed, + isProjectTask, + description, + ) = dlg.getData() task.setSummary(summary) task.setPriority(priority) task.setTaskType(taskType) @@ -532,46 +556,69 @@ task.setProjectTask(isProjectTask) task.setDescription(description) self.__projectTasksSaveTimer.changeOccurred() - + def __newTask(self): """ Private slot to handle the "New Task" context menu entry. """ from .TaskPropertiesDialog import TaskPropertiesDialog - dlg = TaskPropertiesDialog(None, parent=self, - projectOpen=self.projectOpen) + + dlg = TaskPropertiesDialog(None, parent=self, projectOpen=self.projectOpen) if dlg.exec() == QDialog.DialogCode.Accepted: - (summary, priority, taskType, completed, isProjectTask, - description) = dlg.getData() - self.addTask(summary, priority, completed=completed, - isProjectTask=isProjectTask, taskType=taskType, - description=description) - + ( + summary, + priority, + taskType, + completed, + isProjectTask, + description, + ) = dlg.getData() + self.addTask( + summary, + priority, + completed=completed, + isProjectTask=isProjectTask, + taskType=taskType, + description=description, + ) + def __newSubTask(self): """ Private slot to handle the "New Sub-Task" context menu entry. """ parentTask = self.currentItem() projectTask = parentTask.isProjectTask() - + from .TaskPropertiesDialog import TaskPropertiesDialog - dlg = TaskPropertiesDialog(None, parent=self, - projectOpen=self.projectOpen) + + dlg = TaskPropertiesDialog(None, parent=self, projectOpen=self.projectOpen) dlg.setSubTaskMode(projectTask) if dlg.exec() == QDialog.DialogCode.Accepted: - (summary, priority, taskType, completed, isProjectTask, - description) = dlg.getData() - self.addTask(summary, priority, completed=completed, - isProjectTask=isProjectTask, taskType=taskType, - description=description, parentTask=parentTask) - + ( + summary, + priority, + taskType, + completed, + isProjectTask, + description, + ) = dlg.getData() + self.addTask( + summary, + priority, + completed=completed, + isProjectTask=isProjectTask, + taskType=taskType, + description=description, + parentTask=parentTask, + ) + def __markCompleted(self): """ Private slot to handle the "Mark Completed" context menu entry. """ task = self.currentItem() task.setCompleted(True) - + def __deleteCompleted(self): """ Private slot to handle the "Delete Completed Tasks" context menu entry. @@ -586,23 +633,23 @@ if task.isProjectTask: self.__projectTasksSaveTimer.changeOccurred() del task - + self.__checkTopLevelItems() self.__resort() self.__resizeColumns() - + ci = self.currentItem() if ci: ind = self.indexFromItem(ci, self.currentColumn()) self.scrollTo(ind, QAbstractItemView.ScrollHint.PositionAtCenter) - + def __copyTask(self): """ Private slot to handle the "Copy" context menu entry. """ task = self.currentItem() self.copyTask = task - + def __pasteTask(self): """ Private slot to handle the "Paste" context menu entry. @@ -611,29 +658,33 @@ parent = self.copyTask.parent() if not isinstance(parent, Task): parent = None - - self.addTask(self.copyTask.summary, - priority=self.copyTask.priority, - completed=self.copyTask.completed, - description=self.copyTask.description, - isProjectTask=self.copyTask._isProjectTask, - parentTask=parent) - + + self.addTask( + self.copyTask.summary, + priority=self.copyTask.priority, + completed=self.copyTask.completed, + description=self.copyTask.description, + isProjectTask=self.copyTask._isProjectTask, + parentTask=parent, + ) + def __pasteMainTask(self): """ Private slot to handle the "Paste as Main Task" context menu entry. """ if self.copyTask: - self.addTask(self.copyTask.summary, - priority=self.copyTask.priority, - completed=self.copyTask.completed, - description=self.copyTask.description, - isProjectTask=self.copyTask._isProjectTask) - + self.addTask( + self.copyTask.summary, + priority=self.copyTask.priority, + completed=self.copyTask.completed, + description=self.copyTask.description, + isProjectTask=self.copyTask._isProjectTask, + ) + def __deleteSubTasks(self, task): """ Private method to delete all sub-tasks. - + @param task task to delete sub-tasks of (Task) """ for subtask in task.takeChildren(): @@ -642,18 +693,18 @@ if subtask.childCount() > 0: self.__deleteSubTasks(subtask) self.tasks.remove(subtask) - + def __deleteTask(self, task=None): """ Private slot to delete a task. - + @param task task to be deleted @type Task """ if task is None: # called via "Delete Task" context menu entry task = self.currentItem() - + if self.copyTask is task: self.copyTask = None if task.childCount() > 0: @@ -664,16 +715,16 @@ if task.isProjectTask: self.__projectTasksSaveTimer.changeOccurred() del task - + self.__checkTopLevelItems() self.__resort() self.__resizeColumns() - + ci = self.currentItem() if ci: ind = self.indexFromItem(ci, self.currentColumn()) self.scrollTo(ind, QAbstractItemView.ScrollHint.PositionAtCenter) - + def __goToTask(self): """ Private slot to handle the "Go To" context menu entry. @@ -691,7 +742,7 @@ def __activateFilter(self, on): """ Private slot to handle the "Filtered display" context menu entry. - + @param on flag indicating the filter state (boolean) """ if on and not self.taskFilter.hasActiveFilter(): @@ -700,24 +751,27 @@ self.tr("Activate task filter"), self.tr( """The task filter doesn't have any active filters.""" - """ Do you want to configure the filter settings?"""), - yesDefault=True) + """ Do you want to configure the filter settings?""" + ), + yesDefault=True, + ) if not res: on = False else: self.__configureFilter() on = self.taskFilter.hasActiveFilter() - + self.taskFilter.setActive(on) self.__menuFilteredAct.setChecked(on) self.__backMenuFilteredAct.setChecked(on) self.__refreshDisplay() - + def __configureFilter(self): """ Private slot to handle the "Configure filter" context menu entry. """ from .TaskFilterConfigDialog import TaskFilterConfigDialog + dlg = TaskFilterConfigDialog(self.taskFilter) if dlg.exec() == QDialog.DialogCode.Accepted: dlg.configureTaskFilter(self.taskFilter) @@ -730,17 +784,20 @@ scanFilter, ok = QInputDialog.getText( self, self.tr("Scan Filter Patterns"), - self.tr("Enter filename patterns of files" - " to be excluded separated by a comma:"), + self.tr( + "Enter filename patterns of files" + " to be excluded separated by a comma:" + ), QLineEdit.EchoMode.Normal, - self.__projectTasksScanFilter) + self.__projectTasksScanFilter, + ) if ok: self.__projectTasksScanFilter = scanFilter - + def regenerateProjectTasks(self, quiet=False): """ Public slot to regenerate project related tasks. - + @param quiet flag indicating quiet operation @type bool """ @@ -749,44 +806,50 @@ for taskType, markersName in Task.TaskType2MarkersName.items() } files = self.project.pdata["SOURCES"] - + # apply file filter - filterList = [f.strip() - for f in self.__projectTasksScanFilter.split(",") - if f.strip()] + filterList = [ + f.strip() for f in self.__projectTasksScanFilter.split(",") if f.strip() + ] if filterList: for scanFilter in filterList: - files = [f for f in files - if not fnmatch.fnmatch(f, scanFilter)] - + files = [f for f in files if not fnmatch.fnmatch(f, scanFilter)] + # remove all project tasks self.clearProjectTasks(fileOnly=True) - + # now process them if quiet: ppath = self.project.getProjectPath() self.__projectTaskExtractionThread.scan( - markers, [os.path.join(ppath, f) for f in files]) + markers, [os.path.join(ppath, f) for f in files] + ) else: progress = EricProgressDialog( self.tr("Extracting project tasks..."), - self.tr("Abort"), 0, len(files), self.tr("%v/%m Files"), self) + self.tr("Abort"), + 0, + len(files), + self.tr("%v/%m Files"), + self, + ) progress.setMinimumDuration(0) progress.setWindowTitle(self.tr("Tasks")) - + ppath = self.project.getProjectPath() - + now = time.monotonic() for count, file in enumerate(files): progress.setLabelText( - self.tr("Extracting project tasks...\n{0}").format(file)) + self.tr("Extracting project tasks...\n{0}").format(file) + ) progress.setValue(count) if time.monotonic() - now > 0.01: QApplication.processEvents() now = time.monotonic() if progress.wasCanceled(): break - + fn = os.path.join(ppath, file) # read the file and split it into textlines try: @@ -796,15 +859,15 @@ count += 1 progress.setValue(count) continue - + # now search tasks and record them for lineIndex, line in enumerate(lines, start=1): shouldBreak = False - + if line.endswith("__NO-TASK__"): # ignore potential task marker continue - + for taskType, taskMarkers in markers.items(): for taskMarker in taskMarkers: index = line.find(taskMarker) @@ -815,42 +878,42 @@ break if shouldBreak: break - + progress.setValue(len(files)) - + def __configure(self): """ Private method to open the configuration dialog. """ ericApp().getObject("UserInterface").showPreferences("tasksPage") - + def saveProjectTasks(self): """ Public method to write the project tasks. """ if self.projectOpen and Preferences.getProject("TasksProjectAutoSave"): self.project.writeTasks() - + def stopProjectTaskExtraction(self): """ Public method to stop the project task extraction thread. """ self.__projectTaskExtractionThread.requestInterrupt() self.__projectTaskExtractionThread.wait() - + def getTasksScanFilter(self) -> str: """ Public method to get the project scan filter. - + @return project scan filter @rtype str """ return self.__projectTasksScanFilter.strip() - + def setTasksScanFilter(self, filterStr: str): """ Public method to set the project scan filter. - + @param filterStr project scan filter @type str """ @@ -860,35 +923,36 @@ class ProjectTaskExtractionThread(QThread): """ Class implementing a thread to extract tasks related to a project. - + @signal taskFound(str, str, int, TaskType) emitted with the task description, the file name, the line number and task type to signal the presence of a task """ + taskFound = pyqtSignal(str, str, int, TaskType) - + def __init__(self, parent=None): """ Constructor - + @param parent reference to the parent object (QObject) """ super().__init__() - + self.__lock = threading.Lock() self.__interrupt = False - + def requestInterrupt(self): """ Public method to request iterruption of the thread. """ if self.isRunning(): self.__interrupt = True - + def scan(self, markers, files): """ Public method to scan the given list of files for tasks. - + @param markers dictionary of defined task markers @type dict of lists of str @param files list of file names to be scanned @@ -900,10 +964,10 @@ self.__markers = {} for markerType in markers: self.__markers[markerType] = markers[markerType][:] - + if not self.isRunning(): self.start(QThread.Priority.LowPriority) - + def run(self): """ Public thread method to scan the given files. @@ -913,37 +977,36 @@ markers = {} for markerType in self.__markers: markers[markerType] = self.__markers[markerType][:] - + for fn in files: if self.__interrupt: break - + # read the file and split it into textlines try: text, encoding = Utilities.readEncodedFile(fn) lines = text.splitlines() except (UnicodeError, OSError): continue - + # now search tasks and record them for lineIndex, line in enumerate(lines, start=1): if self.__interrupt: break - + found = False - + if line.endswith("__NO-TASK__"): # ignore potential task marker continue - + for taskType, taskMarkers in markers.items(): for taskMarker in taskMarkers: index = line.find(taskMarker) if index > -1: task = line[index:] with self.__lock: - self.taskFound.emit(task, fn, lineIndex, - taskType) + self.taskFound.emit(task, fn, lineIndex, taskType) found = True break if found: