1 // Copyright 2010 Jochen Becher
3 // This file is part of MovieSchedule.
5 // MovieSchedule 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 3 of the License, or
8 // (at your option) any later version.
10 // MovieSchedule 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.
15 // You should have received a copy of the GNU General Public License
16 // along with MovieSchedule. If not, see <http://www.gnu.org/licenses/>.
18 #include "gpsclient.h"
20 #ifdef QT_MOBILITY_LOCATION
21 #include <QGeoPositionInfoSource>
29 #include <QNetworkAccessManager>
30 #include <QNetworkRequest>
31 #include <QNetworkReply>
32 #include <QMutexLocker>
36 static void changed(LocationGPSDevice *device, gpointer userdata)
39 ((GpsClient *) userdata)->GpsChanged();
42 static void connected(LocationGPSDevice *device, gpointer userdata)
45 ((GpsClient *) userdata)->GpsConnected();
48 static void disconnected(LocationGPSDevice *device, gpointer userdata)
51 ((GpsClient *) userdata)->GpsDisconnected();
55 GpsClient::GpsClient()
57 #ifdef QT_MOBILITY_LOCATION
58 _geo_position_info_source(QGeoPositionInfoSource::createDefaultSource(this)),
61 _location_gpsd_control(0),
62 _location_gps_device(0),
63 _time_out_timer(new QTimer(this)),
65 _network(new QNetworkAccessManager(this)),
66 _search_task_id(INVALID_SEARCH_TASK_ID)
69 QMutexLocker locker(&_next_search_task_id_mutex);
70 _search_task_id = _next_search_task_id++;
72 #ifdef QT_MOBILITY_LOCATION
73 connect(_geo_position_info_source, SIGNAL(positionUpdated(QGeoPositionInfo)), this, SLOT(GeoPositionUpdated(const QGeoPositionInfo &)));
74 connect(_geo_position_info_source, SIGNAL(updateTimeout()), this, SLOT(GeoPositionTimedOut()));
77 connect(_time_out_timer, SIGNAL(timeout()), this, SLOT(GpsTimedOut()));
79 connect(_network, SIGNAL(finished(QNetworkReply*)), this, SLOT(ReplyFinished(QNetworkReply*)));
82 GpsClient::~GpsClient()
85 if (_location_gps_device != 0)
86 g_object_unref(_location_gps_device);
87 if (_location_gpsd_control != 0)
88 location_gpsd_control_stop(_location_gpsd_control);
92 void GpsClient::SearchLocation()
94 _semaphore.Activate(GetSearchTaskId());
95 #ifdef QT_MOBILITY_LOCATION
96 _geo_position_info_source->requestUpdate(30 * 1000);
97 emit SearchStarted(GetSearchTaskId());
98 #elif defined(LIBLOCATION)
99 _location_gpsd_control = location_gpsd_control_get_default();
100 if (_location_gpsd_control != 0) {
101 location_gpsd_control_start(_location_gpsd_control);
103 emit SearchStarted(GetSearchTaskId());
104 _location_gps_device = (LocationGPSDevice *) g_object_new(LOCATION_TYPE_GPS_DEVICE, NULL);
105 if (_location_gps_device != 0) {
106 location_gps_device_reset_last_known(_location_gps_device);
107 g_signal_connect(_location_gps_device, "changed", G_CALLBACK(changed), this);
108 g_signal_connect(_location_gps_device, "connected", G_CALLBACK(connected), this);
109 g_signal_connect(_location_gps_device, "disconnected", G_CALLBACK(disconnected), this);
111 _time_out_timer->start(30 * 1000);
113 emit SearchStarted(GetSearchTaskId());
114 emit SearchError(GetSearchTaskId());
115 emit SearchFinished(GetSearchTaskId(), false);
120 void GpsClient::CancelAllRunningSearchs()
122 _semaphore.CancelAll();
125 #ifdef QT_MOBILITY_LOCATION
126 void GpsClient::GeoPositionUpdated(const QGeoPositionInfo &geo_position_info)
128 if (geo_position_info.coordinate().isValid()) {
129 //std::cout << "longitude " << geo_position_info.coordinate().longitude()
130 // << ", latitude " << geo_position_info.coordinate().latitude()
131 // << ", altitude " << geo_position_info.coordinate().altitude()
133 SearchTown(QString("%1").arg(geo_position_info.coordinate().longitude()),
134 QString("%1").arg(geo_position_info.coordinate().latitude()));
135 emit SearchForTownStarted(GetSearchTaskId());
137 //std::cout << "invalid coordinate received" << std::endl;
138 emit SearchError(GetSearchTaskId());
139 emit SearchFinished(GetSearchTaskId(), false);
144 void GpsClient::GeoPositionTimedOut()
146 //std::cout << "time-out" << std::endl;
147 emit SearchError(GetSearchTaskId());
148 emit SearchFinished(GetSearchTaskId(), false);
154 void GpsClient::GpsConnected()
156 //std::cout << "connected" << std::endl;
159 void GpsClient::GpsChanged()
161 if (_location_gps_device->status == LOCATION_GPS_DEVICE_STATUS_FIX
162 && _location_gps_device->fix != 0
163 && (_location_gps_device->fix->fields & LOCATION_GPS_DEVICE_LATLONG_SET) != 0)
165 //std::cout << "longitude " << _location_gps_device->fix->longitude
166 // << ", latitude " << _location_gps_device->fix->latitude
167 // << ", altitude " << _location_gps_device->fix->altitude
168 // << ", eph " << _location_gps_device->fix->eph
170 if (_location_gps_device->fix->eph != LOCATION_GPS_DEVICE_NAN
171 && _location_gps_device->fix->eph <= (20 * 1000 * 100)) // 20km
173 SearchTown(QString("%1").arg(_location_gps_device->fix->longitude),
174 QString("%1").arg(_location_gps_device->fix->latitude));
175 emit SearchForTownStarted(GetSearchTaskId());
177 //std::cout << "waiting for better accuracy" << std::endl;
180 //std::cout << "waiting for location" << std::endl;
184 void GpsClient::GpsDisconnected()
186 //std::cout << "disconnected" << std::endl;
189 void GpsClient::GpsTimedOut()
191 //std::cout << "time-out" << std::endl;
192 emit SearchError(GetSearchTaskId());
193 emit SearchFinished(GetSearchTaskId(), false);
198 void GpsClient::SearchTown(const QString &longitude, const QString &latitude)
200 // TODO: try to fetch a unique city name, at least with country code.
201 // http://code.google.com/intl/en/apis/maps/documentation/geocoding/index.html#ReverseGeocoding
202 QUrl url("http://maps.google.com/maps/geo");
203 url.addEncodedQueryItem("q", QUrl::toPercentEncoding(latitude + "," + longitude));
204 url.addEncodedQueryItem("output", QUrl::toPercentEncoding("xml"));
205 _network->get(QNetworkRequest(url));
208 void GpsClient::ReplyFinished(QNetworkReply *network_reply)
210 if (!network_reply->error()) {
211 QString data = QString::fromUtf8(network_reply->readAll());
212 int start = data.indexOf("<LocalityName>");
214 int end = data.indexOf("</LocalityName>", start);
215 QString town = data.mid(start + 14, end - start - 14);
216 if (!town.isEmpty()) {
217 //std::cout << "Found town " << qPrintable(town) << std::endl;
218 emit TownUpdate(GetSearchTaskId(), town);
219 emit SearchFinished(GetSearchTaskId(), true);
222 //std::cout << "No town found in " << qPrintable(data) << std::endl;
223 emit SearchError(GetSearchTaskId());
224 emit SearchFinished(GetSearchTaskId(), false);
228 //std::cout << "No <LocalityName> found in " << qPrintable(data) << std::endl;
229 emit SearchError(GetSearchTaskId());
230 emit SearchFinished(GetSearchTaskId(), false);
234 network_reply->deleteLater();
237 void GpsClient::NetworkError(QNetworkReply::NetworkError)
239 //std::cout << "Network error" << std::endl;
240 emit SearchError(GetSearchTaskId());
241 emit SearchFinished(GetSearchTaskId(), false);
245 QMutex GpsClient::_next_search_task_id_mutex;
246 int GpsClient::_next_search_task_id = 1;
247 SearchClientSemaphore GpsClient::_semaphore;