blob: cfca57ac9a8405d1f29dfb6a7b421645632cf7b3 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtLocation module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtCore/QTimerEvent>
#include "qgeomappingmanagerengine_p.h"
#include "qgeotilefetcher_p.h"
#include "qgeotilefetcher_p_p.h"
#include "qgeotiledmapreply_p.h"
#include "qgeotilespec_p.h"
#include "qgeotiledmap_p.h"
#include <algorithm>
#include <iterator>
QT_BEGIN_NAMESPACE
QGeoTileFetcher::QGeoTileFetcher(QGeoMappingManagerEngine *parent)
: QObject(*new QGeoTileFetcherPrivate(), parent)
{
Q_D(QGeoTileFetcher);
d->enabled_ = true;
d->engine_ = parent;
}
QGeoTileFetcher::QGeoTileFetcher(QGeoTileFetcherPrivate &dd, QGeoMappingManagerEngine *parent)
: QObject(dd,parent)
{
Q_D(QGeoTileFetcher);
d->enabled_ = true;
d->engine_ = parent;
}
QGeoTileFetcher::~QGeoTileFetcher()
{
}
void QGeoTileFetcher::updateTileRequests(const QSet<QGeoTileSpec> &tilesAdded,
const QSet<QGeoTileSpec> &tilesRemoved)
{
Q_D(QGeoTileFetcher);
QMutexLocker ml(&d->queueMutex_);
cancelTileRequests(tilesRemoved);
std::copy(tilesAdded.cbegin(), tilesAdded.cend(), std::back_inserter(d->queue_));
if (d->enabled_ && initialized() && !d->queue_.isEmpty() && !d->timer_.isActive())
d->timer_.start(0, this);
}
void QGeoTileFetcher::cancelTileRequests(const QSet<QGeoTileSpec> &tiles)
{
Q_D(QGeoTileFetcher);
typedef QSet<QGeoTileSpec>::const_iterator tile_iter;
// No need to lock: called only in updateTileRequests
tile_iter tile = tiles.constBegin();
tile_iter end = tiles.constEnd();
for (; tile != end; ++tile) {
QGeoTiledMapReply *reply = d->invmap_.value(*tile, 0);
if (reply) {
d->invmap_.remove(*tile);
reply->abort();
if (reply->isFinished())
reply->deleteLater();
}
d->queue_.removeAll(*tile);
}
}
void QGeoTileFetcher::requestNextTile()
{
Q_D(QGeoTileFetcher);
QMutexLocker ml(&d->queueMutex_);
if (!d->enabled_)
return;
if (d->queue_.isEmpty())
return;
QGeoTileSpec ts = d->queue_.takeFirst();
if (d->queue_.isEmpty())
d->timer_.stop();
// Check against min/max zoom to prevent sending requests for not existing objects
const QGeoCameraCapabilities & cameraCaps = d->engine_->cameraCapabilities(ts.mapId());
// the ZL in QGeoTileSpec is relative to the native tile size of the provider.
// It gets denormalized in QGeoTiledMap.
if (ts.zoom() < cameraCaps.minimumZoomLevel() || ts.zoom() > cameraCaps.maximumZoomLevel() || !fetchingEnabled())
return;
QGeoTiledMapReply *reply = getTileImage(ts);
if (!reply)
return;
if (reply->isFinished()) {
handleReply(reply, ts);
} else {
connect(reply,
SIGNAL(finished()),
this,
SLOT(finished()),
Qt::QueuedConnection);
d->invmap_.insert(ts, reply);
}
}
void QGeoTileFetcher::finished()
{
Q_D(QGeoTileFetcher);
QMutexLocker ml(&d->queueMutex_);
QGeoTiledMapReply *reply = qobject_cast<QGeoTiledMapReply *>(sender());
if (!reply)
return;
QGeoTileSpec spec = reply->tileSpec();
if (!d->invmap_.contains(spec)) {
reply->deleteLater();
return;
}
d->invmap_.remove(spec);
handleReply(reply, spec);
}
void QGeoTileFetcher::timerEvent(QTimerEvent *event)
{
Q_D(QGeoTileFetcher);
if (event->timerId() != d->timer_.timerId()) {
QObject::timerEvent(event);
return;
}
QMutexLocker ml(&d->queueMutex_);
if (d->queue_.isEmpty() || !initialized()) {
d->timer_.stop();
return;
}
ml.unlock();
requestNextTile();
}
bool QGeoTileFetcher::initialized() const
{
return true;
}
bool QGeoTileFetcher::fetchingEnabled() const
{
return true;
}
void QGeoTileFetcher::handleReply(QGeoTiledMapReply *reply, const QGeoTileSpec &spec)
{
Q_D(QGeoTileFetcher);
if (!d->enabled_) {
reply->deleteLater();
return;
}
if (reply->error() == QGeoTiledMapReply::NoError) {
emit tileFinished(spec, reply->mapImageData(), reply->mapImageFormat());
} else {
emit tileError(spec, reply->errorString());
}
reply->deleteLater();
}
/*******************************************************************************
*******************************************************************************/
QGeoTileFetcherPrivate::QGeoTileFetcherPrivate()
: QObjectPrivate(), enabled_(false), engine_(0)
{
}
QGeoTileFetcherPrivate::~QGeoTileFetcherPrivate()
{
}
QT_END_NAMESPACE