2 Situare - A location system for Facebook
3 Copyright (C) 2010 Ixonos Plc. Authors:
5 Jussi Laitinen - jussi.laitinen@ixonos.com
6 Sami Rämö - sami.ramo@ixonos.com
8 Situare is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 version 2 as published by the Free Software Foundation.
12 Situare is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Situare; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
23 #include <QNetworkAccessManager>
24 #include <QNetworkRequest>
25 #include <QNetworkReply>
29 #include <QNetworkDiskCache>
30 #include <QDesktopServices>
32 #include "mapfetcher.h"
33 #include "mapcommon.h"
35 MapFetcher::MapFetcher(QNetworkAccessManager *manager, QObject *parent)
37 , m_pendingRequestsSize(0)
38 , m_fetchMapImagesTimerRunning(false)
41 QNetworkDiskCache *diskCache = new QNetworkDiskCache(this);
42 diskCache->setCacheDirectory(QDesktopServices::storageLocation(
43 QDesktopServices::CacheLocation));
44 m_manager->setCache(diskCache);
46 connect(m_manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(
47 downloadFinished(QNetworkReply*)));
50 QUrl MapFetcher::buildURL(int zoomLevel, QPoint tileNumbers)
52 QString url = QString("http://tile.openstreetmap.org/mapnik/%1/%2/%3.png")
53 .arg(zoomLevel).arg(tileNumbers.x()).arg(tileNumbers.y());
58 void MapFetcher::checkNextRequestFromCache()
60 qDebug() << __PRETTY_FUNCTION__;
62 int i = newestRequestIndex(false);
65 if (!m_pendingRequests[i].url.isEmpty() && m_pendingRequests[i].url.isValid()) {
66 if (loadImageFromCache(m_pendingRequests[i].url)) {
67 // was found, remove from the list
68 m_pendingRequests.removeAt(i);
71 // didn't found from cache so mark cache checked and leave to queue
72 m_pendingRequests[i].cacheChecked = true;
74 if (m_currentDownloads.size() < MAX_PARALLEL_DOWNLOADS)
80 // schedule checking of the next request if the list is not empty
81 if (newestRequestIndex(false) != -1)
82 QTimer::singleShot(0, this, SLOT(checkNextRequestFromCache()));
84 m_fetchMapImagesTimerRunning = false;
87 void MapFetcher::downloadFinished(QNetworkReply *reply)
89 qDebug() << __PRETTY_FUNCTION__;
91 if (reply->error() == QNetworkReply::NoError) {
93 QUrl url = reply->url();
95 if (!image.load(reply, 0))
101 parseURL(url, zoomLevel, x, y);
103 emit mapImageReceived(zoomLevel, x, y, QPixmap::fromImage(image));
106 emit error(reply->errorString());
109 m_currentDownloads.removeAll(reply);
110 reply->deleteLater();
114 void MapFetcher::enqueueFetchMapImage(int zoomLevel, int x, int y)
116 QUrl url = buildURL(zoomLevel, QPoint(x, y));
118 qDebug() << __PRETTY_FUNCTION__ << "url:" << url.toString();
120 // check if new request is already in the list and move it to the begin of the list...
122 for (int i = 0; i < m_pendingRequests.size(); i++) {
123 if (m_pendingRequests[i].url == url) {
124 m_pendingRequests.move(i, 0);
126 qDebug() << __PRETTY_FUNCTION__ << "URL was already found, moved to begin";
130 // ...or add new request to the begining of the list
132 qDebug() << __PRETTY_FUNCTION__ << "URL was added";
134 request.cacheChecked = false;
136 m_pendingRequests.prepend(request);
139 limitPendingRequestsListSize();
141 if (!m_fetchMapImagesTimerRunning) {
142 m_fetchMapImagesTimerRunning = true;
143 QTimer::singleShot(0, this, SLOT(checkNextRequestFromCache()));
147 void MapFetcher::limitPendingRequestsListSize()
149 qDebug() << __PRETTY_FUNCTION__;
151 while (m_pendingRequests.size() > m_pendingRequestsSize) {
152 m_pendingRequests.removeLast();
156 bool MapFetcher::loadImageFromCache(const QUrl &url)
158 qDebug() << __PRETTY_FUNCTION__;
160 bool imageFound = false;
162 QAbstractNetworkCache *cache = m_manager->cache();
166 QNetworkCacheMetaData metaData = cache->metaData(url);
168 if ((metaData.expirationDate().isValid()) && (url.isValid())) {
170 if (metaData.expirationDate() < QDateTime::currentDateTime()) {
176 QIODevice *cacheImage = cache->data(url);
181 if (image.load(cacheImage, 0)) {
187 parseURL(url, zoomLevel, x, y);
189 emit mapImageReceived(zoomLevel, x, y, QPixmap::fromImage(image));
199 int MapFetcher::newestRequestIndex(bool cacheChecked)
201 qDebug() << __PRETTY_FUNCTION__;
203 if (!m_pendingRequests.isEmpty()) {
204 for (int i = 0; i < m_pendingRequests.size(); i++) {
205 if (m_pendingRequests[i].cacheChecked == cacheChecked) {
214 void MapFetcher::parseURL(const QUrl &url, int &zoom, int &x, int &y)
216 QString path = url.path();
217 QStringList pathParts = path.split("/", QString::SkipEmptyParts);
219 int size = pathParts.size();
222 zoom = (pathParts.at(size-3)).toInt();
223 x = (pathParts.at(size-2)).toInt();
224 QString yString = pathParts.at(size-1);
230 void MapFetcher::setDownloadQueueSize(int size)
232 qDebug() << __PRETTY_FUNCTION__ << "size:" << size;
234 m_pendingRequestsSize = size;
235 limitPendingRequestsListSize();
238 void MapFetcher::startNextDownload()
240 qDebug() << __PRETTY_FUNCTION__;
242 int i = newestRequestIndex(true);
245 QUrl url = m_pendingRequests.takeAt(i).url;
247 QNetworkRequest request(url);
248 request.setRawHeader("User-Agent", "Situare");
249 QNetworkReply *reply = m_manager->get(request);
251 m_currentDownloads.append(reply);