Thu, 30 Dec 2021 11:20:04 +0100
Updated copyright for 2022.
# -*- coding: utf-8 -*- # Copyright (c) 2012 - 2022 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing the time track entry class. """ from PyQt6.QtCore import Qt, QDateTime, QTime class TimeTrackEntry: """ Class implementing the time track entry. """ LineMarker = "Entry: " Separator = "@@" def __init__(self, plugin): """ Constructor @param plugin reference to the plugin object @type TimeTrackerPlugin """ self.__plugin = plugin self.__entryMembersCount = 5 self.__id = -1 self.__startDateTime = QDateTime() # start date and time self.__duration = 0 # duration in minutes self.__task = "" # task specification self.__comment = "" # comment string self.__valid = False # flag for a valid entry self.__continueDateTime = QDateTime() self.__paused = False def __lt__(self, other): """ Special method implementing the less than function. @param other reference to the other object @type TimeTrackEntry @return flag indicating that self is less than other @rtype bool """ return self.__startDateTime < other.getStartDateTime() def toDict(self): """ Public method to convert the time track entry into a dictionary. @return dictionary containing the time track entry data @rtype dict """ if self.__valid: return { "id": self.__id, "start": self.__startDateTime.toString(Qt.DateFormat.ISODate), "duration": self.__duration, "task": self.__task, "comment": self.__comment, } else: return {} def fromDict(self, data): """ Public method to populate the time track entry from a dictionary. @param data dictionary containing the time track entry data @type dict @return ID of the tracker entry; -1 indicates an error @rtype int """ if len(data) != self.__entryMembersCount: return -1 self.__id = data["id"] dt = QDateTime.fromString(data["start"], Qt.DateFormat.ISODate) if not dt.isValid(): return -1 self.__startDateTime = dt self.__duration = data["duration"] self.__task = data["task"] self.__comment = data["comment"] self.__valid = True return self.__id ## def toString(self): ## """ ## Public method to get a string representation of the entry. ## ## @return string representation of the entry (string) ## """ ## if self.__valid: ## dataLine = TimeTrackEntry.Separator.join([ ## str(self.__id), ## self.__startDateTime.toString(Qt.DateFormat.ISODate), ## str(self.__duration), ## self.__task, ## self.__comment, ## ]) ## return "{0}{1}".format(TimeTrackEntry.LineMarker, dataLine) ## else: ## return "" ## ## def fromString(self, line): ## """ ## Public method to populate the entry from the given string. ## ## @param line stringified entry data as generated by toString() (string) ## @return ID of the tracker entry; -1 indicates an error (integer) ## """ ## if not line.startswith(TimeTrackEntry.LineMarker): ## return -1 ## ## line = line.replace(TimeTrackEntry.LineMarker, "") ## dataList = line.split(TimeTrackEntry.Separator) ## if len(dataList) != self.__entryMembersCount: ## return -1 ## ## try: ## self.__id = int(dataList[0]) ## except ValueError: ## return -1 ## ## dt = QDateTime.fromString(dataList[1], Qt.DateFormat.ISODate) ## if not dt.isValid(): ## return -1 ## self.__startDateTime = dt ## ## try: ## dt = int(dataList[2]) ## except ValueError: ## return -1 ## self.__duration = dt ## ## self.__task = dataList[3] ## self.__comment = dataList[4] ## ## self.__valid = True ## return self.__id ## def isValid(self): """ Public method to check the validity of the entry. @return validity of the entry @rtype bool """ return self.__valid def start(self): """ Public method to set the start time of this entry. """ self.__startDateTime = self.__currentDateTime() self.__continueDateTime = QDateTime(self.__startDateTime) def stop(self): """ Public method to stop this entry. """ if not self.__paused: minutes = self.__calculateDuration( self.__continueDateTime, QDateTime.currentDateTime()) self.__duration += minutes if self.__duration >= self.__plugin.getPreferences("MinimumDuration"): self.__valid = True else: self.__duration = 0 self.__valid = False def pause(self): """ Public method to pause the entry. """ if not self.__paused: minutes = self.__calculateDuration( self.__continueDateTime, QDateTime.currentDateTime()) self.__duration += minutes self.__paused = True def continue_(self): """ Public method to continue the entry. """ if self.__paused: self.__continueDateTime = self.__currentDateTime() self.__paused = False def isPaused(self): """ Public method to check for a paused state. @return flag indicating a paused state @rtype bool """ return self.__paused def __currentDateTime(self): """ Private method to get the current date and time without milliseconds. @return current date and time @rtype QDateTime """ dt = QDateTime.currentDateTime() t = dt.time() t2 = QTime(t.hour(), t.minute(), t.second()) dt.setTime(t2) return dt def __calculateDuration(self, start, stop): """ Private method to calculate the duration in minutes. @param start start date and time @type QDateTime @param stop end date and time @type QDateTime @return duration in minutes @rtype int """ secs = start.secsTo(stop) minutes = secs // 60 secsRemaining = secs % 60 if secsRemaining >= 30: minutes += 1 return minutes def getID(self): """ Public method to get the ID of the entry. @return ID of the entry @rtype int """ return self.__id def setID(self, eid): """ Public method to assign an ID to the entry. @param eid ID for the entry @type int """ self.__id = eid def getStartDateTime(self): """ Public method to get the start date and time. @return start date and time @rtype QDateTime """ return self.__startDateTime def setStartDateTime(self, startDateTime): """ Public method to set the start date and time. @param startDateTime start date and time @type QDateTime """ if startDateTime.isValid(): self.__startDateTime = startDateTime self.__valid = ( self.__startDateTime.isValid() and self.__duration >= self.__plugin.getPreferences( "MinimumDuration") ) def getDuration(self): """ Public slot to get the duration. @return duration @rtype int """ return self.__duration def setDuration(self, duration): """ Public method to set the duration. @param duration duration in minutes @type int """ if duration >= self.__plugin.getPreferences("MinimumDuration"): self.__duration = duration self.__valid = ( self.__startDateTime.isValid() and self.__duration >= self.__plugin.getPreferences( "MinimumDuration") ) def addDuration(self, duration): """ Public method to add a duration. @param duration duration to be added in minutes. Negative values are ignored. @type int """ if duration > 0: self.__duration += duration def getTask(self): """ Public method to get the task description. @return task description @rtype str """ return self.__task def setTask(self, description): """ Public method to set the task description. @param description task description @type str """ self.__task = ( description.replace("\r\n", " ").replace("\n", " ") .replace("\r", " ") ) def getComment(self): """ Public method to get the comment. @return comment @rtype str """ return self.__comment def setComment(self, comment): """ Public method to set a comment. @param comment comment to set @type str """ self.__comment = ( comment.replace("\r\n", " ").replace("\n", " ").replace("\r", " ") ) def getEntryData(self): """ Public method to get the entry data. @return entry data as a dictionary with keys 'id', 'paused', 'start_date', 'start_time', 'duration', 'task' and 'comment' containing the entry ID, a flag indicating a paused state, the start date as a string, the start time as a string, the duration, the task and a comment @rtype dict """ return { "id": self.__id, "paused": self.__paused, "start_date": self.__startDateTime.toString("yyyy-MM-dd"), "start_time": self.__startDateTime.toString("hh:mm:ss"), "duration": self.__duration, "task": self.__task, "comment": self.__comment, }