49 @param parent the parent (QWidget) |
49 @param parent the parent (QWidget) |
50 @param project reference to the project object |
50 @param project reference to the project object |
51 """ |
51 """ |
52 super(TaskViewer, self).__init__(parent) |
52 super(TaskViewer, self).__init__(parent) |
53 |
53 |
54 self.setRootIsDecorated(False) |
|
55 self.setItemsExpandable(False) |
|
56 self.setSortingEnabled(True) |
54 self.setSortingEnabled(True) |
57 |
55 |
58 self.__headerItem = QTreeWidgetItem( |
56 self.__headerItem = QTreeWidgetItem( |
59 ["", "", self.tr("Summary"), self.tr("Filename"), |
57 ["", "", self.tr("Summary"), self.tr("Filename"), |
60 self.tr("Line"), ""]) |
58 self.tr("Line"), ""]) |
89 self.tr("&Configure scan options"), |
87 self.tr("&Configure scan options"), |
90 self.__configureProjectTasksScanOptions) |
88 self.__configureProjectTasksScanOptions) |
91 |
89 |
92 self.__menu = QMenu(self) |
90 self.__menu = QMenu(self) |
93 self.__menu.addAction(self.tr("&New Task..."), self.__newTask) |
91 self.__menu.addAction(self.tr("&New Task..."), self.__newTask) |
|
92 self.subtaskItem = self.__menu.addAction( |
|
93 self.tr("New &Sub-Task..."), self.__newSubTask) |
94 self.__menu.addSeparator() |
94 self.__menu.addSeparator() |
95 self.projectTasksMenuItem = self.__menu.addMenu( |
95 self.projectTasksMenuItem = self.__menu.addMenu( |
96 self.__projectTasksMenu) |
96 self.__projectTasksMenu) |
97 self.__menu.addSeparator() |
97 self.__menu.addSeparator() |
98 self.gotoItem = self.__menu.addAction( |
98 self.gotoItem = self.__menu.addAction( |
100 self.__menu.addSeparator() |
100 self.__menu.addSeparator() |
101 self.copyItem = self.__menu.addAction( |
101 self.copyItem = self.__menu.addAction( |
102 self.tr("&Copy"), self.__copyTask) |
102 self.tr("&Copy"), self.__copyTask) |
103 self.pasteItem = self.__menu.addAction( |
103 self.pasteItem = self.__menu.addAction( |
104 self.tr("&Paste"), self.__pasteTask) |
104 self.tr("&Paste"), self.__pasteTask) |
|
105 self.pasteMainItem = self.__menu.addAction( |
|
106 self.tr("Paste as &Main Task"), self.__pasteMainTask) |
105 self.deleteItem = self.__menu.addAction( |
107 self.deleteItem = self.__menu.addAction( |
106 self.tr("&Delete"), self.__deleteTask) |
108 self.tr("&Delete"), self.__deleteTask) |
107 self.__menu.addSeparator() |
109 self.__menu.addSeparator() |
108 self.markCompletedItem = self.__menu.addAction( |
110 self.markCompletedItem = self.__menu.addAction( |
109 self.tr("&Mark Completed"), self.__markCompleted) |
111 self.tr("&Mark Completed"), self.__markCompleted) |
132 self.backProjectTasksMenuItem = self.__backMenu.addMenu( |
134 self.backProjectTasksMenuItem = self.__backMenu.addMenu( |
133 self.__projectTasksMenu) |
135 self.__projectTasksMenu) |
134 self.__backMenu.addSeparator() |
136 self.__backMenu.addSeparator() |
135 self.backPasteItem = self.__backMenu.addAction( |
137 self.backPasteItem = self.__backMenu.addAction( |
136 self.tr("&Paste"), self.__pasteTask) |
138 self.tr("&Paste"), self.__pasteTask) |
|
139 self.backPasteMainItem = self.__menu.addAction( |
|
140 self.tr("Paste as &Main Task"), self.__pasteMainTask) |
137 self.__backMenu.addSeparator() |
141 self.__backMenu.addSeparator() |
138 self.__backMenu.addAction( |
142 self.__backMenu.addAction( |
139 self.tr("Delete Completed &Tasks"), self.__deleteCompleted) |
143 self.tr("Delete Completed &Tasks"), self.__deleteCompleted) |
140 self.__backMenu.addSeparator() |
144 self.__backMenu.addSeparator() |
141 self.__backMenuFilteredAct = self.__backMenu.addAction( |
145 self.__backMenuFilteredAct = self.__backMenu.addAction( |
164 def __resort(self): |
168 def __resort(self): |
165 """ |
169 """ |
166 Private method to resort the tree. |
170 Private method to resort the tree. |
167 """ |
171 """ |
168 self.sortItems(self.sortColumn(), self.header().sortIndicatorOrder()) |
172 self.sortItems(self.sortColumn(), self.header().sortIndicatorOrder()) |
169 |
173 |
170 def __resizeColumns(self): |
174 def __resizeColumns(self): |
171 """ |
175 """ |
172 Private method to resize the list columns. |
176 Private method to resize the list columns. |
173 """ |
177 """ |
174 self.header().resizeSections(QHeaderView.ResizeToContents) |
178 self.header().resizeSections(QHeaderView.ResizeToContents) |
175 self.header().setStretchLastSection(True) |
179 self.header().setStretchLastSection(True) |
176 |
180 |
|
181 def findParentTask(self, parentUid): |
|
182 """ |
|
183 Public method to find a parent task by its ID. |
|
184 |
|
185 @param parentUid uid of the parent task (string) |
|
186 @return reference to the task (Task) |
|
187 """ |
|
188 if not parentUid: |
|
189 return None |
|
190 |
|
191 parentTask = None |
|
192 for task in self.tasks: |
|
193 if task.getUuid() == parentUid: |
|
194 parentTask = task |
|
195 break |
|
196 |
|
197 return parentTask |
|
198 |
177 def __refreshDisplay(self): |
199 def __refreshDisplay(self): |
178 """ |
200 """ |
179 Private method to refresh the display. |
201 Private method to refresh the display. |
180 """ |
202 """ |
181 for task in self.tasks: |
203 for task in self.tasks: |
182 index = self.indexOfTopLevelItem(task) |
204 task.setHidden(not self.taskFilter.showTask(task)) |
183 if self.taskFilter.showTask(task): |
|
184 # show the task |
|
185 if index == -1: |
|
186 self.addTopLevelItem(task) |
|
187 else: |
|
188 # hide the task |
|
189 if index != -1: |
|
190 self.takeTopLevelItem(index) |
|
191 self.__resort() |
205 self.__resort() |
192 self.__resizeColumns() |
206 self.__resizeColumns() |
193 |
207 |
194 def __taskItemActivated(self, itm, col): |
208 def __taskItemActivated(self, itm, col): |
195 """ |
209 """ |
217 coord = self.mapToGlobal(coord) |
231 coord = self.mapToGlobal(coord) |
218 if itm is None: |
232 if itm is None: |
219 self.backProjectTasksMenuItem.setEnabled(self.projectOpen) |
233 self.backProjectTasksMenuItem.setEnabled(self.projectOpen) |
220 if self.copyTask: |
234 if self.copyTask: |
221 self.backPasteItem.setEnabled(True) |
235 self.backPasteItem.setEnabled(True) |
|
236 self.backPasteMainItem.setEnabled(True) |
222 else: |
237 else: |
223 self.backPasteItem.setEnabled(False) |
238 self.backPasteItem.setEnabled(False) |
|
239 self.backPasteMainItem.setEnabled(False) |
224 self.__backMenu.popup(coord) |
240 self.__backMenu.popup(coord) |
225 else: |
241 else: |
226 self.projectTasksMenuItem.setEnabled(self.projectOpen) |
242 self.projectTasksMenuItem.setEnabled(self.projectOpen) |
227 if itm.getFilename(): |
243 if itm.getFilename(): |
228 self.gotoItem.setEnabled(True) |
244 self.gotoItem.setEnabled(True) |
229 self.deleteItem.setEnabled(True) |
245 self.deleteItem.setEnabled(True) |
230 self.markCompletedItem.setEnabled(False) |
246 self.markCompletedItem.setEnabled(False) |
231 self.copyItem.setEnabled(False) |
247 self.copyItem.setEnabled(False) |
|
248 self.subtaskItem.setEnabled(False) |
232 else: |
249 else: |
233 self.gotoItem.setEnabled(False) |
250 self.gotoItem.setEnabled(False) |
234 self.deleteItem.setEnabled(True) |
251 self.deleteItem.setEnabled(True) |
235 self.markCompletedItem.setEnabled(True) |
252 self.markCompletedItem.setEnabled(True) |
236 self.copyItem.setEnabled(True) |
253 self.copyItem.setEnabled(True) |
|
254 self.subtaskItem.setEnabled(True) |
237 if self.copyTask: |
255 if self.copyTask: |
238 self.pasteItem.setEnabled(True) |
256 self.pasteItem.setEnabled(True) |
|
257 self.pasteMainItem.setEnabled(True) |
239 else: |
258 else: |
240 self.pasteItem.setEnabled(False) |
259 self.pasteItem.setEnabled(False) |
|
260 self.pasteMainItem.setEnabled(False) |
241 |
261 |
242 self.__menu.popup(coord) |
262 self.__menu.popup(coord) |
243 |
263 |
244 def setProjectOpen(self, o=False): |
264 def setProjectOpen(self, o=False): |
245 """ |
265 """ |
249 """ |
269 """ |
250 self.projectOpen = o |
270 self.projectOpen = o |
251 |
271 |
252 def addTask(self, summary, priority=1, filename="", lineno=0, |
272 def addTask(self, summary, priority=1, filename="", lineno=0, |
253 completed=False, _time=0, isProjectTask=False, |
273 completed=False, _time=0, isProjectTask=False, |
254 taskType=Task.TypeTodo, description=""): |
274 taskType=Task.TypeTodo, description="", uid="", |
|
275 parentTask=None): |
255 """ |
276 """ |
256 Public slot to add a task. |
277 Public slot to add a task. |
257 |
278 |
258 @param summary summary text of the task (string) |
279 @param summary summary text of the task (string) |
259 @param priority priority of the task (0=high, 1=normal, 2=low) |
280 @param priority priority of the task (0=high, 1=normal, 2=low) |
264 @param isProjectTask flag indicating a task related to the current |
285 @param isProjectTask flag indicating a task related to the current |
265 project (boolean) |
286 project (boolean) |
266 @param taskType type of the task (one of Task.TypeFixme, Task.TypeTodo, |
287 @param taskType type of the task (one of Task.TypeFixme, Task.TypeTodo, |
267 Task.TypeWarning, Task.TypeNote) |
288 Task.TypeWarning, Task.TypeNote) |
268 @param description explanatory text of the task (string) |
289 @param description explanatory text of the task (string) |
269 """ |
290 @param uid unique id of the task (string) |
|
291 @param parentTask reference to the parent task item (Task) |
|
292 @return reference to the task item (Task) |
|
293 """ |
|
294 if parentTask: |
|
295 parentUid = parentTask.getUuid() |
|
296 else: |
|
297 parentUid = "" |
270 task = Task(summary, priority, filename, lineno, completed, |
298 task = Task(summary, priority, filename, lineno, completed, |
271 _time, isProjectTask, taskType, |
299 _time, isProjectTask, taskType, |
272 self.project, description) |
300 self.project, description, uid, parentUid) |
273 self.tasks.append(task) |
301 self.tasks.append(task) |
274 if self.taskFilter.showTask(task): |
302 if parentTask: |
|
303 parentTask.addChild(task) |
|
304 parentTask.setExpanded(True) |
|
305 else: |
275 self.addTopLevelItem(task) |
306 self.addTopLevelItem(task) |
276 self.__resort() |
307 task.setHidden(not self.taskFilter.showTask(task)) |
277 self.__resizeColumns() |
308 self.__resort() |
|
309 self.__resizeColumns() |
278 |
310 |
279 if isProjectTask: |
311 if isProjectTask: |
280 self.__projectTasksSaveTimer.changeOccurred() |
312 self.__projectTasksSaveTimer.changeOccurred() |
|
313 |
|
314 return task |
281 |
315 |
282 def addFileTask(self, summary, filename, lineno, taskType=Task.TypeTodo, |
316 def addFileTask(self, summary, filename, lineno, taskType=Task.TypeTodo, |
283 description=""): |
317 description=""): |
284 """ |
318 """ |
285 Public slot to add a file related task. |
319 Public slot to add a file related task. |
327 Public slot to clear project related tasks. |
361 Public slot to clear project related tasks. |
328 |
362 |
329 @keyparam fileOnly flag indicating to clear only file related |
363 @keyparam fileOnly flag indicating to clear only file related |
330 project tasks (boolean) |
364 project tasks (boolean) |
331 """ |
365 """ |
332 for task in self.tasks[:]: |
366 for task in reversed(self.tasks[:]): |
333 if (fileOnly and task.isProjectFileTask()) or \ |
367 if (fileOnly and task.isProjectFileTask()) or \ |
334 (not fileOnly and task.isProjectTask()): |
368 (not fileOnly and task.isProjectTask()): |
335 if self.copyTask == task: |
369 if self.copyTask == task: |
336 self.copyTask = None |
370 self.copyTask = None |
337 index = self.indexOfTopLevelItem(task) |
371 parent = task.parent() |
338 self.takeTopLevelItem(index) |
372 if parent: |
|
373 parent.removeChild(task) |
|
374 else: |
|
375 index = self.indexOfTopLevelItem(task) |
|
376 self.takeTopLevelItem(index) |
339 self.tasks.remove(task) |
377 self.tasks.remove(task) |
340 del task |
378 del task |
341 |
379 |
342 def clearFileTasks(self, filename, conditionally=False): |
380 def clearFileTasks(self, filename, conditionally=False): |
343 """ |
381 """ |
373 dlg = TaskPropertiesDialog(task, self, self.projectOpen) |
411 dlg = TaskPropertiesDialog(task, self, self.projectOpen) |
374 ro = task.getFilename() != "" |
412 ro = task.getFilename() != "" |
375 if ro: |
413 if ro: |
376 dlg.setReadOnly() |
414 dlg.setReadOnly() |
377 if dlg.exec_() == QDialog.Accepted and not ro: |
415 if dlg.exec_() == QDialog.Accepted and not ro: |
378 data = dlg.getData() |
416 summary, priority, completed, isProjectTask, description = \ |
379 task.setSummary(data[0]) |
417 dlg.getData() |
380 task.setPriority(data[1]) |
418 task.setSummary(summary) |
381 task.setCompleted(data[2]) |
419 task.setPriority(priority) |
382 task.setProjectTask(data[3]) |
420 task.setCompleted(completed) |
383 task.setDescription(data[4]) |
421 task.setProjectTask(isProjectTask) |
|
422 task.setDescription(description) |
384 self.__projectTasksSaveTimer.changeOccurred() |
423 self.__projectTasksSaveTimer.changeOccurred() |
385 |
424 |
386 def __newTask(self): |
425 def __newTask(self): |
387 """ |
426 """ |
388 Private slot to handle the "New Task" context menu entry. |
427 Private slot to handle the "New Task" context menu entry. |
389 """ |
428 """ |
390 from .TaskPropertiesDialog import TaskPropertiesDialog |
429 from .TaskPropertiesDialog import TaskPropertiesDialog |
391 dlg = TaskPropertiesDialog(None, self, self.projectOpen) |
430 dlg = TaskPropertiesDialog(None, self, self.projectOpen) |
392 if dlg.exec_() == QDialog.Accepted: |
431 if dlg.exec_() == QDialog.Accepted: |
393 data = dlg.getData() |
432 summary, priority, completed, isProjectTask, description = \ |
394 self.addTask(data[0], data[1], completed=data[2], |
433 dlg.getData() |
395 isProjectTask=data[3], description=data[4]) |
434 self.addTask(summary, priority, completed=completed, |
|
435 isProjectTask=isProjectTask, description=description) |
|
436 |
|
437 def __newSubTask(self): |
|
438 """ |
|
439 Private slot to handle the "New Sub-Task" context menu entry. |
|
440 """ |
|
441 parentTask = self.currentItem() |
|
442 projectTask = parentTask.isProjectTask() |
|
443 |
|
444 from .TaskPropertiesDialog import TaskPropertiesDialog |
|
445 dlg = TaskPropertiesDialog(None, self, self.projectOpen) |
|
446 dlg.setSubTaskMode(projectTask) |
|
447 if dlg.exec_() == QDialog.Accepted: |
|
448 summary, priority, completed, isProjectTask, description = \ |
|
449 dlg.getData() |
|
450 self.addTask(summary, priority, completed=completed, |
|
451 isProjectTask=isProjectTask, description=description, |
|
452 parentTask=parentTask) |
396 |
453 |
397 def __markCompleted(self): |
454 def __markCompleted(self): |
398 """ |
455 """ |
399 Private slot to handle the "Mark Completed" context menu entry. |
456 Private slot to handle the "Mark Completed" context menu entry. |
400 """ |
457 """ |
403 |
460 |
404 def __deleteCompleted(self): |
461 def __deleteCompleted(self): |
405 """ |
462 """ |
406 Private slot to handle the "Delete Completed Tasks" context menu entry. |
463 Private slot to handle the "Delete Completed Tasks" context menu entry. |
407 """ |
464 """ |
408 for task in self.tasks[:]: |
465 for task in reversed(self.tasks[:]): |
409 if task.isCompleted(): |
466 if task.isCompleted(): |
410 if self.copyTask == task: |
467 if self.copyTask == task: |
411 self.copyTask = None |
468 self.copyTask = None |
412 index = self.indexOfTopLevelItem(task) |
469 parent = task.parent() |
413 self.takeTopLevelItem(index) |
470 if parent: |
|
471 parent.removeChild(task) |
|
472 else: |
|
473 index = self.indexOfTopLevelItem(task) |
|
474 self.takeTopLevelItem(index) |
414 self.tasks.remove(task) |
475 self.tasks.remove(task) |
415 if task.isProjectTask: |
476 if task.isProjectTask: |
416 self.__projectTasksSaveTimer.changeOccurred() |
477 self.__projectTasksSaveTimer.changeOccurred() |
417 del task |
478 del task |
418 ci = self.currentItem() |
479 ci = self.currentItem() |
434 if self.copyTask: |
495 if self.copyTask: |
435 self.addTask(self.copyTask.summary, |
496 self.addTask(self.copyTask.summary, |
436 priority=self.copyTask.priority, |
497 priority=self.copyTask.priority, |
437 completed=self.copyTask.completed, |
498 completed=self.copyTask.completed, |
438 description=self.copyTask.description, |
499 description=self.copyTask.description, |
|
500 isProjectTask=self.copyTask._isProjectTask, |
|
501 parentTask=self.copyTask.parent()) |
|
502 |
|
503 def __pasteMainTask(self): |
|
504 """ |
|
505 Private slot to handle the "Paste as Main Task" context menu entry. |
|
506 """ |
|
507 if self.copyTask: |
|
508 self.addTask(self.copyTask.summary, |
|
509 priority=self.copyTask.priority, |
|
510 completed=self.copyTask.completed, |
|
511 description=self.copyTask.description, |
439 isProjectTask=self.copyTask._isProjectTask) |
512 isProjectTask=self.copyTask._isProjectTask) |
|
513 |
|
514 def __deleteSubTasks(self, task): |
|
515 """ |
|
516 Private method to delete all sub-tasks. |
|
517 |
|
518 @param task task to delete sub-tasks of (Task) |
|
519 """ |
|
520 for subtask in task.takeChildren(): |
|
521 if self.copyTask == subtask: |
|
522 self.copyTask = None |
|
523 if subtask.childCount() > 0: |
|
524 self.__deleteSubTasks(subtask) |
|
525 self.tasks.remove(subtask) |
440 |
526 |
441 def __deleteTask(self): |
527 def __deleteTask(self): |
442 """ |
528 """ |
443 Private slot to handle the "Delete Task" context menu entry. |
529 Private slot to handle the "Delete Task" context menu entry. |
444 """ |
530 """ |
445 task = self.currentItem() |
531 task = self.currentItem() |
446 if self.copyTask == task: |
532 if self.copyTask == task: |
447 self.copyTask = None |
533 self.copyTask = None |
448 index = self.indexOfTopLevelItem(task) |
534 if task.childCount() > 0: |
449 self.takeTopLevelItem(index) |
535 self.__deleteSubTasks(task) |
|
536 parent = task.parent() |
|
537 if parent: |
|
538 parent.removeChild(task) |
|
539 else: |
|
540 index = self.indexOfTopLevelItem(task) |
|
541 self.takeTopLevelItem(index) |
450 self.tasks.remove(task) |
542 self.tasks.remove(task) |
451 if task.isProjectTask: |
543 if task.isProjectTask: |
452 self.__projectTasksSaveTimer.changeOccurred() |
544 self.__projectTasksSaveTimer.changeOccurred() |
453 del task |
545 del task |
454 ci = self.currentItem() |
546 ci = self.currentItem() |