Improved special field handling in text element.
[jspeed] / src / odometer.cpp
1 /*
2  * This file is part of jSpeed.
3  *
4  * jSpeed is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * jSpeed is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with jSpeed.  If not, see <http://www.gnu.org/licenses/>.
16  *
17  */
18
19 #include <QtCore/QTime>
20 #include <QtCore/QDebug>
21 #include <QtCore/QTimer>
22 #include "odometer.h"
23 #include "settings.h"
24
25 namespace
26 {
27     QString const TOTAL_FIELD = "odometer_total";
28     QString const TOTALTIME_FIELD = "odometer_totaltime";
29     QString const TRIP_FIELD = "odometer_trip";
30     QString const TRIPTIME_FIELD = "odometer_triptime";
31     QString const MAXSPEED_FIELD = "odometer_maxspeed";
32     QString const KM_UNIT = "km";
33     QString const MILE_UNIT = "mi";
34     QString const KM_SPEEDUNIT = "km/h";
35     QString const MILE_SPEEDUNIT = "mph";
36     double const SPEED_TRESHOLD = 0.8;
37     double const SPEED_IGNORE_LEVEL = 0.2;
38 }
39
40 Odometer::Odometer(): QObject(0), trip_(0), total_(0),
41 maxSpeed_(0), totalTime_(0), tripTime_(0), fixTimer_(0),
42 mainTimer_(0), emitUpdate_(true), location_(0), signalTimer_(0)
43 {
44     total_ = Settings::instance().value(TOTAL_FIELD, 0).toDouble();
45     totalTime_ = Settings::instance().value(TOTALTIME_FIELD, 0).toULongLong();
46     maxSpeed_ = Settings::instance().value(MAXSPEED_FIELD, 0).toDouble();
47     trip_ = Settings::instance().value(TRIP_FIELD, 0).toDouble();
48     tripTime_ = Settings::instance().value(TRIPTIME_FIELD, 0).toULongLong();
49     signalTimer_ = new QTimer(this);
50     signalTimer_->setSingleShot(false);
51     signalTimer_->setInterval(1000);
52     connect(signalTimer_, SIGNAL(timeout()), this, SIGNAL(timeUpdated()));
53     updateUnit();
54 }
55
56 Odometer::~Odometer()
57 {
58     store();
59     delete fixTimer_;
60     delete mainTimer_;
61     end();
62 }
63
64 Odometer& Odometer::instance()
65 {
66     static Odometer instance;
67     return instance;
68 }
69
70 void Odometer::start()
71 {
72     location_ = new Location;
73     connect(location_, SIGNAL(locationChanged(Location::Fix const&)),
74             this, SLOT(update(Location::Fix const&)));
75     location_->start();
76 }
77
78 void Odometer::end()
79 {
80     delete location_;
81     location_ = 0;
82 }
83
84 void Odometer::update(Location::Fix const& fix)
85 {
86     if(fix.kmSpeed > maxSpeed_)
87     {
88         maxSpeed_ = fix.kmSpeed;
89     }
90
91     if(!fixTimer_)
92     {
93         fixTimer_ = new QTime();
94         fixTimer_->start();
95     }
96
97     int elapsed = fixTimer_->elapsed();
98
99     fixTimer_->restart();
100
101     if(elapsed > 200 && fix.kmSpeed > SPEED_IGNORE_LEVEL && elapsed < 10000)
102     {
103         if(fix.kmSpeed > SPEED_TRESHOLD)
104         {
105             double km = fix.kmSpeed * (static_cast<double>(elapsed) / (1000 * 3600));
106             trip_ += km;
107             total_ += km;
108
109             if(!mainTimer_)
110             {
111                 startTiming();
112             }
113         }
114         else
115         {
116             endTiming();
117         }
118
119         latestFix_ = fix;
120         emit dataUpdated();
121     }
122     else
123     {
124         if(latestFix_.kmSpeed > 0.49)
125         {
126             latestFix_ = fix;
127             latestFix_.speed = 0.0;
128             latestFix_.kmSpeed = 0.0;
129             emit dataUpdated();
130         }
131
132         endTiming();
133     }
134 }
135
136 double Odometer::getTrip() const
137 {
138     return trip_ * Location::getUnitMultiplier();
139 }
140
141 double Odometer::getAverageSpeed() const
142 {
143     int elapsed = getTripTime();
144
145     if(elapsed == 0)
146     {
147         return 0.0;
148     }
149
150     return (static_cast<double>(trip_) * Location::getUnitMultiplier()) / (static_cast<double>(elapsed) / 60.0);
151 }
152
153 double Odometer::getTotal() const
154 {
155     return total_ * Location::getUnitMultiplier();
156 }
157
158 double Odometer::getMaxSpeed() const
159 {
160     return maxSpeed_ * Location::getUnitMultiplier();
161 }
162
163 qulonglong Odometer::getTotalTime() const
164 {
165     return totalTime_ + timeAddition();
166 }
167
168 qulonglong Odometer::getTripTime() const
169 {
170     return tripTime_ + timeAddition();
171 }
172
173 void Odometer::resetTrip()
174 {
175     resetTiming();
176     trip_ = 0;
177     tripTime_ = 0;
178     maxSpeed_ = 0;
179
180     if(emitUpdate_)
181     {
182         emit timeUpdated();
183         emit dataUpdated();
184     }
185 }
186
187 void Odometer::resetTotal()
188 {
189     resetTiming();
190     total_ = 0;
191     totalTime_ = 0;
192
193     if(emitUpdate_)
194     {
195         emit timeUpdated();
196         emit dataUpdated();
197     }
198 }
199
200 void Odometer::resetAll()
201 {
202     emitUpdate_ = false;
203     resetTrip();
204     resetTotal();
205     emitUpdate_ = true;
206     emit timeUpdated();
207     emit dataUpdated();
208 }
209
210 void Odometer::store()
211 {
212     Settings::instance().setValue(TOTAL_FIELD, total_);
213     Settings::instance().setValue(TOTALTIME_FIELD, getTotalTime());
214     Settings::instance().setValue(TRIP_FIELD, trip_);
215     Settings::instance().setValue(TRIPTIME_FIELD, getTripTime());
216     Settings::instance().setValue(MAXSPEED_FIELD, maxSpeed_);
217     Settings::instance().sync();
218 }
219
220 Location::Fix const& Odometer::getLatestFix() const
221 {
222     return latestFix_;
223 }
224
225 QString const& Odometer::getUnit()
226 {
227     if(Location::getUnit() == Location::KM)
228     {
229         return KM_UNIT;
230     }
231     else
232     {
233         return MILE_UNIT;
234     }
235 }
236
237 QString const& Odometer::getSpeedUnit()
238 {
239     if(Location::getUnit() == Location::KM)
240     {
241         return KM_SPEEDUNIT;
242     }
243     else
244     {
245         return MILE_SPEEDUNIT;
246     }
247 }
248
249 void Odometer::updateUnit()
250 {
251     QString unit = Settings::instance().value("unit", "km").toString();
252
253     if(unit == "km")
254     {
255         Location::setUnit(Location::KM);
256     }
257     else if(unit == "mile")
258     {
259         Location::setUnit(Location::MILE);
260     }
261     else
262     {
263         return;
264     }
265
266     emit unitChanged();
267 }
268
269 void Odometer::startTiming()
270 {
271     signalTimer_->start();
272
273     if(mainTimer_)
274     {
275         mainTimer_->restart();
276         return;
277     }
278
279     mainTimer_ = new QTime();
280     mainTimer_->start();
281     signalTimer_->start();
282 }
283
284 void Odometer::endTiming()
285 {
286     signalTimer_->stop();
287
288     if(!mainTimer_)
289     {
290         return;
291     }
292
293     int elapsed = mainTimer_->elapsed() / 1000;
294     totalTime_ += elapsed;
295     tripTime_ += elapsed;
296     delete mainTimer_;
297     mainTimer_ = 0;
298 }
299
300 void Odometer::resetTiming()
301 {
302     if(!mainTimer_)
303     {
304         return;
305     }
306
307     endTiming();
308     startTiming();
309 }
310
311 int Odometer::timeAddition() const
312 {
313     if(mainTimer_)
314     {
315         return mainTimer_->elapsed() / 1000;
316     }
317
318     return 0;
319 }