Added new theme. Made detail screen also themable.
[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     static const int FIX_TIMEOUT = 4000;
37     double const DEFAULT_SPEED_TRESHOLD = 8.0;
38     double const MIN_SPEED_TRESHOLD = 0.8;
39     double const SPEED_IGNORE_LEVEL = 0.01;
40     double const TRESHOLD_POINT1_EPS = 40.0;
41     double const TRESHOLD_POINT1_TRESHOLD = 10.0;
42     double const TRESHOLD_POINT2_EPS = 1.8;
43     double const TRESHOLD_POINT2_TRESHOLD = MIN_SPEED_TRESHOLD;
44     double const TRESHOLD_X = (TRESHOLD_POINT1_TRESHOLD - TRESHOLD_POINT2_TRESHOLD) / (TRESHOLD_POINT1_EPS - TRESHOLD_POINT2_EPS);
45     double const TRESHOLD_Y = TRESHOLD_POINT1_TRESHOLD - (TRESHOLD_POINT1_EPS * TRESHOLD_X);
46 }
47
48 Odometer::Odometer(): QObject(0), trip_(0), total_(0),
49 maxSpeed_(0), totalTime_(0), tripTime_(0), fixTimer_(0),
50 mainTimer_(0), emitUpdate_(true), location_(0), signalTimer_(0)
51 {
52     total_ = Settings::instance().value(TOTAL_FIELD, 0).toDouble();
53     totalTime_ = Settings::instance().value(TOTALTIME_FIELD, 0).toULongLong();
54     maxSpeed_ = Settings::instance().value(MAXSPEED_FIELD, 0).toDouble();
55     trip_ = Settings::instance().value(TRIP_FIELD, 0).toDouble();
56     tripTime_ = Settings::instance().value(TRIPTIME_FIELD, 0).toULongLong();
57     signalTimer_ = new QTimer(this);
58     signalTimer_->setSingleShot(false);
59     signalTimer_->setInterval(1000);
60     connect(signalTimer_, SIGNAL(timeout()), this, SIGNAL(timeUpdated()));
61     updateUnit();
62     timeoutTimer_ = new QTimer(this);
63     timeoutTimer_->setSingleShot(true);
64     connect(timeoutTimer_, SIGNAL(timeout()), this, SLOT(fixTimeout()));
65
66 }
67
68 Odometer::~Odometer()
69 {
70     store();
71     delete fixTimer_;
72     delete mainTimer_;
73     end();
74 }
75
76 Odometer& Odometer::instance()
77 {
78     static Odometer instance;
79     return instance;
80 }
81
82 void Odometer::start()
83 {
84     location_ = new Location;
85     connect(location_, SIGNAL(locationChanged(Location::Fix const&)),
86             this, SLOT(update(Location::Fix const&)));
87     location_->start();
88 }
89
90 void Odometer::end()
91 {
92     delete location_;
93     location_ = 0;
94 }
95
96 void Odometer::update(Location::Fix const& fix)
97 {
98     if(fix.kmSpeed > maxSpeed_)
99     {
100         maxSpeed_ = fix.kmSpeed;
101     }
102
103     if(!fixTimer_)
104     {
105         fixTimer_ = new QTime();
106         fixTimer_->start();
107     }
108
109     int elapsed = fixTimer_->elapsed();
110
111     fixTimer_->restart();
112     timeoutTimer_->start(FIX_TIMEOUT);
113
114     if(fix.kmSpeed > SPEED_IGNORE_LEVEL)
115     {
116         double treshold = DEFAULT_SPEED_TRESHOLD;
117
118         if(fix.eps > 0.01)
119         {
120            treshold = fix.eps * TRESHOLD_X + TRESHOLD_Y;
121
122            if(treshold < MIN_SPEED_TRESHOLD)
123            {
124                treshold = MIN_SPEED_TRESHOLD;
125            }
126         }
127
128         if(fix.kmSpeed > treshold && elapsed > 200 && elapsed < FIX_TIMEOUT)
129         {
130             double km = fix.kmSpeed * (static_cast<double>(elapsed) / (1000 * 3600));
131             trip_ += km;
132             total_ += km;
133
134             if(!mainTimer_)
135             {
136                 startTiming();
137             }
138         }
139         else
140         {
141             endTiming();
142         }
143
144         latestFix_ = fix;
145         emit dataUpdated();
146     }
147     else
148     {
149         fixTimeout();
150     }
151 }
152
153 void Odometer::fixTimeout()
154 {
155     if(latestFix_.kmSpeed > SPEED_IGNORE_LEVEL)
156     {
157         latestFix_ = Location::Fix();
158         emit dataUpdated();
159     }
160
161     endTiming();
162 }
163
164 double Odometer::getTrip() const
165 {
166     return trip_ * Location::getUnitMultiplier();
167 }
168
169 double Odometer::getAverageSpeed() const
170 {
171     int elapsed = getTripTime();
172
173     if(elapsed == 0)
174     {
175         return 0.0;
176     }
177
178     return (static_cast<double>(trip_) * Location::getUnitMultiplier()) / (static_cast<double>(elapsed) / 60.0);
179 }
180
181 double Odometer::getTotal() const
182 {
183     return total_ * Location::getUnitMultiplier();
184 }
185
186 double Odometer::getMaxSpeed() const
187 {
188     return maxSpeed_ * Location::getUnitMultiplier();
189 }
190
191 qulonglong Odometer::getTotalTime() const
192 {
193     return totalTime_ + timeAddition();
194 }
195
196 qulonglong Odometer::getTripTime() const
197 {
198     return tripTime_ + timeAddition();
199 }
200
201 void Odometer::resetTrip()
202 {
203     resetTiming();
204     trip_ = 0;
205     tripTime_ = 0;
206     maxSpeed_ = 0;
207
208     if(emitUpdate_)
209     {
210         emit timeUpdated();
211         emit dataUpdated();
212     }
213 }
214
215 void Odometer::resetTotal()
216 {
217     resetTiming();
218     total_ = 0;
219     totalTime_ = 0;
220
221     if(emitUpdate_)
222     {
223         emit timeUpdated();
224         emit dataUpdated();
225     }
226 }
227
228 void Odometer::resetAll()
229 {
230     emitUpdate_ = false;
231     resetTrip();
232     resetTotal();
233     emitUpdate_ = true;
234     emit timeUpdated();
235     emit dataUpdated();
236 }
237
238 void Odometer::store()
239 {
240     Settings::instance().setValue(TOTAL_FIELD, total_);
241     Settings::instance().setValue(TOTALTIME_FIELD, getTotalTime());
242     Settings::instance().setValue(TRIP_FIELD, trip_);
243     Settings::instance().setValue(TRIPTIME_FIELD, getTripTime());
244     Settings::instance().setValue(MAXSPEED_FIELD, maxSpeed_);
245     Settings::instance().sync();
246 }
247
248 Location::Fix const& Odometer::getLatestFix() const
249 {
250     return latestFix_;
251 }
252
253 double Odometer::getSignalStrength() const
254 {
255     if(!location_)
256     {
257         return 0.0;
258     }
259
260     return location_->getSignalStrength();
261 }
262
263 QString const& Odometer::getUnit()
264 {
265     if(Location::getUnit() == Location::KM)
266     {
267         return KM_UNIT;
268     }
269     else
270     {
271         return MILE_UNIT;
272     }
273 }
274
275 QString const& Odometer::getSpeedUnit()
276 {
277     if(Location::getUnit() == Location::KM)
278     {
279         return KM_SPEEDUNIT;
280     }
281     else
282     {
283         return MILE_SPEEDUNIT;
284     }
285 }
286
287 void Odometer::updateUnit()
288 {
289     QString unit = Settings::instance().value("unit", "km").toString();
290
291     if(unit == "km")
292     {
293         Location::setUnit(Location::KM);
294     }
295     else if(unit == "mile")
296     {
297         Location::setUnit(Location::MILE);
298     }
299     else
300     {
301         return;
302     }
303
304     emit unitChanged();
305 }
306
307 void Odometer::startTiming()
308 {
309     signalTimer_->start();
310
311     if(mainTimer_)
312     {
313         mainTimer_->restart();
314         return;
315     }
316
317     mainTimer_ = new QTime();
318     mainTimer_->start();
319     signalTimer_->start();
320 }
321
322 void Odometer::endTiming()
323 {
324     signalTimer_->stop();
325
326     if(!mainTimer_)
327     {
328         return;
329     }
330
331     int elapsed = mainTimer_->elapsed() / 1000;
332     totalTime_ += elapsed;
333     tripTime_ += elapsed;
334     delete mainTimer_;
335     mainTimer_ = 0;
336 }
337
338 void Odometer::resetTiming()
339 {
340     if(!mainTimer_)
341     {
342         return;
343     }
344
345     endTiming();
346     startTiming();
347 }
348
349 int Odometer::timeAddition() const
350 {
351     if(mainTimer_)
352     {
353         return mainTimer_->elapsed() / 1000;
354     }
355
356     return 0;
357 }