1 /*
2   CharmDataModel.h
3 
4   This file is part of Charm, a task-based time tracking application.
5 
6   Copyright (C) 2007-2018 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
7 
8   Author: Mirko Boehm <mirko.boehm@kdab.com>
9   Author: Frank Osterfeld <frank.osterfeld@kdab.com>
10   Author: Allen Winter <allen.winter@kdab.com>
11   Author: David Faure <david.faure@kdab.com>
12 
13   This program is free software; you can redistribute it and/or modify
14   it under the terms of the GNU General Public License as published by
15   the Free Software Foundation, either version 2 of the License, or
16   (at your option) any later version.
17 
18   This program is distributed in the hope that it will be useful,
19   but WITHOUT ANY WARRANTY; without even the implied warranty of
20   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21   GNU General Public License for more details.
22 
23   You should have received a copy of the GNU General Public License
24   along with this program.  If not, see <http://www.gnu.org/licenses/>.
25 */
26 
27 #ifndef CHARMDATAMODEL_H
28 #define CHARMDATAMODEL_H
29 
30 #include <QObject>
31 #include <QTimer>
32 
33 #include "Task.h"
34 #include "State.h"
35 #include "Event.h"
36 #include "TimeSpans.h"
37 #include "TaskTreeItem.h"
38 #include "CharmDataModelAdapterInterface.h"
39 #include "SmartNameCache.h"
40 
41 class QAbstractItemModel;
42 
43 /** CharmDataModel is the application's model.
44     CharmDataModel holds all data that makes up the application's
45     current data space: the list of tasks, the list of events, and the
46     list of active (currently timed) events.
47     It will notify all registered CharmDataModelAdapterInterfaces
48     about changes in the model. Those interfaces could, for example,
49     implement QAbstractItemModel.
50 */
51 class CharmDataModel : public QObject
52 {
53     Q_OBJECT
54     friend class ImportExportTests;
55 
56 public:
57     CharmDataModel();
58     ~CharmDataModel() override;
59 
60     void stateChanged(State previous, State next);
61     /** Register a CharmDataModelAdapterInterface. */
62     void registerAdapter(CharmDataModelAdapterInterface *);
63     /** Unregister a CharmDataModelAdapterInterface. */
64     void unregisterAdapter(CharmDataModelAdapterInterface *);
65 
66     /** Retrieve a task for the given task id.
67         If called with Zero as the task id, it will return the
68         imaginary root that has all top-levels as it's children.
69     */
70     const TaskTreeItem &taskTreeItem(TaskId id) const;
71     /** Convenience method: retrieve the task directly. */
72     const Task &getTask(TaskId id) const;
73     /** Get all tasks as a TaskList.
74         Warning: this might be slow. */
75     TaskList getAllTasks() const;
76     /** Retrieve an event for the given event id. */
77     const Event &eventForId(EventId id) const;
78     /** Constant access to the map of events. */
79     const EventMap &eventMap() const;
80     /**
81      * Get all events that start in a given time frame (e.g. a given day, a given week etc.)
82      * More precisely, all events that start at or after @p start, and start before @p end (@p end excluded!)
83      */
84     EventIdList eventsThatStartInTimeFrame(const QDate &start, const QDate &end) const;
85     // convenience overload
86     EventIdList eventsThatStartInTimeFrame(const TimeSpan &timeSpan) const;
87     const Event &activeEventFor(TaskId id) const;
88     EventIdList activeEvents() const;
89     int activeEventCount() const;
90     TaskTreeItem &parentItem(const Task &task);   // FIXME const???
91     bool taskExists(TaskId id);
92     /** True if task is in the subtree below parent.
93      * parent is not element of the subtree, and thus not it's own child. */
94     bool isParentOf(TaskId parent, TaskId task) const;
95 
96     // handling of active events:
97     /** Is an event active for the task with this id? */
98     bool isTaskActive(TaskId id) const;
99     /** Is this event active? */
100     bool isEventActive(EventId id) const;
101     /** Start a new event with this task. */
102     void startEventRequested(const Task &);
103     /** Stop the active event for this task. */
104     void endEventRequested(const Task &);
105     /** Stop all tasks. */
106     void endAllEventsRequested();
107     /** Activate this event. */
108     bool activateEvent(const Event &);
109 
110     /** Provide a list of the most frequently used tasks.
111       * Only tasks that have been used so far will be taken into account, so the list might be empty. */
112     TaskIdList mostFrequentlyUsedTasks() const;
113     /** Provide a list of the most recently used tasks.
114       * Only tasks that have been used so far will be taken into account, so the list might be empty. */
115     TaskIdList mostRecentlyUsedTasks() const;
116 
117     /** Create a full task name from the specified TaskId. */
118     QString fullTaskName(const Task &) const;
119 
120     /** Create a "smart" task name (name and shortest path that makes the name unique) from the specified TaskId. */
121     QString smartTaskName(const Task &) const;
122 
123     /** Get the task id and full name as a single string. */
124     QString taskIdAndFullNameString(TaskId id) const;
125 
126     /** Get the task id and name as a single string. */
127     QString taskIdAndNameString(TaskId id) const;
128 
129     /** Get the task id and smart name as a single string. */
130     QString taskIdAndSmartNameString(TaskId id) const;
131 
132     bool operator==(const CharmDataModel &other) const;
133 
134 Q_SIGNALS:
135     // these need to be implemented in the respective application to
136     // be able to track time:
137     void makeAndActivateEvent(const Task &);
138     void requestEventModification(const Event &, const Event &);
139     void sysTrayUpdate(const QString &, bool);
140     void resetGUIState();
141 
142 public Q_SLOTS:
143     void setAllTasks(const TaskList &tasks);
144     void addTask(const Task &);
145     void modifyTask(const Task &);
146     void deleteTask(const Task &);
147     void clearTasks();
148 
149     void setAllEvents(const EventList &events);
150     void addEvent(const Event &);
151     void modifyEvent(const Event &);
152     void deleteEvent(const Event &);
153     void clearEvents();
154 
155 private:
156     void determineTaskPaddingLength();
157     bool eventExists(EventId id);
158 
159     Task &findTask(TaskId id);
160     Event &findEvent(EventId id);
161 
162     int totalDuration() const;
163     QString eventsString() const;
164     QString totalDurationString() const;
165     void updateToolTip();
166 
167     TaskTreeItem::Map m_tasks;
168     TaskTreeItem m_rootItem;
169 
170     EventMap m_events;
171     EventIdList m_activeEventIds;
172     // adapters are notified when the model changes
173     CharmDataModelAdapterList m_adapters;
174 
175     // event update timer:
176     QTimer m_timer;
177     SmartNameCache m_nameCache;
178 
179 private Q_SLOTS:
180     void eventUpdateTimerEvent();
181 
182 private:
183     // functions only used for testing:
184     CharmDataModel *clone() const;
185 };
186 #endif
187