|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2005 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing a class to store task data. |
|
8 """ |
|
9 |
|
10 import contextlib |
|
11 import enum |
|
12 import os |
|
13 import time |
|
14 |
|
15 from PyQt5.QtCore import Qt, QUuid |
|
16 from PyQt5.QtWidgets import QTreeWidgetItem |
|
17 |
|
18 import UI.PixmapCache |
|
19 import Preferences |
|
20 |
|
21 |
|
22 class TaskType(enum.IntEnum): |
|
23 """ |
|
24 Class defining the task types. |
|
25 """ |
|
26 NONE = 255 |
|
27 FIXME = 0 |
|
28 TODO = 1 |
|
29 WARNING = 2 |
|
30 NOTE = 3 |
|
31 TEST = 4 |
|
32 DOCU = 5 |
|
33 |
|
34 |
|
35 class TaskPriority(enum.IntEnum): |
|
36 """ |
|
37 Class defining the task priorities. |
|
38 """ |
|
39 HIGH = 0 |
|
40 NORMAL = 1 |
|
41 LOW = 2 |
|
42 |
|
43 |
|
44 # TODO: eric7: separate into Task and TaskItem(QTreeWidgetItem) |
|
45 class Task(QTreeWidgetItem): |
|
46 """ |
|
47 Class implementing the task data structure. |
|
48 """ |
|
49 TaskType2IconName = { |
|
50 TaskType.FIXME: "taskFixme", # __NO-TASK__ |
|
51 TaskType.TODO: "taskTodo", # __NO-TASK__ |
|
52 TaskType.WARNING: "taskWarning", # __NO-TASK__ |
|
53 TaskType.NOTE: "taskNote", # __NO-TASK__ |
|
54 TaskType.TEST: "taskTest", # __NO-TASK__ |
|
55 TaskType.DOCU: "taskDocu", # __NO-TASK__ |
|
56 } |
|
57 TaskType2ColorName = { |
|
58 TaskType.FIXME: "TasksFixmeColor", # __NO-TASK__ |
|
59 TaskType.TODO: "TasksTodoColor", # __NO-TASK__ |
|
60 TaskType.WARNING: "TasksWarningColor", # __NO-TASK__ |
|
61 TaskType.NOTE: "TasksNoteColor", # __NO-TASK__ |
|
62 TaskType.TEST: "TasksTestColor", # __NO-TASK__ |
|
63 TaskType.DOCU: "TasksDocuColor", # __NO-TASK__ |
|
64 } |
|
65 TaskType2MarkersName = { |
|
66 TaskType.FIXME: "TasksFixmeMarkers", # __NO-TASK__ |
|
67 TaskType.TODO: "TasksTodoMarkers", # __NO-TASK__ |
|
68 TaskType.WARNING: "TasksWarningMarkers", # __NO-TASK__ |
|
69 TaskType.NOTE: "TasksNoteMarkers", # __NO-TASK__ |
|
70 TaskType.TEST: "TasksTestMarkers", # __NO-TASK__ |
|
71 TaskType.DOCU: "TasksDocuMarkers", # __NO-TASK__ |
|
72 } |
|
73 |
|
74 def __init__(self, summary, priority=TaskPriority.NORMAL, filename="", |
|
75 lineno=0, completed=False, _time=0, isProjectTask=False, |
|
76 taskType=TaskType.TODO, project=None, description="", |
|
77 uid="", parentUid=""): |
|
78 """ |
|
79 Constructor |
|
80 |
|
81 @param summary summary text of the task |
|
82 @type str |
|
83 @param priority priority of the task |
|
84 @type TaskPriority |
|
85 @param filename filename containing the task |
|
86 @type str |
|
87 @param lineno line number containing the task |
|
88 @type int |
|
89 @param completed flag indicating completion status |
|
90 @type bool |
|
91 @param _time creation time of the task (if 0 use current time) |
|
92 @type float |
|
93 @param isProjectTask flag indicating a task related to the current |
|
94 project |
|
95 @type bool |
|
96 @param taskType type of the task |
|
97 @type TaskType |
|
98 @param project reference to the project object |
|
99 @type Project |
|
100 @param description explanatory text of the task |
|
101 @type str |
|
102 @param uid unique id of the task |
|
103 @type str |
|
104 @param parentUid unique id of the parent task |
|
105 @type str |
|
106 """ |
|
107 super().__init__() |
|
108 |
|
109 self.summary = summary |
|
110 self.description = description |
|
111 self.filename = filename |
|
112 self.lineno = lineno |
|
113 self.completed = completed |
|
114 self.created = _time and _time or time.time() |
|
115 self._isProjectTask = isProjectTask |
|
116 self.project = project |
|
117 if uid: |
|
118 self.uid = uid |
|
119 else: |
|
120 self.uid = QUuid.createUuid().toString() |
|
121 self.parentUid = parentUid |
|
122 |
|
123 if isProjectTask: |
|
124 self.filename = self.project.getRelativePath(self.filename) |
|
125 |
|
126 self.setData(0, Qt.ItemDataRole.DisplayRole, "") |
|
127 self.setData(1, Qt.ItemDataRole.DisplayRole, "") |
|
128 self.setData(2, Qt.ItemDataRole.DisplayRole, self.summary) |
|
129 self.setData(3, Qt.ItemDataRole.DisplayRole, self.filename) |
|
130 self.setData(4, Qt.ItemDataRole.DisplayRole, self.lineno or "") |
|
131 |
|
132 if self.completed: |
|
133 self.setIcon(0, UI.PixmapCache.getIcon("taskCompleted")) |
|
134 strikeOut = True |
|
135 else: |
|
136 self.setIcon(0, UI.PixmapCache.getIcon("empty")) |
|
137 strikeOut = False |
|
138 for column in range(2, 5): |
|
139 f = self.font(column) |
|
140 f.setStrikeOut(strikeOut) |
|
141 self.setFont(column, f) |
|
142 |
|
143 self.setPriority(priority) |
|
144 |
|
145 self.setTaskType(taskType) |
|
146 self.setTextAlignment(4, Qt.AlignmentFlag.AlignRight) |
|
147 |
|
148 def colorizeTask(self): |
|
149 """ |
|
150 Public slot to set the colors of the task item. |
|
151 """ |
|
152 boldFont = self.font(0) |
|
153 boldFont.setBold(True) |
|
154 nonBoldFont = self.font(0) |
|
155 nonBoldFont.setBold(False) |
|
156 for col in range(5): |
|
157 with contextlib.suppress(KeyError): |
|
158 self.setBackground( |
|
159 col, Preferences.getTasks( |
|
160 Task.TaskType2ColorName[self.taskType])) |
|
161 |
|
162 if self._isProjectTask: |
|
163 self.setFont(col, boldFont) |
|
164 else: |
|
165 self.setFont(col, nonBoldFont) |
|
166 |
|
167 def setSummary(self, summary): |
|
168 """ |
|
169 Public slot to update the description. |
|
170 |
|
171 @param summary summary text of the task (string) |
|
172 """ |
|
173 self.summary = summary |
|
174 self.setText(2, self.summary) |
|
175 |
|
176 def setDescription(self, description): |
|
177 """ |
|
178 Public slot to update the description field. |
|
179 |
|
180 @param description descriptive text of the task |
|
181 @type str |
|
182 """ |
|
183 self.description = description |
|
184 |
|
185 def setPriority(self, priority): |
|
186 """ |
|
187 Public slot to update the priority. |
|
188 |
|
189 @param priority priority of the task |
|
190 @type TaskPriority |
|
191 """ |
|
192 self.priority = priority |
|
193 |
|
194 if self.priority == TaskPriority.NORMAL: |
|
195 self.setIcon(1, UI.PixmapCache.getIcon("empty")) |
|
196 elif self.priority == TaskPriority.HIGH: |
|
197 self.setIcon(1, UI.PixmapCache.getIcon("taskPrioHigh")) |
|
198 elif self.priority == TaskPriority.LOW: |
|
199 self.setIcon(1, UI.PixmapCache.getIcon("taskPrioLow")) |
|
200 else: |
|
201 self.setIcon(1, UI.PixmapCache.getIcon("empty")) |
|
202 |
|
203 def setTaskType(self, taskType): |
|
204 """ |
|
205 Public method to update the task type. |
|
206 |
|
207 @param taskType type of the task |
|
208 @type TaskType |
|
209 """ |
|
210 self.taskType = taskType |
|
211 |
|
212 try: |
|
213 self.setIcon(2, UI.PixmapCache.getIcon( |
|
214 Task.TaskType2IconName[self.taskType])) |
|
215 except KeyError: |
|
216 self.setIcon(2, UI.PixmapCache.getIcon("empty")) |
|
217 |
|
218 self.colorizeTask() |
|
219 |
|
220 def setCompleted(self, completed): |
|
221 """ |
|
222 Public slot to update the completed flag. |
|
223 |
|
224 @param completed flag indicating completion status (boolean) |
|
225 """ |
|
226 self.completed = completed |
|
227 if self.completed: |
|
228 self.setIcon(0, UI.PixmapCache.getIcon("taskCompleted")) |
|
229 strikeOut = True |
|
230 else: |
|
231 self.setIcon(0, UI.PixmapCache.getIcon("empty")) |
|
232 strikeOut = False |
|
233 for column in range(2, 5): |
|
234 f = self.font(column) |
|
235 f.setStrikeOut(strikeOut) |
|
236 self.setFont(column, f) |
|
237 |
|
238 # set the completion status for all children |
|
239 for index in range(self.childCount()): |
|
240 self.child(index).setCompleted(completed) |
|
241 |
|
242 def isCompleted(self): |
|
243 """ |
|
244 Public slot to return the completion status. |
|
245 |
|
246 @return flag indicating the completion status (boolean) |
|
247 """ |
|
248 return self.completed |
|
249 |
|
250 def getFilename(self): |
|
251 """ |
|
252 Public method to retrieve the task's filename. |
|
253 |
|
254 @return filename (string) |
|
255 """ |
|
256 if self._isProjectTask and self.filename: |
|
257 return os.path.join(self.project.getProjectPath(), self.filename) |
|
258 else: |
|
259 return self.filename |
|
260 |
|
261 def isFileTask(self): |
|
262 """ |
|
263 Public slot to get an indication, if this task is related to a file. |
|
264 |
|
265 @return flag indicating a file task (boolean) |
|
266 """ |
|
267 return self.filename != "" |
|
268 |
|
269 def getLineno(self): |
|
270 """ |
|
271 Public method to retrieve the task's linenumber. |
|
272 |
|
273 @return linenumber (integer) |
|
274 """ |
|
275 return self.lineno |
|
276 |
|
277 def getUuid(self): |
|
278 """ |
|
279 Public method to get the task's uid. |
|
280 |
|
281 @return uid (string) |
|
282 """ |
|
283 return self.uid |
|
284 |
|
285 def getParentUuid(self): |
|
286 """ |
|
287 Public method to get the parent task's uid. |
|
288 |
|
289 @return parent uid (string) |
|
290 """ |
|
291 return self.parentUid |
|
292 |
|
293 def setProjectTask(self, pt): |
|
294 """ |
|
295 Public method to set the project relation flag. |
|
296 |
|
297 @param pt flag indicating a project task (boolean) |
|
298 """ |
|
299 self._isProjectTask = pt |
|
300 self.colorizeTask() |
|
301 |
|
302 def isProjectTask(self): |
|
303 """ |
|
304 Public slot to return the project relation status. |
|
305 |
|
306 @return flag indicating the project relation status (boolean) |
|
307 """ |
|
308 return self._isProjectTask |
|
309 |
|
310 def isProjectFileTask(self): |
|
311 """ |
|
312 Public slot to get an indication, if this task is related to a |
|
313 project file. |
|
314 |
|
315 @return flag indicating a project file task (boolean) |
|
316 """ |
|
317 return self._isProjectTask and self.filename != "" |
|
318 |
|
319 def toDict(self): |
|
320 """ |
|
321 Public method to convert the task data to a dictionary. |
|
322 |
|
323 @return dictionary containing the task data |
|
324 @rtype dict |
|
325 """ |
|
326 return { |
|
327 "summary": self.summary.strip(), |
|
328 "description": self.description.strip(), |
|
329 "priority": self.priority.value, |
|
330 "lineno": self.lineno, |
|
331 "completed": self.completed, |
|
332 "created": self.created, |
|
333 "type": self.taskType.value, |
|
334 "uid": self.uid, |
|
335 "parent_uid": self.parentUid, |
|
336 "expanded": self.isExpanded(), |
|
337 "filename": self.getFilename(), |
|
338 } |