/* * This file only: * Copyright (C) 2003 Mark Bucciarelli * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA. * */ #ifndef KARM_STORAGE_H #define KARM_STORAGE_H #include #include #include "journal.h" #include "reportcriteria.h" #include "desktoplist.h" #include #include #include "resourcecalendar.h" #include class TQDateTime; class Preferences; class Task; class TaskView; class HistoryEvent; /** * Singleton to store/retrieve KArm data to/from persistent storage. * * The storage is an iCalendar file. Also included are methods to * import KArm data from the two legacy file formats. * * All logic that deals with getting and saving data should go here. The * storage logic has changed at least twice already in KArm's history, and * chances are good it will change again (for example, allowing KOrganizer and * KArm to access the same iCalendar file simultaneously). * * Prior to KDE 3.2, KArm just stored totals for each task--a session total * and a task total. The session total was reset to zero each time KArm * started up or after the user reset the session times to zero. With the * release of KDE 3.2, KArm now stores these task totals as well as logging * the history of each start/stop event; that is, every time you start a timer * and then stop a timer on a task, KArm records this as an iCalendar event. * * @short Logic that gets and stores KArm data to disk. * @author Mark Bucciarelli */ class KarmStorage { public: /* * Return reference to storage singleton. * * The constructors are private, so this must be used to create a * KarmStorage instance. */ static KarmStorage *instance(); /* * Load the list view with tasks read from iCalendar file. * * Parses iCalendar file, builds list view items in the proper * hierarchy, and loads them into the list view widget. * * If the file name passed in is the same as the last file name that was * loaded, this method does nothing. * * This method considers any of the following conditions errors: * * @li the iCalendar file does not exist * @li the iCalendar file is not readable * @li the list group currently has list items * @li an iCalendar todo has no related to attribute * @li a todo is related to another todo which does not exist * * @param taskview The list group used in the TaskView * @param preferences The current KArm preferences. * @param fileName Override preferences' filename * * @return empty string if success, error message if error. * */ TQString load(TaskView* taskview, const Preferences* preferences, TQString fileName="" ); /* * Return the name of the iCal file */ TQString icalfile(); /* * Build up the taskview. * * This is needed if the iCal file has been modified */ TQString buildTaskView(KCal::ResourceCalendar *rc, TaskView *view); /* Close calendar and clear view. Release lock if holding one. */ void closeStorage(TaskView* view); /* * Save all tasks and their totals to an iCalendar file. * * All tasks must have an associated VTODO object already created in the * calendar file; that is, the task->uid() must refer to a valid VTODO in * the calender. * Delivers empty string if successful, else error msg. * * @param taskview The list group used in the TaskView */ TQString save(TaskView* taskview); /** * Read tasks and their total times from a text file (legacy storage). * * This reads from one of the two legacy file formats. In this version, * the tqparent task times do not include the sum of all their tqchildren's * times. * * The format of the file is zero or more lines of: * 1 task id (a number) * time in minutes * string task name * [string] desktops, in which to count. e.g. "1,2,5" (optional) */ TQString loadFromFlatFile(TaskView* taskview, const TQString& filename); /** * Reads tasks and their total times from text file (legacy). * * This is the older legacy format, where the task totals included the * tqchildren totals. * * @see loadFromFlatFile */ TQString loadFromFlatFileCumulative(TaskView* taskview, const TQString& filename); /** Output a report based on contents of ReportCriteria. */ TQString report( TaskView *taskview, const ReportCriteria &rc ); /** * Log the change in a task's time. * * We create an iCalendar event to store each change. The event start * date is set to the current datetime. If time is added to the task, the * task end date is set to start time + delta. If the time is negative, * the end date is set to the start time. * * In both cases (postive or negative delta), we create a custom iCalendar * property that stores the delta (in seconds). This property is called * X-KDE-karm-duration. * * Note that the KArm UI allows the user to change both the session and * the total task time, and this routine does not account for all posibile * cases. For example, it is possible for the user to do something crazy * like add 10 minutes to the session time and subtract 50 minutes from * the total time. Although this change violates a basic law of physics, * it is allowed. * * For now, you should pass in the change to the total task time. * Eventually, the UI should be changed. * * @param task The task the change is for. * @param delta Change in task time, in seconds. Can be negative. */ void changeTime(const Task* task, const long deltaSeconds); /** * Book time to a task. * * Creates an iCalendar event and adds it to the calendar. Does not write * calender to disk, just adds event to calendar in memory. However, the * resource framework does try to get a lock on the file. After a * succesful lock, the calendar marks this incidence as modified and then * releases the lock. * * @param task Task * @param startDateTime Date and time the booking starts. * @param durationInSeconds Duration of time to book, in seconds. * * @return true if event was added, false if not (if, for example, the * attempted file lock failed). */ bool bookTime(const Task* task, const TQDateTime& startDateTime, long durationInSeconds); /** * Log a change to a task name. * * For iCalendar storage, there is no need to log an Event for this event, * since unique id's are used to link Events to Todos. No matter how many * times you change a task's name, the uid stays the same. * * @param task The task * @param oldname The old name of the task. The new name is in the task * object already. */ void setName(const Task* task, const TQString& oldname) { Q_UNUSED(task); Q_UNUSED(oldname); } /** * Log the event that a timer has started for a task. * * For the iCalendar storage, there is no need to log anything for this * event. We log an event when the timer is stopped. * * @param task The task the timer was started for. */ void startTimer(const Task* task) { Q_UNUSED(task); } /** * Log the event that the timer has stopped for this task. * * The task stores the last time a timer was started, so we log a new iCal * Event with the start and end times for this task. * @see KarmStorage::changeTime * * @param task The task the timer was stopped for. */ void stopTimer(const Task* task, TQDateTime when=TQDateTime::tqcurrentDateTime()); /** * Log a new comment for this task. * * iCal allows multiple comment tags. So we just add a new comment to the * todo for this task and write the calendar. * * @param task The task that gets the comment * @param comment The comment */ void addComment(const Task* task, const TQString& comment); /** * Remove this task from iCalendar file. * * Removes task as well as all event history for this task. * * @param task The task to be removed. * @return true if change was saved, false otherwise */ bool removeTask(Task* task); /** * Add this task from iCalendar file. * * Create a new KCal::Todo object and load with task information. If * tqparent is not zero, then set the RELATED-TO attribute for this Todo. * * @param task The task to be removed. * @param tqparent The tqparent of this task. Must have a uid() that is in * the existing calendar. If zero, this task is considered a root task. * @return The unique ID for the new VTODO. Return an null TQString if * there was an error creating the new calendar object. */ TQString addTask(const Task* task, const Task* tqparent); /** * Check if the iCalendar file currently loaded has any Todos in it. * * @return true if iCalendar file has any todos */ bool isEmpty(); /** * Check if iCalendar file name in the preferences has changed since the * last call to load. If there is no calendar file currently loaded, * return false. * * @param preferences Set of KArm preferences. * * @return true if a previous file has been loaded and the iCalendar file * specified in the preferences is different. */ bool isNewStorage(const Preferences* preferences) const; /** Return a list of start/stop events for the given date range. */ TQValueList getHistory(const TQDate& from, const TQDate& to); private: static KarmStorage *_instance; KCal::ResourceCalendar *_calendar; TQString _icalfile; KarmStorage(); void adjustFromLegacyFileFormat(Task* task); bool parseLine(TQString line, long *time, TQString *name, int *level, DesktopList* desktopList); TQString writeTaskAsTodo (Task* task, const int level, TQPtrStack< KCal::Todo >& parents); bool saveCalendar(); KCal::Event* baseEvent(const Task*); bool remoteResource( const TQString& file ) const; /** * Writes all tasks and their totals to a Comma-Separated Values file. * * The format of this file is zero or more lines of: * taskName,subtaskName,..,sessionTime,time,totalSessionTime,totalTime * the number of subtasks is determined at runtime. */ TQString exportcsvFile( TaskView *taskview, const ReportCriteria &rc ); /** * Write task history to file as comma-delimited data. */ TQString exportcsvHistory ( TaskView* taskview, const TQDate& from, const TQDate& to, const ReportCriteria &rc ); long printTaskHistory ( const Task *task, const TQMap& taskdaytotals, TQMap& daytotals, const TQDate& from, const TQDate& to, const int level, std::vector &matrix, const ReportCriteria &rc ); }; /** * One start/stop event that has been logged. * * When a task is running and the user stops it, KArm logs this event and * saves it in the history. This class represents such an event read from * storage, and abstracts it from the specific storage used. */ class HistoryEvent { public: /** Needed to be used in a value list. */ HistoryEvent() {} HistoryEvent(TQString uid, TQString name, long duration, TQDateTime start, TQDateTime stop, TQString todoUid); TQString uid() {return _uid; } TQString name() {return _name; } /** In seconds. */ long duration() {return _duration; } TQDateTime start() {return _start; } TQDateTime stop() { return _stop; } TQString todoUid() {return _todoUid; } private: TQString _uid; TQString _todoUid; TQString _name; long _duration; TQDateTime _start; TQDateTime _stop; }; #endif // KARM_STORAGE_H