Added initial harmattan packaging.
[gpsdata] / src / mainwindow.cpp
1 /*
2  *  GPSData for Maemo.
3  *  Copyright (C) 2011 Roman Moravcik
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #include <QtGui>
21 #include <QString>
22 #include <QChar>
23 #include <qnumeric.h>
24
25 #ifdef Q_OS_SYMBIAN
26 # include <eikenv.h>
27 # include <eikappui.h>
28 # include <aknenv.h>
29 # include <aknappui.h>
30 #endif
31
32 #ifdef Q_WS_MAEMO_5
33 # include <QtDBus>
34 #endif
35
36 #include "mainwindow.h"
37 #include "gpscompasswindow.h"
38 #include "satelliteviewwindow.h"
39
40 #ifdef Q_OS_SYMBIAN
41 # include "satellitesignalstrengthwindow.h"
42 #endif
43
44 MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
45 {
46     m_satellitesInView = 0;
47     m_satellitesInUse = 0;
48 #ifdef Q_WS_MAEMO_5
49     m_screenLocked = false;
50 #endif
51
52     m_position = QGeoPositionInfoSource::createDefaultSource(0);
53     if (m_position) {
54         connect(m_position, SIGNAL(positionUpdated(const QGeoPositionInfo &)), this,
55                 SLOT(onPositionUpdated(const QGeoPositionInfo &)));
56
57         m_position->setUpdateInterval(3);
58         m_position->startUpdates();
59     }
60
61     m_satellite = QGeoSatelliteInfoSource::createDefaultSource(0);
62     if (m_satellite) {
63         connect(m_satellite, SIGNAL(satellitesInViewUpdated(const QList<QGeoSatelliteInfo> &)), this,
64                 SLOT(onSatellitesInViewUpdated(const QList<QGeoSatelliteInfo> &)));
65         connect(m_satellite, SIGNAL(satellitesInUseUpdated(const QList<QGeoSatelliteInfo> &)), this,
66                 SLOT(onSatellitesInUseUpdated(const QList<QGeoSatelliteInfo> &)));
67
68         m_satellite->startUpdates();
69     }
70
71     createUi();
72     createMenu();
73     updateUi();
74
75 #ifdef Q_WS_MAEMO_5
76     registerScreenLockMonitor();
77 #endif
78 }
79
80 MainWindow::~MainWindow()
81 {
82     if (m_satellite) {
83         m_satellite->stopUpdates();
84         delete m_satellite;
85     }
86
87     if (m_position) {
88         m_position->stopUpdates();
89         delete m_position;
90     }
91 }
92 void MainWindow::createUi()
93 {
94     QWidget *widget = new QWidget;
95     setCentralWidget(widget);
96
97 #ifdef Q_OS_SYMBIAN
98     const CAknAppUiBase::TAppUiOrientation uiOrientation = CAknAppUi::EAppUiOrientationPortrait;
99     CAknAppUi* appUi = dynamic_cast<CAknAppUi*> (CEikonEnv::Static()->AppUi());
100     TRAPD(error,
101           if (appUi)
102           appUi->SetOrientationL(uiOrientation);
103             );
104     Q_UNUSED(error)
105 #elif defined(Q_WS_MAEMO_5)
106     setAttribute(Qt::WA_Maemo5PortraitOrientation, true);
107     setAttribute(Qt::WA_Maemo5StackedWindow);
108 #endif
109
110     setWindowTitle(tr("GPSData"));
111
112     QVBoxLayout *mainLayout = new QVBoxLayout();
113     widget->setLayout(mainLayout);
114
115     QFormLayout *layout = new QFormLayout();
116     layout->setMargin(8);
117     layout->setSpacing(8);
118     layout->setLabelAlignment(Qt::AlignLeft);
119     mainLayout->addLayout(layout);
120
121     m_latitude = new QLabel();
122     m_latitude->setDisabled(true);
123     layout->addRow(tr("Latitude:"), m_latitude);
124
125     m_longitude = new QLabel();
126     m_longitude->setDisabled(true);
127     layout->addRow(tr("Longtitude:"), m_longitude);
128
129     m_accuracy = new QLabel();
130     m_accuracy->setDisabled(true);
131     layout->addRow(tr("Accuracy:"), m_accuracy);
132
133     m_altitude = new QLabel();
134     m_altitude->setDisabled(true);
135     layout->addRow(tr("Altitude:"), m_altitude);
136
137     m_altitudeAccuracy = new QLabel();
138     m_altitudeAccuracy->setDisabled(true);
139     layout->addRow(tr("Altitude accura.:"), m_altitudeAccuracy);
140
141     m_direction = new QLabel();
142     m_direction->setDisabled(true);
143     layout->addRow(tr("Direction:"), m_direction);
144
145     m_magneticDeclination = new QLabel();
146     m_magneticDeclination->setDisabled(true);
147     layout->addRow(tr("Magnetic declin.:"), m_magneticDeclination);
148
149     m_groundSpeed = new QLabel();
150     m_groundSpeed->setDisabled(true);
151     layout->addRow(tr("Ground speed:"), m_groundSpeed);
152
153     m_verticalSpeed = new QLabel();
154     m_verticalSpeed->setDisabled(true);
155     layout->addRow(tr("Vertical speed:"), m_verticalSpeed);
156
157     m_mode = new QLabel();
158     m_mode->setDisabled(true);
159     layout->addRow(tr("Mode:"), m_mode);
160
161     m_time = new QLabel();
162     m_time->setDisabled(true);
163     layout->addRow(tr("GPS Timestamp:"), m_time);
164
165     m_satUsedView = new QLabel();
166     m_satUsedView->setDisabled(true);
167     layout->addRow(tr("Used/View sat.:"), m_satUsedView);
168
169 #ifdef Q_WS_MAEMO_5
170     m_satelliteSignalStrength = new SatelliteSignalStrength();
171     m_satelliteSignalStrength->showTitle(true);
172     mainLayout->addWidget(m_satelliteSignalStrength);
173 #endif
174 }
175
176 void MainWindow::createMenu()
177 {
178
179 #if defined(Q_OS_SYMBIAN)
180     QAction *menuSoftkey = new QAction(tr("Menu"), this);
181     menuSoftkey->setSoftKeyRole(QAction::PositiveSoftKey);
182     addAction(menuSoftkey);
183
184     QMenu *menu = new QMenu();
185     menuSoftkey->setMenu(menu);
186 #else
187     QMenuBar *menu = new QMenuBar();
188     setMenuBar(menu);
189 #endif
190
191 #ifdef Q_OS_SYMBIAN
192     QAction *satelliteSignalStrengthAction = new QAction(tr("Signal strength"), this);
193     menu->addAction(satelliteSignalStrengthAction);
194     connect(satelliteSignalStrengthAction, SIGNAL(triggered()), this, SLOT(onSatelliteSignalStrengthMenuClicked()));
195 #endif
196
197     QAction *satelliteViewAction = new QAction(tr("Satellite view"), this);
198     menu->addAction(satelliteViewAction);
199     connect(satelliteViewAction, SIGNAL(triggered()), this, SLOT(onSatelliteViewMenuClicked()));
200
201     QAction *gpsCompassAction = new QAction(tr("GPS compass"), this);
202     menu->addAction(gpsCompassAction);
203     connect(gpsCompassAction, SIGNAL(triggered()), this, SLOT(onGpsCompassMenuClicked()));
204 }
205
206
207 void MainWindow::updateUi()
208 {
209     /* Don't update if window is not visible */
210     if (!isVisible())
211         return;
212
213     if (m_positionInfo.isValid()){
214         m_latitude->setText(convertCoordinate(m_positionInfo.coordinate().latitude(), LatitudeCoordinate));
215         m_longitude->setText(convertCoordinate(m_positionInfo.coordinate().longitude(), LongitudeCoordinate));
216
217         if ((!qIsNaN(m_positionInfo.coordinate().altitude())) &&
218             (m_positionInfo.coordinate().type() != QGeoCoordinate::InvalidCoordinate)) {
219             m_altitude->setText(formatLength(m_positionInfo.coordinate().altitude()));
220
221             if (m_positionInfo.hasAttribute(QGeoPositionInfo::VerticalAccuracy))
222                 m_altitudeAccuracy->setText(formatLength(m_positionInfo.attribute(QGeoPositionInfo::VerticalAccuracy)));
223             else
224                 m_altitudeAccuracy->clear();
225         } else {
226             m_altitude->clear();
227             m_altitudeAccuracy->clear();
228         }
229
230         if (m_positionInfo.coordinate().type() == QGeoCoordinate::Coordinate2D)
231             m_mode->setText("2D");
232         else if (m_positionInfo.coordinate().type() == QGeoCoordinate::Coordinate3D)
233             m_mode->setText("3D");
234         else
235             m_mode->clear();
236
237         m_time->setText(m_positionInfo.timestamp().toString("dd.MM.yyyy hh:mm:ss"));
238
239         if (m_positionInfo.hasAttribute(QGeoPositionInfo::HorizontalAccuracy))
240             m_accuracy->setText(formatLength(m_positionInfo.attribute(QGeoPositionInfo::HorizontalAccuracy)));
241         else
242             m_accuracy->clear();
243
244         if (m_positionInfo.hasAttribute(QGeoPositionInfo::GroundSpeed))
245             m_groundSpeed->setText(convertSpeed(m_positionInfo.attribute(QGeoPositionInfo::GroundSpeed)));
246         else
247             m_groundSpeed->clear();
248
249         if (m_positionInfo.hasAttribute(QGeoPositionInfo::VerticalSpeed))
250             m_verticalSpeed->setText(convertSpeed(m_positionInfo.attribute(QGeoPositionInfo::VerticalSpeed)));
251         else
252             m_verticalSpeed->clear();
253
254         if (m_positionInfo.hasAttribute(QGeoPositionInfo::Direction))
255             m_direction->setText(formatDirection(m_positionInfo.attribute(QGeoPositionInfo::Direction)));
256         else
257             m_direction->clear();
258
259         if (m_positionInfo.hasAttribute(QGeoPositionInfo::MagneticVariation))
260             m_magneticDeclination->setText(formatDirection(m_positionInfo.attribute(QGeoPositionInfo::MagneticVariation)));
261         else
262             m_magneticDeclination->clear();
263
264         m_satUsedView->setText(QString::number(m_satellitesInUse) + " / " + QString::number(m_satellitesInView));
265     } else {
266         m_latitude->setText(tr("Waiting for GPS data"));
267         m_longitude->clear();
268         m_accuracy->clear();
269         m_altitude->clear();
270         m_altitudeAccuracy->clear();
271         m_direction->clear();
272         m_groundSpeed->clear();
273         m_verticalSpeed->clear();
274         m_mode->clear();
275         m_time->clear();
276         m_satUsedView->clear();
277     }
278 }
279
280 QString MainWindow::convertCoordinate(double coordinate, CoordinateType type) const
281 {
282     QString s;
283     QChar degree(0x00B0);
284
285     double coordinateAbs = qAbs(coordinate);
286     double coordinateMin = (coordinateAbs - int(coordinateAbs)) * 60;
287     double coordinateSec = (coordinateMin - int(coordinateMin)) * 60;
288
289     s = QString("%1%2 %3' %4\"")
290         .arg(QString::number(int(coordinateAbs)))
291         .arg(degree)
292         .arg(QString::number(int(coordinateMin)))
293         .arg(QString::number(coordinateSec, 'f', 3));
294
295     if (type == LatitudeCoordinate) {
296         if (coordinate > 0)
297             s.append(" N");
298         else
299             s.append(" S");
300     } else {
301         if (coordinate > 0)
302             s.append(" E");
303         else
304             s.append(" W");
305     }
306
307     return s;
308 }
309
310 QString MainWindow::convertSpeed(double speed) const
311 {
312     QString s;
313
314     s.sprintf("%.2f km/h", speed * 3.6);
315
316     return s;
317 }
318
319 QString MainWindow::formatLength(double length) const
320 {
321     QString s;
322
323     if (length > 10000)
324         s.sprintf("%.2f km", length / 10000);
325     else
326         s.sprintf("%.2f m", length);
327
328     return s;
329 }
330
331 QString MainWindow::formatDirection(double length) const
332 {
333     QString s;
334     QChar degree(0x00B0);
335
336     s = QString("%1%2").arg(QString::number(length, 'f', 2)).arg(degree);
337
338     return s;
339 }
340
341 void MainWindow::onPositionUpdated(const QGeoPositionInfo &position)
342 {
343 #ifdef Q_WS_MAEMO_5
344     if (m_screenLocked)
345         return;
346 #endif
347
348     if (position.isValid()) {
349         m_positionInfo = position;
350         updateUi();
351     }
352 }
353
354 void MainWindow::onSatellitesInViewUpdated(const QList<QGeoSatelliteInfo> &satellites)
355 {
356 #ifdef Q_WS_MAEMO_5
357     if (m_screenLocked)
358         return;
359
360     m_satelliteSignalStrength->updateWidget(satellites, false);
361 #endif
362     m_satellitesInView = satellites.count();
363     updateUi();
364 }
365
366 void MainWindow::onSatellitesInUseUpdated(const QList<QGeoSatelliteInfo> &satellites)
367 {
368 #ifdef Q_WS_MAEMO_5
369     if (m_screenLocked)
370         return;
371
372     m_satelliteSignalStrength->updateWidget(satellites, true);
373 #endif
374     m_satellitesInUse = satellites.count();
375     updateUi();
376 }
377
378 #ifdef Q_OS_SYMBIAN
379 void MainWindow::onSatelliteSignalStrengthMenuClicked()
380 {
381     SatelliteSignalStrengthWindow *satelliteSignalStrengthWindow = new SatelliteSignalStrengthWindow(this);
382     satelliteSignalStrengthWindow->setSatelliteInfoSource(m_satellite);
383     satelliteSignalStrengthWindow->showMaximized();
384 }
385 #endif
386
387 void MainWindow::onSatelliteViewMenuClicked()
388 {
389     SatelliteViewWindow *satelliteViewWindow = new SatelliteViewWindow(this);
390     satelliteViewWindow->setSatelliteInfoSource(m_satellite);
391 #if defined(Q_OS_SYMBIAN)
392     satelliteViewWindow->showMaximized();
393 #elif defined(Q_WS_MAEMO_5)
394     satelliteViewWindow->show();
395 #endif
396 }
397
398 void MainWindow::onGpsCompassMenuClicked()
399 {
400     GpsCompassWindow *gpsCompassWindow = new GpsCompassWindow(this);
401     gpsCompassWindow->setPositionInfoSource(m_position);
402 #if defined(Q_OS_SYMBIAN) || defined(Q_WS_MAEMO_5)
403     gpsCompassWindow->showMaximized();
404 #else
405     gpsCompassWindow->show();
406 #endif
407 }
408
409 #ifdef Q_WS_MAEMO_5
410 void MainWindow::registerScreenLockMonitor()
411 {
412     QDBusConnection::systemBus().connect("",
413                                          "/com/nokia/mce/signal",
414                                          "com.nokia.mce.signal",
415                                          "tklock_mode_ind",
416                                          this,
417                                          SLOT(onScreenLocked(QString)));
418 }
419
420 void MainWindow::onScreenLocked(QString state)
421 {
422     bool locked;
423
424     if(state == "unlocked")
425         locked = false;
426     else
427         locked = true;
428
429     if (m_screenLocked != locked) {
430         m_screenLocked = locked;
431         emit screenLocked(m_screenLocked);
432     }
433 }
434 #endif