MapFetcher::MapFetcher(QNetworkAccessManager *manager, QObject *parent)
: QObject(parent)
- , m_isFetchMapImagesTimerRunning(false)
+ , m_pendingRequestsSize(0)
+ , m_fetchMapImagesTimerRunning(false)
, m_manager(manager)
{
QNetworkDiskCache *diskCache = new QNetworkDiskCache(this);
downloadFinished(QNetworkReply*)));
}
-void MapFetcher::enqueueFetchMapImage(QUrl url)
+void MapFetcher::downloadFinished(QNetworkReply *reply)
{
qDebug() << __PRETTY_FUNCTION__;
- // check if new url is already in the list and move it to end
- // or append new url if not found
- int index;
- if ((index = m_fetchMapImagesList.indexOf(url)) != -1)
- m_fetchMapImagesList.move(index, m_fetchMapImagesList.size() - 1);
- else
- m_fetchMapImagesList << url;
+ if (reply->error() == QNetworkReply::NoError) {
+ QImage image;
+ QUrl url = reply->url();
- // limit list size
- if (m_fetchMapImagesList.size() > DOWNLOAD_QUEUE_SIZE)
- m_fetchMapImagesList.removeFirst();
+ if (!image.load(reply, 0))
+ image = QImage();
- if (!m_isFetchMapImagesTimerRunning) {
- m_isFetchMapImagesTimerRunning = true;
- QTimer::singleShot(0, this, SLOT(fetchMapImage()));
+ emit mapImageReceived(url, QPixmap::fromImage(image));
+ }
+ else {
+ emit error(reply->errorString());
}
+
+ m_currentDownloads.removeAll(reply);
+ reply->deleteLater();
+ startNextDownload();
}
-void MapFetcher::fetchMapImage()
+void MapFetcher::enqueueFetchMapImage(QUrl url)
+{
+ qDebug() << __PRETTY_FUNCTION__ << "url:" << url.toString();
+
+ // check if new request is already in the list and move it to the begin of the list...
+ bool found = false;
+ for (int i = 0; i < m_pendingRequests.size(); i++) {
+ if (m_pendingRequests[i].url == url) {
+ m_pendingRequests.move(i, 0);
+ found = true;
+ qDebug() << __PRETTY_FUNCTION__ << "URL was already found, moved to begin";
+ break;
+ }
+ }
+ // ...or add new request to the begining of the list
+ if (!found) {
+ qDebug() << __PRETTY_FUNCTION__ << "URL was added";
+ Request request;
+ request.cacheChecked = false;
+ request.url = url;
+ m_pendingRequests.prepend(request);
+ }
+
+ limitPendingRequestsListSize();
+
+ if (!m_fetchMapImagesTimerRunning) {
+ m_fetchMapImagesTimerRunning = true;
+ QTimer::singleShot(0, this, SLOT(checkNextRequestFromCache()));
+ }
+}
+
+int MapFetcher::newestRequestIndex(bool cacheChecked)
{
qDebug() << __PRETTY_FUNCTION__;
- if (!m_fetchMapImagesList.isEmpty()) {
- QUrl url = m_fetchMapImagesList.takeLast();
+ if (!m_pendingRequests.isEmpty()) {
+ for (int i = 0; i < m_pendingRequests.size(); i++) {
+ if (m_pendingRequests[i].cacheChecked == cacheChecked) {
+ return i;
+ }
+ }
+ }
+
+ return -1;
+}
+
+void MapFetcher::checkNextRequestFromCache()
+{
+ qDebug() << __PRETTY_FUNCTION__;
- if (!url.isEmpty() && url.isValid()) {
- if (!loadImageFromCache(url)) {
- if (m_downloadQueue.size() >= DOWNLOAD_QUEUE_SIZE)
- m_downloadQueue.dequeue();
+ int i = newestRequestIndex(false);
- m_downloadQueue.enqueue(url);
+ if (i != -1) {
+ if (!m_pendingRequests[i].url.isEmpty() && m_pendingRequests[i].url.isValid()) {
+ if (loadImageFromCache(m_pendingRequests[i].url)) {
+ // was found, remove from the list
+ m_pendingRequests.removeAt(i);
+ }
+ else {
+ // didn't found from cache so mark cache checked and leave to queue
+ m_pendingRequests[i].cacheChecked = true;
if (m_currentDownloads.size() < MAX_PARALLEL_DOWNLOADS)
startNextDownload();
}
}
- // schedule fetching of the next tile if the list is not empty
- if (!m_fetchMapImagesList.isEmpty())
- QTimer::singleShot(0, this, SLOT(fetchMapImage()));
+ // schedule checking of the next request if the list is not empty
+ if (newestRequestIndex(false) != -1)
+ QTimer::singleShot(0, this, SLOT(checkNextRequestFromCache()));
else
- m_isFetchMapImagesTimerRunning = false;
+ m_fetchMapImagesTimerRunning = false;
+}
+
+void MapFetcher::limitPendingRequestsListSize()
+{
+ qDebug() << __PRETTY_FUNCTION__;
+
+ while (m_pendingRequests.size() > m_pendingRequestsSize) {
+ m_pendingRequests.removeLast();
+ }
}
bool MapFetcher::loadImageFromCache(const QUrl &url)
return imageFound;
}
-void MapFetcher::startNextDownload()
+void MapFetcher::setDownloadQueueSize(int size)
{
- qDebug() << __PRETTY_FUNCTION__;
+ qDebug() << __PRETTY_FUNCTION__ << "size:" << size;
- if (m_downloadQueue.isEmpty())
- return;
-
- QUrl url = m_downloadQueue.dequeue();
-
- QNetworkRequest request(url);
- request.setRawHeader("User-Agent", "Situare");
- QNetworkReply *reply = m_manager->get(request);
-
- m_currentDownloads.append(reply);
+ m_pendingRequestsSize = size;
+ limitPendingRequestsListSize();
}
-void MapFetcher::downloadFinished(QNetworkReply *reply)
+void MapFetcher::startNextDownload()
{
qDebug() << __PRETTY_FUNCTION__;
- if (reply->error() == QNetworkReply::NoError) {
- QImage image;
- QUrl url = reply->url();
+ int i = newestRequestIndex(true);
- if (!image.load(reply, 0))
- image = QImage();
+ if (i != -1) {
+ QUrl url = m_pendingRequests.takeAt(i).url;
- emit mapImageReceived(url, QPixmap::fromImage(image));
- }
- else {
- emit error(reply->errorString());
- }
+ QNetworkRequest request(url);
+ request.setRawHeader("User-Agent", "Situare");
+ QNetworkReply *reply = m_manager->get(request);
- m_currentDownloads.removeAll(reply);
- reply->deleteLater();
- startNextDownload();
+ m_currentDownloads.append(reply);
+ }
}
#include <QtCore>
#include <QNetworkAccessManager>
-#include "mapfetcher.h"
-
class QNetworkReply;
class QUrl;
{
Q_OBJECT
+ /**
+ * @brief Struct for download requests
+ *
+ * @typedef Request
+ */
+ typedef struct _Request {
+ bool cacheChecked; ///< Is this request already checked from the cache
+ QUrl url; ///< URL
+ } Request;
+
public:
/**
* @brief Constructor for MapFetcher.
/*******************************************************************************
* CLASS SPECIFIC MEMBER FUNCTIONS AND SLOTS
******************************************************************************/
+public:
+ /**
+ * @brief Set size of the download queue
+ *
+ * @param size New size
+ */
+ void setDownloadQueueSize(int size);
+
public slots:
/**
void enqueueFetchMapImage(QUrl url);
private:
+
+ /**
+ * @brief Limit pending requests list size to m_pendingRequestsSize
+ *
+ */
+ void limitPendingRequestsListSize();
+
/**
* @brief Loads image from cache if it's available and emits imageReveived
* signal with url and image. If image is in cache returns true, false
*/
bool loadImageFromCache(const QUrl &url);
+ /**
+ * @brief Find first item based on criteria if the request is already checked from the cache
+ *
+ * If cacheChecked is true, then returns index of the first request which is already
+ * checked from the cache. If cacheChecked is false then returns first item which
+ * isn't checked from the cache. Returns -1 if the item is not found.
+ *
+ * @param cacheChecked Search criteria
+ * @return Index of the first matching request, or -1 if not found.
+ */
+ int newestRequestIndex(bool cacheChecked);
+
private slots:
/**
void downloadFinished(QNetworkReply *reply);
/**
- * @brief Fetch next map image.
+ * @brief Check next request if it is found from cache
*
- * Next queued request is taken from the queue and fetching is started
+ * Next queued request, which is not already checked against cache, is taken
+ * from the queue and checked against cache. If not found from cache, then
+ * cache checked flag is set. New download is started if there aren't too
+ * many simultaneus downloads already running.
*/
- void fetchMapImage();
+ void checkNextRequestFromCache();
/**
* @brief This slot is called when next download is started. Takes url
******************************************************************************/
private:
static const int MAX_PARALLEL_DOWNLOADS = 2; ///< Max simultaneous parallel downloads
- static const int DOWNLOAD_QUEUE_SIZE = 50; ///< Max downloads waiting in queue
QList<QNetworkReply*> m_currentDownloads; ///< List of current downloads
- QQueue<QUrl> m_downloadQueue; ///< Queue of pending requests
- QList<QUrl> m_fetchMapImagesList; ///< "Queue" for map image fetching requests
- bool m_isFetchMapImagesTimerRunning; ///< is the singleshot timer already running
- QNetworkAccessManager *m_manager; ///< Network access manager
+ int m_pendingRequestsSize; ///< Max number of pending requests
+ bool m_fetchMapImagesTimerRunning; ///< is the singleshot timer already running
+ QNetworkAccessManager *m_manager; ///< Network access manager
+ QList<Request> m_pendingRequests; ///< List of map image fetching requests
};
#endif