b292819cac9e86299d271f413f2b391c20670686
[situare] / src / engine / engine.cpp
1  /*
2     Situare - A location system for Facebook
3     Copyright (C) 2010  Ixonos Plc. Authors:
4
5         Kaj Wallin - kaj.wallin@ixonos.com
6         Henri Lampela - henri.lampela@ixonos.com
7         Jussi Laitinen - jussi.laitinen@ixonos.com
8         Sami Rämö - sami.ramo@ixonos.com
9
10     Situare is free software; you can redistribute it and/or
11     modify it under the terms of the GNU General Public License
12     version 2 as published by the Free Software Foundation.
13
14     Situare is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU General Public License for more details.
18
19     You should have received a copy of the GNU General Public License
20     along with Situare; if not, write to the Free Software
21     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
22     USA.
23  */
24
25 #include <cmath>
26
27 #include <QMessageBox>
28 #include <QNetworkReply>
29
30 #include "application.h"
31 #include "common.h"
32 #include "contactmanager.h"
33 #include "../error.h"
34 #include "facebookservice/facebookauthentication.h"
35 #include "gps/gpsposition.h"
36 #include "map/mapengine.h"
37 #include "routing/geocodingservice.h"
38 #include "routing/routingservice.h"
39 #include "mce.h"
40 #include "network/networkaccessmanager.h"
41 #include "situareservice/situareservice.h"
42 #include "ui/mainwindow.h"
43 #include "qmlui/geomap.h"
44 #include "qmlui/rotation.h"
45 #include "qmlui/loginlogic.h"
46 #include <qdeclarative.h>
47 #include <QDeclarativeView>
48 #include <QDeclarativeContext>
49 #include <QApplication>
50 #include <QDesktopWidget>
51 #include <QDeclarativeEngine>
52 #include "engine.h"
53 #include "routing/routemodel.h"
54 #include "user/friendmodel.h"
55 #include "user/profile.h"
56 #include "qmlui/userimageprovider.h"
57 #include "updatelocation.h"
58
59 #ifdef Q_WS_MAEMO_5
60 #include <QX11Info>
61 #include <X11/Xatom.h>
62 #include <X11/Xlib.h>
63 #endif
64
65 const QString SETTINGS_GPS_ENABLED = "GPS_ENABLED"; ///< GPS setting
66 const QString SETTINGS_AUTO_CENTERING_ENABLED = "AUTO_CENTERING_ENABLED";///< Auto centering setting
67 const int DEFAULT_ZOOM_LEVEL_WHEN_GPS_IS_AVAILABLE = 12;  ///< Default zoom level when GPS available
68 const qreal USER_MOVEMENT_MINIMUM_LONGITUDE_DIFFERENCE = 0.003;///< Min value for user move latitude
69 const qreal USER_MOVEMENT_MINIMUM_LATITUDE_DIFFERENCE = 0.001;///< Min value for user move longitude
70 const int MIN_UPDATE_INTERVAL_MSECS = 5*60*1000;
71
72 class SituareEnginePrivate
73 {
74     Q_DECLARE_PUBLIC(SituareEngine)
75     SituareEngine* q_ptr;
76
77 public:
78     FilteredFriendModel friendProxyModel;
79     FriendModel friendModel;
80     RouteModel routeModel;
81     Profile profile;
82     UpdateLocation updateLocation;
83
84     QDeclarativeView* ui;
85
86     int progressIndicatorCount;
87
88     SituareEnginePrivate(SituareEngine* parent)
89         : q_ptr(parent), routeModel(0), ui(0), progressIndicatorCount(0)
90     {}
91
92     void toggleProgressIndicator(bool value)
93     {
94 #ifdef QML_UI
95         qDebug() << __PRETTY_FUNCTION__;
96
97     #ifdef Q_WS_MAEMO_5
98         if(value) {
99             progressIndicatorCount++;
100             ui->setAttribute(Qt::WA_Maemo5ShowProgressIndicator, true);
101         } else {
102             if(progressIndicatorCount > 0)
103                 progressIndicatorCount--;
104
105             if(progressIndicatorCount == 0)
106                 ui->setAttribute(Qt::WA_Maemo5ShowProgressIndicator, false);
107         }
108     #else
109         Q_UNUSED(value);
110     #endif // Q_WS_MAEMO_5
111 #else
112         Q_Q(SituareEngine);
113         q->m_ui->toggleProgressIndicator(value);
114 #endif
115     }
116
117     void grabZoomKeys(bool grab)
118     {
119 #ifdef QML_UI
120 #ifdef Q_WS_MAEMO_5
121         // Can't grab keys unless we have a window id
122         if (!ui->winId())
123             return;
124
125         unsigned long val = (grab) ? 1 : 0;
126         Atom atom = XInternAtom(QX11Info::display(), "_HILDON_ZOOM_KEY_ATOM", False);
127         if (!atom)
128             return;
129
130         XChangeProperty (QX11Info::display(),
131                          ui->winId(),
132                          atom,
133                          XA_INTEGER,
134                          32,
135                          PropModeReplace,
136                          reinterpret_cast<unsigned char *>(&val),
137                          1);
138 #endif
139 #endif
140         Q_UNUSED(grab);
141     }
142 };
143
144 SituareEngine::SituareEngine()
145     : d_ptr(new SituareEnginePrivate(this)),
146       m_autoCenteringEnabled(false),
147       m_automaticUpdateFirstStart(true),
148       m_automaticUpdateRequest(false),
149       m_userMoved(false),
150       m_automaticUpdateIntervalTimer(0),
151       m_lastUpdatedGPSPosition(GeoCoordinate())
152 {
153     qDebug() << __PRETTY_FUNCTION__;
154
155     m_ui = new MainWindow;
156     m_ui->updateItemVisibility(false);
157
158     Application *application = static_cast<Application *>(qApp);
159     application->registerWindow(m_ui->winId());
160
161     connect(application, SIGNAL(topmostWindowChanged(bool)),
162             this, SLOT(topmostWindowChanged(bool)));
163
164     m_networkAccessManager = new NetworkAccessManager(this);
165
166     // build MapEngine
167     m_mapEngine = new MapEngine(this);
168     m_ui->setMapViewScene(m_mapEngine->scene());
169
170     // build GPS
171     m_gps = new GPSPosition(this);
172
173     // build SituareService
174     m_situareService = new SituareService(this);
175
176     // build FacebookAuthenticator
177     m_facebookAuthenticator = new FacebookAuthentication(m_ui, this);
178
179     // build routing service
180     m_routingService = new RoutingService(this); // create this when needed, not in constructor!
181
182     // build geocoding service
183     m_geocodingService = new GeocodingService(this);
184
185     // connect signals
186     signalsFromMapEngine();
187     signalsFromGeocodingService();
188     signalsFromGPS();
189     signalsFromRoutingService();
190     signalsFromSituareService();
191     signalsFromMainWindow();
192     signalsFromFacebookAuthenticator();
193
194     connect(this, SIGNAL(userLocationReady(User*)),
195             m_ui, SIGNAL(userLocationReady(User*)));
196
197     connect(this, SIGNAL(friendsLocationsReady(QList<User*>&)),
198             m_ui, SIGNAL(friendsLocationsReady(QList<User*>&)));
199
200     connect(this, SIGNAL(userLocationReady(User*)),
201             m_mapEngine, SLOT(receiveOwnLocation(User*)));
202
203     connect(this, SIGNAL(friendsLocationsReady(QList<User*>&)),
204             m_mapEngine, SIGNAL(friendsLocationsReady(QList<User*>&)));
205
206     connect(this, SIGNAL(friendImageReady(User*)),
207             m_ui, SIGNAL(friendImageReady(User*)));
208
209     connect(this, SIGNAL(friendImageReady(User*)),
210             m_mapEngine, SIGNAL(friendImageReady(User*)));
211
212     m_automaticUpdateIntervalTimer = new QTimer(this);
213     connect(m_automaticUpdateIntervalTimer, SIGNAL(timeout()),
214             this, SLOT(startAutomaticUpdate()));
215
216     // signals connected, now it's time to show the main window
217     // but init the MapEngine before so starting location is set
218     m_mapEngine->init();
219
220 #ifdef QML_UI
221     qmlRegisterType<GeoMap>("MapPlugin", 1, 0, "GeoMap");
222
223     Q_D(SituareEngine);
224
225     d->ui = new QDeclarativeView(QApplication::desktop());
226     d->grabZoomKeys(true);
227 #ifdef Q_WS_MAEMO_5
228 //    d->ui->setAttribute(Qt::WA_Maemo5AutoOrientation, true);
229 #endif
230
231     d->friendProxyModel.setSourceModel(&d->friendModel);
232
233     Rotation *rotation = new Rotation();
234     d->ui->rootContext()->setContextProperty("deviceRotation", static_cast<QObject *>(rotation));
235     d->ui->rootContext()->setContextProperty("facebookAuthenticator", m_facebookAuthenticator);
236     d->ui->rootContext()->setContextProperty("routingModel", &d->routeModel);
237     d->ui->rootContext()->setContextProperty("friendModel", &d->friendProxyModel);
238     d->ui->rootContext()->setContextProperty("userProfile", &d->profile);
239     d->ui->rootContext()->setContextProperty("locationUpdate", &d->updateLocation);
240     d->ui->rootContext()->setContextProperty("engine", this);
241
242     d->ui->setSource(QUrl("qrc:/Main.qml"));
243     d->ui->setResizeMode(QDeclarativeView::SizeRootObjectToView);
244     d->ui->engine()->addImageProvider(QLatin1String("user"), new UserImageProvider(&d->friendModel, &d->profile));
245     d->ui->show();
246
247     GeoMap* geoMap = qobject_cast<GeoMap*>(d->ui->rootObject()->findChild<QObject*>("geoMap"));
248     Q_ASSERT(geoMap);
249     geoMap->setFriendModels(&d->friendModel, &d->friendProxyModel);
250     geoMap->setRouteModel(&d->routeModel);
251
252     connect(d->ui->engine()->networkAccessManager(),
253             SIGNAL(sslErrors(QNetworkReply*, QList<QSslError>)),
254             m_facebookAuthenticator, SLOT(sslErrors(QNetworkReply*, QList<QSslError>)));
255     d->ui->engine()->networkAccessManager()->setCookieJar(new NetworkCookieJar());
256
257 #else
258     m_ui->show();
259 #endif
260
261     m_gps->setMode(GPSPosition::Default);
262     initializeGpsAndAutocentering();
263
264     m_mce = new MCE(this);
265     connect(m_mce, SIGNAL(displayOff(bool)), this, SLOT(setPowerSaving(bool)));
266
267     m_contactManager = new ContactManager(this);
268     m_contactManager->requestContactGuids();
269
270     m_facebookAuthenticator->login();
271
272     connect(&d->updateLocation, SIGNAL(locationUpdate(QString,bool)),
273             this, SLOT(requestUpdateLocation(QString,bool)));
274 }
275
276 SituareEngine::~SituareEngine()
277 {
278     qDebug() << __PRETTY_FUNCTION__;
279
280     Q_D(SituareEngine);
281     d->grabZoomKeys(false);
282
283     delete m_ui;
284
285     QSettings settings(SETTINGS_ORGANIZATION_NAME, SETTINGS_APPLICATION_NAME);
286     settings.setValue(SETTINGS_GPS_ENABLED, m_gps->isRunning());
287     settings.setValue(SETTINGS_AUTO_CENTERING_ENABLED, m_autoCenteringEnabled);
288 }
289
290 void SituareEngine::changeAutoCenteringSetting(bool enabled)
291 {
292     qDebug() << __PRETTY_FUNCTION__ << enabled;
293
294     m_autoCenteringEnabled = enabled;
295     setAutoCentering(enabled);
296 }
297
298 void SituareEngine::disableAutoCentering()
299 {
300     qDebug() << __PRETTY_FUNCTION__;
301
302     changeAutoCenteringSetting(false);
303 }
304
305 void SituareEngine::draggingModeTriggered()
306 {
307     qDebug() << __PRETTY_FUNCTION__;
308
309     if (m_mce)
310         m_mce->vibrationFeedback();
311 }
312
313 void SituareEngine::enableAutomaticLocationUpdate(bool enabled, int updateIntervalMsecs)
314 {
315     qDebug() << __PRETTY_FUNCTION__;
316
317     //Show automatic update confirmation dialog
318     if (m_automaticUpdateFirstStart && m_gps->isRunning() && enabled) {
319         m_ui->showEnableAutomaticUpdateLocationDialog(
320                 tr("Do you want to enable automatic location update with %1 min update interval?")
321                 .arg(updateIntervalMsecs/1000/60));
322         m_automaticUpdateFirstStart = false;
323     } else {
324         if (enabled && m_gps->isRunning()) {
325             m_ui->buildInformationBox(tr("Automatic location update enabled"));
326             if (updateIntervalMsecs < MIN_UPDATE_INTERVAL_MSECS)
327                 m_automaticUpdateIntervalTimer->setInterval(MIN_UPDATE_INTERVAL_MSECS);
328             else
329                 m_automaticUpdateIntervalTimer->setInterval(updateIntervalMsecs);
330
331             connect(m_gps, SIGNAL(position(GeoCoordinate, qreal)),
332                     this, SLOT(requestAutomaticUpdateIfMoved(GeoCoordinate)));
333
334             m_automaticUpdateIntervalTimer->start();
335
336         } else {
337             disconnect(m_gps, SIGNAL(position(GeoCoordinate, qreal)),
338                     this, SLOT(requestAutomaticUpdateIfMoved(GeoCoordinate)));
339
340             m_automaticUpdateIntervalTimer->stop();
341         }
342     }
343 }
344
345 void SituareEngine::error(const int context, const int error)
346 {
347     Q_D(SituareEngine);
348     qDebug() << __PRETTY_FUNCTION__;
349     switch(error)
350     {
351     case SituareError::ERROR_GENERAL:
352         if(context == ErrorContext::SITUARE) {
353             d->toggleProgressIndicator(false);
354             m_ui->buildInformationBox(tr("Unknown server error"), true);
355         }
356         break;
357     case 1: //errors: SituareError::ERROR_MISSING_ARGUMENT and QNetworkReply::ConnectionRefusedError
358         d->toggleProgressIndicator(false);
359         if(context == ErrorContext::SITUARE) {
360             m_ui->buildInformationBox(tr("Missing parameter from request"), true);
361         } else if(context == ErrorContext::NETWORK) {
362             m_ui->buildInformationBox(tr("Connection refused by the server"), true);
363         }
364         break;
365     case QNetworkReply::RemoteHostClosedError:
366         if(context == ErrorContext::NETWORK) {
367             d->toggleProgressIndicator(false);
368             m_ui->buildInformationBox(tr("Connection closed by the server"), true);
369         }
370         break;
371     case QNetworkReply::HostNotFoundError:
372         if(context == ErrorContext::NETWORK) {
373             d->toggleProgressIndicator(false);
374             m_ui->buildInformationBox(tr("Remote server not found"), true);
375         }
376         break;
377     case QNetworkReply::TimeoutError:
378         if(context == ErrorContext::NETWORK) {
379             d->toggleProgressIndicator(false);
380             m_ui->buildInformationBox(tr("Connection timed out"), true);
381         }
382         break;
383     case QNetworkReply::UnknownNetworkError:
384         if(context == ErrorContext::NETWORK) {
385             d->toggleProgressIndicator(false);
386             m_ui->buildInformationBox(tr("No network connection"), true);
387         }
388         break;
389     case SituareError::SESSION_EXPIRED:
390         m_ui->buildInformationBox(tr("Session expired. Please login again"), true);
391         m_facebookAuthenticator->logOut();
392         m_facebookAuthenticator->login();
393         break;
394     case SituareError::UPDATE_FAILED:
395         d->toggleProgressIndicator(false);
396         m_ui->buildInformationBox(tr("Update failed, please try again"), true);
397         break;
398     case SituareError::DATA_RETRIEVAL_FAILED:
399         d->toggleProgressIndicator(false);
400         m_ui->buildInformationBox(tr("Data retrieval failed, please try again"), true);
401         break;
402     case SituareError::ADDRESS_RETRIEVAL_FAILED:
403         d->toggleProgressIndicator(false);
404         m_ui->buildInformationBox(tr("Address retrieval failed"), true);
405         break;
406     case SituareError::IMAGE_DOWNLOAD_FAILED:
407         m_ui->buildInformationBox(tr("Image download failed"), true);
408         break;
409     case SituareError::MAP_IMAGE_DOWNLOAD_FAILED:
410         m_ui->buildInformationBox(tr("Map image download failed"), true);
411         break;
412     case SituareError::GPS_INITIALIZATION_FAILED:
413         setGPS(false);
414         m_ui->buildInformationBox(tr("GPS initialization failed"), true);
415         break;
416     case SituareError::INVALID_JSON:
417         m_ui->buildInformationBox(tr("Malformatted reply from server"), true);
418         m_ui->loggedIn(false);
419         m_facebookAuthenticator->clearAccountInformation(false); // clean all
420         break;
421     case SituareError::ERROR_ROUTING_FAILED:
422         d->toggleProgressIndicator(false);
423         m_ui->buildInformationBox(tr("Routing failed"), true);
424         break;
425     case SituareError::ERROR_LOCATION_SEARCH_FAILED:
426         m_ui->buildInformationBox(tr("No results found"), true);
427         break;
428     default:
429         d->toggleProgressIndicator(false);
430         if(context == ErrorContext::NETWORK)
431             qCritical() << __PRETTY_FUNCTION__ << "QNetworkReply::NetworkError: " << error;
432         else
433             qCritical() << __PRETTY_FUNCTION__ << "Unknown error: " << error;
434         break;
435     }
436 }
437
438 void SituareEngine::imageReady(User *user)
439 {
440     qDebug() << __PRETTY_FUNCTION__;
441     Q_D(SituareEngine);
442     if(user->type()) {
443         emit userLocationReady(user);
444         d->profile.setProfile(*user);
445     } else {
446         emit friendImageReady(user);
447         d->friendModel.resetFriends();
448     }
449 }
450
451 void SituareEngine::initializeGpsAndAutocentering()
452 {
453     qDebug() << __PRETTY_FUNCTION__;
454
455     QSettings settings(SETTINGS_ORGANIZATION_NAME, SETTINGS_APPLICATION_NAME);
456     QVariant gpsEnabled = settings.value(SETTINGS_GPS_ENABLED);
457     QVariant autoCenteringEnabled = settings.value(SETTINGS_AUTO_CENTERING_ENABLED);
458
459     if (m_gps->isInitialized()) {
460
461         if (gpsEnabled.toString().isEmpty()) { // First start. Situare.conf file does not exists
462
463             connect(m_gps, SIGNAL(position(GeoCoordinate, qreal)),
464                     this, SLOT(setFirstStartZoomLevel()));
465
466             changeAutoCenteringSetting(true);
467             setGPS(true);
468
469             m_ui->buildInformationBox(tr("GPS enabled"));
470
471         } else { // Normal start
472             changeAutoCenteringSetting(autoCenteringEnabled.toBool());
473             setGPS(gpsEnabled.toBool());
474
475             if (gpsEnabled.toBool())
476                 m_ui->buildInformationBox(tr("GPS enabled"));
477         }
478     } else {
479         setGPS(false);
480     }
481 }
482
483 void SituareEngine::locationSearch(QString location)
484 {
485     qDebug() << __PRETTY_FUNCTION__;
486
487     if(!location.isEmpty())
488         m_geocodingService->requestLocation(location);
489 }
490
491 void SituareEngine::loginActionPressed()
492 {
493     qDebug() << __PRETTY_FUNCTION__;
494
495     if (m_facebookAuthenticator->isLoggedIn())
496         m_facebookAuthenticator->logOut(true);
497     else if (m_networkAccessManager->isConnected())
498         m_facebookAuthenticator->login();
499     else
500         error(ErrorContext::NETWORK, QNetworkReply::UnknownNetworkError);
501 }
502
503 void SituareEngine::onLogin()
504 {
505     qDebug() << __PRETTY_FUNCTION__;
506
507     m_ui->loggedIn(true);
508
509     m_situareService->fetchLocations();
510
511     if (m_gps->isRunning())
512         m_ui->readAutomaticLocationUpdateSettings();
513 }
514
515 void SituareEngine::onLogout()
516 {
517     qDebug() << __PRETTY_FUNCTION__;
518
519     m_ui->loggedIn(false);
520     m_situareService->updateSession(""); // empty session string means logged out
521     m_automaticUpdateFirstStart = true;
522 }
523
524 void SituareEngine::refreshUserData()
525 {
526     Q_D(SituareEngine);
527
528     qDebug() << __PRETTY_FUNCTION__;
529
530     if (m_networkAccessManager->isConnected()) {
531         d->toggleProgressIndicator(true);
532         m_situareService->fetchLocations();
533     }
534     else {
535         error(ErrorContext::NETWORK, QNetworkReply::UnknownNetworkError);
536     }
537 }
538
539 void SituareEngine::requestAddress()
540 {
541     qDebug() << __PRETTY_FUNCTION__;
542
543     if (m_networkAccessManager->isConnected()) {
544         if (m_gps->isRunning())
545             m_situareService->reverseGeo(m_gps->lastPosition());
546         else
547             m_situareService->reverseGeo(m_mapEngine->centerGeoCoordinate());
548     }
549     else {
550         error(ErrorContext::NETWORK, QNetworkReply::UnknownNetworkError);
551     }
552 }
553
554 void SituareEngine::requestUpdateLocation(const QString &status, bool publish)
555 {
556     qDebug() << __PRETTY_FUNCTION__;
557     Q_D(SituareEngine);
558
559     if (m_networkAccessManager->isConnected()) {
560         d->toggleProgressIndicator(true);
561
562         if (m_gps->isRunning())
563             m_situareService->updateLocation(m_gps->lastPosition(), status, publish);
564         else
565             m_situareService->updateLocation(m_mapEngine->centerGeoCoordinate(), status, publish);
566     }
567     else {
568         error(ErrorContext::NETWORK, QNetworkReply::UnknownNetworkError);
569     }
570 }
571
572 void SituareEngine::requestAutomaticUpdateIfMoved(GeoCoordinate position)
573 {
574     qDebug() << __PRETTY_FUNCTION__;
575
576     if ((fabs(m_lastUpdatedGPSPosition.longitude() - position.longitude()) >
577          USER_MOVEMENT_MINIMUM_LONGITUDE_DIFFERENCE) ||
578         (fabs(m_lastUpdatedGPSPosition.latitude() - position.latitude()) >
579          USER_MOVEMENT_MINIMUM_LATITUDE_DIFFERENCE)) {
580
581         m_lastUpdatedGPSPosition = position;
582         m_userMoved = true;
583     }
584
585     if (m_automaticUpdateRequest && m_userMoved) {
586         requestUpdateLocation(tr("Automatic location update"));
587         m_automaticUpdateRequest = false;
588         m_userMoved = false;
589     }
590 }
591
592 void SituareEngine::routeParsed(Route &route)
593 {
594     qDebug() << __PRETTY_FUNCTION__;
595
596     Q_D(SituareEngine);
597
598     d->routeModel.setSegments(route.segments(), route.geometryPoints());
599
600     d->toggleProgressIndicator(false);
601 }
602
603 void SituareEngine::routeTo(const GeoCoordinate &endPointCoordinates)
604 {
605     Q_D(SituareEngine);
606     qDebug() << __PRETTY_FUNCTION__;
607
608     d->toggleProgressIndicator(true);
609
610     if (m_gps->isRunning())
611         m_routingService->requestRoute(m_gps->lastPosition(), endPointCoordinates);
612     else
613         m_routingService->requestRoute(m_mapEngine->centerGeoCoordinate(), endPointCoordinates);
614 }
615
616 void SituareEngine::routeToCursor()
617 {
618     qDebug() << __PRETTY_FUNCTION__;
619
620     routeTo(m_mapEngine->centerGeoCoordinate());
621 }
622
623 void SituareEngine::setAutoCentering(bool enabled)
624 {
625     qDebug() << __PRETTY_FUNCTION__ << enabled;
626
627     m_ui->setIndicatorButtonEnabled(enabled);
628     m_mapEngine->setAutoCentering(enabled);
629     m_ui->setCrosshairVisibility(!enabled);
630
631     if (enabled) {
632         setGPS(true);
633         m_gps->requestLastPosition();
634     }
635 }
636
637 void SituareEngine::setFirstStartZoomLevel()
638 {
639     qDebug() << __PRETTY_FUNCTION__;
640
641     if (m_autoCenteringEnabled) // autocentering is disabled when map is scrolled
642         m_mapEngine->setZoomLevel(DEFAULT_ZOOM_LEVEL_WHEN_GPS_IS_AVAILABLE);
643
644     disconnect(m_gps, SIGNAL(position(GeoCoordinate, qreal)),
645                this, SLOT(setFirstStartZoomLevel()));
646 }
647
648 void SituareEngine::setGPS(bool enabled)
649 {
650     qDebug() << __PRETTY_FUNCTION__ << enabled;
651
652     if (m_gps->isInitialized()) {
653         m_ui->setGPSButtonEnabled(enabled);
654         m_mapEngine->setGPSEnabled(enabled);
655
656         if (enabled && !m_gps->isRunning()) {
657             m_gps->start();
658             m_gps->requestLastPosition();
659
660             if(m_facebookAuthenticator->isLoggedIn())
661                 m_ui->readAutomaticLocationUpdateSettings();
662         }
663         else if (!enabled && m_gps->isRunning()) {
664             m_gps->stop();
665             changeAutoCenteringSetting(false);
666             enableAutomaticLocationUpdate(false);
667         }
668     }
669     else {
670         if (enabled)
671             m_ui->buildInformationBox(tr("Unable to start GPS"));
672         m_ui->setGPSButtonEnabled(false);
673         m_mapEngine->setGPSEnabled(false);
674     }
675 }
676
677 void SituareEngine::setPowerSaving(bool enabled)
678 {
679     qDebug() << __PRETTY_FUNCTION__ << enabled;
680
681     m_gps->enablePowerSave(enabled);
682
683     if(m_autoCenteringEnabled)
684         m_mapEngine->setAutoCentering(!enabled);
685 }
686
687 void SituareEngine::showContactDialog(const QString &facebookId)
688 {
689     qDebug() << __PRETTY_FUNCTION__;
690
691     QString guid = m_contactManager->contactGuid(facebookId);
692
693     if (!guid.isEmpty())
694         m_ui->showContactDialog(guid);
695     else
696         m_ui->buildInformationBox(tr("Unable to find contact.\nAdd Facebook IM "
697                                      "account from Conversations to use this feature."), true);
698 }
699
700 void SituareEngine::signalsFromFacebookAuthenticator()
701 {
702     qDebug() << __PRETTY_FUNCTION__;
703
704     connect(m_facebookAuthenticator, SIGNAL(error(int, int)),
705             this, SLOT(error(int, int)));
706
707     connect(m_facebookAuthenticator, SIGNAL(loggedIn(QString, bool)),
708             m_situareService, SLOT(updateSession(QString)));
709
710     connect(m_facebookAuthenticator, SIGNAL(loggedIn(QString, bool)),
711             this, SLOT(onLogin()));
712
713     connect(m_facebookAuthenticator, SIGNAL(loggedOut()), this, SLOT(onLogout()));
714 }
715
716 void SituareEngine::signalsFromGeocodingService()
717 {
718     qDebug() << __PRETTY_FUNCTION__;
719
720     connect(m_geocodingService, SIGNAL(locationDataParsed(const QList<Location>&)),
721             m_ui, SIGNAL(locationDataParsed(const QList<Location>&)));
722
723     connect(m_geocodingService, SIGNAL(error(int, int)),
724             this, SLOT(error(int, int)));
725 }
726
727 void SituareEngine::signalsFromGPS()
728 {
729     qDebug() << __PRETTY_FUNCTION__;
730
731     connect(m_gps, SIGNAL(position(GeoCoordinate, qreal)),
732             m_mapEngine, SLOT(gpsPositionUpdate(GeoCoordinate, qreal)));
733
734     connect(m_gps, SIGNAL(timeout()),
735             m_ui, SLOT(gpsTimeout()));
736
737     connect(m_gps, SIGNAL(error(int, int)),
738             this, SLOT(error(int, int)));
739 }
740
741 void SituareEngine::signalsFromMainWindow()
742 {
743     qDebug() << __PRETTY_FUNCTION__;
744
745     connect(m_ui, SIGNAL(error(int, int)),
746             this, SLOT(error(int, int)));
747
748     connect(m_ui, SIGNAL(loginActionPressed()),
749             this, SLOT(loginActionPressed()));
750
751     // signals from map view
752     connect(m_ui, SIGNAL(mapViewScrolled(SceneCoordinate)),
753             m_mapEngine, SLOT(setCenterPosition(SceneCoordinate)));
754
755     connect(m_ui, SIGNAL(mapViewResized(QSize)),
756             m_mapEngine, SLOT(viewResized(QSize)));
757
758     connect(m_ui, SIGNAL(viewZoomFinished()),
759             m_mapEngine, SLOT(viewZoomFinished()));
760
761     // signals from zoom buttons (zoom panel and volume buttons)
762     connect(m_ui, SIGNAL(zoomIn()),
763             m_mapEngine, SLOT(zoomIn()));
764
765     connect(m_ui, SIGNAL(zoomOut()),
766             m_mapEngine, SLOT(zoomOut()));
767
768     // signals from menu buttons
769     connect(m_ui, SIGNAL(gpsTriggered(bool)),
770             this, SLOT(setGPS(bool)));
771
772     connect(m_ui, SIGNAL(requestReverseGeo()),
773             this, SLOT(requestAddress()));
774
775     connect(m_ui, SIGNAL(enableAutomaticLocationUpdate(bool, int)),
776             this, SLOT(enableAutomaticLocationUpdate(bool, int)));
777
778     // signals from user info tab
779     connect(m_ui, SIGNAL(refreshUserData()),
780             this, SLOT(refreshUserData()));
781
782     connect(m_ui, SIGNAL(centerToCoordinates(GeoCoordinate)),
783             m_mapEngine, SLOT(centerToCoordinates(GeoCoordinate)));
784
785     // routing signal from friend list tab & search location tab
786     connect(m_ui, SIGNAL(routeTo(const GeoCoordinate&)),
787             this, SLOT(routeTo(const GeoCoordinate&)));
788
789     // signals from location search panel
790     connect(m_ui,
791             SIGNAL(locationItemClicked(const GeoCoordinate&, const GeoCoordinate&)),
792             m_mapEngine,
793             SLOT(showMapArea(const GeoCoordinate&, const GeoCoordinate&)));
794
795     connect(m_ui, SIGNAL(searchHistoryItemClicked(QString)),
796             this, SLOT(locationSearch(QString)));
797
798     // signals from routing tab
799     connect(m_ui, SIGNAL(clearRoute()),
800             m_mapEngine, SLOT(clearRoute()));
801
802     connect(m_ui, SIGNAL(routeToCursor()),
803             this, SLOT(routeToCursor()));
804
805     // signals from distance indicator button
806     connect(m_ui, SIGNAL(autoCenteringTriggered(bool)),
807             this, SLOT(changeAutoCenteringSetting(bool)));
808
809     connect(m_ui, SIGNAL(draggingModeTriggered()),
810             this, SLOT(draggingModeTriggered()));
811
812     // signal from search location dialog
813     connect(m_ui, SIGNAL(searchForLocation(QString)),
814             this, SLOT(locationSearch(QString)));
815
816     // signal from friend list panel
817     connect(m_ui, SIGNAL(requestContactDialog(const QString &)),
818             this, SLOT(showContactDialog(const QString &)));
819 }
820
821 void SituareEngine::signalsFromMapEngine()
822 {
823     qDebug() << __PRETTY_FUNCTION__;
824
825     connect(m_mapEngine, SIGNAL(error(int, int)),
826             this, SLOT(error(int, int)));
827
828     connect(m_mapEngine, SIGNAL(locationChanged(SceneCoordinate)),
829             m_ui, SIGNAL(centerToSceneCoordinates(SceneCoordinate)));
830
831     connect(m_mapEngine, SIGNAL(zoomLevelChanged(int)),
832             m_ui, SIGNAL(zoomLevelChanged(int)));
833
834     connect(m_mapEngine, SIGNAL(mapScrolledManually()),
835             this, SLOT(disableAutoCentering()));
836
837     connect(m_mapEngine, SIGNAL(maxZoomLevelReached()),
838             m_ui, SIGNAL(maxZoomLevelReached()));
839
840     connect(m_mapEngine, SIGNAL(minZoomLevelReached()),
841             m_ui, SIGNAL(minZoomLevelReached()));
842
843     connect(m_mapEngine, SIGNAL(locationItemClicked(QList<QString>)),
844             m_ui, SIGNAL(locationItemClicked(QList<QString>)));
845
846     connect(m_mapEngine, SIGNAL(newMapResolution(qreal)),
847             m_ui, SIGNAL(newMapResolution(qreal)));
848
849     connect(m_mapEngine, SIGNAL(directionIndicatorValuesUpdate(qreal, qreal, bool)),
850             m_ui, SIGNAL(directionIndicatorValuesUpdate(qreal, qreal, bool)));
851 }
852
853 void SituareEngine::signalsFromRoutingService()
854 {
855     qDebug() << __PRETTY_FUNCTION__;
856
857     connect(m_routingService, SIGNAL(routeParsed(Route&)),
858             this, SLOT(routeParsed(Route&)));
859
860     connect(m_routingService, SIGNAL(routeParsed(Route&)),
861             m_mapEngine, SLOT(setRoute(Route&)));
862
863     connect(m_routingService, SIGNAL(routeParsed(Route&)),
864             m_ui, SIGNAL(routeParsed(Route&)));
865
866     connect(m_routingService, SIGNAL(error(int, int)),
867             this, SLOT(error(int, int)));
868 }
869
870 void SituareEngine::signalsFromSituareService()
871 {
872     qDebug() << __PRETTY_FUNCTION__;
873
874     connect(m_situareService, SIGNAL(error(int, int)),
875             this, SLOT(error(int, int)));
876
877     connect(m_situareService, SIGNAL(imageReady(User*)),
878             this, SLOT(imageReady(User*)));
879
880     connect(m_situareService, SIGNAL(reverseGeoReady(QString)),
881             m_ui, SIGNAL(reverseGeoReady(QString)));
882
883     connect(m_situareService, SIGNAL(userDataChanged(User*, QList<User*>&)),
884             this, SLOT(userDataChanged(User*, QList<User*>&)));
885
886     connect(m_situareService, SIGNAL(updateWasSuccessful()),
887             this, SLOT(updateWasSuccessful()));
888
889     Q_D(SituareEngine);
890     connect(m_situareService, SIGNAL(updateWasSuccessful()), &d->updateLocation, SLOT(clear()));
891 }
892
893 void SituareEngine::startAutomaticUpdate()
894 {
895     qDebug() << __PRETTY_FUNCTION__;
896
897     m_gps->requestUpdate();
898     m_automaticUpdateRequest = true;
899 }
900
901 void SituareEngine::topmostWindowChanged(bool isMainWindow)
902 {
903     qDebug() << __PRETTY_FUNCTION__;
904
905     setPowerSaving(!isMainWindow);
906 }
907
908 void SituareEngine::updateWasSuccessful()
909 {
910     qDebug() << __PRETTY_FUNCTION__;
911
912     if (m_networkAccessManager->isConnected())
913         m_situareService->fetchLocations();
914     else
915         error(ErrorContext::NETWORK, QNetworkReply::UnknownNetworkError);
916 }
917
918 void SituareEngine::userDataChanged(User *user, QList<User *> &friendsList)
919 {
920     qDebug() << __PRETTY_FUNCTION__;
921     Q_D(SituareEngine);
922     d->toggleProgressIndicator(false);
923
924     emit userLocationReady(user);
925     d->profile.setProfile(*user);
926
927     emit friendsLocationsReady(friendsList);
928     d->friendModel.setFriends(friendsList);
929 }
930
931 void SituareEngine::routeFromTo(double fromLatitude, double fromLongitude, double toLatitude, double toLongitude)
932 {
933     qDebug() << __PRETTY_FUNCTION__;
934
935     Q_D(SituareEngine);
936     d->toggleProgressIndicator(true);
937
938     m_routingService->requestRoute(GeoCoordinate(fromLatitude, fromLongitude), GeoCoordinate(toLatitude, toLongitude));
939 }