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