Tasks/TaskViewer.py

changeset 3990
5dd6edf8540a
parent 3656
441956d8fce5
child 3994
04792ff88ddf
equal deleted inserted replaced
3987:57354896fd29 3990:5dd6edf8540a
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()

eric ide

mercurial