60 Public method to activate the time tracker. |
60 Public method to activate the time tracker. |
61 """ |
61 """ |
62 from .TimeTrackerWidget import TimeTrackerWidget |
62 from .TimeTrackerWidget import TimeTrackerWidget |
63 |
63 |
64 self.__widget = TimeTrackerWidget(self) |
64 self.__widget = TimeTrackerWidget(self) |
65 self.__ui.addSideWidget(self.__ui.BottomSide, self.__widget, |
65 self.__ui.addSideWidget( |
66 UI.PixmapCache.getIcon(os.path.join("TimeTracker", "icons", "clock.png")), |
66 self.__ui.BottomSide, self.__widget, |
|
67 UI.PixmapCache.getIcon( |
|
68 os.path.join("TimeTracker", "icons", "clock.png")), |
67 self.tr("Time Tracker")) |
69 self.tr("Time Tracker")) |
68 |
70 |
69 self.__activateAct = E5Action(self.trUtf8('Time Tracker'), |
71 self.__activateAct = E5Action( |
70 self.trUtf8('T&ime Tracker'), |
72 self.trUtf8('Time Tracker'), |
71 QKeySequence(self.trUtf8("Alt+Shift+I")), |
73 self.trUtf8('T&ime Tracker'), |
72 0, self, |
74 QKeySequence(self.trUtf8("Alt+Shift+I")), |
73 'time_tracker_activate') |
75 0, self, |
|
76 'time_tracker_activate') |
74 self.__activateAct.setStatusTip(self.trUtf8( |
77 self.__activateAct.setStatusTip(self.trUtf8( |
75 "Switch the input focus to the Time Tracker window.")) |
78 "Switch the input focus to the Time Tracker window.")) |
76 self.__activateAct.setWhatsThis(self.trUtf8( |
79 self.__activateAct.setWhatsThis(self.trUtf8( |
77 """<b>Activate Time Tracker</b>""" |
80 """<b>Activate Time Tracker</b>""" |
78 """<p>This switches the input focus to the Time Tracker window.</p>""" |
81 """<p>This switches the input focus to the Time Tracker""" |
|
82 """ window.</p>""" |
79 )) |
83 )) |
80 self.__activateAct.triggered[()].connect(self.__activateWidget) |
84 self.__activateAct.triggered[()].connect(self.__activateWidget) |
81 |
85 |
82 self.__ui.addE5Actions([self.__activateAct], 'ui') |
86 self.__ui.addE5Actions([self.__activateAct], 'ui') |
83 menu = self.__ui.getMenu("subwindow") |
87 menu = self.__ui.getMenu("subwindow") |
106 self.__trackerFilePath = os.path.join( |
110 self.__trackerFilePath = os.path.join( |
107 self.__e5project.getProjectManagementDir(), |
111 self.__e5project.getProjectManagementDir(), |
108 TimeTracker.FileName) |
112 TimeTracker.FileName) |
109 |
113 |
110 self.__readTrackerEntries() |
114 self.__readTrackerEntries() |
111 self.__widget.showTrackerEntries(sorted(self.__entries.values(), reverse=True)) |
115 self.__widget.showTrackerEntries(sorted(self.__entries.values(), |
|
116 reverse=True)) |
112 self.__widget.setEnabled(True) |
117 self.__widget.setEnabled(True) |
113 |
118 |
114 self.startTrackerEntry() |
119 self.startTrackerEntry() |
115 |
120 |
116 def projectClosed(self): |
121 def projectClosed(self): |
130 try: |
135 try: |
131 f = open(self.__trackerFilePath, "r", encoding="utf-8") |
136 f = open(self.__trackerFilePath, "r", encoding="utf-8") |
132 data = f.read() |
137 data = f.read() |
133 f.close() |
138 f.close() |
134 except (IOError, OSError) as err: |
139 except (IOError, OSError) as err: |
135 E5MessageBox.critical(self.__ui, |
140 E5MessageBox.critical( |
|
141 self.__ui, |
136 self.trUtf8("Read Time Tracker File"), |
142 self.trUtf8("Read Time Tracker File"), |
137 self.trUtf8("""<p>The time tracker file <b>{0}</b> could not be""" |
143 self.trUtf8("""<p>The time tracker file <b>{0}</b> could""" |
138 """ read.</p><p>Reason: {1}</p>""").format( |
144 """ not be read.</p><p>Reason: {1}</p>""") |
139 self.__trackerFilePath, str(err))) |
145 .format(self.__trackerFilePath, str(err))) |
140 return |
146 return |
141 |
147 |
142 from .TimeTrackEntry import TimeTrackEntry |
148 from .TimeTrackEntry import TimeTrackEntry |
143 |
149 |
144 invalidCount = 0 |
150 invalidCount = 0 |
149 self.__entries[eid] = entry |
155 self.__entries[eid] = entry |
150 else: |
156 else: |
151 invalidCount += 1 |
157 invalidCount += 1 |
152 |
158 |
153 if invalidCount: |
159 if invalidCount: |
154 E5MessageBox.information(self.__ui, |
160 E5MessageBox.information( |
|
161 self.__ui, |
155 self.trUtf8("Read Time Tracker File"), |
162 self.trUtf8("Read Time Tracker File"), |
156 self.trUtf8("""<p>The time tracker file <b>{0}</b> contained""" |
163 self.trUtf8("""<p>The time tracker file <b>{0}</b>""" |
157 """ %n invalid entries. These have been discarded.</p>""", |
164 """ contained %n invalid entries. These""" |
158 "", invalidCount).format(self.__trackerFilePath)) |
165 """ have been discarded.</p>""", "", |
|
166 invalidCount).format(self.__trackerFilePath)) |
159 |
167 |
160 def saveTrackerEntries(self, filePath="", ids=[]): |
168 def saveTrackerEntries(self, filePath="", ids=[]): |
161 """ |
169 """ |
162 Public slot to save the tracker entries to a file. |
170 Public slot to save the tracker entries to a file. |
163 |
171 |
164 @keyparam filePath path and name of the file to write the entries to (string) |
172 @keyparam filePath path and name of the file to write the entries to |
|
173 (string) |
165 @keyparam ids list of entry IDs to be written (list of integer) |
174 @keyparam ids list of entry IDs to be written (list of integer) |
166 """ |
175 """ |
167 if not filePath: |
176 if not filePath: |
168 filePath = self.__trackerFilePath |
177 filePath = self.__trackerFilePath |
169 if ids: |
178 if ids: |
170 entriesList = [self.__entries[eid] for eid in ids if eid in self.__entries] |
179 entriesList = [self.__entries[eid] for eid in ids |
|
180 if eid in self.__entries] |
171 else: |
181 else: |
172 entriesList = self.__entries.values() |
182 entriesList = self.__entries.values() |
173 try: |
183 try: |
174 f = open(filePath, "w", encoding="utf-8") |
184 f = open(filePath, "w", encoding="utf-8") |
175 for entry in entriesList: |
185 for entry in entriesList: |
176 if entry.isValid(): |
186 if entry.isValid(): |
177 f.write(entry.toString() + "\n") |
187 f.write(entry.toString() + "\n") |
178 f.close() |
188 f.close() |
179 except (IOError, OSError) as err: |
189 except (IOError, OSError) as err: |
180 E5MessageBox.critical(self.__ui, |
190 E5MessageBox.critical( |
|
191 self.__ui, |
181 self.trUtf8("Save Time Tracker File"), |
192 self.trUtf8("Save Time Tracker File"), |
182 self.trUtf8("""<p>The time tracker file <b>{0}</b> could not be""" |
193 self.trUtf8("""<p>The time tracker file <b>{0}</b> could""" |
183 """ saved.</p><p>Reason: {1}</p>""").format( |
194 """ not be saved.</p><p>Reason: {1}</p>""") |
184 self.__trackerFilePath, str(err))) |
195 .format(self.__trackerFilePath, str(err))) |
185 |
196 |
186 def importTrackerEntries(self, fname): |
197 def importTrackerEntries(self, fname): |
187 """ |
198 """ |
188 Public slot to import tracker entries from a file. |
199 Public slot to import tracker entries from a file. |
189 |
200 |
192 try: |
203 try: |
193 f = open(fname, "r", encoding="utf-8") |
204 f = open(fname, "r", encoding="utf-8") |
194 data = f.read() |
205 data = f.read() |
195 f.close() |
206 f.close() |
196 except (IOError, OSError) as err: |
207 except (IOError, OSError) as err: |
197 E5MessageBox.critical(self.__ui, |
208 E5MessageBox.critical( |
|
209 self.__ui, |
198 self.trUtf8("Import Time Tracker File"), |
210 self.trUtf8("Import Time Tracker File"), |
199 self.trUtf8("""<p>The time tracker file <b>{0}</b> could not be""" |
211 self.trUtf8("""<p>The time tracker file <b>{0}</b> could""" |
200 """ read.</p><p>Reason: {1}</p>""").format( |
212 """ not be read.</p><p>Reason: {1}</p>""") |
201 fname, str(err))) |
213 .format(fname, str(err))) |
202 return |
214 return |
203 |
215 |
204 from .TimeTrackEntry import TimeTrackEntry |
216 from .TimeTrackEntry import TimeTrackEntry |
205 |
217 |
206 invalidCount = 0 |
218 invalidCount = 0 |
234 if self.__plugin.getPreferences("AutoSave"): |
246 if self.__plugin.getPreferences("AutoSave"): |
235 self.saveTrackerEntries() |
247 self.saveTrackerEntries() |
236 |
248 |
237 if invalidCount != 0 or duplicateCount != 0: |
249 if invalidCount != 0 or duplicateCount != 0: |
238 if invalidCount != 0 and duplicateCount != 0: |
250 if invalidCount != 0 and duplicateCount != 0: |
239 msg = self.tr("""<p>The time tracker file <b>{0}</b> contained""" |
251 msg = self.tr( |
|
252 """<p>The time tracker file <b>{0}</b> contained""" |
240 """ %n invalid entries.""", |
253 """ %n invalid entries.""", |
241 "", invalidCount).format(fname) |
254 "", invalidCount).format(fname) |
242 msg += " " + self.tr(""" %n duplicate entries were detected.""", |
255 msg += " " + self.tr( |
243 "", duplicateCount) |
256 """ %n duplicate entries were detected.""", "", |
|
257 duplicateCount) |
244 elif duplicateCount != 0: |
258 elif duplicateCount != 0: |
245 msg = self.tr("""<p>The time tracker file <b>{0}</b> contained""" |
259 msg = self.tr( |
|
260 """<p>The time tracker file <b>{0}</b> contained""" |
246 """ %n duplicate entries.""", |
261 """ %n duplicate entries.""", |
247 "", duplicateCount).format(fname) |
262 "", duplicateCount).format(fname) |
248 elif invalidCount != 0: |
263 elif invalidCount != 0: |
249 msg = self.tr("""<p>The time tracker file <b>{0}</b> contained""" |
264 msg = self.tr( |
|
265 """<p>The time tracker file <b>{0}</b> contained""" |
250 """ %n invalid entries.""", |
266 """ %n invalid entries.""", |
251 "", invalidCount).format(fname) |
267 "", invalidCount).format(fname) |
252 msg += " " + self.tr(""" %n entries have been ignored.</p>""", |
268 msg += " " + self.tr( |
|
269 """ %n entries have been ignored.</p>""", |
253 "", invalidCount + duplicateCount) |
270 "", invalidCount + duplicateCount) |
254 E5MessageBox.information(self.__ui, |
271 E5MessageBox.information( |
|
272 self.__ui, |
255 self.trUtf8("Import Time Tracker File"), |
273 self.trUtf8("Import Time Tracker File"), |
256 msg) |
274 msg) |
257 |
275 |
258 self.__widget.clear() |
276 self.__widget.clear() |
259 self.__widget.showTrackerEntries(sorted(self.__entries.values(), reverse=True)) |
277 self.__widget.showTrackerEntries(sorted(self.__entries.values(), |
|
278 reverse=True)) |
260 self.__widget.setCurrentEntry(self.__currentEntry) |
279 self.__widget.setCurrentEntry(self.__currentEntry) |
261 |
280 |
262 def addTrackerEntry(self, startDateTime, duration, task, comment): |
281 def addTrackerEntry(self, startDateTime, duration, task, comment): |
263 """ |
282 """ |
264 Public method to add a new tracker entry based on the given data. |
283 Public method to add a new tracker entry based on the given data. |
291 entry.setTask(task) |
310 entry.setTask(task) |
292 entry.setComment(comment) |
311 entry.setComment(comment) |
293 self.__entries[nextID] = entry |
312 self.__entries[nextID] = entry |
294 |
313 |
295 self.__widget.clear() |
314 self.__widget.clear() |
296 self.__widget.showTrackerEntries(sorted(self.__entries.values(), reverse=True)) |
315 self.__widget.showTrackerEntries(sorted(self.__entries.values(), |
|
316 reverse=True)) |
297 self.__widget.setCurrentEntry(self.__currentEntry) |
317 self.__widget.setCurrentEntry(self.__currentEntry) |
298 |
318 |
299 def pauseTrackerEntry(self): |
319 def pauseTrackerEntry(self): |
300 """ |
320 """ |
301 Public method to pause the current tracker entry. |
321 Public method to pause the current tracker entry. |
395 |
417 |
396 if self.__plugin.getPreferences("AutoSave"): |
418 if self.__plugin.getPreferences("AutoSave"): |
397 self.saveTrackerEntries() |
419 self.saveTrackerEntries() |
398 |
420 |
399 self.__widget.clear() |
421 self.__widget.clear() |
400 self.__widget.showTrackerEntries(sorted(self.__entries.values(), reverse=True)) |
422 self.__widget.showTrackerEntries(sorted(self.__entries.values(), |
|
423 reverse=True)) |
401 self.__widget.setCurrentEntry(self.__currentEntry) |
424 self.__widget.setCurrentEntry(self.__currentEntry) |
402 |
425 |
403 def mergeDuplicateTrackerEntries(self): |
426 def mergeDuplicateTrackerEntries(self): |
404 """ |
427 """ |
405 Public slot to merge duplicate time tracker entries. |
428 Public slot to merge duplicate time tracker entries. |
406 |
429 |
407 If entries with the identical start date and time are found, the durations |
430 If entries with the identical start date and time are found, the |
408 of these entries are added. |
431 durations of these entries are added. |
409 """ |
432 """ |
410 entries = {} |
433 entries = {} |
411 for entry in self.__entries.values(): |
434 for entry in self.__entries.values(): |
412 dt = entry.getStartDateTime() |
435 dt = entry.getStartDateTime() |
413 if dt in entries: |
436 if dt in entries: |
424 |
447 |
425 if self.__plugin.getPreferences("AutoSave"): |
448 if self.__plugin.getPreferences("AutoSave"): |
426 self.saveTrackerEntries() |
449 self.saveTrackerEntries() |
427 |
450 |
428 self.__widget.clear() |
451 self.__widget.clear() |
429 self.__widget.showTrackerEntries(sorted(self.__entries.values(), reverse=True)) |
452 self.__widget.showTrackerEntries(sorted(self.__entries.values(), |
|
453 reverse=True)) |
430 self.__widget.setCurrentEntry(self.__currentEntry) |
454 self.__widget.setCurrentEntry(self.__currentEntry) |
431 |
455 |
432 def entryChanged(self): |
456 def entryChanged(self): |
433 """ |
457 """ |
434 Public method to indicate an external change to any of the entries. |
458 Public method to indicate an external change to any of the entries. |