68ecd57eeec0ecf5df3f2d3f4255cffa55c6a820
[speedfreak] / Client / carmainwindow.cpp
1 /*
2  * CarMainWindow main class
3  *
4  * @author     Toni Jussila <toni.jussila@fudeco.com>
5  * @author     Janne Änäkkälä <janne.anakkala@fudeco.com>
6  * @author     Tiina Kivilinna-Korhola <tiina.kivilinna-korhola@fudeco.com>
7  * @author     Olavi Pulkkinen <olavi.pulkkinen@fudeco.com>
8  * @author     Rikhard Kuutti <rikhard.kuutti@fudeco.com>
9  * @author     Kai Rasilainen <kai.rasilainen@fudeco.com>
10  * @copyright  (c) 2010 Speed Freak team
11  * @license    http://opensource.org/licenses/gpl-license.php GNU Public License
12  */
13
14 #include "carmainwindow.h"
15 #include "math.h"
16
17 #define kAccelerometerSampleRate    50
18 #define kFilteringFactor            0.2
19 #define kSecondsInHour              3600
20
21 /**
22   *Constructor of this class.
23   *@param QWidget pointer to parent object. By default the value is NULL.
24   */
25 CarMainWindow::CarMainWindow(QWidget *parent):QMainWindow(parent), ui(new Ui::CarMainWindow)
26 {
27     ui->setupUi(this);
28     ui->tabWidget->setCurrentWidget(this->ui->StartTab);
29     result = new ResultDialog();
30     //measure = new MeasureDialog();
31     welcomeDialog = new WelcomeDialog();
32     welcomeDialog->show();
33
34     initComboBoxStartTabUnits();
35     initListViewStartTabAccelerationCategories();
36
37     myLogin = new LoginWindow(this);
38     categorylist = new CategoryList();
39     myHttpClient = new HttpClient(this);
40     myRegistration = new Registration(this);
41     connect(myRegistration,SIGNAL(sendregistration()),this,SLOT(regUserToServer()));
42     connect(myLogin,SIGNAL(userNameChanged()),this,SLOT(userLogin()));
43     myRoute = new RouteDialog( this);
44
45     //GPS
46     location = new Maemo5Location(this);
47     gpsData = new GPSData(location);
48     connect(location,SIGNAL(agnss()),this,SLOT(gpsStatus()));
49     gpsTime = new QDateTime();
50
51     time = 0;
52     speed = 0;
53     timer = new QTimer();
54
55     // Accelerometer
56     accelerometer = new Accelerometer();
57
58     reverseAccelerationFlag = false;
59     vehicleStartedMoving = false;
60     isNewRun = true;
61     isSetup = false;
62     stopTime = 0;
63     accelerationStartThreshold = 0.02;
64
65     QTimer *accelerometerTimer = new QTimer(this);
66     connect(accelerometerTimer, SIGNAL(timeout()), this, SLOT(readAccelerometerData()));
67     accelerometerTimer->start(kAccelerometerSampleRate);
68
69     // Calculate
70     calculate = new Calculate();
71     //connect(calculate, SIGNAL(checkPointReached()), this, SLOT(handleCheckPoint()));
72
73     resetAccelerometerMeasurements();
74
75     measures = new Measures();
76     this->initializeMeasures();
77
78     timer->setInterval(300);
79
80     connect(this->timer, SIGNAL(timeout()), this, SLOT(after_timeout()));
81     connect(myLogin, SIGNAL( userNameChanged()), this, SLOT(updateUserName()));
82
83     ui->labelMeasureTabResult->hide();
84
85     this->setWindowTitle("Speed Freak");
86
87 }
88
89 /**
90   *Destructor of this class. Deletes all dynamic objects and sets them to NULL.
91   */
92 CarMainWindow::~CarMainWindow()
93 {
94     delete ui;
95     ui = NULL;
96     //delete result;
97     //delete measure;
98     delete categorylist;
99     categorylist = NULL;
100     delete welcomeDialog;
101     welcomeDialog = NULL;
102     delete myRoute;
103     myRoute = NULL;
104     delete gpsData;
105     gpsData = NULL;
106     delete gpsTime;
107     gpsTime = NULL;
108 }
109
110 /**
111   *This function is used to .
112   *@param
113   */
114 void CarMainWindow::changeEvent(QEvent *e)
115 {
116     QMainWindow::changeEvent(e);
117     switch (e->type()) {
118     case QEvent::LanguageChange:
119         ui->retranslateUi(this);
120         break;
121     default:
122         break;
123     }
124 }
125
126 /**
127   *This slot function is called when ever list view is update. Start-tab view.
128   */
129 void CarMainWindow::on_listViewStartTabAccelerationCategories_clicked(QModelIndex index)
130 {
131     QString str = index.data().toString();
132     QStringList list = str.split("-");
133     QStringList list2 = list[1].split(" ");
134
135     ui->lineEditStartTabMin->setText(list[0]);
136     ui->lineEditStartTabMax->setText(list2[0]);
137     updateComboBoxStartTabUnits(list2[1]);
138 }
139
140 /**
141   *This slot function is called when ever auto start button clicked. Start-tab view.
142   */
143 void CarMainWindow::on_autoStartButton_clicked()
144 {
145     choice = ui->listViewStartTabAccelerationCategories->currentIndex();
146     choiceInt = choice.row();
147     qDebug() << choiceInt;
148     if (choiceInt == 0)
149     {
150         ui->labelMeasureTabHeader->setText("Accelerate to 40 km/h");
151         result->setDiagramGapStem(75);
152     }
153
154     else if (choiceInt == 1)
155     {
156         ui->labelMeasureTabHeader->setText("Accelerate to 100 km/h");
157         result->setDiagramGapStem(30);
158     }
159
160     else
161     {
162         ui->labelMeasureTabHeader->setText("Accelerate to 80 km/h");
163         result->setDiagramGapStem(37.5);
164     }
165     ui->labelMeasureTabResult->setText("");
166     //delete measure;
167     //measure = NULL;
168     //measure = new MeasureDialog();
169    // connect(measure, SIGNAL(speedAchieved()), this, SLOT(openResultView()));
170     timer->start();
171     // Show measure dialog.
172     //measure->show();
173
174     // TODO: Move next if else to the function which is called when target speed
175     // has reached.
176     if (choiceInt == 0)
177     {
178         if (floor(this->measures->getTime40kmh()) <= 5)
179         {
180             result->setDiagramGapHorizontal(80);
181         }
182
183         else if (floor(this->measures->getTime40kmh()) <= 10)
184         {
185             result->setDiagramGapHorizontal(40);
186         }
187
188         else
189         {
190             result->setDiagramGapHorizontal(20);
191         }
192     }
193
194     else
195     {
196         if (floor(this->measures->getTime40kmh()) <= 5)
197         {
198             result->setDiagramGapHorizontal(80);
199         }
200
201         else if (floor(this->measures->getTime40kmh()) <= 10)
202         {
203             result->setDiagramGapHorizontal(40);
204         }
205
206         else
207         {
208             result->setDiagramGapHorizontal(20);
209         }
210     }
211
212     ui->tabWidget->setCurrentWidget(this->ui->tabMeasureResult);
213 }
214
215 /**
216   *This slot function is called when ever list view is update. Start-tab view.
217   *@param QString unit.
218   */
219 void CarMainWindow::updateComboBoxStartTabUnits(QString unit)
220 {
221     ui->comboBoxStartTabUnits->setCurrentIndex(ui->comboBoxStartTabUnits->findText(unit, Qt::MatchExactly));
222 }
223
224 /**
225   *This function is used to init unit combobox. Start-tab view.
226   */
227 void CarMainWindow::initComboBoxStartTabUnits()
228 {
229     units << "km/h" << "km" << "h" << "m" << "min" << "Mile" << "Mph" << "in" << "ft" << "yrd";
230     ui->comboBoxStartTabUnits->addItems(units);
231 }
232
233 /**
234   *This function is used to set items to unit combobox. Start-tab view.
235   *@param QStringlist units
236   */
237 void CarMainWindow::setComboBoxStartTabUnits(QStringList units)
238 {
239     ui->comboBoxStartTabUnits->addItems(units);
240 }
241
242 /**
243   *This function is used to init listViewStartTabAccelerationCategories. Start-tab view.
244   */
245 void CarMainWindow::initListViewStartTabAccelerationCategories()
246 {
247     accelerationCategoriesStartTab << "0-40 km/h" << "0-100 km/h"; //<< "0-1/4 Mile" << "0-1/8 Mile" << "0-50 km" << "50-100 Mile" << "0-60 Mph" << "0-100 m" << "0-50 ft" << "0-50 yrd" << "0-500 in";
248     QAbstractItemModel *model = new StringListModel(accelerationCategoriesStartTab);
249     ui->listViewStartTabAccelerationCategories->setModel(model);
250 }
251
252 /**
253   *This function is used to set items to listViewStartTabAccelerationCategories. Start-tab view.
254   *@param QStringlist accelerationCategoriesStartTab
255   */
256 void CarMainWindow::setListViewStartTabAccelerationCategories(QStringList accelerationCategoriesStartTab)
257 {
258     QAbstractItemModel *model = new StringListModel(accelerationCategoriesStartTab);
259     ui->listViewStartTabAccelerationCategories->setModel(model);
260 }
261
262 /**
263   *This function is used to set items to category combobox. Top-tab view.
264   *@param
265   */
266 void CarMainWindow::setCategoryCompoBox()
267 {
268     ui->comboBoxTopCategory->addItems(categorylist->getCategoryList());
269 }
270
271 /**
272   *This function is used to set items to labelTopList. Top-tab view.
273   *@param QString category
274   */
275 void CarMainWindow::setListViewTopList(QString category, int size)
276 {
277     QString topList;
278     topList.append( categorylist->getTopList(category, size));
279     ui->labelTopList->setText(topList);
280 }
281
282 /**
283   *This slot function is called when speed is achieved in measure dialog. Opens result dialog.
284   */
285 void CarMainWindow::openResultView()
286 {
287     //result->saveMeasuresToArray(measure->measures);
288     // Show result dialog.
289     //result->show();
290     ui->pushButtonSendResult->setEnabled(true);
291     QString timeInteger;
292     if (choiceInt == 0)
293     {
294         if (floor(this->measures->getTime40kmh()) <= 5)
295         {
296             result->setDiagramGapHorizontal(80);
297         }
298
299         else if (floor(this->measures->getTime40kmh()) <= 10)
300         {
301             result->setDiagramGapHorizontal(40);
302         }
303
304         else
305         {
306             result->setDiagramGapHorizontal(20);
307         }
308     }
309
310     else
311     {
312         if (floor(this->measures->getTime40kmh()) <= 5)
313         {
314             result->setDiagramGapHorizontal(80);
315         }
316
317         else if (floor(this->measures->getTime40kmh()) <= 10)
318         {
319             result->setDiagramGapHorizontal(40);
320         }
321
322         else
323         {
324             result->setDiagramGapHorizontal(20);
325         }
326     }
327     timeInteger.setNum(this->measures->getTime40kmh());
328     //time = "0 - 40 km/h: ";
329     //time.append(timeInteger);
330     //ui->labelResult40kmh->setText(time);
331     ui->labelMeasureTabResult->show();
332     ui->labelMeasureTabResult->setText(timeInteger);
333     //ui->tabWidget->setCurrentWidget(this->ui->tabMeasureResult);
334 }
335
336 /**
337   *This slot function is called when registrate button is clicked.
338   */
339 void CarMainWindow::on_registratePushButton_clicked()
340 {
341     myRegistration->show();
342 }
343
344 /**
345   *This slot function is called when ever refresh button clicked. Top-tab view.
346   */
347 void CarMainWindow::on_buttonTopRefresh_clicked()
348 {
349     myHttpClient->requestCategories();
350     setCategoryCompoBox();
351 }
352
353 /**
354   *This slot function is called when ever category combobox current index changed. Top-tab view.
355   *@param QString category
356   *@todo Check where limitNr is taken.
357   */
358 void CarMainWindow::on_comboBoxTopCategory_currentIndexChanged(QString category)
359 {
360     int limitNr = 5;                    //replace with real value?
361     QString limit = QString::number(limitNr);
362     category = "acceleration-0-100";    //replace with real value from category list/top window
363     myHttpClient->requestTopList(category, limit);
364     setListViewTopList(category,10);
365 }
366
367 /**
368   *This slot function is called when ever category combobox activated. Top-tab view.
369   *@param QString category
370   */
371 void CarMainWindow::on_comboBoxTopCategory_activated(QString category)
372 {
373     setListViewTopList(category,10);
374 }
375
376 /**
377   *This slot function is called when set/change user button is clicked.
378   */
379 void CarMainWindow::on_setUserPushButton_clicked()
380 {
381     myLogin->show();
382 }
383
384 /**
385   *@brief Just for development, for the real button is not shown until
386   *measurin started and there are results.
387   *@todo Implement with real code and yet leave sendXml in the bottom in use.
388   */
389 void CarMainWindow::on_manualStartButton_clicked()
390 {
391
392 }
393
394 /**
395   * This slot function is called when timer gives timeout signal. Checks current speed
396   * and stores times in measure class.
397   */
398 void CarMainWindow::after_timeout()
399 {
400     QString timeString, speedString;
401     time++;
402     speed = speed +10;
403
404     if (floor(speed) == 10)
405     {
406         measures->setTime10kmh(time);
407     }
408
409     else if (floor(speed) == 20)
410     {
411         measures->setTime20kmh(time);
412     }
413
414     else if (floor(speed) == 30)
415     {
416         measures->setTime30kmh(time);
417     }
418
419     else if (floor(speed) == 40)
420     {
421         measures->setTime40kmh(time);
422     }
423
424     else if (floor(speed) == 50)
425     {
426         measures->setTime50kmh(time);
427     }
428
429     else if (floor(speed) == 60)
430     {
431         measures->setTime60kmh(time);
432     }
433
434     else if (floor(speed) == 70)
435     {
436         measures->setTime70kmh(time);
437     }
438
439     else if (floor(speed) == 80)
440     {
441         measures->setTime80kmh(time);
442     }
443
444     else if (floor(speed) == 90)
445     {
446         measures->setTime90kmh(time);
447     }
448
449     else if (floor(speed) == 100)
450     {
451         measures->setTime100kmh(time);
452     }
453
454     else
455     {
456
457     }
458
459     // If speed is over 40 km/h emits speedAchieved() signal and close this dialog.
460     if (speed >= 40.0)
461     {
462         timer->stop();
463         time = 0;
464         speed = 0;
465         //emit this->speedAchieved();
466         this->openResultView();
467         //this->close();
468
469     }
470
471     // Updates speed and time.
472     else
473     {
474         timeString.setNum(time);
475         speedString.setNum(speed);
476         ui->labelMeasureTabTime->setText(timeString);
477         ui->labelMeasureTabSpeed->setText(speedString);
478
479         timer->start();
480     }
481
482 }
483
484 /**
485   * Initializes measures class's member variables.
486   */
487 void CarMainWindow::initializeMeasures()
488 {
489     measures->setTime10kmh(0);
490     measures->setTime20kmh(0);
491     measures->setTime30kmh(0);
492     measures->setTime40kmh(0);
493     measures->setTime50kmh(0);
494     measures->setTime60kmh(0);
495     measures->setTime70kmh(0);
496     measures->setTime80kmh(0);
497     measures->setTime90kmh(0);
498     measures->setTime100kmh(0);
499 }
500
501 /**
502   * This slot function is called when Abort button is clicked.
503   */
504 void CarMainWindow::on_pushButtonMeasureTabAbort_clicked()
505 {
506     measures->setTime10kmh(0);
507     measures->setTime20kmh(0);
508     measures->setTime30kmh(0);
509     measures->setTime40kmh(0);
510     measures->setTime50kmh(0);
511     measures->setTime60kmh(0);
512     measures->setTime70kmh(0);
513     measures->setTime80kmh(0);
514     measures->setTime90kmh(0);
515     measures->setTime100kmh(0);
516     timer->stop();
517     time = 0;
518     speed = 0;
519     ui->tabWidget->setCurrentWidget(this->ui->StartTab);
520     //this->close();
521 }
522
523 void CarMainWindow::on_pushButtonSendResult_clicked()
524 {
525     myHttpClient->sendResultXml();
526     ui->pushButtonSendResult->setEnabled(false);
527 }
528
529 void CarMainWindow::updateUserName()
530 {
531     QString newUserName;
532
533     newUserName = myLogin->getUserName();
534     ui->userNameLabel->setText( "User: " + newUserName);
535
536     if (newUserName.length())
537     {
538        ui->setUserPushButton->setText( "Change User");
539        this->setWindowTitle("Speed freak - " + newUserName);
540     }
541     else
542     {
543         ui->setUserPushButton->setText( "Set User");
544         this->setWindowTitle("Speed freak");
545     }
546 }
547
548 void CarMainWindow::regUserToServer()
549 {
550     myHttpClient->requestRegistration();
551 }
552
553
554 void CarMainWindow::on_drawRoutePushButton_clicked()
555 {
556     myRoute->show();
557 }
558
559 /**
560   * Opens result dialog when show result button is clicked.
561   * Sends measures as parameter to the resultdialogs saveMeasuresToArray-function.
562   */
563 void CarMainWindow::on_pushButtonShowResultDialog_clicked()
564 {
565     Measures meas;
566     meas.setTime10kmh(1.3);
567     meas.setTime20kmh(2.5);
568     meas.setTime30kmh(3.6);
569     meas.setTime40kmh(6.7);
570     meas.setTime50kmh(7.3);
571     meas.setTime60kmh(7.5);
572     meas.setTime70kmh(8.6);
573     meas.setTime80kmh(8.7);
574     meas.setTime90kmh(9.6);
575     meas.setTime100kmh(9.9);
576     result->setDiagramGapHorizontal(40);
577     result->saveMeasuresToArray(&meas);
578     this->result->show();
579 }
580
581 void CarMainWindow::userLogin()
582 {
583     myHttpClient->checkLogin();
584 }
585
586 /**
587   * Resets Accelerometer measurement variables
588   */
589 void CarMainWindow::resetAccelerometerMeasurements()
590 {
591     currentAcceleration = 0;
592     currentAccelerationString = "";
593     currentSpeed = "";
594     currentTime = 0;
595     distanceTraveled = "";
596     firstAcceleration = 0;
597     //horsepower = null;
598     isNewRun = true;
599     //lastScreenUpdateInSeconds = 0;
600     previousTime = 0;
601     reverseAccelerationFlag = false;
602     stopWatch.setHMS(0, 0, 0, 0);
603     //accelerometer->stop();
604     totalTime = "";
605     vehicleStartedMoving = false;
606     calculate->reset();
607 }
608
609 /**
610   * This function is called to handle checkpoints
611   *@param totalTime total time elapsed since starting measurements
612   *@param currentSpeed current speed of the device
613   */
614 void CarMainWindow::handleCheckPoint(double totalTime, double currentSpeed)
615 {
616     // TODO
617     //totalTime;
618     //currentSpeed;
619     return;
620 }
621
622 /**
623   *This function is called to read (and process) data from the accelerometer
624   */
625 void CarMainWindow::readAccelerometerData()
626 {
627     QString s;
628     double changeInAcceleration = 0;
629     qreal x, y, z;
630
631     accelerometer->getAcceleration(x, y, z);
632     accelerometer->smoothData(x, y, z);
633
634     // Apply calibration
635     x -= accelerometer->getCalibrationX();
636     y -= accelerometer->getCalibrationY();
637     z -= accelerometer->getCalibrationZ();
638
639     QString str = QString("acc x: " + QString::number(x) + "\n" +
640                           "acc y: " + QString::number(y) + "\n" +
641                           "acc z: " + QString::number(z) + "\n");
642
643     if (!vehicleStartedMoving)
644     {
645         if (isNewRun)
646         {
647             firstAcceleration = sqrt(x*x + y*y + z*z);
648             //firstAcceleration = y; // first read
649             isNewRun = false;
650         }
651     }
652
653     currentAcceleration = sqrt(x*x + y*y + z*z);
654     changeInAcceleration = (currentAcceleration - firstAcceleration); // firstAcceleration only gets set once
655
656     if (((abs(changeInAcceleration) <= accelerationStartThreshold)
657                 && !vehicleStartedMoving))
658     {
659         return;
660     }
661
662     if (reverseAccelerationFlag)
663     {
664         // will be false until after 1st calculation
665         if ((changeInAcceleration <= 0))
666         {
667             // actually increasing here...
668             changeInAcceleration = abs(changeInAcceleration);
669         }
670         else
671         {
672             // actually decreasing here...
673             changeInAcceleration = (changeInAcceleration * -1);
674         }
675     }
676     if (!vehicleStartedMoving)
677     {
678         if ((changeInAcceleration < 0))
679         {
680             // we started to move backwards first time through
681             reverseAccelerationFlag = true;
682             changeInAcceleration = abs(changeInAcceleration);
683         }
684         vehicleStartedMoving = true;
685
686         stopWatch.setHMS(0, 0, 0, 0);
687         stopWatch.start();
688     }
689     //  keep the following line as close to the SetKinematicsProperties method as possible
690     currentTime = stopWatch.elapsed();
691     calculate->calculateParameters(changeInAcceleration, (currentTime - previousTime)/1000);
692     previousTime = currentTime;
693
694     s.sprintf("%.2f", changeInAcceleration);
695     currentAccelerationString = s;
696
697     speed = 0.0;
698     speed = calculate->getCurrentSpeed();
699     speed = ((speed*1000)/kSecondsInHour);
700     s.sprintf("%.2f", speed);
701     currentSpeed = s;
702
703     s.sprintf("%.2f", calculate->getDistanceTraveled());
704     distanceTraveled = s;
705
706     // TODO
707     //distanceTraveled;
708     //horsepower;
709
710     time = calculate->getTotalTime();
711
712     s.sprintf("%.2f", time);
713     totalTime = s;
714
715     str.append("ca: " + currentAccelerationString + " G\n" );
716     str.append("cspeed: " + currentSpeed + " km/h \n" );
717     str.append("dist: " + distanceTraveled + " m \n" );
718     str.append("time: " + totalTime + " s \n" );
719
720     if ((stopTime > 0) && (previousTime >= stopTime))
721     {
722         // we want to end at a stopping point that the user chose
723         // output results
724         resetAccelerometerMeasurements();
725     }
726 }
727
728 /**
729   *This function is used to calibrate accelerometer
730   */
731 void CarMainWindow::calibrateAccelerometer()
732 {
733     resetAccelerometerMeasurements();
734     accelerometer->calibrate();
735 }
736
737 /**
738   *This slot function is called when GPS on checkbox state changed.  Route-tab view.
739   *@param int GPSState
740   */
741 void CarMainWindow::on_gpsOnCheckBox_stateChanged(int GPSState)
742 {
743     if (GPSState == 0)
744     {
745         ui->labelRouteTabGPSStatus->setText("GPS off");//testing
746         location->stopPollingGPS();
747     }
748     else
749     {
750         ui->labelRouteTabGPSStatus->setText("GPS on");//testing
751         location->startPollingGPS();
752     }
753 }
754
755 /**
756   *This slot function is called when GPS status changed.  Route-tab view.
757   */
758 void CarMainWindow::gpsStatus()
759 {
760     if (ui->gpsOnCheckBox->isChecked())
761     {
762         if (location->getSatellitesInUse() >= 4)
763         {
764             //Set status
765             ui->labelRouteTabGPSStatus->setText("GPS ready");
766
767             //Set time
768             gpsTime->setTime_t(location->getTime());
769             ui->labelRouteTabGPSTime->setText(gpsTime->toString());
770
771             //Set latitude & longitude
772             ui->labelRouteTabLatitude->setText("Lat: " + QString::number(location->getLatitude()));
773             ui->labelRouteTabLongitude->setText("Lon: " + QString::number(location->getLongitude()));
774         }
775
776         else
777         {
778             ui->labelRouteTabGPSStatus->setText("Waiting for GPS");
779         }
780     }
781 }