3#include <QtCore/QApplicationStatic>
5#include <QtCore/QDirIterator>
6#include <QtCore/QRegularExpression>
7#include <QtCore/QSettings>
8#include <QtCore/QStorageInfo>
9#include <QtCore/QTemporaryDir>
10#include <QtQml/QQmlEngine>
25using namespace Qt::StringLiterals;
33 return _mapEngineManager();
36QGCMapEngineManager::QGCMapEngineManager(QObject *parent)
40 qCDebug(QGCMapEngineManagerLog) <<
this;
42 (void) qmlRegisterUncreatableType<QGCMapEngineManager>(
"QGroundControl.QGCMapEngineManager", 1, 0,
"QGCMapEngineManager",
"Reference only");
47QGCMapEngineManager::~QGCMapEngineManager()
51 qCDebug(QGCMapEngineManagerLog) <<
this;
54void QGCMapEngineManager::updateForCurrentView(
double lon0,
double lat0,
double lon1,
double lat1,
int minZoom,
int maxZoom,
const QString &mapName)
58 _bottomRightLat = lat1;
59 _bottomRightLon = lon1;
64 _elevationSet.
clear();
66 for (
int z = minZoom; z <= maxZoom; z++) {
71 if (_fetchElevation) {
72 const QString elevationProviderName = SettingsManager::instance()->flightMapSettings()->
elevationMapProvider()->rawValue().toString();
80 qCDebug(QGCMapEngineManagerLog) << lat0 << lon0 << lat1 << lon1 << minZoom << maxZoom;
83QString QGCMapEngineManager::tileCountStr()
const
88QString QGCMapEngineManager::tileSizeStr()
const
93void QGCMapEngineManager::loadTileSets()
95 if (_tileSets->
count() > 0) {
110 if (tileSet->type() == QStringLiteral(
"Invalid")) {
111 tileSet->setMapTypeStr(QStringLiteral(
"Various"));
114 tileSet->setManager(
this);
115 _tileSets->
append(tileSet);
119void QGCMapEngineManager::startDownload(
const QString &name,
const QString &mapType)
123 set->setMapTypeStr(mapType);
124 set->setTopleftLat(_topleftLat);
125 set->setTopleftLon(_topleftLon);
126 set->setBottomRightLat(_bottomRightLat);
127 set->setBottomRightLon(_bottomRightLon);
128 set->setMinZoom(_minZoom);
129 set->setMaxZoom(_maxZoom);
130 set->setTotalTileSize(_imageSet.
tileSize);
131 set->setTotalTileCount(
static_cast<quint32
>(_imageSet.
tileCount));
132 set->setType(mapType);
141 qCWarning(QGCMapEngineManagerLog) <<
"No Tiles to save";
147 const QString elevationProviderName = SettingsManager::instance()->flightMapSettings()->
elevationMapProvider()->rawValue().toString();
148 set->setMapTypeStr(elevationProviderName);
149 set->setTopleftLat(_topleftLat);
150 set->setTopleftLon(_topleftLon);
151 set->setBottomRightLat(_bottomRightLat);
152 set->setBottomRightLon(_bottomRightLon);
155 set->setTotalTileSize(_elevationSet.
tileSize);
156 set->setTotalTileCount(
static_cast<quint32
>(_elevationSet.
tileCount));
157 set->setType(elevationProviderName);
166 qCWarning(QGCMapEngineManagerLog) <<
"No Tiles to save";
172 qCDebug(QGCMapEngineManagerLog) <<
"New tile set saved (" << set->name() <<
"). Starting download...";
176 set->createDownloadTask();
179void QGCMapEngineManager::saveSetting(
const QString &key,
const QString &value)
182 settings.beginGroup(kQmlOfflineMapKeyName);
183 settings.setValue(key, value);
186QString QGCMapEngineManager::loadSetting(
const QString &key,
const QString &defaultValue)
189 settings.beginGroup(kQmlOfflineMapKeyName);
190 return settings.value(key, defaultValue).toString();
193QStringList QGCMapEngineManager::mapTypeList(
const QString &provider)
195 QStringList mapStringList = mapList();
196 mapStringList = mapStringList.filter(QRegularExpression(provider));
198 static const QRegularExpression providerType = QRegularExpression(uR
"(^([^\ ]*) (.*)$)"_s);
199 (void) mapStringList.replaceInStrings(providerType, "\\2");
200 (void) mapStringList.removeDuplicates();
202 return mapStringList;
207 qCDebug(QGCMapEngineManagerLog) <<
"Deleting tile set" << tileSet->name();
209 if (tileSet->defaultSet()) {
210 for (qsizetype i = 0; i < _tileSets->
count(); i++ ) {
213 set->setDeleting(
true);
224 tileSet->setDeleting(
true);
235void QGCMapEngineManager::renameTileSet(
QGCCachedTileSet *tileSet,
const QString &newName)
238 QString name = newName;
239 while (findName(name)) {
240 name = QString(
"%1 (%2)").arg(newName).arg(idx++);
243 qCDebug(QGCMapEngineManagerLog) <<
"Renaming tile set" << tileSet->name() <<
"to" << name;
244 tileSet->setName(name);
254void QGCMapEngineManager::_tileSetDeleted(quint64 setID)
256 for (qsizetype i = 0; i < _tileSets->
count(); i++ ) {
258 if (set && (set->id() == setID)) {
272 task = QStringLiteral(
"Fetch Tile Set");
275 task = QStringLiteral(
"Create Tile Set");
278 task = QStringLiteral(
"Get Tile Download List");
281 task = QStringLiteral(
"Update Tile Download Status");
284 task = QStringLiteral(
"Delete Tile Set");
287 task = QStringLiteral(
"Reset Tile Sets");
290 task = QStringLiteral(
"Export Tile Sets");
293 task = QStringLiteral(
"Database Error");
297 QString serror = QStringLiteral(
"Error in task: ") + task;
298 serror += QStringLiteral(
"\nError description:\n");
301 setErrorMessage(serror);
303 qCWarning(QGCMapEngineManagerLog) << serror;
306void QGCMapEngineManager::_updateTotals(quint32 totaltiles, quint64 totalsize, quint32 defaulttiles, quint64 defaultsize)
308 for (qsizetype i = 0; i < _tileSets->
count(); i++) {
310 if (set && set->defaultSet()) {
311 set->setSavedTileSize(totalsize);
312 set->setSavedTileCount(totaltiles);
313 set->setTotalTileCount(defaulttiles);
314 set->setTotalTileSize(defaultsize);
320bool QGCMapEngineManager::findName(
const QString &name)
const
322 for (qsizetype i = 0; i < _tileSets->
count(); i++) {
323 const QGCCachedTileSet*
const set = qobject_cast<const QGCCachedTileSet*>(_tileSets->
get(i));
324 if (set && (set->name() == name)) {
332void QGCMapEngineManager::selectAll()
334 for (qsizetype i = 0; i < _tileSets->
count(); i++) {
337 set->setSelected(
true);
342void QGCMapEngineManager::selectNone()
344 for (qsizetype i = 0; i < _tileSets->
count(); i++) {
347 set->setSelected(
false);
352int QGCMapEngineManager::selectedCount()
const
356 for (qsizetype i = 0; i < _tileSets->
count(); i++) {
357 const QGCCachedTileSet*
const set = qobject_cast<const QGCCachedTileSet*>(_tileSets->
get(i));
358 if (set && set->selected()) {
366bool QGCMapEngineManager::importSets(
const QString &path)
368 setImportAction(ImportAction::ActionNone);
370 if (path.isEmpty()) {
374 setImportAction(ImportAction::ActionImporting);
388bool QGCMapEngineManager::exportSets(
const QString &path)
390 setImportAction(ImportAction::ActionNone);
392 if (path.isEmpty()) {
396 QList<TileSetRecord> records;
398 for (qsizetype i = 0; i < _tileSets->
count(); i++) {
400 if (set && set->selected()) {
402 rec.
setID = set->id();
403 rec.
name = set->name();
412 rec.
numTiles = set->totalTileCount();
414 rec.
date = set->creationDate().toSecsSinceEpoch();
419 if (records.isEmpty()) {
423 setImportAction(ImportAction::ActionExporting);
437void QGCMapEngineManager::_actionCompleted()
439 const ImportAction oldState = _importAction;
440 setImportAction(ImportAction::ActionDone);
442 if (oldState == ImportAction::ActionImporting) {
447QString QGCMapEngineManager::getUniqueName()
const
451 const QString name = QStringLiteral(
"Tile Set ") + QString::asprintf(
"%03d", count++);
452 if (!findName(name)) {
458QStringList QGCMapEngineManager::mapList()
463QStringList QGCMapEngineManager::mapProviderList()
465 QStringList mapStringList = mapList();
466 const QStringList elevationStringList = elevationProviderList();
467 for (
const QString &elevationProviderName : elevationStringList) {
468 (void) mapStringList.removeAll(elevationProviderName);
471 static const QRegularExpression providerType = QRegularExpression(uR
"(^([^\ ]*) (.*)$)"_s);
472 (void) mapStringList.replaceInStrings(providerType, "\\1");
473 (void) mapStringList.removeDuplicates();
475 return mapStringList;
478QStringList QGCMapEngineManager::elevationProviderList()
483bool QGCMapEngineManager::importArchive(
const QString &archivePath)
485 if (archivePath.isEmpty()) {
486 setErrorMessage(tr(
"No archive path specified"));
490 if (!QFile::exists(archivePath)) {
491 setErrorMessage(tr(
"Archive file not found: %1").arg(archivePath));
496 setErrorMessage(tr(
"Not a supported archive format: %1").arg(archivePath));
500 if (_importAction == ImportAction::ActionImporting) {
501 setErrorMessage(tr(
"Import already in progress"));
505 const QString tempPath = QDir::temp().filePath(QStringLiteral(
"qgc_tiles_") + QString::number(QDateTime::currentMSecsSinceEpoch()));
506 if (!QDir().mkpath(tempPath)) {
507 setErrorMessage(tr(
"Could not create temporary directory"));
511 _extractionOutputDir = tempPath;
513 if (_extractionJob ==
nullptr) {
516 this, &QGCMapEngineManager::_handleExtractionProgress);
518 this, &QGCMapEngineManager::_handleExtractionFinished);
521 setImportAction(ImportAction::ActionImporting);
522 setActionProgress(0);
528void QGCMapEngineManager::_handleExtractionProgress(qreal progress)
530 setActionProgress(
static_cast<int>(progress * 50.0));
533void QGCMapEngineManager::_handleExtractionFinished(
bool success)
536 const QString
error = _extractionJob !=
nullptr ? _extractionJob->errorString() : tr(
"Extraction failed");
537 setErrorMessage(
error);
538 setImportAction(ImportAction::ActionDone);
539 QDir(_extractionOutputDir).removeRecursively();
540 _extractionOutputDir.clear();
545 QDirIterator it(_extractionOutputDir, {QStringLiteral(
"*.db"), QStringLiteral(
"*.sqlite")},
546 QDir::Files, QDirIterator::Subdirectories);
551 if (dbPath.isEmpty()) {
552 setErrorMessage(tr(
"No tile database found in archive"));
553 setImportAction(ImportAction::ActionDone);
554 QDir(_extractionOutputDir).removeRecursively();
555 _extractionOutputDir.clear();
559 qCDebug(QGCMapEngineManagerLog) <<
"Found tile database:" << dbPath;
564 QDir(_extractionOutputDir).removeRecursively();
565 _extractionOutputDir.clear();
568 setActionProgress(50 + (percentage / 2));
573 setErrorMessage(tr(
"Failed to start import task"));
574 setImportAction(ImportAction::ActionDone);
575 QDir(_extractionOutputDir).removeRecursively();
576 _extractionOutputDir.clear();
QObject wrapper for async compression operations using QtConcurrent/QPromise.
#define QGC_LOGGING_CATEGORY(name, categoryStr)
Q_APPLICATION_STATIC(QGCMapEngineManager, _mapEngineManager)
QGCMapEngine * getQGCMapEngine()
Fact *elevationMapProvider READ elevationMapProvider CONSTANT Fact * elevationMapProvider()
void progressChanged(qreal progress)
Emitted when progress changes (0.0 to 1.0)
void finished(bool success)
void extractArchive(const QString &archivePath, const QString &outputDirectoryPath, qint64 maxBytes=0)
void tileSetSaved(QGCCachedTileSet *tileSet)
void tileSetDeleted(quint64 setID)
void actionProgress(int percentage)
void tileSetFetched(QGCCachedTileSet *tileSet)
void actionProgress(int percentage)
void taskError(QGCMapTask::TaskType type, const QString &error)
bool addTask(QGCMapTask *task)
void updateTotals(quint32 totaltiles, quint64 totalsize, quint32 defaulttiles, quint64 defaultsize)
@ taskUpdateTileDownloadState
@ taskGetTileDownloadList
void error(QGCMapTask::TaskType type, const QString &errorString)
void append(QObject *object)
Caller maintains responsibility for object ownership and deletion.
QObject * removeAt(int index)
int count() const override final
void clear() override final
static QStringList getProviderTypes()
static QGCTileSet getTileCount(int zoom, double topleftLon, double topleftLat, double bottomRightLon, double bottomRightLat, QStringView mapType)
static bool isElevation(int qtMapId)
static QStringList getElevationProviderTypes()
static int getQtMapIdFromProviderType(QStringView type)
bool isArchiveFile(const QString &filePath)
Check if file path indicates an archive file (.zip, .tar, .tar.gz, etc.)