10 generated tasks are derived from a comment with a special |
10 generated tasks are derived from a comment with a special |
11 introductory text. This text is configurable. |
11 introductory text. This text is configurable. |
12 """ |
12 """ |
13 |
13 |
14 import os |
14 import os |
15 import time |
|
16 import fnmatch |
15 import fnmatch |
17 |
16 |
18 from PyQt4.QtCore import pyqtSignal, QRegExp, Qt |
17 from PyQt4.QtCore import pyqtSignal, Qt |
19 from PyQt4.QtGui import QHeaderView, QLineEdit, QTreeWidget, QDialog, QInputDialog, \ |
18 from PyQt4.QtGui import QHeaderView, QLineEdit, QTreeWidget, QDialog, QInputDialog, \ |
20 QApplication, QMenu, QAbstractItemView, QProgressDialog, QTreeWidgetItem |
19 QApplication, QMenu, QAbstractItemView, QProgressDialog, QTreeWidgetItem |
21 |
20 |
22 from E5Gui.E5Application import e5App |
21 from E5Gui.E5Application import e5App |
23 from E5Gui import E5MessageBox |
22 from E5Gui import E5MessageBox |
24 |
23 |
|
24 from .Task import Task |
25 from .TaskPropertiesDialog import TaskPropertiesDialog |
25 from .TaskPropertiesDialog import TaskPropertiesDialog |
|
26 from .TaskFilter import TaskFilter |
26 from .TaskFilterConfigDialog import TaskFilterConfigDialog |
27 from .TaskFilterConfigDialog import TaskFilterConfigDialog |
27 |
28 |
28 import UI.PixmapCache |
29 import UI.PixmapCache |
29 |
30 |
30 import Preferences |
31 import Preferences |
31 import Utilities |
32 import Utilities |
32 |
33 |
33 from Utilities.AutoSaver import AutoSaver |
34 from Utilities.AutoSaver import AutoSaver |
34 |
|
35 |
|
36 class Task(QTreeWidgetItem): |
|
37 """ |
|
38 Class implementing the task data structure. |
|
39 """ |
|
40 def __init__(self, description, priority=1, filename="", lineno=0, |
|
41 completed=False, _time=0, isProjectTask=False, |
|
42 isBugfixTask=False, project=None, longtext=""): |
|
43 """ |
|
44 Constructor |
|
45 |
|
46 @param parent parent widget of the task (QWidget) |
|
47 @param description descriptive text of the task (string) |
|
48 @param priority priority of the task (0=high, 1=normal, 2=low) |
|
49 @param filename filename containing the task (string) |
|
50 @param lineno line number containing the task (integer) |
|
51 @param completed flag indicating completion status (boolean) |
|
52 @param _time creation time of the task (float, if 0 use current time) |
|
53 @param isProjectTask flag indicating a task related to the current project |
|
54 (boolean) |
|
55 @param isBugfixTask flag indicating a bugfix task (boolean) |
|
56 @param project reference to the project object (Project) |
|
57 @param longtext explanatory text of the task (string) |
|
58 """ |
|
59 super().__init__() |
|
60 |
|
61 self.description = description |
|
62 self.longtext = longtext |
|
63 if priority in [0, 1, 2]: |
|
64 self.priority = priority |
|
65 else: |
|
66 self.priority = 1 |
|
67 self.filename = filename |
|
68 self.lineno = lineno |
|
69 self.completed = completed |
|
70 self.created = _time and _time or time.time() |
|
71 self._isProjectTask = isProjectTask |
|
72 self.isBugfixTask = isBugfixTask |
|
73 self.project = project |
|
74 |
|
75 if isProjectTask: |
|
76 self.filename = self.project.getRelativePath(self.filename) |
|
77 |
|
78 self.setData(0, Qt.DisplayRole, "") |
|
79 self.setData(1, Qt.DisplayRole, "") |
|
80 self.setData(2, Qt.DisplayRole, self.description) |
|
81 self.setData(3, Qt.DisplayRole, self.filename) |
|
82 self.setData(4, Qt.DisplayRole, self.lineno or "") |
|
83 |
|
84 if self.completed: |
|
85 self.setIcon(0, UI.PixmapCache.getIcon("taskCompleted.png")) |
|
86 strikeOut = True |
|
87 else: |
|
88 self.setIcon(0, UI.PixmapCache.getIcon("empty.png")) |
|
89 strikeOut = False |
|
90 for column in range(2, 5): |
|
91 f = self.font(column) |
|
92 f.setStrikeOut(strikeOut) |
|
93 self.setFont(column, f) |
|
94 |
|
95 if self.priority == 1: |
|
96 self.setIcon(1, UI.PixmapCache.getIcon("empty.png")) |
|
97 elif self.priority == 0: |
|
98 self.setIcon(1, UI.PixmapCache.getIcon("taskPrioHigh.png")) |
|
99 elif self.priority == 2: |
|
100 self.setIcon(1, UI.PixmapCache.getIcon("taskPrioLow.png")) |
|
101 else: |
|
102 self.setIcon(1, UI.PixmapCache.getIcon("empty.png")) |
|
103 |
|
104 self.colorizeTask() |
|
105 self.setTextAlignment(4, Qt.AlignRight) |
|
106 |
|
107 def colorizeTask(self): |
|
108 """ |
|
109 Public slot to set the colors of the task item. |
|
110 """ |
|
111 for col in range(5): |
|
112 if self.isBugfixTask: |
|
113 self.setTextColor(col, Preferences.getTasks("TasksBugfixColour")) |
|
114 else: |
|
115 self.setTextColor(col, Preferences.getTasks("TasksColour")) |
|
116 if self._isProjectTask: |
|
117 self.setBackgroundColor(col, Preferences.getTasks("TasksProjectBgColour")) |
|
118 else: |
|
119 self.setBackgroundColor(col, Preferences.getTasks("TasksBgColour")) |
|
120 |
|
121 def setDescription(self, description): |
|
122 """ |
|
123 Public slot to update the description. |
|
124 |
|
125 @param longtext explanatory text of the task (string) |
|
126 """ |
|
127 self.description = description |
|
128 self.setText(2, self.description) |
|
129 |
|
130 def setLongText(self, longtext): |
|
131 """ |
|
132 Public slot to update the longtext field. |
|
133 |
|
134 @param longtext descriptive text of the task (string) |
|
135 """ |
|
136 self.longtext = longtext |
|
137 |
|
138 def setPriority(self, priority): |
|
139 """ |
|
140 Public slot to update the priority. |
|
141 |
|
142 @param priority priority of the task (0=high, 1=normal, 2=low) |
|
143 """ |
|
144 if priority in [0, 1, 2]: |
|
145 self.priority = priority |
|
146 else: |
|
147 self.priority = 1 |
|
148 |
|
149 if self.priority == 1: |
|
150 self.setIcon(1, UI.PixmapCache.getIcon("empty.png")) |
|
151 elif self.priority == 0: |
|
152 self.setIcon(1, UI.PixmapCache.getIcon("taskPrioHigh.png")) |
|
153 elif self.priority == 2: |
|
154 self.setIcon(1, UI.PixmapCache.getIcon("taskPrioLow.png")) |
|
155 else: |
|
156 self.setIcon(1, UI.PixmapCache.getIcon("empty.png")) |
|
157 |
|
158 def setCompleted(self, completed): |
|
159 """ |
|
160 Public slot to update the completed flag. |
|
161 |
|
162 @param completed flag indicating completion status (boolean) |
|
163 """ |
|
164 self.completed = completed |
|
165 if self.completed: |
|
166 self.setIcon(0, UI.PixmapCache.getIcon("taskCompleted.png")) |
|
167 strikeOut = True |
|
168 else: |
|
169 self.setIcon(0, UI.PixmapCache.getIcon("empty.png")) |
|
170 strikeOut = False |
|
171 for column in range(2, 5): |
|
172 f = self.font(column) |
|
173 f.setStrikeOut(strikeOut) |
|
174 self.setFont(column, f) |
|
175 |
|
176 def isCompleted(self): |
|
177 """ |
|
178 Public slot to return the completion status. |
|
179 |
|
180 @return flag indicating the completion status (boolean) |
|
181 """ |
|
182 return self.completed |
|
183 |
|
184 def getFilename(self): |
|
185 """ |
|
186 Public method to retrieve the tasks filename. |
|
187 |
|
188 @return filename (string) |
|
189 """ |
|
190 if self._isProjectTask and self.filename: |
|
191 return os.path.join(self.project.getProjectPath(), self.filename) |
|
192 else: |
|
193 return self.filename |
|
194 |
|
195 def getLineno(self): |
|
196 """ |
|
197 Public method to retrieve the tasks linenumber. |
|
198 |
|
199 @return linenumber (integer) |
|
200 """ |
|
201 return self.lineno |
|
202 |
|
203 def setProjectTask(self, pt): |
|
204 """ |
|
205 Public method to set the project relation flag. |
|
206 |
|
207 @param pt flag indicating a project task (boolean) |
|
208 """ |
|
209 self._isProjectTask = pt |
|
210 self.colorizeTask() |
|
211 |
|
212 def isProjectTask(self): |
|
213 """ |
|
214 Public slot to return the project relation status. |
|
215 |
|
216 @return flag indicating the project relation status (boolean) |
|
217 """ |
|
218 return self._isProjectTask |
|
219 |
|
220 |
|
221 class TaskFilter(object): |
|
222 """ |
|
223 Class implementing a filter for tasks. |
|
224 """ |
|
225 def __init__(self): |
|
226 """ |
|
227 Constructor |
|
228 """ |
|
229 self.active = False |
|
230 |
|
231 self.descriptionFilter = None |
|
232 self.filenameFilter = None |
|
233 self.typeFilter = None # standard (False) or bugfix (True) |
|
234 self.scopeFilter = None # global (False) or project (True) |
|
235 self.statusFilter = None # uncompleted (False) or completed (True) |
|
236 self.prioritiesFilter = None # list of priorities [0 (high), 1 (normal), 2 (low)] |
|
237 |
|
238 def setActive(self, enabled): |
|
239 """ |
|
240 Public method to activate the filter. |
|
241 |
|
242 @param enabled flag indicating the activation state (boolean) |
|
243 """ |
|
244 self.active = enabled |
|
245 |
|
246 def setDescriptionFilter(self, filter): |
|
247 """ |
|
248 Public method to set the description filter. |
|
249 |
|
250 @param filter a regular expression for the description filter |
|
251 to set (string) or None |
|
252 """ |
|
253 if not filter: |
|
254 self.descriptionFilter = None |
|
255 else: |
|
256 self.descriptionFilter = QRegExp(filter) |
|
257 |
|
258 def setFileNameFilter(self, filter): |
|
259 """ |
|
260 Public method to set the filename filter. |
|
261 |
|
262 @param filter a wildcard expression for the filename filter |
|
263 to set (string) or None |
|
264 """ |
|
265 if not filter: |
|
266 self.filenameFilter = None |
|
267 else: |
|
268 self.filenameFilter = QRegExp(filter) |
|
269 self.filenameFilter.setPatternSyntax(QRegExp.Wildcard) |
|
270 |
|
271 def setTypeFilter(self, type_): |
|
272 """ |
|
273 Public method to set the type filter. |
|
274 |
|
275 @param type_ flag indicating a bugfix task (boolean) or None |
|
276 """ |
|
277 self.typeFilter = type_ |
|
278 |
|
279 def setScopeFilter(self, scope): |
|
280 """ |
|
281 Public method to set the scope filter. |
|
282 |
|
283 @param scope flag indicating a project task (boolean) or None |
|
284 """ |
|
285 self.scopeFilter = scope |
|
286 |
|
287 def setStatusFilter(self, status): |
|
288 """ |
|
289 Public method to set the status filter. |
|
290 |
|
291 @param status flag indicating a completed task (boolean) or None |
|
292 """ |
|
293 self.statusFilter = status |
|
294 |
|
295 def setPrioritiesFilter(self, priorities): |
|
296 """ |
|
297 Public method to set the priorities filter. |
|
298 |
|
299 @param priorities list of task priorities (list of integer) or None |
|
300 """ |
|
301 self.prioritiesFilter = priorities |
|
302 |
|
303 def hasActiveFilter(self): |
|
304 """ |
|
305 Public method to check for active filters. |
|
306 |
|
307 @return flag indicating an active filter was found (boolean) |
|
308 """ |
|
309 return self.descriptionFilter is not None or \ |
|
310 self.filenameFilter is not None or \ |
|
311 self.typeFilter is not None or \ |
|
312 self.scopeFilter is not None or \ |
|
313 self.statusFilter is not None or \ |
|
314 self.prioritiesFilter is not None |
|
315 |
|
316 def showTask(self, task): |
|
317 """ |
|
318 Public method to check, if a task should be shown. |
|
319 |
|
320 @param task reference to the task object to check (Task) |
|
321 @return flag indicating whether the task should be shown (boolean) |
|
322 """ |
|
323 if not self.active: |
|
324 return True |
|
325 |
|
326 if self.descriptionFilter and \ |
|
327 self.descriptionFilter.indexIn(task.description) == -1: |
|
328 return False |
|
329 |
|
330 if self.filenameFilter and \ |
|
331 not self.filenameFilter.exactMatch(task.filename): |
|
332 return False |
|
333 |
|
334 if self.typeFilter is not None and \ |
|
335 self.typeFilter != task.isBugfixTask: |
|
336 return False |
|
337 |
|
338 if self.scopeFilter is not None and \ |
|
339 self.scopeFilter != task._isProjectTask: |
|
340 return False |
|
341 |
|
342 if self.statusFilter is not None and \ |
|
343 self.statusFilter != task.completed: |
|
344 return False |
|
345 |
|
346 if self.prioritiesFilter is not None and \ |
|
347 not task.priority in self.prioritiesFilter: |
|
348 return False |
|
349 |
|
350 return True |
|
351 |
35 |
352 |
36 |
353 class TaskViewer(QTreeWidget): |
37 class TaskViewer(QTreeWidget): |
354 """ |
38 """ |
355 Class implementing the task viewer. |
39 Class implementing the task viewer. |
556 @param lineno line number containing the task (integer) |
240 @param lineno line number containing the task (integer) |
557 @param completed flag indicating completion status (boolean) |
241 @param completed flag indicating completion status (boolean) |
558 @param _time creation time of the task (float, if 0 use current time) |
242 @param _time creation time of the task (float, if 0 use current time) |
559 @param isProjectTask flag indicating a task related to the current |
243 @param isProjectTask flag indicating a task related to the current |
560 project (boolean) |
244 project (boolean) |
561 @param isBugfixTask flag indicating a bugfix task (boolean) |
245 @param taskType type of the task (one of Task.TypeFixme, Task.TypeTodo, |
|
246 Task.TypeWarning, Task.TypeNote) |
562 @param longtext explanatory text of the task (string) |
247 @param longtext explanatory text of the task (string) |
563 """ |
248 """ |
564 task = Task(description, priority, filename, lineno, completed, |
249 task = Task(description, priority, filename, lineno, completed, |
565 _time, isProjectTask, isBugfixTask, |
250 _time, isProjectTask, taskType, |
566 self.project, longtext) |
251 self.project, longtext) |
567 self.tasks.append(task) |
252 self.tasks.append(task) |
568 if self.taskFilter.showTask(task): |
253 if self.taskFilter.showTask(task): |
569 self.addTopLevelItem(task) |
254 self.addTopLevelItem(task) |
570 self.__resort() |
255 self.__resort() |
571 self.__resizeColumns() |
256 self.__resizeColumns() |
572 |
257 |
573 if isProjectTask: |
258 if isProjectTask: |
574 self.__projectTasksSaveTimer.changeOccurred() |
259 self.__projectTasksSaveTimer.changeOccurred() |
575 |
260 |
576 def addFileTask(self, description, filename, lineno, isBugfixTask=False, |
261 def addFileTask(self, description, filename, lineno, taskType=Task.TypeTodo, |
577 longtext=""): |
262 longtext=""): |
578 """ |
263 """ |
579 Public slot to add a file related task. |
264 Public slot to add a file related task. |
580 |
265 |
581 @param description descriptive text of the task (string) |
266 @param description descriptive text of the task (string) |
582 @param filename filename containing the task (string) |
267 @param filename filename containing the task (string) |
583 @param lineno line number containing the task (integer) |
268 @param lineno line number containing the task (integer) |
584 @param isBugfixTask flag indicating a bugfix task (boolean) |
269 @param taskType type of the task (one of Task.TypeFixme, Task.TypeTodo, |
|
270 Task.TypeWarning, Task.TypeNote) |
585 @param longtext explanatory text of the task (string) |
271 @param longtext explanatory text of the task (string) |
586 """ |
272 """ |
587 self.addTask(description, filename=filename, lineno=lineno, |
273 self.addTask(description, filename=filename, lineno=lineno, |
588 isProjectTask=( |
274 isProjectTask=( |
589 self.project and self.project.isProjectSource(filename)), |
275 self.project and self.project.isProjectSource(filename)), |
590 isBugfixTask=isBugfixTask, longtext=longtext) |
276 taskType=taskType, longtext=longtext) |
591 |
277 |
592 def getProjectTasks(self): |
278 def getProjectTasks(self): |
593 """ |
279 """ |
594 Public method to retrieve all project related tasks. |
280 Public method to retrieve all project related tasks. |
595 |
281 |