1/*
2 Copyright (C) 2014 by Elvis Angelaccio <elvis.angelaccio@kdemail.net>
3
4 This file is part of Kronometer.
5
6 Kronometer is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 2 of the License, or
9 (at your option) any later version.
10
11 Kronometer is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Kronometer. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20#include "stopwatch.h"
21
22#include <QTimerEvent>
23#include <QDataStream>
24#include <QDomElement>
25#include <QCoreApplication>
26
27Stopwatch::Stopwatch(QObject *parent) : QObject(parent), timerId(INACTIVE_TIMER_ID), state(State::INACTIVE), granularity(HUNDREDTHS), zero(0, 0){}
28
29void Stopwatch::setGranularity(Granularity g)
30{
31 granularity = g;
32}
33
34bool Stopwatch::isRunning() const
35{
36 return state == State::RUNNING;
37}
38
39bool Stopwatch::isPaused() const
40{
41 return state == State::PAUSED;
42}
43
44bool Stopwatch::isInactive() const
45{
46 return state == State::INACTIVE;
47}
48
49bool Stopwatch::serialize(QDataStream& out)
50{
51 if (state != State::PAUSED) {
52 return false;
53 }
54
55 out << accumulator;
56
57 return true;
58}
59
60bool Stopwatch::deserialize(QDataStream& in)
61{
62 if (state != State::INACTIVE) {
63 return false;
64 }
65
66 in >> accumulator;
67 state = State::PAUSED;
68
69 emit time(zero.addMSecs(accumulator)); // it signals that has been deserialized and can be resumed
70
71 return true;
72}
73
74bool Stopwatch::serialize(QDomElement& element, const QString& attributeName)
75{
76 if (state != State::PAUSED or attributeName.isEmpty()) {
77 return false;
78 }
79
80 element.setAttribute(attributeName, accumulator);
81
82 return true;
83}
84
85bool Stopwatch::deserialize(QDomElement& element, const QString& attributeName)
86{
87 if (state != State::INACTIVE or attributeName.isEmpty()) {
88 return false;
89 }
90
91 QString acc = element.attribute(attributeName);
92 accumulator = acc.toLongLong();
93
94 if (accumulator == 0) {
95 return false; // invalid attribute name or value
96 }
97
98 state = State::PAUSED;
99
100 emit time(zero.addMSecs(accumulator)); // it signals that has been deserialized and can be resumed
101
102 return true;
103}
104
105void Stopwatch::onStart()
106{
107 if (state == State::INACTIVE) {
108 accumulator = 0;
109 elapsedTimer.start();
110
111 if (timerId == INACTIVE_TIMER_ID) {
112 timerId = startTimer(granularity);
113 }
114 }
115 else if (state == State::PAUSED) {
116 elapsedTimer.restart();
117 timerId = startTimer(granularity);
118 }
119
120 state = State::RUNNING;
121}
122
123void Stopwatch::onPause()
124{
125 if (elapsedTimer.isValid()) {
126 accumulator += elapsedTimer.elapsed();
127 }
128
129 elapsedTimer.invalidate();
130 state = State::PAUSED;
131}
132
133void Stopwatch::onReset()
134{
135 elapsedTimer.invalidate(); // if state is running, it will emit a zero time at next timerEvent() call
136 QCoreApplication::processEvents();
137 emit time(zero);
138 state = State::INACTIVE;
139}
140
141void Stopwatch::onLap()
142{
143 qint64 lapTime = 0;
144
145 lapTime += accumulator;
146
147 if (elapsedTimer.isValid()) {
148 lapTime += elapsedTimer.elapsed();
149 }
150
151 emit lap(zero.addMSecs(lapTime));
152}
153
154void Stopwatch::timerEvent(QTimerEvent *event)
155{
156 if (event->timerId() != timerId) { // forward undesired events
157 QObject::timerEvent(event);
158 return;
159 }
160
161 qint64 t = 0;
162
163 t += accumulator;
164
165 if (elapsedTimer.isValid()) {
166 t += elapsedTimer.elapsed();
167 emit time(zero.addMSecs(t));
168 }
169 else {
170 killTimer(timerId);
171 timerId = INACTIVE_TIMER_ID;
172 }
173}
174