|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2021 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing a class representing the tasks JSON file. |
|
8 """ |
|
9 |
|
10 import json |
|
11 import time |
|
12 |
|
13 from PyQt5.QtCore import QObject |
|
14 |
|
15 from E5Gui import E5MessageBox |
|
16 from E5Gui.E5OverrideCursor import E5OverridenCursor |
|
17 from E5Gui.E5Application import e5App |
|
18 |
|
19 import Preferences |
|
20 |
|
21 |
|
22 class TasksFile(QObject): |
|
23 """ |
|
24 Class representing the tasks JSON file. |
|
25 """ |
|
26 def __init__(self, isGlobal: bool, parent: QObject = None): |
|
27 """ |
|
28 Constructor |
|
29 |
|
30 @param isGlobal flag indicating a file for global tasks |
|
31 @type bool |
|
32 @param parent reference to the parent object |
|
33 @type QObject (optional) |
|
34 """ |
|
35 super(TasksFile, self).__init__(parent) |
|
36 self.__isGlobal = isGlobal |
|
37 |
|
38 def writeFile(self, filename: str) -> bool: |
|
39 """ |
|
40 Public method to write the tasks data to a tasks JSON file. |
|
41 |
|
42 @param filename name of the tasks file |
|
43 @type str |
|
44 @return flag indicating a successful write |
|
45 @rtype bool |
|
46 """ |
|
47 # prepare the session data dictionary |
|
48 # step 0: header |
|
49 tasksDict = {} |
|
50 tasksDict["header"] = {} |
|
51 if self.__isGlobal: |
|
52 tasksDict["header"] = { |
|
53 "comment": "eric tasks file", |
|
54 "saved": time.strftime('%Y-%m-%d, %H:%M:%S'), |
|
55 "warning": ( |
|
56 "This file was generated automatically, do not edit." |
|
57 ), |
|
58 } |
|
59 # step 1: project scan filter |
|
60 tasksDict["ProjectScanFilter"] = "" |
|
61 |
|
62 # step 2: tasks |
|
63 tasksDict["Tasks"] = [ |
|
64 task.toDict() |
|
65 for task in e5App().getObject("TaskViewer").getGlobalTasks() |
|
66 ] |
|
67 else: |
|
68 tasksDict["header"] = { |
|
69 "comment": "eric tasks file for project {0}".format( |
|
70 e5App().getObject("Project").getProjectName()), |
|
71 "warning": ( |
|
72 "This file was generated automatically, do not edit." |
|
73 ), |
|
74 } |
|
75 # TODO: replace 'XMLTimestamp' by 'Timestamp' |
|
76 if Preferences.getProject("XMLTimestamp"): |
|
77 tasksDict["header"]["saved"] = ( |
|
78 time.strftime('%Y-%m-%d, %H:%M:%S') |
|
79 ) |
|
80 # step 1: project scan filter |
|
81 tasksDict["ProjectScanFilter"] = ( |
|
82 e5App().getObject("TaskViewer").getTasksScanFilter() |
|
83 ) |
|
84 |
|
85 # step 2: tasks |
|
86 tasksDict["Tasks"] = [ |
|
87 task.toDict() |
|
88 for task in e5App().getObject("TaskViewer").getProjectTasks() |
|
89 ] |
|
90 |
|
91 try: |
|
92 jsonString = json.dumps(tasksDict, indent=2) |
|
93 with open(filename, "w") as f: |
|
94 f.write(jsonString) |
|
95 except (TypeError, EnvironmentError) as err: |
|
96 with E5OverridenCursor(): |
|
97 E5MessageBox.critical( |
|
98 None, |
|
99 self.tr("Save Tasks"), |
|
100 self.tr( |
|
101 "<p>The tasks file <b>{0}</b> could not be" |
|
102 " written.</p><p>Reason: {1}</p>" |
|
103 ).format(filename, str(err)) |
|
104 ) |
|
105 return False |
|
106 |
|
107 return True |
|
108 |
|
109 def readFile(self, filename: str) -> bool: |
|
110 """ |
|
111 Public method to read the tasks data from a task JSON file. |
|
112 |
|
113 @param filename name of the project file |
|
114 @type str |
|
115 @return flag indicating a successful read |
|
116 @rtype bool |
|
117 """ |
|
118 try: |
|
119 with open(filename, "r") as f: |
|
120 jsonString = f.read() |
|
121 tasksDict = json.loads(jsonString) |
|
122 except (EnvironmentError, json.JSONDecodeError) as err: |
|
123 E5MessageBox.critical( |
|
124 None, |
|
125 self.tr("Read Tasks"), |
|
126 self.tr( |
|
127 "<p>The tasks file <b>{0}</b> could not be read.</p>" |
|
128 "<p>Reason: {1}</p>" |
|
129 ).format(filename, str(err)) |
|
130 ) |
|
131 return False |
|
132 |
|
133 viewer = e5App().getObject("TaskViewer") |
|
134 if tasksDict["ProjectScanFilter"]: |
|
135 viewer.setTasksScanFilter(tasksDict["ProjectScanFilter"]) |
|
136 |
|
137 addedTasks = [] |
|
138 for task in tasksDict["Tasks"]: |
|
139 addedTask = viewer.addTask( |
|
140 task["summary"], priority=task["priority"], |
|
141 filename=task["filename"], lineno=task["lineno"], |
|
142 completed=task["completed"], _time=task["created"], |
|
143 isProjectTask=not self.__isGlobal, taskType=task["type"], |
|
144 description=task["description"], uid=task["uid"], |
|
145 parentTask=task["parent_uid"]) |
|
146 addedTasks.append((addedTask, task["expanded"])) |
|
147 |
|
148 for task, expanded in addedTasks: |
|
149 task.setExpanded(expanded) |
|
150 |
|
151 return True |