16#include "GeoSceneTextureTileDataset.h"
17#include "GeoSceneTileDataset.h"
18#include "GeoSceneTypes.h"
19#include "GeoSceneVectorTileDataset.h"
20#include "GeoDataDocument.h"
21#include "HttpDownloadManager.h"
22#include "MarbleDebug.h"
23#include "MarbleDirs.h"
25#include "TileLoaderHelper.h"
26#include "ParseRunnerPlugin.h"
27#include "ParsingRunner.h"
34TileLoader::TileLoader(HttpDownloadManager *
const downloadManager,
const PluginManager *pluginManager) :
35 m_pluginManager(pluginManager)
37 qRegisterMetaType<DownloadUsage>(
"DownloadUsage" );
46TileLoader::~TileLoader()
54QImage TileLoader::loadTileImage( GeoSceneTextureTileDataset
const *textureLayer, TileId
const & tileId, DownloadUsage
const usage )
56 QString const fileName = tileFileName( textureLayer, tileId );
58 TileStatus
status = tileStatus( textureLayer, tileId );
62 if (
status == Available ) {
63 mDebug() << tileId <<
"StateUptodate";
65 Q_ASSERT(
status == Expired );
66 mDebug() << tileId <<
"StateExpired";
67 triggerDownload( textureLayer, tileId, usage );
70 QImage const image( fileName );
71 if ( !image.isNull() ) {
80 QImage replacementTile = scaledLowerLevelTile( textureLayer, tileId );
81 Q_ASSERT( !replacementTile.
isNull() );
83 triggerDownload( textureLayer, tileId, usage );
85 return replacementTile;
89GeoDataDocument *TileLoader::loadTileVectorData( GeoSceneVectorTileDataset
const *textureLayer, TileId
const & tileId, DownloadUsage
const usage )
93 QString const fileName = tileFileName( textureLayer, tileId );
95 TileStatus
status = tileStatus( textureLayer, tileId );
99 if (
status == Available ) {
100 mDebug() << tileId <<
"StateUptodate";
102 Q_ASSERT(
status == Expired );
103 mDebug() << tileId <<
"StateExpired";
104 triggerDownload( textureLayer, tileId, usage );
107 QFile file ( fileName );
108 if ( file.exists() ) {
111 GeoDataDocument* document = openVectorFile(fileName);
118 triggerDownload( textureLayer, tileId, usage );
130void TileLoader::downloadTile( GeoSceneTileDataset
const *tileData, TileId
const &tileId, DownloadUsage
const usage )
132 triggerDownload( tileData, tileId, usage );
135int TileLoader::maximumTileLevel( GeoSceneTileDataset
const & tileData )
139 if ( tileData.maximumTileLevel() >= 0 ) {
140 return tileData.maximumTileLevel();
143 int maximumTileLevel = -1;
144 const QFileInfo themeStr( tileData.themeStr() );
145 const QString tilepath = themeStr.isAbsolute() ? themeStr.absoluteFilePath() : MarbleDirs::path( tileData.themeStr() );
152 for (; it !=
end; ++it ) {
154 const int value = (*it).toInt( &ok, 10 );
156 if ( ok && value > maximumTileLevel )
157 maximumTileLevel = value;
162 return maximumTileLevel + 1;
165bool TileLoader::baseTilesAvailable( GeoSceneTileDataset
const & tileData )
167 const int levelZeroColumns = tileData.levelZeroColumns();
168 const int levelZeroRows = tileData.levelZeroRows();
174 for (
int column = 0; result && column < levelZeroColumns; ++column ) {
175 for (
int row = 0; result && row < levelZeroRows; ++row ) {
176 const TileId id( 0, 0, column, row );
177 const QString tilepath = tileFileName( &tileData,
id );
180 mDebug() <<
"Base tile " << tileData.relativeTileFileName(
id ) <<
" is missing for source dir " << tileData.sourceDir();
188TileLoader::TileStatus TileLoader::tileStatus( GeoSceneTileDataset
const *tileData,
const TileId &tileId )
190 QString const fileName = tileFileName( tileData, tileId );
192 if ( !fileInfo.exists() ) {
196 const QDateTime lastModified = fileInfo.lastModified();
197 const int expireSecs = tileData->expire();
199 return isExpired ? Expired : Available;
205 Q_ASSERT( components.
size() == 5 );
207 QString const origin = components[0];
208 QString const sourceDir = components[ 1 ];
209 int const zoomLevel = components[ 2 ].toInt();
210 int const tileX = components[ 3 ].toInt();
211 int const tileY = components[ 4 ].toInt();
213 TileId
const id = TileId( sourceDir, zoomLevel, tileX, tileY );
215 if (origin == GeoSceneTypes::GeoSceneTextureTileType) {
220 emit tileCompleted(
id, tileImage );
224void TileLoader::updateTile(
const QString &fileName,
const QString &idStr)
227 Q_ASSERT( components.
size() == 5 );
229 QString const origin = components[0];
230 QString const sourceDir = components[ 1 ];
231 int const zoomLevel = components[ 2 ].toInt();
232 int const tileX = components[ 3 ].toInt();
233 int const tileY = components[ 4 ].toInt();
235 TileId
const id = TileId( sourceDir, zoomLevel, tileX, tileY );
236 if (origin == GeoSceneTypes::GeoSceneVectorTileType) {
237 GeoDataDocument* document = openVectorFile(MarbleDirs::path(fileName));
239 emit tileCompleted(
id, document);
244QString TileLoader::tileFileName( GeoSceneTileDataset
const * tileData, TileId
const & tileId )
246 QString const fileName = tileData->relativeTileFileName( tileId );
248 return dirInfo.isAbsolute() ? fileName : MarbleDirs::path( fileName );
251void TileLoader::triggerDownload( GeoSceneTileDataset
const *tileData, TileId
const &
id, DownloadUsage
const usage )
253 if (
id.zoomLevel() > 0) {
254 int minValue = tileData->maximumTileLevel() == -1 ?
id.zoomLevel() : qMin(
id.zoomLevel(), tileData->maximumTileLevel() );
255 if (
id.zoomLevel() != qMax(tileData->minimumTileLevel(), minValue) ) {
261 QUrl const sourceUrl = tileData->downloadUrl(
id );
262 QString const destFileName = tileData->relativeTileFileName(
id );
263 QString const idStr =
QString(
"%1:%2:%3:%4:%5" ).
arg( tileData->nodeType(), tileData->sourceDir() ).
arg(
id.zoomLevel() ).
arg(
id.x() ).
arg(
id.y() );
264 emit downloadTile( sourceUrl, destFileName, idStr, usage );
267QImage TileLoader::scaledLowerLevelTile(
const GeoSceneTextureTileDataset * textureData, TileId
const &
id )
271 int const minimumLevel = textureData->minimumTileLevel();
272 for (
int level = qMax<int>( 0,
id.zoomLevel() - 1 );
level >= 0; --
level ) {
273 if (level > 0 && level < minimumLevel) {
276 int const deltaLevel =
id.zoomLevel() -
level;
278 TileId
const replacementTileId(
id.mapThemeIdHash(), level,
279 id.x() >> deltaLevel,
id.y() >> deltaLevel );
280 QString const fileName = tileFileName( textureData, replacementTileId );
281 mDebug() <<
"TileLoader::scaledLowerLevelTile" <<
"trying" << fileName;
284 if ( level == 0 && toScale.
isNull() ) {
285 mDebug() <<
"No level zero tile installed in map theme dir. Falling back to a transparent image for now.";
286 QSize tileSize = textureData->tileSize();
287 Q_ASSERT( !tileSize.
isEmpty() );
289 toScale.
fill( qRgba( 0, 0, 0, 0 ) );
292 if ( !toScale.
isNull() ) {
294 int const restTileX =
id.x() % ( 1 << deltaLevel );
295 int const restTileY =
id.y() % ( 1 << deltaLevel );
296 int const partWidth = qMax(1, toScale.
width() >> deltaLevel);
297 int const partHeight = qMax(1, toScale.
height() >> deltaLevel);
298 int const startX = restTileX * partWidth;
299 int const startY = restTileY * partHeight;
300 mDebug() <<
"QImage::copy:" << startX << startY << partWidth << partHeight;
301 QImage const part = toScale.
copy( startX, startY, partWidth, partHeight );
302 mDebug() <<
"QImage::scaled:" << toScale.
size();
307 Q_ASSERT_X(
false,
"scaled image",
"level zero image missing" );
311GeoDataDocument *TileLoader::openVectorFile(
const QString &fileName)
const
316 const QString completeSuffix = fileInfo.completeSuffix().
toLower();
318 for(
const ParseRunnerPlugin *plugin: plugins ) {
319 QStringList const extensions = plugin->fileExtensions();
320 if ( extensions.
contains( suffix ) || extensions.
contains( completeSuffix ) ) {
321 ParsingRunner* runner = plugin->newRunner();
323 GeoDataDocument* document = runner->parseFile(fileName, UserDocument, error);
324 if (!document && !
error.isEmpty()) {
325 mDebug() <<
QString(
"Failed to open vector tile %1: %2").
arg(fileName, error);
332 mDebug() <<
"Unable to open vector tile " << fileName <<
": No suitable plugin registered to parse this file format";
338#include "moc_TileLoader.cpp"
Q_SCRIPTABLE CaptureState status()
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
QStringView level(QStringView ifopt)
const QList< QKeySequence > & end()
Binds a QML item to a specific geodetic location in screen coordinates.
DownloadUsage
This enum is used to describe the type of download.
QDateTime currentDateTime()
qint64 secsTo(const QDateTime &other) const const
QStringList entryList(Filters filters, SortFlags sort) const const
bool exists() const const
QImage copy(const QRect &rectangle) const const
void fill(Qt::GlobalColor color)
QImage fromData(QByteArrayView data, const char *format)
bool isNull() const const
QImage scaled(const QSize &size, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformMode) const const
const_iterator constBegin() const const
const_iterator constEnd() const const
qsizetype size() const const
bool isEmpty() const const
QString arg(Args &&... args) const const
bool isEmpty() const const
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QString toLower() const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)