Commit 0878dfa2 authored by Gus Grubba's avatar Gus Grubba Committed by GitHub

Merge pull request #4817 from dogmaphobic/exportTileSet

Map Tile Set Import/Export
parents fbc34cc5 71813e49
......@@ -119,7 +119,9 @@ public:
taskUpdateTileDownloadState,
taskDeleteTileSet,
taskPruneCache,
taskReset
taskReset,
taskExport,
taskImport
};
QGCMapTask(TaskType type)
......@@ -365,5 +367,80 @@ signals:
void resetCompleted();
};
//-----------------------------------------------------------------------------
class QGCExportTileTask : public QGCMapTask
{
Q_OBJECT
public:
QGCExportTileTask(QVector<QGCCachedTileSet*> sets, QString path)
: QGCMapTask(QGCMapTask::taskExport)
, _sets(sets)
, _path(path)
{}
~QGCExportTileTask()
{
}
QVector<QGCCachedTileSet*> sets() { return _sets; }
QString path() { return _path; }
void setExportCompleted()
{
emit actionCompleted();
}
void setProgress(int percentage)
{
emit actionProgress(percentage);
}
private:
QVector<QGCCachedTileSet*> _sets;
QString _path;
signals:
void actionCompleted ();
void actionProgress (int percentage);
};
//-----------------------------------------------------------------------------
class QGCImportTileTask : public QGCMapTask
{
Q_OBJECT
public:
QGCImportTileTask(QString path, bool replace)
: QGCMapTask(QGCMapTask::taskImport)
, _path(path)
, _replace(replace)
{}
~QGCImportTileTask()
{
}
QString path () { return _path; }
bool replace () { return _replace; }
void setImportCompleted()
{
emit actionCompleted();
}
void setProgress(int percentage)
{
emit actionProgress(percentage);
}
private:
QString _path;
bool _replace;
signals:
void actionCompleted ();
void actionProgress (int percentage);
};
#endif // QGC_MAP_ENGINE_DATA_H
......@@ -52,6 +52,7 @@ QGCCachedTileSet::QGCCachedTileSet(const QString& name)
, _noMoreTiles(false)
, _batchRequested(false)
, _manager(NULL)
, _selected(false)
{
}
......@@ -349,3 +350,14 @@ QGCCachedTileSet::setManager(QGCMapEngineManager* mgr)
{
_manager = mgr;
}
//-----------------------------------------------------------------------------
void
QGCCachedTileSet::setSelected(bool sel)
{
_selected = sel;
emit selectedChanged();
if(_manager) {
emit _manager->selectedCountChanged();
}
}
......@@ -72,6 +72,8 @@ public:
Q_PROPERTY(quint32 errorCount READ errorCount NOTIFY errorCountChanged)
Q_PROPERTY(QString errorCountStr READ errorCountStr NOTIFY errorCountChanged)
Q_PROPERTY(bool selected READ selected WRITE setSelected NOTIFY selectedChanged)
Q_INVOKABLE void createDownloadTask ();
Q_INVOKABLE void resumeDownloadTask ();
Q_INVOKABLE void cancelDownloadTask ();
......@@ -109,7 +111,9 @@ public:
bool downloading () { return _downloading; }
quint32 errorCount () { return _errorCount; }
QString errorCountStr ();
bool selected () { return _selected; }
void setSelected (bool sel);
void setName (QString name) { _name = name; }
void setMapTypeStr (QString typeStr) { _mapTypeStr = typeStr; }
void setTopleftLat (double lat) { _topleftLat = lat; }
......@@ -142,6 +146,7 @@ signals:
void savedTileSizeChanged ();
void completeChanged ();
void errorCountChanged ();
void selectedChanged ();
private slots:
void _tileListFetched (QList<QGCTile*> tiles);
......@@ -181,6 +186,7 @@ private:
bool _noMoreTiles;
bool _batchRequested;
QGCMapEngineManager* _manager;
bool _selected;
};
#endif // QGC_MAP_TILE_SET_H
......
......@@ -31,6 +31,7 @@
const char* kDefaultSet = "Default Tile Set";
const QString kSession = QLatin1String("QGeoTileWorkerSession");
const QString kExportSession = QLatin1String("QGeoTileExportSession");
QGC_LOGGING_CATEGORY(QGCTileCacheLog, "QGCTileCacheLog")
......@@ -153,6 +154,12 @@ QGCCacheWorker::run()
case QGCMapTask::taskReset:
_resetCacheDatabase(task);
break;
case QGCMapTask::taskExport:
_exportSets(task);
break;
case QGCMapTask::taskImport:
_importSets(task);
break;
case QGCMapTask::taskTestInternet:
_testInternet();
break;
......@@ -262,8 +269,7 @@ QGCCacheWorker::_saveTile(QGCMapTask *mtask)
void
QGCCacheWorker::_getTile(QGCMapTask* mtask)
{
if(!_valid) {
mtask->setError("No Cache Database");
if(!_testTask(mtask)) {
return;
}
bool found = false;
......@@ -291,8 +297,7 @@ QGCCacheWorker::_getTile(QGCMapTask* mtask)
void
QGCCacheWorker::_getTileSets(QGCMapTask* mtask)
{
if(!_valid) {
mtask->setError("No Cache Database");
if(!_testTask(mtask)) {
return;
}
QGCFetchTileSetTask* task = static_cast<QGCFetchTileSetTask*>(mtask);
......@@ -506,8 +511,7 @@ QGCCacheWorker::_createTileSet(QGCMapTask *mtask)
void
QGCCacheWorker::_getTileDownloadList(QGCMapTask* mtask)
{
if(!_valid) {
mtask->setError("No Cache Database");
if(!_testTask(mtask)) {
return;
}
QList<QGCTile*> tiles;
......@@ -538,8 +542,7 @@ QGCCacheWorker::_getTileDownloadList(QGCMapTask* mtask)
void
QGCCacheWorker::_updateTileDownloadState(QGCMapTask* mtask)
{
if(!_valid) {
mtask->setError("No Cache Database");
if(!_testTask(mtask)) {
return;
}
QGCUpdateTileDownloadStateTask* task = static_cast<QGCUpdateTileDownloadStateTask*>(mtask);
......@@ -563,8 +566,7 @@ QGCCacheWorker::_updateTileDownloadState(QGCMapTask* mtask)
void
QGCCacheWorker::_pruneCache(QGCMapTask* mtask)
{
if(!_valid) {
mtask->setError("No Cache Database");
if(!_testTask(mtask)) {
return;
}
QGCPruneCacheTask* task = static_cast<QGCPruneCacheTask*>(mtask);
......@@ -594,8 +596,7 @@ QGCCacheWorker::_pruneCache(QGCMapTask* mtask)
void
QGCCacheWorker::_deleteTileSet(QGCMapTask* mtask)
{
if(!_valid) {
mtask->setError("No Cache Database");
if(!_testTask(mtask)) {
return;
}
QGCDeleteTileSetTask* task = static_cast<QGCDeleteTileSetTask*>(mtask);
......@@ -613,12 +614,12 @@ QGCCacheWorker::_deleteTileSet(QGCMapTask* mtask)
_updateTotals();
task->setTileSetDeleted();
}
//-----------------------------------------------------------------------------
void
QGCCacheWorker::_resetCacheDatabase(QGCMapTask* mtask)
{
if(!_valid) {
mtask->setError("No Cache Database");
if(!_testTask(mtask)) {
return;
}
QGCResetTask* task = static_cast<QGCResetTask*>(mtask);
......@@ -632,10 +633,288 @@ QGCCacheWorker::_resetCacheDatabase(QGCMapTask* mtask)
query.exec(s);
s = QString("DROP TABLE TilesDownload");
query.exec(s);
_createDB();
_valid = _createDB(_db);
task->setResetCompleted();
}
//-----------------------------------------------------------------------------
void
QGCCacheWorker::_importSets(QGCMapTask* mtask)
{
if(!_testTask(mtask)) {
return;
}
QGCImportTileTask* task = static_cast<QGCImportTileTask*>(mtask);
//-- If replacing, simply copy over it
if(task->replace()) {
//-- Close and delete old database
if(_db) {
delete _db;
_db = NULL;
QSqlDatabase::removeDatabase(kSession);
}
QFile file(_databasePath);
file.remove();
//-- Copy given database
QFile::copy(task->path(), _databasePath);
task->setProgress(25);
_init();
if(_valid) {
task->setProgress(50);
_db = new QSqlDatabase(QSqlDatabase::addDatabase("QSQLITE", kSession));
_db->setDatabaseName(_databasePath);
_db->setConnectOptions("QSQLITE_ENABLE_SHARED_CACHE");
_valid = _db->open();
}
task->setProgress(100);
} else {
//-- Open imported set
QSqlDatabase* dbImport = new QSqlDatabase(QSqlDatabase::addDatabase("QSQLITE", kExportSession));
dbImport->setDatabaseName(task->path());
dbImport->setConnectOptions("QSQLITE_ENABLE_SHARED_CACHE");
if (dbImport->open()) {
QSqlQuery query(*dbImport);
//-- Prepare progress report
quint64 tileCount = 0;
quint64 currentCount = 0;
QString s;
s = QString("SELECT COUNT(tileID) FROM Tiles");
if(query.exec(s)) {
if(query.next()) {
tileCount = query.value(0).toULongLong();
}
}
if(!tileCount) {
qWarning() << "No tiles found in imported database";
tileCount = 1; //-- Let it run through
}
//-- Iterate Tile Sets
s = QString("SELECT * FROM TileSets ORDER BY defaultSet DESC, name ASC");
if(query.exec(s)) {
while(query.next()) {
QString name = query.value("name").toString();
quint64 setID = query.value("setID").toULongLong();
QString mapType = query.value("typeStr").toString();
double topleftLat = query.value("topleftLat").toDouble();
double topleftLon = query.value("topleftLon").toDouble();
double bottomRightLat = query.value("bottomRightLat").toDouble();
double bottomRightLon = query.value("bottomRightLon").toDouble();
int minZoom = query.value("minZoom").toInt();
int maxZoom = query.value("maxZoom").toInt();
int type = query.value("type").toInt();
quint32 numTiles = query.value("numTiles").toUInt();
int defaultSet = query.value("defaultSet").toInt();
quint64 insertSetID = _getDefaultTileSet();
//-- If not default set, create new one
if(!defaultSet) {
//-- Check if we have this tile set already
int testCount = 0;
while (true) {
QString testName;
testName.sprintf("%s %03d", name.toLatin1().data(), ++testCount);
if(!_findTileSetID(testName, insertSetID) || testCount > 99) {
if(testCount > 1) {
name = testName;
}
break;
}
}
//-- Create new set
QSqlQuery cQuery(*_db);
cQuery.prepare("INSERT INTO TileSets("
"name, typeStr, topleftLat, topleftLon, bottomRightLat, bottomRightLon, minZoom, maxZoom, type, numTiles, defaultSet, date"
") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
cQuery.addBindValue(name);
cQuery.addBindValue(mapType);
cQuery.addBindValue(topleftLat);
cQuery.addBindValue(topleftLon);
cQuery.addBindValue(bottomRightLat);
cQuery.addBindValue(bottomRightLon);
cQuery.addBindValue(minZoom);
cQuery.addBindValue(maxZoom);
cQuery.addBindValue(type);
cQuery.addBindValue(numTiles);
cQuery.addBindValue(defaultSet);
cQuery.addBindValue(QDateTime::currentDateTime().toTime_t());
if(!cQuery.exec()) {
task->setError("Error adding imported tile set to database");
break;
} else {
//-- Get just created (auto-incremented) setID
insertSetID = cQuery.lastInsertId().toULongLong();
}
}
//-- Find set tiles
QSqlQuery cQuery(*_db);
QSqlQuery subQuery(*dbImport);
QString sb = QString("SELECT * FROM Tiles WHERE tileID IN (SELECT A.tileID FROM SetTiles A JOIN SetTiles B ON A.tileID = B.tileID WHERE B.setID = %1 GROUP BY A.tileID HAVING COUNT(A.tileID) = 1)").arg(setID);
if(subQuery.exec(sb)) {
_db->transaction();
while(subQuery.next()) {
QString hash = subQuery.value("hash").toString();
QString format = subQuery.value("format").toString();
QByteArray img = subQuery.value("tile").toByteArray();
int type = subQuery.value("type").toInt();
//-- Save tile
cQuery.prepare("INSERT INTO Tiles(hash, format, tile, size, type, date) VALUES(?, ?, ?, ?, ?, ?)");
cQuery.addBindValue(hash);
cQuery.addBindValue(format);
cQuery.addBindValue(img);
cQuery.addBindValue(img.size());
cQuery.addBindValue(type);
cQuery.addBindValue(QDateTime::currentDateTime().toTime_t());
if(cQuery.exec()) {
quint64 importTileID = cQuery.lastInsertId().toULongLong();
QString s = QString("INSERT INTO SetTiles(tileID, setID) VALUES(%1, %2)").arg(importTileID).arg(insertSetID);
cQuery.prepare(s);
cQuery.exec();
currentCount++;
task->setProgress((int)((double)currentCount / (double)tileCount * 100.0));
}
}
_db->commit();
//-- Update tile count
s = QString("SELECT COUNT(size) FROM Tiles A INNER JOIN SetTiles B on A.tileID = B.tileID WHERE B.setID = %1").arg(insertSetID);
if(cQuery.exec(s)) {
if(cQuery.next()) {
quint64 count = cQuery.value(0).toULongLong();
s = QString("UPDATE TileSets SET numTiles = %1 WHERE setID = %2").arg(count).arg(insertSetID);
cQuery.exec(s);
}
}
}
}
} else {
task->setError("No tile set in database");
}
delete dbImport;
QSqlDatabase::removeDatabase(kExportSession);
} else {
task->setError("Error opening import database");
}
}
task->setImportCompleted();
}
//-----------------------------------------------------------------------------
void
QGCCacheWorker::_exportSets(QGCMapTask* mtask)
{
if(!_testTask(mtask)) {
return;
}
QGCExportTileTask* task = static_cast<QGCExportTileTask*>(mtask);
//-- Delete target if it exists
QFile file(task->path());
file.remove();
//-- Create exported database
QSqlDatabase *dbExport = new QSqlDatabase(QSqlDatabase::addDatabase("QSQLITE", kExportSession));
dbExport->setDatabaseName(task->path());
dbExport->setConnectOptions("QSQLITE_ENABLE_SHARED_CACHE");
if (dbExport->open()) {
if(_createDB(dbExport, false)) {
//-- Prepare progress report
quint64 tileCount = 0;
quint64 currentCount = 0;
for(int i = 0; i < task->sets().count(); i++) {
QGCCachedTileSet* set = task->sets()[i];
//-- Default set has no unique tiles
if(set->defaultSet()) {
tileCount += set->totalTileCount();
} else {
tileCount += set->uniqueTileCount();
}
}
if(!tileCount) {
tileCount = 1;
}
//-- Iterate sets to save
for(int i = 0; i < task->sets().count(); i++) {
QGCCachedTileSet* set = task->sets()[i];
//-- Create Tile Exported Set
QSqlQuery exportQuery(*dbExport);
exportQuery.prepare("INSERT INTO TileSets("
"name, typeStr, topleftLat, topleftLon, bottomRightLat, bottomRightLon, minZoom, maxZoom, type, numTiles, defaultSet, date"
") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
exportQuery.addBindValue(set->name());
exportQuery.addBindValue(set->mapTypeStr());
exportQuery.addBindValue(set->topleftLat());
exportQuery.addBindValue(set->topleftLon());
exportQuery.addBindValue(set->bottomRightLat());
exportQuery.addBindValue(set->bottomRightLon());
exportQuery.addBindValue(set->minZoom());
exportQuery.addBindValue(set->maxZoom());
exportQuery.addBindValue(set->type());
exportQuery.addBindValue(set->totalTileCount());
exportQuery.addBindValue(set->defaultSet());
exportQuery.addBindValue(QDateTime::currentDateTime().toTime_t());
if(!exportQuery.exec()) {
task->setError("Error adding tile set to exported database");
break;
} else {
//-- Get just created (auto-incremented) setID
quint64 exportSetID = exportQuery.lastInsertId().toULongLong();
//-- Find set tiles
QString s = QString("SELECT * FROM SetTiles WHERE setID = %1").arg(set->id());
QSqlQuery query(*_db);
if(query.exec(s)) {
dbExport->transaction();
while(query.next()) {
quint64 tileID = query.value("tileID").toULongLong();
//-- Get tile
QString s = QString("SELECT * FROM Tiles WHERE tileID = \"%1\"").arg(tileID);
QSqlQuery subQuery(*_db);
if(subQuery.exec(s)) {
if(subQuery.next()) {
QString hash = subQuery.value("hash").toString();
QString format = subQuery.value("format").toString();
QByteArray img = subQuery.value("tile").toByteArray();
int type = subQuery.value("type").toInt();
//-- Save tile
exportQuery.prepare("INSERT INTO Tiles(hash, format, tile, size, type, date) VALUES(?, ?, ?, ?, ?, ?)");
exportQuery.addBindValue(hash);
exportQuery.addBindValue(format);
exportQuery.addBindValue(img);
exportQuery.addBindValue(img.size());
exportQuery.addBindValue(type);
exportQuery.addBindValue(QDateTime::currentDateTime().toTime_t());
if(exportQuery.exec()) {
quint64 exportTileID = exportQuery.lastInsertId().toULongLong();
QString s = QString("INSERT INTO SetTiles(tileID, setID) VALUES(%1, %2)").arg(exportTileID).arg(exportSetID);
exportQuery.prepare(s);
exportQuery.exec();
currentCount++;
task->setProgress((int)((double)currentCount / (double)tileCount * 100.0));
}
}
}
}
}
dbExport->commit();
}
}
} else {
task->setError("Error creating export database");
}
} else {
qCritical() << "Map Cache SQL error (create export database):" << dbExport->lastError();
task->setError("Error opening export database");
}
delete dbExport;
QSqlDatabase::removeDatabase(kExportSession);
task->setExportCompleted();
}
//-----------------------------------------------------------------------------
bool QGCCacheWorker::_testTask(QGCMapTask* mtask)
{
if(!_valid) {
mtask->setError("No Cache Database");
return false;
}
return true;
}
//-----------------------------------------------------------------------------
bool
QGCCacheWorker::_init()
......@@ -648,7 +927,10 @@ QGCCacheWorker::_init()
_db->setDatabaseName(_databasePath);
_db->setConnectOptions("QSQLITE_ENABLE_SHARED_CACHE");
if (_db->open()) {
_createDB();
_valid = _createDB(_db);
if(!_valid) {
_failed = true;
}
} else {
qCritical() << "Map Cache SQL error (init() open db):" << _db->lastError();
_failed = true;
......@@ -665,10 +947,11 @@ QGCCacheWorker::_init()
}
//-----------------------------------------------------------------------------
void
QGCCacheWorker::_createDB()
bool
QGCCacheWorker::_createDB(QSqlDatabase* db, bool createDefault)
{
QSqlQuery query(*_db);
bool res = false;
QSqlQuery query(*db);
if(!query.exec(
"CREATE TABLE IF NOT EXISTS Tiles ("
"tileID INTEGER PRIMARY KEY NOT NULL, "
......@@ -719,13 +1002,13 @@ QGCCacheWorker::_createDB()
qWarning() << "Map Cache SQL error (create TilesDownload db):" << query.lastError().text();
} else {
//-- Database it ready for use
_valid = true;
res = true;
}
}
}
}
//-- Create default tile set
if(_valid) {
if(res && createDefault) {
QString s = QString("SELECT name FROM TileSets WHERE name = \"%1\"").arg(kDefaultSet);
if(query.exec(s)) {
if(!query.next()) {
......@@ -734,19 +1017,19 @@ QGCCacheWorker::_createDB()
query.addBindValue(1);
query.addBindValue(QDateTime::currentDateTime().toTime_t());
if(!query.exec()) {
qWarning() << "Map Cache SQL error (Creating default tile set):" << _db->lastError();
_valid = false;
qWarning() << "Map Cache SQL error (Creating default tile set):" << db->lastError();
res = false;
}
}
} else {
qWarning() << "Map Cache SQL error (Looking for default tile set):" << _db->lastError();
qWarning() << "Map Cache SQL error (Looking for default tile set):" << db->lastError();
}
}
if(!_valid) {
if(!res) {
QFile file(_databasePath);
file.remove();
}
_failed = !_valid;
return res;
}
//-----------------------------------------------------------------------------
......
......@@ -59,13 +59,16 @@ private:
void _deleteTileSet (QGCMapTask* mtask);
void _resetCacheDatabase (QGCMapTask* mtask);
void _pruneCache (QGCMapTask* mtask);
void _exportSets (QGCMapTask* mtask);
void _importSets (QGCMapTask* mtask);
bool _testTask (QGCMapTask* mtask);
void _testInternet ();
quint64 _findTile (const QString hash);
bool _findTileSetID (const QString name, quint64& setID);
void _updateSetTotals (QGCCachedTileSet* set);
bool _init ();
void _createDB ();
bool _createDB (QSqlDatabase *db, bool createDefault = true);
quint64 _getDefaultTileSet ();
void _updateTotals ();
......
......@@ -20,6 +20,7 @@ import QGroundControl.Controls 1.0
import QGroundControl.ScreenTools 1.0
import QGroundControl.Palette 1.0
import QGroundControl.FlightMap 1.0
import QGroundControl.QGCMapEngineManager 1.0
QGCView {
id: offlineMapView
......@@ -37,7 +38,9 @@ QGCView {
property string savedMapType: ""
property bool _showPreview: true
property bool _defaultSet: offlineMapView && offlineMapView._currentSelection && offlineMapView._currentSelection.defaultSet
property real _margins: ScreenTools.defaultFontPixelWidth / 2
property real _margins: ScreenTools.defaultFontPixelWidth * 0.5
property real _buttonSize: ScreenTools.defaultFontPixelWidth * 12
property real _bigButtonSize: ScreenTools.defaultFontPixelWidth * 16
property bool _saveRealEstate: ScreenTools.isTinyScreen || ScreenTools.isShortScreen
property real _adjustableFontPointSize: _saveRealEstate ? ScreenTools.smallFontPointSize : ScreenTools.defaultFontPointSize
......@@ -100,15 +103,27 @@ QGCView {
_map.visible = true
_tileSetList.visible = false
infoView.visible = false
_exporTiles.visible = false
addNewSetView.visible = true
}
function showList() {
_exporTiles.visible = false
isMapInteractive = false
_map.visible = false
_tileSetList.visible = true
infoView.visible = false
addNewSetView.visible = false
QGroundControl.mapEngineManager.resetAction();
}
function showExport() {
isMapInteractive = false
_map.visible = false
_tileSetList.visible = false
infoView.visible = false
addNewSetView.visible = false
_exporTiles.visible = true
}
function showInfo() {
......@@ -796,7 +811,7 @@ QGCView {
clip: true
anchors.margins: ScreenTools.defaultFontPixelWidth
anchors.top: parent.top
anchors.bottom: _optionsButton.top
anchors.bottom: _listButtonRow.top
anchors.left: parent.left
anchors.right: parent.right
contentHeight: _cacheList.height
......@@ -806,7 +821,6 @@ QGCView {
width: Math.min(_tileSetList.width, (ScreenTools.defaultFontPixelWidth * 50).toFixed(0))
spacing: ScreenTools.defaultFontPixelHeight * 0.5
anchors.horizontalCenter: parent.horizontalCenter
OfflineMapButton {
id: firstButton
text: qsTr("Add new set")
......@@ -834,15 +848,365 @@ QGCView {
}
}
}
QGCButton {
id: _optionsButton
text: qsTr("Options")
Row {
id: _listButtonRow
visible: _tileSetList.visible
spacing: _margins
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.margins: ScreenTools.defaultFontPixelWidth
anchors.horizontalCenter: parent.horizontalCenter
QGCButton {
text: qsTr("Import")
width: _buttonSize
visible: !ScreenTools.isMobile
onClicked: rootLoader.sourceComponent = importDialog
}
QGCButton {
text: qsTr("Export")
width: _buttonSize
visible: !ScreenTools.isMobile
enabled: QGroundControl.mapEngineManager.tileSets.count > 1
onClicked: showExport()
}
QGCButton {
text: qsTr("Options")
width: _buttonSize
onClicked: showDialog(optionsDialogComponent, qsTr("Offline Maps Options"), qgcView.showDialogDefaultWidth, StandardButton.Save | StandardButton.Cancel)
}
}
//-- Export Tile Sets
QGCFlickable {
id: _exporTiles
clip: true
visible: false
anchors.margins: ScreenTools.defaultFontPixelWidth
anchors.top: parent.top
anchors.bottom: _exportButtonRow.top
anchors.left: parent.left
anchors.right: parent.right
contentHeight: _exportList.height
Column {
id: _exportList
width: Math.min(_exporTiles.width, (ScreenTools.defaultFontPixelWidth * 50).toFixed(0))
spacing: ScreenTools.defaultFontPixelHeight * 0.5
anchors.horizontalCenter: parent.horizontalCenter
QGCLabel {
text: qsTr("Select Tile Sets to Export")
font.pointSize: ScreenTools.mediumFontPointSize
}
Item { width: 1; height: ScreenTools.defaultFontPixelHeight; }
Repeater {
model: QGroundControl.mapEngineManager.tileSets
delegate: QGCCheckBox {
text: object.name
checked: object.selected
onClicked: {
object.selected = checked
}
}
}
}
}
Row {
id: _exportButtonRow
visible: _exporTiles.visible
spacing: _margins
anchors.bottom: parent.bottom
anchors.margins: ScreenTools.defaultFontPixelWidth
anchors.horizontalCenter: parent.horizontalCenter
QGCButton {
text: qsTr("Select All")
width: _bigButtonSize
onClicked: QGroundControl.mapEngineManager.selectAll()
}
QGCButton {
text: qsTr("Select None")
width: _bigButtonSize
onClicked: QGroundControl.mapEngineManager.selectNone()
}
QGCButton {
text: qsTr("Export to Disk")
width: _bigButtonSize
enabled: QGroundControl.mapEngineManager.selectedCount > 0
onClicked: {
showList();
if(QGroundControl.mapEngineManager.exportSets()) {
rootLoader.sourceComponent = exportToDiskProgress
}
}
}
QGCButton {
text: qsTr("Export to Device")
width: _bigButtonSize
enabled: QGroundControl.mapEngineManager.selectedCount > 0
onClicked: {
rootLoader.sourceComponent = exportToDevice
}
}
QGCButton {
text: qsTr("Cancel")
width: _bigButtonSize
onClicked: showList()
}
}
} // QGCViewPanel
Component {
id: exportToDiskProgress
Rectangle {
width: mainWindow.width
height: mainWindow.height
color: "black"
anchors.centerIn: parent
Rectangle {
width: parent.width * 0.5
height: exportCol.height * 1.25
radius: ScreenTools.defaultFontPixelWidth
color: qgcPal.windowShadeDark
border.color: qgcPal.text
anchors.centerIn: parent
Column {
id: exportCol
spacing: ScreenTools.defaultFontPixelHeight
width: parent.width
anchors.centerIn: parent
QGCLabel {
text: QGroundControl.mapEngineManager.importAction === QGCMapEngineManager.ActionExporting ? qsTr("Tile Set Export Progress") : qsTr("Tile Set Export Completed")
font.family: ScreenTools.demiboldFontFamily
font.pointSize: ScreenTools.mediumFontPointSize
anchors.horizontalCenter: parent.horizontalCenter
}
ProgressBar {
id: progressBar
width: parent.width * 0.45
maximumValue: 100
value: QGroundControl.mapEngineManager.actionProgress
anchors.horizontalCenter: parent.horizontalCenter
}
BusyIndicator {
visible: QGroundControl.mapEngineManager.exporting
running: QGroundControl.mapEngineManager.exporting
width: exportCloseButton.height
height: exportCloseButton.height
anchors.horizontalCenter: parent.horizontalCenter
}
QGCButton {
id: exportCloseButton
text: qsTr("Close")
width: _buttonSize
visible: !QGroundControl.mapEngineManager.exporting
anchors.horizontalCenter: parent.horizontalCenter
onClicked: {
rootLoader.sourceComponent = null
}
}
}
}
}
}
Component {
id: importDialog
Rectangle {
width: mainWindow.width
height: mainWindow.height
color: "black"
anchors.centerIn: parent
Rectangle {
width: parent.width * 0.45
height: importCol.height * 1.5
radius: ScreenTools.defaultFontPixelWidth
color: qgcPal.windowShadeDark
border.color: qgcPal.text
anchors.centerIn: parent
Column {
id: importCol
spacing: ScreenTools.defaultFontPixelHeight
width: parent.width
anchors.centerIn: parent
QGCLabel {
text: {
if(QGroundControl.mapEngineManager.importAction === QGCMapEngineManager.ActionNone) {
return qsTr("Map Tile Set Import");
} else if(QGroundControl.mapEngineManager.importAction === QGCMapEngineManager.ActionImporting) {
return qsTr("Map Tile Set Import Progress");
} else {
return qsTr("Map Tile Set Import Completed");
}
}
font.family: ScreenTools.demiboldFontFamily
font.pointSize: ScreenTools.mediumFontPointSize
anchors.horizontalCenter: parent.horizontalCenter
}
ProgressBar {
id: progressBar
width: parent.width * 0.45
maximumValue: 100
visible: QGroundControl.mapEngineManager.importAction === QGCMapEngineManager.ActionImporting
value: QGroundControl.mapEngineManager.actionProgress
anchors.horizontalCenter: parent.horizontalCenter
}
BusyIndicator {
visible: QGroundControl.mapEngineManager.importAction === QGCMapEngineManager.ActionImporting
running: QGroundControl.mapEngineManager.importAction === QGCMapEngineManager.ActionImporting
width: ScreenTools.defaultFontPixelWidth * 2
height: width
anchors.horizontalCenter: parent.horizontalCenter
}
ExclusiveGroup { id: radioGroup }
Column {
spacing: ScreenTools.defaultFontPixelHeight
width: ScreenTools.defaultFontPixelWidth * 24
anchors.horizontalCenter: parent.horizontalCenter
QGCRadioButton {
exclusiveGroup: radioGroup
text: qsTr("Append to existing set")
checked: !QGroundControl.mapEngineManager.importReplace
onClicked: QGroundControl.mapEngineManager.importReplace = !checked
visible: QGroundControl.mapEngineManager.importAction === QGCMapEngineManager.ActionNone
}
QGCRadioButton {
exclusiveGroup: radioGroup
text: qsTr("Replace existing set")
checked: QGroundControl.mapEngineManager.importReplace
onClicked: QGroundControl.mapEngineManager.importReplace = checked
visible: QGroundControl.mapEngineManager.importAction === QGCMapEngineManager.ActionNone
}
}
QGCButton {
text: qsTr("Close")
width: _bigButtonSize * 1.25
visible: QGroundControl.mapEngineManager.importAction === QGCMapEngineManager.ActionDone
anchors.horizontalCenter: parent.horizontalCenter
onClicked: {
showList();
rootLoader.sourceComponent = null
}
}
Row {
spacing: _margins
visible: QGroundControl.mapEngineManager.importAction === QGCMapEngineManager.ActionNone
anchors.horizontalCenter: parent.horizontalCenter
QGCButton {
text: qsTr("Import From Disk")
width: _bigButtonSize * 1.25
onClicked: {
if(!QGroundControl.mapEngineManager.importSets()) {
showList();
rootLoader.sourceComponent = null
}
}
}
QGCButton {
text: qsTr("Import From Device")
width: _bigButtonSize * 1.25
onClicked: {
rootLoader.sourceComponent = importFromDevice
}
}
QGCButton {
text: qsTr("Cancel")
width: _bigButtonSize * 1.25
onClicked: {
showList();
rootLoader.sourceComponent = null
}
}
}
}
}
}
}
Component {
id: importFromDevice
Rectangle {
width: mainWindow.width
height: mainWindow.height
color: "black"
anchors.centerIn: parent
Rectangle {
width: parent.width * 0.45
height: importCol.height * 1.5
radius: ScreenTools.defaultFontPixelWidth
color: qgcPal.windowShadeDark
border.color: qgcPal.text
anchors.centerIn: parent
Column {
id: importCol
spacing: ScreenTools.defaultFontPixelHeight
width: parent.width
anchors.centerIn: parent
QGCLabel {
text: qsTr("Map Tile Set Import From Device");
font.family: ScreenTools.demiboldFontFamily
font.pointSize: ScreenTools.mediumFontPointSize
anchors.horizontalCenter: parent.horizontalCenter
}
QGCLabel {
text: qsTr("NOT YET IMPLEMENTED");
font.family: ScreenTools.demiboldFontFamily
font.pointSize: ScreenTools.mediumFontPointSize
anchors.horizontalCenter: parent.horizontalCenter
}
QGCButton {
text: qsTr("Close")
width: _bigButtonSize * 1.25
anchors.horizontalCenter: parent.horizontalCenter
onClicked: {
showList();
rootLoader.sourceComponent = null
}
}
}
}
}
}
Component {
id: exportToDevice
Rectangle {
width: mainWindow.width
height: mainWindow.height
color: "black"
anchors.centerIn: parent
Rectangle {
width: parent.width * 0.45
height: importCol.height * 1.5
radius: ScreenTools.defaultFontPixelWidth
color: qgcPal.windowShadeDark
border.color: qgcPal.text
anchors.centerIn: parent
Column {
id: importCol
spacing: ScreenTools.defaultFontPixelHeight
width: parent.width
anchors.centerIn: parent
QGCLabel {
text: qsTr("Map Tile Set Export To Device");
font.family: ScreenTools.demiboldFontFamily
font.pointSize: ScreenTools.mediumFontPointSize
anchors.horizontalCenter: parent.horizontalCenter
}
QGCLabel {
text: qsTr("NOT YET IMPLEMENTED");
font.family: ScreenTools.demiboldFontFamily
font.pointSize: ScreenTools.mediumFontPointSize
anchors.horizontalCenter: parent.horizontalCenter
}
QGCButton {
text: qsTr("Close")
width: _bigButtonSize * 1.25
anchors.horizontalCenter: parent.horizontalCenter
onClicked: {
showList();
rootLoader.sourceComponent = null
}
}
}
}
}
}
} // QGCView
......@@ -11,6 +11,11 @@
/// @file
/// @author Gus Grubba <mavlink@grubba.com>
#if !defined(__mobile__)
#include "QGCFileDialog.h"
#include "MainWindow.h"
#endif
#include "QGCMapEngineManager.h"
#include "QGCApplication.h"
#include "QGCMapTileSet.h"
......@@ -36,6 +41,9 @@ QGCMapEngineManager::QGCMapEngineManager(QGCApplication* app)
, _setID(UINT64_MAX)
, _freeDiskSpace(0)
, _diskSpace(0)
, _actionProgress(0)
, _importAction(ActionNone)
, _importReplace(false)
{
}
......@@ -308,6 +316,9 @@ QGCMapEngineManager::taskError(QGCMapTask::TaskType type, QString error)
case QGCMapTask::taskReset:
task = "Reset Tile Sets";
break;
case QGCMapTask::taskExport:
task = "Export Tile Sets";
break;
default:
task = "Database Error";
break;
......@@ -351,6 +362,142 @@ QGCMapEngineManager::findName(const QString& name)
return false;
}
//-----------------------------------------------------------------------------
void
QGCMapEngineManager::selectAll() {
for(int i = 0; i < _tileSets.count(); i++ ) {
QGCCachedTileSet* set = qobject_cast<QGCCachedTileSet*>(_tileSets.get(i));
Q_ASSERT(set);
set->setSelected(true);
}
}
//-----------------------------------------------------------------------------
void
QGCMapEngineManager::selectNone() {
for(int i = 0; i < _tileSets.count(); i++ ) {
QGCCachedTileSet* set = qobject_cast<QGCCachedTileSet*>(_tileSets.get(i));
Q_ASSERT(set);
set->setSelected(false);
}
}
//-----------------------------------------------------------------------------
int
QGCMapEngineManager::selectedCount() {
int count = 0;
for(int i = 0; i < _tileSets.count(); i++ ) {
QGCCachedTileSet* set = qobject_cast<QGCCachedTileSet*>(_tileSets.get(i));
Q_ASSERT(set);
if(set->selected()) {
count++;
}
}
return count;
}
//-----------------------------------------------------------------------------
bool
QGCMapEngineManager::importSets(QString path) {
_importAction = ActionNone;
emit importActionChanged();
QString dir = path;
if(dir.isEmpty()) {
#if defined(__mobile__)
//-- TODO: This has to be something fixed
dir = QDir(QDir::homePath()).filePath(QString("export_%1.db").arg(QDateTime::currentDateTime().toTime_t()));
#else
dir = QGCFileDialog::getOpenFileName(
MainWindow::instance(),
"Export Tile Set",
QDir::homePath(),
"Tile Sets (*.qgctiledb)");
#endif
}
if(!dir.isEmpty()) {
_importAction = ActionImporting;
emit importActionChanged();
QGCImportTileTask* task = new QGCImportTileTask(dir, _importReplace);
connect(task, &QGCImportTileTask::actionCompleted, this, &QGCMapEngineManager::_actionCompleted);
connect(task, &QGCImportTileTask::actionProgress, this, &QGCMapEngineManager::_actionProgressHandler);
connect(task, &QGCMapTask::error, this, &QGCMapEngineManager::taskError);
getQGCMapEngine()->addTask(task);
return true;
}
return false;
}
//-----------------------------------------------------------------------------
bool
QGCMapEngineManager::exportSets(QString path) {
_importAction = ActionNone;
emit importActionChanged();
QString dir = path;
if(dir.isEmpty()) {
#if defined(__mobile__)
dir = QDir(QDir::homePath()).filePath(QString("export_%1.db").arg(QDateTime::currentDateTime().toTime_t()));
#else
dir = QGCFileDialog::getSaveFileName(
MainWindow::instance(),
"Export Tile Set",
QDir::homePath(),
"Tile Sets (*.qgctiledb)",
"qgctiledb",
true);
#endif
}
if(!dir.isEmpty()) {
QVector<QGCCachedTileSet*> sets;
for(int i = 0; i < _tileSets.count(); i++ ) {
QGCCachedTileSet* set = qobject_cast<QGCCachedTileSet*>(_tileSets.get(i));
Q_ASSERT(set);
if(set->selected()) {
sets.append(set);
}
}
if(sets.count()) {
_importAction = ActionExporting;
emit importActionChanged();
QGCExportTileTask* task = new QGCExportTileTask(sets, dir);
connect(task, &QGCExportTileTask::actionCompleted, this, &QGCMapEngineManager::_actionCompleted);
connect(task, &QGCExportTileTask::actionProgress, this, &QGCMapEngineManager::_actionProgressHandler);
connect(task, &QGCMapTask::error, this, &QGCMapEngineManager::taskError);
getQGCMapEngine()->addTask(task);
return true;
}
}
return false;
}
//-----------------------------------------------------------------------------
void
QGCMapEngineManager::_actionProgressHandler(int percentage)
{
_actionProgress = percentage;
emit actionProgressChanged();
}
//-----------------------------------------------------------------------------
void
QGCMapEngineManager::_actionCompleted()
{
ImportAction oldState = _importAction;
_importAction = ActionDone;
emit importActionChanged();
//-- If we just imported, reload it all
if(oldState == ActionImporting) {
loadTileSets();
}
}
//-----------------------------------------------------------------------------
void
QGCMapEngineManager::resetAction()
{
_importAction = ActionNone;
emit importActionChanged();
}
//-----------------------------------------------------------------------------
QString
QGCMapEngineManager::getUniqueName()
......
......@@ -29,6 +29,14 @@ public:
QGCMapEngineManager(QGCApplication* app);
~QGCMapEngineManager();
enum ImportAction {
ActionNone,
ActionImporting,
ActionExporting,
ActionDone,
};
Q_ENUMS(ImportAction)
Q_PROPERTY(int tileX0 READ tileX0 NOTIFY tileX0Changed)
Q_PROPERTY(int tileX1 READ tileX1 NOTIFY tileX1Changed)
Q_PROPERTY(int tileY0 READ tileY0 NOTIFY tileY0Changed)
......@@ -46,6 +54,12 @@ public:
//-- Disk Space in MB
Q_PROPERTY(quint32 freeDiskSpace READ freeDiskSpace NOTIFY freeDiskSpaceChanged)
Q_PROPERTY(quint32 diskSpace READ diskSpace CONSTANT)
//-- Tile set export
Q_PROPERTY(int selectedCount READ selectedCount NOTIFY selectedCountChanged)
Q_PROPERTY(int actionProgress READ actionProgress NOTIFY actionProgressChanged)
Q_PROPERTY(ImportAction importAction READ importAction NOTIFY importActionChanged)
Q_PROPERTY(bool importReplace READ importReplace WRITE setImportReplace NOTIFY importReplaceChanged)
Q_INVOKABLE void loadTileSets ();
Q_INVOKABLE void updateForCurrentView (double lon0, double lat0, double lon1, double lat1, int minZoom, int maxZoom, const QString& mapName);
......@@ -55,6 +69,11 @@ public:
Q_INVOKABLE void deleteTileSet (QGCCachedTileSet* tileSet);
Q_INVOKABLE QString getUniqueName ();
Q_INVOKABLE bool findName (const QString& name);
Q_INVOKABLE void selectAll ();
Q_INVOKABLE void selectNone ();
Q_INVOKABLE bool exportSets (QString path = QString());
Q_INVOKABLE bool importSets (QString path = QString());
Q_INVOKABLE void resetAction ();
int tileX0 () { return _totalSet.tileX0; }
int tileX1 () { return _totalSet.tileX1; }
......@@ -72,10 +91,15 @@ public:
QString errorMessage () { return _errorMessage; }
quint64 freeDiskSpace () { return _freeDiskSpace; }
quint64 diskSpace () { return _diskSpace; }
int selectedCount ();
int actionProgress () { return _actionProgress; }
ImportAction importAction () { return _importAction; }
bool importReplace () { return _importReplace; }
void setMapboxToken (QString token);
void setMaxMemCache (quint32 size);
void setMaxDiskCache (quint32 size);
void setImportReplace (bool replace) { _importReplace = replace; emit importReplaceChanged(); }
void setErrorMessage (const QString& error) { _errorMessage = error; emit errorMessageChanged(); }
......@@ -95,6 +119,10 @@ signals:
void maxDiskCacheChanged ();
void errorMessageChanged ();
void freeDiskSpaceChanged ();
void selectedCountChanged ();
void actionProgressChanged ();
void importActionChanged ();
void importReplaceChanged ();
public slots:
void taskError (QGCMapTask::TaskType type, QString error);
......@@ -105,6 +133,8 @@ private slots:
void _tileSetDeleted (quint64 setID);
void _updateTotals (quint32 totaltiles, quint64 totalsize, quint32 defaulttiles, quint64 defaultsize);
void _resetCompleted ();
void _actionCompleted ();
void _actionProgressHandler (int percentage);
private:
void _updateDiskFreeSpace ();
......@@ -122,6 +152,9 @@ private:
quint32 _diskSpace;
QmlObjectListModel _tileSets;
QString _errorMessage;
int _actionProgress;
ImportAction _importAction;
bool _importReplace;
};
#endif
......@@ -232,14 +232,14 @@ Rectangle {
}
Repeater {
model: _corePlugin.settingsPages
visible: _corePlugin.options.combineSettingsAndSetup
model: _corePlugin ? _corePlugin.settingsPages : []
visible: _corePlugin && _corePlugin.options.combineSettingsAndSetup
SubMenuButton {
imageResource: modelData.icon
setupIndicator: false
exclusiveGroup: setupButtonGroup
text: modelData.title
visible: _corePlugin.options.combineSettingsAndSetup
visible: _corePlugin && _corePlugin.options.combineSettingsAndSetup
onClicked: panelLoader.setSource(modelData.url)
Layout.fillWidth: true
}
......@@ -312,7 +312,7 @@ Rectangle {
SubMenuButton {
setupIndicator: false
exclusiveGroup: setupButtonGroup
visible: QGroundControl.multiVehicleManager.parameterReadyVehicleAvailable && _corePlugin.showAdvancedUI
visible: QGroundControl.multiVehicleManager && QGroundControl.multiVehicleManager.parameterReadyVehicleAvailable && _corePlugin.showAdvancedUI
text: "Parameters"
Layout.fillWidth: true
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment