diff --git a/qgcresources.qrc b/qgcresources.qrc
index 5760508c963e66bd6ab159603a0c637366439d54..f7b69b43b782e20e3e16a0d0fee6a9ec784eddc0 100644
--- a/qgcresources.qrc
+++ b/qgcresources.qrc
@@ -139,6 +139,7 @@
resources/buttonRight.svg
resources/JoystickBezel.png
resources/JoystickBezelLight.png
+ resources/notile.png
resources/Pause.svg
resources/Play.svg
resources/PowerButton.svg
diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro
index 7d2199c61640dc0b3dabb29e11acd7f48bd774d7..3e021fcc90cf63c2e280e1081aa0bb28e17b0d69 100644
--- a/qgroundcontrol.pro
+++ b/qgroundcontrol.pro
@@ -204,6 +204,8 @@ INCLUDEPATH += \
src/ui/uas \
src/VehicleSetup \
src/ViewWidgets \
+ src/QtLocationPlugin \
+ src/QtLocationPlugin/QMLControl \
FORMS += \
src/ui/MainWindow.ui \
@@ -287,7 +289,8 @@ HEADERS += \
src/AutoPilotPlugins/PX4/PX4AirframeLoader.h \
src/AutoPilotPlugins/APM/APMAirframeLoader.h \
src/QmlControls/QGCImageProvider.h \
- src/AutoPilotPlugins/APM/APMRemoteParamsDownloader.h
+ src/AutoPilotPlugins/APM/APMRemoteParamsDownloader.h \
+ src/QtLocationPlugin/QMLControl/QGCMapEngineManager.h \
DebugBuild {
HEADERS += \
@@ -410,7 +413,8 @@ SOURCES += \
src/AutoPilotPlugins/PX4/PX4AirframeLoader.cc \
src/AutoPilotPlugins/APM/APMAirframeLoader.cc \
src/QmlControls/QGCImageProvider.cc \
- src/AutoPilotPlugins/APM/APMRemoteParamsDownloader.cc
+ src/AutoPilotPlugins/APM/APMRemoteParamsDownloader.cc \
+ src/QtLocationPlugin/QMLControl/QGCMapEngineManager.cc \
DebugBuild {
SOURCES += \
diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc
index 595fe8ada565e7bdc764f76012b7fa8ae39087ea..7846913c9dbd15ecbe588f2a050984c40d30de83 100644
--- a/qgroundcontrol.qrc
+++ b/qgroundcontrol.qrc
@@ -27,6 +27,7 @@
src/ui/preferences/MavlinkSettings.qml
src/ui/preferences/MockLink.qml
src/ui/preferences/MockLinkSettings.qml
+ src/QtLocationPlugin/QMLControl/OfflineMap.qml
src/ui/preferences/SerialSettings.qml
src/ui/preferences/TcpSettings.qml
src/ui/preferences/UdpSettings.qml
@@ -143,6 +144,7 @@
src/VehicleSetup/SetupView.qml
src/test.qml
src/VehicleSetup/VehicleSummary.qml
+ src/QmlControls/OfflineMapButton.qml
src/MissionManager/MavCmdInfoCommon.json
diff --git a/resources/notile.png b/resources/notile.png
new file mode 100644
index 0000000000000000000000000000000000000000..cbd241ee61906d0e5ccba100d3410c629a668fc5
Binary files /dev/null and b/resources/notile.png differ
diff --git a/src/FlightMap/FlightMapSettings.cc b/src/FlightMap/FlightMapSettings.cc
index c963721d2510390ef2c5466a8475a1292a1e1a60..63c34e59c160b697ee8549ecd1e16a2fe8197b27 100644
--- a/src/FlightMap/FlightMapSettings.cc
+++ b/src/FlightMap/FlightMapSettings.cc
@@ -43,7 +43,7 @@ void FlightMapSettings::setToolbox(QGCToolbox *toolbox)
qmlRegisterUncreatableType ("QGroundControl", 1, 0, "FlightMapSetting", "Reference only");
- _supportedMapProviders << "Bing" << "Google" << "OpenStreetMap";
+ _supportedMapProviders << "Bing" << "Google"; // << "OpenStreetMap";
_loadSettings();
}
@@ -93,8 +93,10 @@ void FlightMapSettings::_setMapTypesForCurrentProvider(void)
_mapTypes << "Street Map" << "Satellite Map" << "Hybrid Map";
} else if (_mapProvider == "Google") {
_mapTypes << "Street Map" << "Satellite Map" << "Terrain Map";
+ /*
} else if (_mapProvider == "OpenStreetMap") {
_mapTypes << "Street Map";
+ */
}
emit mapTypesChanged(_mapTypes);
diff --git a/src/QGCToolbox.cc b/src/QGCToolbox.cc
index c99f2e1b2edda333454e803fd2ee9f9a11b6f7ab..fa07e45390253bce5f607dda35b682b189e58b84 100644
--- a/src/QGCToolbox.cc
+++ b/src/QGCToolbox.cc
@@ -34,6 +34,7 @@
#include "MultiVehicleManager.h"
#include "QGCImageProvider.h"
#include "UASMessageHandler.h"
+#include "QGCMapEngineManager.h"
QGCToolbox::QGCToolbox(QGCApplication* app)
: _audioOutput(NULL)
@@ -48,6 +49,7 @@ QGCToolbox::QGCToolbox(QGCApplication* app)
, _mavlinkProtocol(NULL)
, _missionCommands(NULL)
, _multiVehicleManager(NULL)
+ , _mapEngineManager(NULL)
, _uasMessageHandler(NULL)
{
_audioOutput = new GAudioOutput(app);
@@ -62,6 +64,7 @@ QGCToolbox::QGCToolbox(QGCApplication* app)
_mavlinkProtocol = new MAVLinkProtocol(app);
_missionCommands = new MissionCommands(app);
_multiVehicleManager = new MultiVehicleManager(app);
+ _mapEngineManager = new QGCMapEngineManager(app);
_uasMessageHandler = new UASMessageHandler(app);
_audioOutput->setToolbox(this);
@@ -76,6 +79,7 @@ QGCToolbox::QGCToolbox(QGCApplication* app)
_mavlinkProtocol->setToolbox(this);
_missionCommands->setToolbox(this);
_multiVehicleManager->setToolbox(this);
+ _mapEngineManager->setToolbox(this);
_uasMessageHandler->setToolbox(this);
}
@@ -91,6 +95,7 @@ QGCToolbox::~QGCToolbox()
delete _linkManager;
delete _mavlinkProtocol;
delete _missionCommands;
+ delete _mapEngineManager;
delete _multiVehicleManager;
delete _uasMessageHandler;
}
diff --git a/src/QGCToolbox.h b/src/QGCToolbox.h
index d420067303ef12e093c79e63c9165fdf6166b246..348a0b7b0c87c8fd828093662891d53d961f20c7 100644
--- a/src/QGCToolbox.h
+++ b/src/QGCToolbox.h
@@ -37,6 +37,7 @@ class LinkManager;
class MAVLinkProtocol;
class MissionCommands;
class MultiVehicleManager;
+class QGCMapEngineManager;
class QGCApplication;
class QGCImageProvider;
class UASMessageHandler;
@@ -58,6 +59,7 @@ public:
MAVLinkProtocol* mavlinkProtocol(void) { return _mavlinkProtocol; }
MissionCommands* missionCommands(void) { return _missionCommands; }
MultiVehicleManager* multiVehicleManager(void) { return _multiVehicleManager; }
+ QGCMapEngineManager* mapEngineManager(void) { return _mapEngineManager; }
QGCImageProvider* imageProvider() { return _imageProvider; }
UASMessageHandler* uasMessageHandler(void) { return _uasMessageHandler; }
@@ -74,6 +76,7 @@ private:
MAVLinkProtocol* _mavlinkProtocol;
MissionCommands* _missionCommands;
MultiVehicleManager* _multiVehicleManager;
+ QGCMapEngineManager* _mapEngineManager;
UASMessageHandler* _uasMessageHandler;
};
diff --git a/src/QmlControls/OfflineMapButton.qml b/src/QmlControls/OfflineMapButton.qml
new file mode 100644
index 0000000000000000000000000000000000000000..ca819323bd78bef74c3ea925fd58bf265778d065
--- /dev/null
+++ b/src/QmlControls/OfflineMapButton.qml
@@ -0,0 +1,103 @@
+import QtQuick 2.5
+import QtQuick.Controls 1.2
+
+import QGroundControl.Palette 1.0
+import QGroundControl.ScreenTools 1.0
+
+Rectangle
+{
+ id: __mapButton
+
+ property var __qgcPal: QGCPalette { colorGroupEnabled: enabled }
+ property bool __showHighlight: (__pressed | __hovered | checked) && !__forceHoverOff
+
+ property bool __forceHoverOff: false
+ property int __lastGlobalMouseX: 0
+ property int __lastGlobalMouseY: 0
+ property bool __pressed: false
+ property bool __hovered: false
+
+ property bool checked: false
+ property bool complete: false
+ property alias text: nameLabel.text
+ property alias size: sizeLabel.text
+
+ signal clicked()
+
+ color: __showHighlight ? __qgcPal.buttonHighlight : __qgcPal.button
+ anchors.margins: ScreenTools.defaultFontPixelWidth
+ Row {
+ anchors.centerIn: parent
+ QGCLabel {
+ id: nameLabel
+ width: __mapButton.width * 0.4
+ color: __showHighlight ? __qgcPal.buttonHighlightText : __qgcPal.buttonText
+ anchors.verticalCenter: parent.verticalCenter
+ }
+ QGCLabel {
+ id: sizeLabel
+ width: __mapButton.width * 0.4
+ horizontalAlignment: Text.AlignRight
+ anchors.verticalCenter: parent.verticalCenter
+ color: __showHighlight ? __qgcPal.buttonHighlightText : __qgcPal.buttonText
+ }
+ Item {
+ width: ScreenTools.defaultFontPixelWidth * 2
+ height: 1
+ }
+ Rectangle {
+ width: sizeLabel.height * 0.5
+ height: sizeLabel.height * 0.5
+ radius: width / 2
+ color: complete ? "#31f55b" : "#fc5656"
+ opacity: sizeLabel.text.length > 0 ? 1 : 0
+ anchors.verticalCenter: parent.verticalCenter
+ }
+ Item {
+ width: ScreenTools.defaultFontPixelWidth * 2
+ height: 1
+ }
+ QGCColoredImage {
+ width: sizeLabel.height * 0.8
+ height: sizeLabel.height * 0.8
+ source: "/res/buttonRight.svg"
+ mipmap: true
+ fillMode: Image.PreserveAspectFit
+ color: __showHighlight ? __qgcPal.buttonHighlightText : __qgcPal.buttonText
+ anchors.verticalCenter: parent.verticalCenter
+ }
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ hoverEnabled: true
+ onMouseXChanged: {
+ __lastGlobalMouseX = ScreenTools.mouseX()
+ __lastGlobalMouseY = ScreenTools.mouseY()
+ }
+ onMouseYChanged: {
+ __lastGlobalMouseX = ScreenTools.mouseX()
+ __lastGlobalMouseY = ScreenTools.mouseY()
+ }
+ onEntered: { __hovered = true; __forceHoverOff = false; hoverTimer.start() }
+ onExited: { __hovered = false; __forceHoverOff = false; hoverTimer.stop() }
+ onPressed: { __pressed = true; }
+ onReleased: { __pressed = false; }
+ onClicked: {
+ __mapButton.clicked()
+ }
+ }
+
+ Timer {
+ id: hoverTimer
+ interval: 250
+ repeat: true
+ onTriggered: {
+ if (__lastGlobalMouseX !== ScreenTools.mouseX() || __lastGlobalMouseY !== ScreenTools.mouseY()) {
+ __forceHoverOff = true
+ } else {
+ __forceHoverOff = false
+ }
+ }
+ }
+}
diff --git a/src/QmlControls/QGroundControl.Controls.qmldir b/src/QmlControls/QGroundControl.Controls.qmldir
index 8992d4123ac97a539f70f6b1a69a3c238660e28c..05526e6b6c2932f1e6380fad5c22aeb11ecc25e4 100644
--- a/src/QmlControls/QGroundControl.Controls.qmldir
+++ b/src/QmlControls/QGroundControl.Controls.qmldir
@@ -35,3 +35,4 @@ SubMenuButton 1.0 SubMenuButton.qml
VehicleRotationCal 1.0 VehicleRotationCal.qml
VehicleSummaryRow 1.0 VehicleSummaryRow.qml
ViewWidget 1.0 ViewWidget.qml
+OfflineMapButton 1.0 OfflineMapButton.qml
diff --git a/src/QmlControls/QGroundControlQmlGlobal.cc b/src/QmlControls/QGroundControlQmlGlobal.cc
index 5c8afa2d87dc704b80e46bb60bd8514fd7342b20..1cc5f77348409456b542e80601d2398302d45eca 100644
--- a/src/QmlControls/QGroundControlQmlGlobal.cc
+++ b/src/QmlControls/QGroundControlQmlGlobal.cc
@@ -39,6 +39,7 @@ QGroundControlQmlGlobal::QGroundControlQmlGlobal(QGCApplication* app)
, _linkManager(NULL)
, _missionCommands(NULL)
, _multiVehicleManager(NULL)
+ , _mapEngineManager(NULL)
, _virtualTabletJoystick(false)
, _offlineEditingFirmwareTypeFact(QString(), "OfflineEditingFirmwareType", FactMetaData::valueTypeUint32, (uint32_t)MAV_AUTOPILOT_ARDUPILOTMEGA)
, _offlineEditingFirmwareTypeMetaData(FactMetaData::valueTypeUint32)
@@ -65,12 +66,12 @@ QGroundControlQmlGlobal::~QGroundControlQmlGlobal()
void QGroundControlQmlGlobal::setToolbox(QGCToolbox* toolbox)
{
QGCTool::setToolbox(toolbox);
-
- _flightMapSettings = toolbox->flightMapSettings();
- _homePositionManager = toolbox->homePositionManager();
- _linkManager = toolbox->linkManager();
- _missionCommands = toolbox->missionCommands();
- _multiVehicleManager = toolbox->multiVehicleManager();
+ _flightMapSettings = toolbox->flightMapSettings();
+ _homePositionManager = toolbox->homePositionManager();
+ _linkManager = toolbox->linkManager();
+ _missionCommands = toolbox->missionCommands();
+ _multiVehicleManager = toolbox->multiVehicleManager();
+ _mapEngineManager = toolbox->mapEngineManager();
}
diff --git a/src/QmlControls/QGroundControlQmlGlobal.h b/src/QmlControls/QGroundControlQmlGlobal.h
index 82d737d68f978fc62cf9ab8728bdef7936493247..0970cfa4e4e2ea37eeb8eaf94cf5e15926c85101 100644
--- a/src/QmlControls/QGroundControlQmlGlobal.h
+++ b/src/QmlControls/QGroundControlQmlGlobal.h
@@ -55,6 +55,7 @@ public:
Q_PROPERTY(LinkManager* linkManager READ linkManager CONSTANT)
Q_PROPERTY(MissionCommands* missionCommands READ missionCommands CONSTANT)
Q_PROPERTY(MultiVehicleManager* multiVehicleManager READ multiVehicleManager CONSTANT)
+ Q_PROPERTY(QGCMapEngineManager* mapEngineManager READ mapEngineManager CONSTANT)
Q_PROPERTY(qreal zOrderTopMost READ zOrderTopMost CONSTANT) ///< z order for top most items, toolbar, main window sub view
Q_PROPERTY(qreal zOrderWidgets READ zOrderWidgets CONSTANT) ///< z order value to widgets, for example: zoom controls, hud widgetss
@@ -96,9 +97,10 @@ public:
FlightMapSettings* flightMapSettings () { return _flightMapSettings; }
HomePositionManager* homePositionManager () { return _homePositionManager; }
- LinkManager* linkManager () { return _linkManager; }
- MissionCommands* missionCommands () { return _missionCommands; }
+ LinkManager* linkManager () { return _linkManager; }
+ MissionCommands* missionCommands () { return _missionCommands; }
MultiVehicleManager* multiVehicleManager () { return _multiVehicleManager; }
+ QGCMapEngineManager* mapEngineManager () { return _mapEngineManager; }
qreal zOrderTopMost () { return 1000; }
qreal zOrderWidgets () { return 100; }
@@ -151,6 +153,7 @@ private:
LinkManager* _linkManager;
MissionCommands* _missionCommands;
MultiVehicleManager* _multiVehicleManager;
+ QGCMapEngineManager* _mapEngineManager;
bool _virtualTabletJoystick;
diff --git a/src/QtLocationPlugin/OpenPilotMaps.cc b/src/QtLocationPlugin/OpenPilotMaps.cc
deleted file mode 100644
index 8816d85269f7195b0acd8a62921dcac6fff9e546..0000000000000000000000000000000000000000
--- a/src/QtLocationPlugin/OpenPilotMaps.cc
+++ /dev/null
@@ -1,511 +0,0 @@
-/*=====================================================================
-
-QGroundControl Open Source Ground Control Station
-
-(c) 2009, 2015 QGROUNDCONTROL PROJECT
-
-This file is part of the QGROUNDCONTROL project
-
- QGROUNDCONTROL is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- QGROUNDCONTROL is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with QGROUNDCONTROL. If not, see .
-
-======================================================================*/
-
-/**
- * @file
- * @brief QGC Open Pilot Mapping Tools
- * @author Gus Grubba
- * Original work: The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
- */
-
-#include
-#include
-#include
-#include
-
-#include "OpenPilotMaps.h"
-
-namespace OpenPilot {
-
-const QString ProviderStrings::kLevelsForSigPacSpainMap[] =
- { "0", "1", "2", "3", "4",
- "MTNSIGPAC",
- "MTN2000", "MTN2000", "MTN2000", "MTN2000", "MTN2000",
- "MTN200", "MTN200", "MTN200",
- "MTN25", "MTN25",
- "ORTOFOTOS", "ORTOFOTOS", "ORTOFOTOS", "ORTOFOTOS" };
-
-ProviderStrings::ProviderStrings()
-{
- // Google version strings
- VersionGoogleMap = "m@313";
- VersionGoogleSatellite = "s@177";
- VersionGoogleLabels = "h@313";
- VersionGoogleTerrain = "t@132,r@313";
- SecGoogleWord = "Galileo";
-
- // Google (China) version strings
- VersionGoogleMapChina = "m@132";
- VersionGoogleSatelliteChina = "s@71";
- VersionGoogleLabelsChina = "h@132";
- VersionGoogleTerrainChina = "t@125,r@132";
-
- // Google (Korea) version strings
- VersionGoogleMapKorea = "kr1.12";
- VersionGoogleSatelliteKorea = "66";
- VersionGoogleLabelsKorea = "kr1t.12";
-
- ///
- /// Google Maps API generated using http://greatmaps.codeplex.com/
- /// from http://code.google.com/intl/en-us/apis/maps/signup.html
- ///
- GoogleMapsAPIKey = "ABQIAAAAWaQgWiEBF3lW97ifKnAczhRAzBk5Igf8Z5n2W3hNnMT0j2TikxTLtVIGU7hCLLHMAuAMt-BO5UrEWA";
-
- // Yahoo version strings
- VersionYahooMap = "4.3";
- VersionYahooSatellite = "1.9";
- VersionYahooLabels = "4.3";
-
- // BingMaps
- VersionBingMaps = "563";
-
- // YandexMap
- VersionYandexMap = "2.16.0";
-
- ///
- /// Bing Maps Customer Identification, more info here
- /// http://msdn.microsoft.com/en-us/library/bb924353.aspx
- ///
- BingMapsClientToken = "";
-}
-
-UrlFactory::UrlFactory(QNetworkAccessManager *network)
- : _timeout(5 * 1000)
- , _googleVersionRetrieved(false)
- , _network(network)
- , _googleReply(NULL)
-{
-}
-
-UrlFactory::~UrlFactory()
-{
- if(_googleReply)
- _googleReply->deleteLater();
-}
-
-QString UrlFactory::_tileXYToQuadKey(const int& tileX, const int& tileY, const int& levelOfDetail) const
-{
- QString quadKey;
- for (int i = levelOfDetail; i > 0; i--) {
- char digit = '0';
- int mask = 1 << (i - 1);
- if ((tileX & mask) != 0) {
- digit++;
- }
- if ((tileY & mask) != 0) {
- digit++;
- digit++;
- }
- quadKey.append(digit);
- }
- return quadKey;
-}
-
-int UrlFactory::_getServerNum(const QPoint &pos, const int &max) const
-{
- return (pos.x() + 2 * pos.y()) % max;
-}
-
-void UrlFactory::_networkReplyError(QNetworkReply::NetworkError error)
-{
- qWarning() << "Could not connect to google maps. Error:" << error;
- if(_googleReply)
- {
- _googleReply->deleteLater();
- _googleReply = NULL;
- }
-}
-
-void UrlFactory::_replyDestroyed()
-{
- _googleReply = NULL;
-}
-
-void UrlFactory::_googleVersionCompleted()
-{
- if (!_googleReply || (_googleReply->error() != QNetworkReply::NoError)) {
- qDebug() << "Error collecting Google maps version info";
- return;
- }
- QString html = QString(_googleReply->readAll());
- QRegExp reg("\"*http://mts0.google.com/vt/lyrs=m@(\\d*)", Qt::CaseInsensitive);
- if (reg.indexIn(html) != -1) {
- QStringList gc = reg.capturedTexts();
- VersionGoogleMap = QString("m@%1").arg(gc[1]);
- VersionGoogleMapChina = VersionGoogleMap;
- VersionGoogleMapKorea = VersionGoogleMap;
- }
- reg = QRegExp("\"*http://mts0.google.com/vt/lyrs=h@(\\d*)", Qt::CaseInsensitive);
- if (reg.indexIn(html) != -1) {
- QStringList gc = reg.capturedTexts();
- VersionGoogleLabels = QString("h@%1").arg(gc[1]);
- VersionGoogleLabelsChina = VersionGoogleLabels;
- VersionGoogleLabelsKorea = VersionGoogleLabels;
- }
- reg = QRegExp("\"*http://khms0.google.com/kh/v=(\\d*)", Qt::CaseInsensitive);
- if (reg.indexIn(html) != -1) {
- QStringList gc = reg.capturedTexts();
- VersionGoogleSatellite = "s@" + gc[1];
- VersionGoogleSatelliteKorea = VersionGoogleSatellite;
- VersionGoogleSatelliteChina = VersionGoogleSatellite;
- }
- reg = QRegExp("\"*http://mts0.google.com/vt/lyrs=t@(\\d*),r@(\\d*)", Qt::CaseInsensitive);
- if (reg.indexIn(html) != -1) {
- QStringList gc = reg.capturedTexts();
- VersionGoogleTerrain = QString("t@%1,r@%2").arg(gc[1]).arg(gc[2]);
- VersionGoogleTerrainChina = VersionGoogleTerrain;
- VersionGoogleTerrainChina = VersionGoogleTerrain;
- }
- _googleReply->deleteLater();
- _googleReply = NULL;
-}
-
-void UrlFactory::_tryCorrectGoogleVersions()
-{
- QMutexLocker locker(&_googleVersionMutex);
- if (_googleVersionRetrieved) {
- return;
- }
- _googleVersionRetrieved = true;
- if(_network)
- {
- QNetworkRequest qheader;
- QNetworkProxy proxy = _network->proxy();
- QNetworkProxy tProxy;
- tProxy.setType(QNetworkProxy::NoProxy);
- _network->setProxy(tProxy);
- QString url = "http://maps.google.com/maps?output=classic";
- qheader.setUrl(QUrl(url));
-#if defined Q_OS_MAC
- QByteArray userAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:21.0) Gecko/20100101 Firefox/21.0";
-#elif defined Q_OS_WIN32
- QByteArray userAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7";
-#else
- QByteArray userAgent = "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:21.0) Gecko/20130331 Firefox/21.0";
-#endif
- qheader.setRawHeader("User-Agent", userAgent);
- _googleReply = _network->get(qheader);
- connect(_googleReply, &QNetworkReply::finished, this, &UrlFactory::_googleVersionCompleted);
- connect(_googleReply, &QNetworkReply::destroyed, this, &UrlFactory::_replyDestroyed);
-
- connect(_googleReply, static_cast(&QNetworkReply::error),
- this, &UrlFactory::_networkReplyError);
- _network->setProxy(proxy);
- }
-}
-
-QString UrlFactory::makeImageUrl(const MapType &type, const QPoint& pos, const int &zoom, const QString &language)
-{
- switch (type) {
- case GoogleMap:
- {
- // http://mt1.google.com/vt/lyrs=m
- QString server = "mt";
- QString request = "vt";
- QString sec1 = ""; // after &x=...
- QString sec2 = ""; // after &zoom=...
- _getSecGoogleWords(pos, sec1, sec2);
- _tryCorrectGoogleVersions();
- return QString("http://%1%2.google.com/%3/lyrs=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10&scale=2").arg(server).arg(_getServerNum(pos, 4)).arg(request).arg(VersionGoogleMap).arg(language).arg(pos.x()).arg(sec1).arg(pos.y()).arg(zoom).arg(sec2);
- }
- break;
- case GoogleSatellite:
- {
- // http://mt1.google.com/vt/lyrs=s
- QString server = "mt";
- QString request = "vt";
- QString sec1 = ""; // after &x=...
- QString sec2 = ""; // after &zoom=...
- _getSecGoogleWords(pos, sec1, sec2);
- _tryCorrectGoogleVersions();
- return QString("http://%1%2.google.com/%3/lyrs=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10&scale=2").arg(server).arg(_getServerNum(pos, 4)).arg(request).arg(VersionGoogleSatellite).arg(language).arg(pos.x()).arg(sec1).arg(pos.y()).arg(zoom).arg(sec2);
- }
- break;
- case GoogleLabels:
- {
- QString server = "mts";
- QString request = "vt";
- QString sec1 = ""; // after &x=...
- QString sec2 = ""; // after &zoom=...
- _getSecGoogleWords(pos, sec1, sec2);
- _tryCorrectGoogleVersions();
- return QString("http://%1%2.google.com/%3/lyrs=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(_getServerNum(pos, 4)).arg(request).arg(VersionGoogleLabels).arg(language).arg(pos.x()).arg(sec1).arg(pos.y()).arg(zoom).arg(sec2);
- }
- break;
- case GoogleTerrain:
- {
- QString server = "mts";
- QString request = "vt";
- QString sec1 = ""; // after &x=...
- QString sec2 = ""; // after &zoom=...
- _getSecGoogleWords(pos, sec1, sec2);
- _tryCorrectGoogleVersions();
- return QString("http://%1%2.google.com/%3/v=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10&scale=2").arg(server).arg(_getServerNum(pos, 4)).arg(request).arg(VersionGoogleTerrain).arg(language).arg(pos.x()).arg(sec1).arg(pos.y()).arg(zoom).arg(sec2);
- }
- break;
- case GoogleMapChina:
- {
- QString server = "mt";
- QString request = "vt";
- QString sec1 = ""; // after &x=...
- QString sec2 = ""; // after &zoom=...
- _getSecGoogleWords(pos, sec1, sec2);
- _tryCorrectGoogleVersions();
- // http://mt0.google.cn/vt/v=w2.101&hl=zh-CN&gl=cn&x=12&y=6&z=4&s=Ga
- return QString("http://%1%2.google.cn/%3/lyrs=%4&hl=%5&gl=cn&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(_getServerNum(pos, 4)).arg(request).arg(VersionGoogleMapChina).arg("zh-CN").arg(pos.x()).arg(sec1).arg(pos.y()).arg(zoom).arg(sec2);
- }
- break;
- case GoogleSatelliteChina:
- {
- QString server = "mt";
- QString request = "vt";
- QString sec1 = ""; // after &x=...
- QString sec2 = ""; // after &zoom=...
- _getSecGoogleWords(pos, sec1, sec2);
- _tryCorrectGoogleVersions();
- // http://khm0.google.cn/kh/v=46&x=12&y=6&z=4&s=Ga
- return QString("http://%1%2.google.cn/%3/lyrs=%4&gl=cn&x=%5%6&y=%7&z=%8&s=%9").arg(server).arg(_getServerNum(pos, 4)).arg(request).arg(VersionGoogleSatelliteChina).arg(pos.x()).arg(sec1).arg(pos.y()).arg(zoom).arg(sec2);
- }
- break;
- case GoogleLabelsChina:
- {
- QString server = "mt";
- QString request = "vt";
- QString sec1 = ""; // after &x=...
- QString sec2 = ""; // after &zoom=...
- _getSecGoogleWords(pos, sec1, sec2);
- _tryCorrectGoogleVersions();
- // http://mt0.google.cn/vt/v=w2t.110&hl=zh-CN&gl=cn&x=12&y=6&z=4&s=Ga
- return QString("http://%1%2.google.cn/%3/imgtp=png32&lyrs=%4&hl=%5&gl=cn&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(_getServerNum(pos, 4)).arg(request).arg(VersionGoogleLabelsChina).arg("zh-CN").arg(pos.x()).arg(sec1).arg(pos.y()).arg(zoom).arg(sec2);
- }
- break;
- case GoogleTerrainChina:
- {
- QString server = "mt";
- QString request = "vt";
- QString sec1 = ""; // after &x=...
- QString sec2 = ""; // after &zoom=...
- _getSecGoogleWords(pos, sec1, sec2);
- _tryCorrectGoogleVersions();
- // http://mt0.google.cn/vt/v=w2p.110&hl=zh-CN&gl=cn&x=12&y=6&z=4&s=Ga
- return QString("http://%1%2.google.com/%3/lyrs=%4&hl=%5&gl=cn&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(_getServerNum(pos, 4)).arg(request).arg(VersionGoogleTerrainChina).arg("zh-CN").arg(pos.x()).arg(sec1).arg(pos.y()).arg(zoom).arg(sec2);
- }
- break;
- case GoogleMapKorea:
- {
- QString server = "mts";
- QString request = "vt";
- QString sec1 = ""; // after &x=...
- QString sec2 = ""; // after &zoom=...
- _getSecGoogleWords(pos, sec1, sec2);
- _tryCorrectGoogleVersions();
- // http://mts0.google.com/vt/lyrs=m@224000000&hl=ko&gl=KR&src=app&x=107&y=50&z=7&s=Gal
- // http://mts0.google.com/mt/v=kr1.11&hl=ko&x=109&y=49&z=7&s=
- QString ret = QString("http://%1%2.google.com/%3/lyrs=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(_getServerNum(pos, 4)).arg(request).arg(VersionGoogleMapKorea).arg(language).arg(pos.x()).arg(sec1).arg(pos.y()).arg(zoom).arg(sec2);
- return ret;
- }
- break;
- case GoogleSatelliteKorea:
- {
- QString server = "khms";
- QString request = "kh";
- QString sec1 = ""; // after &x=...
- QString sec2 = ""; // after &zoom=...
- _getSecGoogleWords(pos, sec1, sec2);
- _tryCorrectGoogleVersions();
- // http://khm1.google.co.kr/kh/v=54&x=109&y=49&z=7&s=
- return QString("http://%1%2.google.co.kr/%3/v=%4&x=%5%6&y=%7&z=%8&s=%9").arg(server).arg(_getServerNum(pos, 4)).arg(request).arg(VersionGoogleSatelliteKorea).arg(pos.x()).arg(sec1).arg(pos.y()).arg(zoom).arg(sec2);
- }
- break;
- case GoogleLabelsKorea:
- {
- QString server = "mts";
- QString request = "mt";
- QString sec1 = ""; // after &x=...
- QString sec2 = ""; // after &zoom=...
- _getSecGoogleWords(pos, sec1, sec2);
- _tryCorrectGoogleVersions();
- // http://mts1.gmaptiles.co.kr/mt/v=kr1t.11&hl=lt&x=109&y=50&z=7&s=G
- return QString("http://%1%2.gmaptiles.co.kr/%3/v=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(_getServerNum(pos, 4)).arg(request).arg(VersionGoogleLabelsKorea).arg(language).arg(pos.x()).arg(sec1).arg(pos.y()).arg(zoom).arg(sec2);
- }
- break;
- case YahooMap:
- {
- return QString("http://maps%1.yimg.com/hx/tl?v=%2&.intl=%3&x=%4&y=%5&z=%6&r=1").arg(((_getServerNum(pos, 2)) + 1)).arg(VersionYahooMap).arg(language).arg(pos.x()).arg((((1 << zoom) >> 1) - 1 - pos.y())).arg((zoom + 1));
- }
- case YahooSatellite:
- {
- return QString("http://maps%1.yimg.com/ae/ximg?v=%2&t=a&s=256&.intl=%3&x=%4&y=%5&z=%6&r=1").arg("3").arg(VersionYahooSatellite).arg(language).arg(pos.x()).arg(((1 << zoom) >> 1) - 1 - pos.y()).arg(zoom + 1);
- }
- break;
- case YahooLabels:
- {
- return QString("http://maps%1.yimg.com/hx/tl?v=%2&t=h&.intl=%3&x=%4&y=%5&z=%6&r=1").arg("1").arg(VersionYahooLabels).arg(language).arg(pos.x()).arg(((1 << zoom) >> 1) - 1 - pos.y()).arg(zoom + 1);
- }
- break;
- case OpenStreetMap:
- {
- char letter = "abc"[_getServerNum(pos, 3)];
- return QString("http://%1.tile.openstreetmap.org/%2/%3/%4.png").arg(letter).arg(zoom).arg(pos.x()).arg(pos.y());
- }
- break;
- case OpenStreetOsm:
- {
- char letter = "abc"[_getServerNum(pos, 3)];
- return QString("http://%1.tah.openstreetmap.org/Tiles/tile/%2/%3/%4.png").arg(letter).arg(zoom).arg(pos.x()).arg(pos.y());
- }
- break;
- case OpenStreetMapSurfer:
- {
- // http://tiles1.mapsurfer.net/tms_r.ashx?x=37378&y=20826&z=16
- return QString("http://tiles1.mapsurfer.net/tms_r.ashx?x=%1&y=%2&z=%3").arg(pos.x()).arg(pos.y()).arg(zoom);
- }
- break;
- case OpenStreetMapSurferTerrain:
- {
- // http://tiles2.mapsurfer.net/tms_t.ashx?x=9346&y=5209&z=14
- return QString("http://tiles2.mapsurfer.net/tms_t.ashx?x=%1&y=%2&z=%3").arg(pos.x()).arg(pos.y()).arg(zoom);
- }
- break;
- case BingMap:
- {
- QString key = _tileXYToQuadKey(pos.x(), pos.y(), zoom);
- return QString("http://ecn.t%1.tiles.virtualearth.net/tiles/r%2.png?g=%3&mkt=%4%5").arg(_getServerNum(pos, 4)).arg(key).arg(VersionBingMaps).arg(language).arg(!(BingMapsClientToken.isNull() | BingMapsClientToken.isEmpty()) ? "&token=" + BingMapsClientToken : QString(""));
- }
- break;
- case BingSatellite:
- {
- QString key = _tileXYToQuadKey(pos.x(), pos.y(), zoom);
- return QString("http://ecn.t%1.tiles.virtualearth.net/tiles/a%2.jpeg?g=%3&mkt=%4%5").arg(_getServerNum(pos, 4)).arg(key).arg(VersionBingMaps).arg(language).arg(!(BingMapsClientToken.isNull() | BingMapsClientToken.isEmpty()) ? "&token=" + BingMapsClientToken : QString(""));
- }
- break;
- case BingHybrid:
- {
- QString key = _tileXYToQuadKey(pos.x(), pos.y(), zoom);
- return QString("http://ecn.t%1.tiles.virtualearth.net/tiles/h%2.jpeg?g=%3&mkt=%4%5").arg(_getServerNum(pos, 4)).arg(key).arg(VersionBingMaps).arg(language).arg(!(BingMapsClientToken.isNull() | BingMapsClientToken.isEmpty()) ? "&token=" + BingMapsClientToken : QString(""));
- }
- case ArcGIS_Map:
- {
- // http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer/tile/0/0/0.jpg
- return QString("http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer/tile/%1/%2/%3").arg(zoom).arg(pos.y()).arg(pos.x());
- }
- break;
- case ArcGIS_Satellite:
- {
- // http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_Imagery_World_2D/MapServer/tile/1/0/1.jpg
- return QString("http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_Imagery_World_2D/MapServer/tile/%1/%2/%3").arg(zoom).arg(pos.y()).arg(pos.x());
- }
- break;
- case ArcGIS_ShadedRelief:
- {
- // http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_ShadedRelief_World_2D/MapServer/tile/1/0/1.jpg
- return QString("http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_ShadedRelief_World_2D/MapServer/tile/%1/%2/%3").arg(zoom).arg(pos.y()).arg(pos.x());
- }
- break;
- case ArcGIS_Terrain:
- {
- // http://server.arcgisonline.com/ArcGIS/rest/services/NGS_Topo_US_2D/MapServer/tile/4/3/15
- return QString("http://server.arcgisonline.com/ArcGIS/rest/services/NGS_Topo_US_2D/MapServer/tile/%1/%2/%3").arg(zoom).arg(pos.y()).arg(pos.x());
- }
- break;
- case ArcGIS_MapsLT_OrtoFoto:
- {
- // http://www.maps.lt/ortofoto/mapslt_ortofoto_vector_512/map/_alllayers/L02/R0000001b/C00000028.jpg
- // http://arcgis.maps.lt/ArcGIS/rest/services/mapslt_ortofoto/MapServer/tile/0/9/13
- // return string.Format("http://www.maps.lt/ortofoto/mapslt_ortofoto_vector_512/map/_alllayers/L{0:00}/R{1:x8}/C{2:x8}.jpg", zoom, pos.y(), pos.x());
- // http://dc1.maps.lt/cache/mapslt_ortofoto_512/map/_alllayers/L03/R0000001c/C00000029.jpg
- // return string.Format("http://arcgis.maps.lt/ArcGIS/rest/services/mapslt_ortofoto/MapServer/tile/{0}/{1}/{2}", zoom, pos.y(), pos.x());
- // http://dc1.maps.lt/cache/mapslt_ortofoto_512/map/_alllayers/L03/R0000001d/C0000002a.jpg
- // TODO verificar
- return QString("http://dc1.maps.lt/cache/mapslt_ortofoto/map/_alllayers/L%1/R%2/C%3.jpg").arg(zoom, 2, 10, (QChar)'0').arg(pos.y(), 8, 16, (QChar)'0').arg(pos.x(), 8, 16, (QChar)'0');
- }
- break;
- case ArcGIS_MapsLT_Map:
- {
- // http://www.maps.lt/ortofoto/mapslt_ortofoto_vector_512/map/_alllayers/L02/R0000001b/C00000028.jpg
- // http://arcgis.maps.lt/ArcGIS/rest/services/mapslt_ortofoto/MapServer/tile/0/9/13
- // return string.Format("http://www.maps.lt/ortofoto/mapslt_ortofoto_vector_512/map/_alllayers/L{0:00}/R{1:x8}/C{2:x8}.jpg", zoom, pos.y(), pos.x());
- // http://arcgis.maps.lt/ArcGIS/rest/services/mapslt/MapServer/tile/7/1162/1684.png
- // http://dc1.maps.lt/cache/mapslt_512/map/_alllayers/L03/R0000001b/C00000029.png
- // TODO verificar
- // http://dc1.maps.lt/cache/mapslt/map/_alllayers/L02/R0000001c/C00000029.png
- return QString("http://dc1.maps.lt/cache/mapslt/map/_alllayers/L%1/R%2/C%3.png").arg(zoom, 2, 10, (QChar)'0').arg(pos.y(), 8, 16, (QChar)'0').arg(pos.x(), 8, 16, (QChar)'0');
- }
- break;
- case ArcGIS_MapsLT_Map_Labels:
- {
- // http://arcgis.maps.lt/ArcGIS/rest/services/mapslt_ortofoto_overlay/MapServer/tile/0/9/13
- // return string.Format("http://arcgis.maps.lt/ArcGIS/rest/services/mapslt_ortofoto_overlay/MapServer/tile/{0}/{1}/{2}", zoom, pos.y(), pos.x());
- // http://dc1.maps.lt/cache/mapslt_ortofoto_overlay_512/map/_alllayers/L03/R0000001d/C00000029.png
- // TODO verificar
- return QString("http://dc1.maps.lt/cache/mapslt_ortofoto_overlay/map/_alllayers/L%1/R%2/C%3.png").arg(zoom, 2, 10, (QChar)'0').arg(pos.y(), 8, 16, (QChar)'0').arg(pos.x(), 8, 16, (QChar)'0');
- }
- break;
- case PergoTurkeyMap:
- {
- // http://{domain}/{layerName}/{zoomLevel}/{first3LetterOfTileX}/{second3LetterOfTileX}/{third3LetterOfTileX}/{first3LetterOfTileY}/{second3LetterOfTileY}/{third3LetterOfTileXY}.png
- // http://map3.pergo.com.tr/tile/00/000/000/001/000/000/000.png
- // That means: Zoom Level: 0 TileX: 1 TileY: 0
- // http://domain/tile/14/000/019/371/000/011/825.png
- // That means: Zoom Level: 14 TileX: 19371 TileY:11825
- // string x = pos.x().ToString("000000000").Insert(3, "/").Insert(7, "/"); // - 000/000/001
- // string y = pos.y().ToString("000000000").Insert(3, "/").Insert(7, "/"); // - 000/000/000
- QString x = QString("%1").arg(QString::number(pos.x()), 9, (QChar)'0');
- x.insert(3, "/").insert(7, "/");
- QString y = QString("%1").arg(QString::number(pos.y()), 9, (QChar)'0');
- y.insert(3, "/").insert(7, "/");
- // "http://map03.pergo.com.tr/tile/2/000/000/003/000/000/002.png"
- return QString("http://map%1.pergo.com.tr/tile/%2/%3/%4.png").arg(_getServerNum(pos, 4)).arg(zoom, 2, 10, (QChar)'0').arg(x).arg(y);
- }
- break;
- case SigPacSpainMap:
- {
- return QString("http://sigpac.mapa.es/kmlserver/raster/%1@3785/%2.%3.%4.img").arg(kLevelsForSigPacSpainMap[zoom]).arg(zoom).arg(pos.x()).arg((2 << (zoom - 1)) - pos.y() - 1);
- }
- break;
- case YandexMapRu:
- {
- QString server = "vec";
- // http://vec01.maps.yandex.ru/tiles?l=map&v=2.10.2&x=1494&y=650&z=11
- return QString("http://%1").arg(server) + QString("0%2.maps.yandex.ru/tiles?l=map&v=%3&x=%4&y=%5&z=%6").arg(_getServerNum(pos, 4) + 1).arg(VersionYandexMap).arg(pos.x()).arg(pos.y()).arg(zoom);
- }
- break;
- default:
- qWarning("Unknown map id %d\n", type);
- break;
- }
- return QString::null;
-}
-
-void UrlFactory::_getSecGoogleWords(const QPoint &pos, QString &sec1, QString &sec2)
-{
- sec1 = ""; // after &x=...
- sec2 = ""; // after &zoom=...
- int seclen = ((pos.x() * 3) + pos.y()) % 8;
- sec2 = SecGoogleWord.left(seclen);
- if (pos.y() >= 10000 && pos.y() < 100000) {
- sec1 = "&s=";
- }
-}
-
-}
diff --git a/src/QtLocationPlugin/OpenPilotMaps.h b/src/QtLocationPlugin/OpenPilotMaps.h
deleted file mode 100644
index a8fc609ded8214c5c5fc3b0acda5bb61fab851bf..0000000000000000000000000000000000000000
--- a/src/QtLocationPlugin/OpenPilotMaps.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/*=====================================================================
-
-QGroundControl Open Source Ground Control Station
-
-(c) 2009, 2015 QGROUNDCONTROL PROJECT
-
-This file is part of the QGROUNDCONTROL project
-
- QGROUNDCONTROL is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- QGROUNDCONTROL is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with QGROUNDCONTROL. If not, see .
-
-======================================================================*/
-
-/**
- * @file
- * @brief QGC Open Pilot Mapping Tools
- * @author Gus Grubba
- * Original work: The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
- */
-
-#ifndef OPENPILOTTOOLS_H
-#define OPENPILOTTOOLS_H
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-#define MAX_MAP_ZOOM (20.0)
-
-namespace OpenPilot {
-
-enum MapType
-{
- GoogleMap = 1,
- GoogleSatellite = 4,
- GoogleLabels = 8,
- GoogleTerrain = 16,
- GoogleHybrid = 20,
-
- GoogleMapChina = 22,
- GoogleSatelliteChina = 24,
- GoogleLabelsChina = 26,
- GoogleTerrainChina = 28,
- GoogleHybridChina = 29,
-
- OpenStreetMap = 32,
- OpenStreetOsm = 33,
- OpenStreetMapSurfer = 34,
- OpenStreetMapSurferTerrain=35,
-
- YahooMap = 64,
- YahooSatellite = 128,
- YahooLabels = 256,
- YahooHybrid = 333,
-
- BingMap = 444,
- BingSatellite = 555,
- BingHybrid = 666,
-
- ArcGIS_Map = 777,
- ArcGIS_Satellite = 788,
- ArcGIS_ShadedRelief = 799,
- ArcGIS_Terrain = 811,
-
- ArcGIS_MapsLT_Map = 1000,
- ArcGIS_MapsLT_OrtoFoto = 1001,
- ArcGIS_MapsLT_Map_Labels= 1002,
- ArcGIS_MapsLT_Map_Hybrid= 1003,
-
- PergoTurkeyMap = 2001,
- SigPacSpainMap = 3001,
-
- GoogleMapKorea = 4001,
- GoogleSatelliteKorea = 4002,
- GoogleLabelsKorea = 4003,
- GoogleHybridKorea = 4005,
-
- YandexMapRu = 5000
-};
-
-class ProviderStrings : public QObject {
- Q_OBJECT
-public:
- ProviderStrings();
- static const QString kLevelsForSigPacSpainMap[];
- QString GoogleMapsAPIKey;
- // Google version strings
- QString VersionGoogleMap;
- QString VersionGoogleSatellite;
- QString VersionGoogleLabels;
- QString VersionGoogleTerrain;
- QString SecGoogleWord;
- // Google (China) version strings
- QString VersionGoogleMapChina;
- QString VersionGoogleSatelliteChina;
- QString VersionGoogleLabelsChina;
- QString VersionGoogleTerrainChina;
- // Google (Korea) version strings
- QString VersionGoogleMapKorea;
- QString VersionGoogleSatelliteKorea;
- QString VersionGoogleLabelsKorea;
- ///
- /// Google Maps API generated using http://greatmaps.codeplex.com/
- /// from http://code.google.com/intl/en-us/apis/maps/signup.html
- ///
- // Yahoo version strings
- QString VersionYahooMap;
- QString VersionYahooSatellite;
- QString VersionYahooLabels;
- // BingMaps
- QString VersionBingMaps;
- // YandexMap
- QString VersionYandexMap;
- ///
- /// Bing Maps Customer Identification, more info here
- /// http://msdn.microsoft.com/en-us/library/bb924353.aspx
- ///
- QString BingMapsClientToken;
-};
-
-class UrlFactory : public ProviderStrings {
- Q_OBJECT
-public:
-
- UrlFactory(QNetworkAccessManager* network);
- ~UrlFactory();
-
- QString makeImageUrl (const MapType &type, const QPoint &pos, const int &zoom, const QString &language);
-
-private slots:
- void _networkReplyError (QNetworkReply::NetworkError error);
- void _googleVersionCompleted ();
- void _replyDestroyed ();
-
-private:
- void _getSecGoogleWords (const QPoint &pos, QString &sec1, QString &sec2);
- int _getServerNum (const QPoint& pos, const int &max) const;
- void _tryCorrectGoogleVersions ();
- QString _tileXYToQuadKey (const int &tileX, const int &tileY, const int &levelOfDetail) const;
-
- int _timeout;
- bool _googleVersionRetrieved;
- QNetworkAccessManager* _network;
- QNetworkReply* _googleReply;
- QMutex _googleVersionMutex;
- QByteArray _userAgent;
-};
-
-}
-
-#endif // FOO_H
diff --git a/src/QtLocationPlugin/QGCLocationPlugin.pri b/src/QtLocationPlugin/QGCLocationPlugin.pri
index d0673c45f3b0bacc10559a8ef5f7cb94cf3dfbe3..9e44cae4f498d6c4bc61194b54d5d5bdb90df2b8 100644
--- a/src/QtLocationPlugin/QGCLocationPlugin.pri
+++ b/src/QtLocationPlugin/QGCLocationPlugin.pri
@@ -17,22 +17,29 @@ contains(QT_VERSION, 5.5.1) {
}
HEADERS += \
- $$PWD/qgeoserviceproviderpluginqgc.h \
- $$PWD/qgeotiledmappingmanagerengineqgc.h \
- $$PWD/qgeotilefetcherqgc.h \
- $$PWD/qgeomapreplyqgc.h \
- $$PWD/qgeocodingmanagerengineqgc.h \
- $$PWD/qgeocodereplyqgc.h \
- $$PWD/OpenPilotMaps.h
+ $$PWD/QGCMapEngine.h \
+ $$PWD/QGCMapEngineData.h \
+ $$PWD/QGCMapTileSet.h \
+ $$PWD/QGCMapUrlEngine.h \
+ $$PWD/QGCTileCacheWorker.h \
+ $$PWD/QGeoCodeReplyQGC.h \
+ $$PWD/QGeoCodingManagerEngineQGC.h \
+ $$PWD/QGeoMapReplyQGC.h \
+ $$PWD/QGeoServiceProviderPluginQGC.h \
+ $$PWD/QGeoTileFetcherQGC.h \
+ $$PWD/QGeoTiledMappingManagerEngineQGC.h \
SOURCES += \
- $$PWD/qgeoserviceproviderpluginqgc.cpp \
- $$PWD/qgeotiledmappingmanagerengineqgc.cpp \
- $$PWD/qgeotilefetcherqgc.cpp \
- $$PWD/qgeomapreplyqgc.cpp \
- $$PWD/qgeocodingmanagerengineqgc.cpp \
- $$PWD/qgeocodereplyqgc.cpp \
- $$PWD/OpenPilotMaps.cc
+ $$PWD/QGCMapEngine.cpp \
+ $$PWD/QGCMapTileSet.cpp \
+ $$PWD/QGCMapUrlEngine.cpp \
+ $$PWD/QGCTileCacheWorker.cpp \
+ $$PWD/QGeoCodeReplyQGC.cpp \
+ $$PWD/QGeoCodingManagerEngineQGC.cpp \
+ $$PWD/QGeoMapReplyQGC.cpp \
+ $$PWD/QGeoServiceProviderPluginQGC.cpp \
+ $$PWD/QGeoTileFetcherQGC.cpp \
+ $$PWD/QGeoTiledMappingManagerEngineQGC.cpp \
OTHER_FILES += \
$$PWD/qgc_maps_plugin.json
diff --git a/src/QtLocationPlugin/QGCMapEngine.cpp b/src/QtLocationPlugin/QGCMapEngine.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d093f3b2c167f4f1fdb96c3dae1cefa0862adbaa
--- /dev/null
+++ b/src/QtLocationPlugin/QGCMapEngine.cpp
@@ -0,0 +1,432 @@
+/*=====================================================================
+
+QGroundControl Open Source Ground Control Station
+
+(c) 2009, 2016 QGROUNDCONTROL PROJECT
+
+This file is part of the QGROUNDCONTROL project
+
+ QGROUNDCONTROL is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ QGROUNDCONTROL is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QGROUNDCONTROL. If not, see .
+
+======================================================================*/
+
+/**
+ * @file
+ * @brief Map Tile Cache
+ *
+ * @author Gus Grubba
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#include "QGCMapEngine.h"
+#include "QGCMapTileSet.h"
+
+Q_DECLARE_METATYPE(QGCMapTask::TaskType)
+Q_DECLARE_METATYPE(QGCTile)
+Q_DECLARE_METATYPE(QList)
+
+static const char* kDbFileName = "qgcMapCache.db";
+static QLocale kLocale;
+
+struct stQGeoTileCacheQGCMapTypes {
+ const char* name;
+ UrlFactory::MapType type;
+};
+
+//-- IMPORTANT
+// Changes here must reflect those in QGeoTiledMappingManagerEngineQGC.cpp
+
+stQGeoTileCacheQGCMapTypes kMapTypes[] = {
+ {"Google Street Map", UrlFactory::GoogleMap},
+ {"Google Satellite Map", UrlFactory::GoogleSatellite},
+ {"Google Terrain Map", UrlFactory::GoogleTerrain},
+ {"Bing Street Map", UrlFactory::BingMap},
+ {"Bing Satellite Map", UrlFactory::BingSatellite},
+ {"Bing Hybrid Map", UrlFactory::BingHybrid},
+ {"MapQuest Street Map", UrlFactory::MapQuestMap},
+ {"MapQuest Satellite Map", UrlFactory::MapQuestSat}
+ /*
+ {"Open Street Map", UrlFactory::OpenStreetMap}
+ */
+};
+
+#define NUM_MAPS (sizeof(kMapTypes) / sizeof(stQGeoTileCacheQGCMapTypes))
+
+stQGeoTileCacheQGCMapTypes kMapBoxTypes[] = {
+ {"MapBox Street Map", UrlFactory::MapBoxStreets},
+ {"MapBox Satellite Map", UrlFactory::MapBoxSatellite},
+ {"MapBox High Contrast Map",UrlFactory::MapBoxHighContrast},
+ {"MapBox Light Map", UrlFactory::MapBoxLight},
+ {"MapBox Dark Map", UrlFactory::MapBoxDark},
+ {"MapBox Hybrid Map", UrlFactory::MapBoxHybrid},
+ {"MapBox Wheat Paste Map", UrlFactory::MapBoxWheatPaste},
+ {"MapBox Streets Basic Map",UrlFactory::MapBoxStreetsBasic},
+ {"MapBox Comic Map", UrlFactory::MapBoxComic},
+ {"MapBox Outdoors Map", UrlFactory::MapBoxOutdoors},
+ {"MapBox Run, Byke and Hike Map", UrlFactory::MapBoxRunBikeHike},
+ {"MapBox Pencil Map", UrlFactory::MapBoxPencil},
+ {"MapBox Pirates Map", UrlFactory::MapBoxPirates},
+ {"MapBox Emerald Map", UrlFactory::MapBoxEmerald}
+};
+
+#define NUM_MAPBOXMAPS (sizeof(kMapBoxTypes) / sizeof(stQGeoTileCacheQGCMapTypes))
+
+static const char* kMapBoxTokenKey = "MapBoxToken";
+static const char* kMaxDiskCacheKey = "MaxDiskCache";
+static const char* kMaxMemCacheKey = "MaxMemoryCache";
+
+//-----------------------------------------------------------------------------
+// Singleton
+static QGCMapEngine* kMapEngine = NULL;
+QGCMapEngine*
+getQGCMapEngine()
+{
+ if(!kMapEngine)
+ kMapEngine = new QGCMapEngine();
+ return kMapEngine;
+}
+
+//-----------------------------------------------------------------------------
+void
+destroyMapEngine()
+{
+ if(kMapEngine) {
+ delete kMapEngine;
+ kMapEngine = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+QGCMapEngine::QGCMapEngine()
+ : _urlFactory(new UrlFactory())
+#ifdef WE_ARE_KOSHER
+ //-- TODO: Get proper version
+ #if defined Q_OS_MAC
+ , _userAgent("QGroundControl (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.75.14 (KHTML, like Gecko) Version/2.9.0")
+ #elif defined Q_OS_WIN32
+ , _userAgent("QGroundControl (Windows; Windows NT 6.0) (KHTML, like Gecko) Version/2.9.0")
+ #else
+ , _userAgent("QGroundControl (X11; Ubuntu; Linux x86_64) (KHTML, like Gecko) Version/2.9.0")
+ #endif
+#else
+ #if defined Q_OS_MAC
+ , _userAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:25.0) Gecko/20100101 Firefox/25.0")
+ #elif defined Q_OS_WIN32
+ , _userAgent("Mozilla/5.0 (Windows NT 6.1; WOW64; rv:31.0) Gecko/20130401 Firefox/31.0")
+ #else
+ , _userAgent("Mozilla/5.0 (X11; Linux i586; rv:31.0) Gecko/20100101 Firefox/31.0")
+ #endif
+#endif
+ , _maxDiskCache(0)
+ , _maxMemCache(0)
+ , _prunning(false)
+{
+ qRegisterMetaType();
+ qRegisterMetaType();
+ qRegisterMetaType>();
+ connect(&_worker, &QGCCacheWorker::updateTotals, this, &QGCMapEngine::_updateTotals);
+}
+
+//-----------------------------------------------------------------------------
+QGCMapEngine::~QGCMapEngine()
+{
+ _worker.quit();
+ _worker.wait();
+ if(_urlFactory)
+ delete _urlFactory;
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCMapEngine::init()
+{
+#ifdef __mobile__
+ QString cacheDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QLatin1String("/QGCMapCache55");
+#else
+ QString cacheDir = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + QLatin1String("/QGCMapCache55");
+#endif
+ if(!QDir::root().mkpath(cacheDir)) {
+ qWarning() << "Could not create mapping disk cache directory: " << cacheDir;
+ cacheDir = QDir::homePath() + QLatin1String("/.qgcmapscache/");
+ if(!QDir::root().mkpath(cacheDir)) {
+ qWarning() << "Could not create mapping disk cache directory: " << cacheDir;
+ cacheDir.clear();
+ }
+ }
+ _cachePath = cacheDir;
+ if(!_cachePath.isEmpty()) {
+ _cacheFile = kDbFileName;
+ _worker.setDatabaseFile(_cachePath + "/" + _cacheFile);
+ qDebug() << "Map Cache in:" << _cachePath << "/" << _cacheFile;
+ } else {
+ qCritical() << "Could not find suitable map cache directory.";
+ }
+ QGCMapTask* task = new QGCMapTask(QGCMapTask::taskInit);
+ _worker.enqueueTask(task);
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCMapEngine::addTask(QGCMapTask* task)
+{
+ _worker.enqueueTask(task);
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCMapEngine::cacheTile(UrlFactory::MapType type, int x, int y, int z, const QByteArray& image, const QString &format, qulonglong set)
+{
+ QString hash = getTileHash(type, x, y, z);
+ cacheTile(type, hash, image, format, set);
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCMapEngine::cacheTile(UrlFactory::MapType type, const QString& hash, const QByteArray& image, const QString& format, qulonglong set)
+{
+ QGCSaveTileTask* task = new QGCSaveTileTask(new QGCCacheTile(hash, image, format, type, set));
+ _worker.enqueueTask(task);
+}
+
+//-----------------------------------------------------------------------------
+QString
+QGCMapEngine::getTileHash(UrlFactory::MapType type, int x, int y, int z)
+{
+ return QString().sprintf("%04d%08d%08d%03d", (int)type, x, y, z);
+}
+
+//-----------------------------------------------------------------------------
+UrlFactory::MapType
+QGCMapEngine::hashToType(const QString& hash)
+{
+ QString type = hash.mid(0,4);
+ return (UrlFactory::MapType)type.toInt();
+}
+
+//-----------------------------------------------------------------------------
+QGCFetchTileTask*
+QGCMapEngine::createFetchTileTask(UrlFactory::MapType type, int x, int y, int z)
+{
+ QString hash = getTileHash(type, x, y, z);
+ QGCFetchTileTask* task = new QGCFetchTileTask(hash);
+ return task;
+}
+
+//-----------------------------------------------------------------------------
+QGCTileSet
+QGCMapEngine::getTileCount(int zoom, double topleftLon, double topleftLat, double bottomRightLon, double bottomRightLat, UrlFactory::MapType mapType)
+{
+ if(zoom < 1) zoom = 1;
+ if(zoom > 18) zoom = 18;
+ QGCTileSet set;
+ set.tileX0 = long2tileX(topleftLon, zoom);
+ set.tileY0 = lat2tileY(topleftLat, zoom);
+ set.tileX1 = long2tileX(bottomRightLon, zoom);
+ set.tileY1 = lat2tileY(bottomRightLat, zoom);
+ set.tileCount = (quint64)((quint64)set.tileX1 - (quint64)set.tileX0 + 1) * (quint64)((quint64)set.tileY1 - (quint64)set.tileY0 + 1);
+ set.tileSize = UrlFactory::averageSizeForType(mapType) * set.tileCount;
+ return set;
+}
+
+//-----------------------------------------------------------------------------
+int
+QGCMapEngine::long2tileX(double lon, int z)
+{
+ return (int)(floor((lon + 180.0) / 360.0 * pow(2.0, z)));
+}
+
+//-----------------------------------------------------------------------------
+int
+QGCMapEngine::lat2tileY(double lat, int z)
+{
+ return (int)(floor((1.0 - log( tan(lat * M_PI/180.0) + 1.0 / cos(lat * M_PI/180.0)) / M_PI) / 2.0 * pow(2.0, z)));
+}
+
+//-----------------------------------------------------------------------------
+UrlFactory::MapType
+QGCMapEngine::getTypeFromName(const QString& name)
+{
+ size_t i;
+ for(i = 0; i < NUM_MAPS; i++) {
+ if(name.compare(kMapTypes[i].name, Qt::CaseInsensitive) == 0)
+ return kMapTypes[i].type;
+ }
+ for(i = 0; i < NUM_MAPBOXMAPS; i++) {
+ if(name.compare(kMapBoxTypes[i].name, Qt::CaseInsensitive) == 0)
+ return kMapBoxTypes[i].type;
+ }
+ return UrlFactory::Invalid;
+}
+
+//-----------------------------------------------------------------------------
+QStringList
+QGCMapEngine::getMapNameList()
+{
+ QStringList mapList;
+ for(size_t i = 0; i < NUM_MAPS; i++) {
+ mapList << kMapTypes[i].name;
+ }
+ if(!getMapBoxToken().isEmpty()) {
+ for(size_t i = 0; i < NUM_MAPBOXMAPS; i++) {
+ mapList << kMapBoxTypes[i].name;
+ }
+ }
+ return mapList;
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCMapEngine::setMapBoxToken(const QString& token)
+{
+ QSettings settings;
+ settings.setValue(kMapBoxTokenKey, token);
+ _mapBoxToken = token;
+}
+
+//-----------------------------------------------------------------------------
+QString
+QGCMapEngine::getMapBoxToken()
+{
+ if(_mapBoxToken.isEmpty()) {
+ QSettings settings;
+ _mapBoxToken = settings.value(kMapBoxTokenKey).toString();
+ }
+ return _mapBoxToken;
+}
+
+//-----------------------------------------------------------------------------
+quint32
+QGCMapEngine::getMaxDiskCache()
+{
+ if(!_maxDiskCache) {
+ QSettings settings;
+ _maxDiskCache = settings.value(kMaxDiskCacheKey, 1024).toUInt();
+ }
+ return _maxDiskCache;
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCMapEngine::setMaxDiskCache(quint32 size)
+{
+ QSettings settings;
+ settings.setValue(kMaxDiskCacheKey, size);
+ _maxDiskCache = size;
+}
+
+//-----------------------------------------------------------------------------
+quint32
+QGCMapEngine::getMaxMemCache()
+{
+ if(!_maxMemCache) {
+ QSettings settings;
+#ifdef __mobile__
+ _maxMemCache = settings.value(kMaxMemCacheKey, 16).toUInt();
+#else
+ _maxMemCache = settings.value(kMaxMemCacheKey, 128).toUInt();
+#endif
+ }
+ return _maxMemCache;
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCMapEngine::setMaxMemCache(quint32 size)
+{
+ QSettings settings;
+ settings.setValue(kMaxMemCacheKey, size);
+ _maxMemCache = size;
+}
+
+//-----------------------------------------------------------------------------
+QString
+QGCMapEngine::bigSizeToString(quint64 size)
+{
+ if(size < 1024)
+ return kLocale.toString(size);
+ else if(size < 1024 * 1024)
+ return kLocale.toString((double)size / 1024.0, 'f', 1) + "kB";
+ else if(size < 1024 * 1024 * 1024)
+ return kLocale.toString((double)size / (1024.0 * 1024.0), 'f', 1) + "MB";
+ else if(size < 1024.0 * 1024.0 * 1024.0 * 1024.0)
+ return kLocale.toString((double)size / (1024.0 * 1024.0 * 1024.0), 'f', 1) + "GB";
+ else
+ return kLocale.toString((double)size / (1024.0 * 1024.0 * 1024.0 * 1024), 'f', 1) + "TB";
+}
+
+//-----------------------------------------------------------------------------
+QString
+QGCMapEngine::numberToString(quint32 number)
+{
+ return kLocale.toString(number);
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCMapEngine::_updateTotals(quint32 totaltiles, quint64 totalsize, quint32 defaulttiles, quint64 defaultsize)
+{
+ emit updateTotals(totaltiles, totalsize, defaulttiles, defaultsize);
+ quint64 maxSize = getMaxDiskCache() * 1024 * 1024;
+ if(!_prunning && defaultsize > maxSize) {
+ //-- Prune Disk Cache
+ _prunning = true;
+ QGCPruneCacheTask* task = new QGCPruneCacheTask(defaultsize - maxSize);
+ connect(task, &QGCPruneCacheTask::pruned, this, &QGCMapEngine::_pruned);
+ getQGCMapEngine()->addTask(task);
+ }
+}
+//-----------------------------------------------------------------------------
+void
+QGCMapEngine::_pruned()
+{
+ _prunning = false;
+}
+
+//-----------------------------------------------------------------------------
+int
+QGCMapEngine::concurrentDownloads(UrlFactory::MapType type)
+{
+ switch(type) {
+ case UrlFactory::GoogleMap:
+ case UrlFactory::GoogleSatellite:
+ case UrlFactory::GoogleTerrain:
+ case UrlFactory::BingMap:
+ case UrlFactory::BingSatellite:
+ case UrlFactory::BingHybrid:
+ return 12;
+ case UrlFactory::MapQuestMap:
+ case UrlFactory::MapQuestSat:
+ return 8;
+ default:
+ break;
+ }
+ return 6;
+}
+
+//-----------------------------------------------------------------------------
+QGCCreateTileSetTask::~QGCCreateTileSetTask()
+{
+ //-- If not sent out, delete it
+ if(!_saved && _tileSet)
+ delete _tileSet;
+}
+
+// Resolution math: https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Resolution_and_Scale
+
diff --git a/src/QtLocationPlugin/QGCMapEngine.h b/src/QtLocationPlugin/QGCMapEngine.h
new file mode 100644
index 0000000000000000000000000000000000000000..f9654c6c2cf8e0f90da454de6b432d990770d240
--- /dev/null
+++ b/src/QtLocationPlugin/QGCMapEngine.h
@@ -0,0 +1,137 @@
+/*=====================================================================
+
+QGroundControl Open Source Ground Control Station
+
+(c) 2009, 2016 QGROUNDCONTROL PROJECT
+
+This file is part of the QGROUNDCONTROL project
+
+ QGROUNDCONTROL is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ QGROUNDCONTROL is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QGROUNDCONTROL. If not, see .
+
+======================================================================*/
+
+/**
+ * @file
+ * @brief Map Tile Cache
+ *
+ * @author Gus Grubba
+ *
+ */
+
+#ifndef QGC_MAP_ENGINE_H
+#define QGC_MAP_ENGINE_H
+
+#include
+
+#include "QGCMapUrlEngine.h"
+#include "QGCMapEngineData.h"
+#include "QGCTileCacheWorker.h"
+
+//-----------------------------------------------------------------------------
+class QGCTileSet
+{
+public:
+ QGCTileSet()
+ {
+ clear();
+ }
+ QGCTileSet& operator += (QGCTileSet& other)
+ {
+ tileX0 += other.tileX0;
+ tileX1 += other.tileX1;
+ tileY0 += other.tileY0;
+ tileY1 += other.tileY1;
+ tileCount += other.tileCount;
+ tileSize += other.tileSize;
+ return *this;
+ }
+ void clear()
+ {
+ tileX0 = 0;
+ tileX1 = 0;
+ tileY0 = 0;
+ tileY1 = 0;
+ tileCount = 0;
+ tileSize = 0;
+ }
+
+ int tileX0;
+ int tileX1;
+ int tileY0;
+ int tileY1;
+ quint64 tileCount;
+ quint64 tileSize;
+};
+
+//-----------------------------------------------------------------------------
+class QGCMapEngine : public QObject
+{
+ Q_OBJECT
+public:
+ QGCMapEngine ();
+ ~QGCMapEngine ();
+
+ void init ();
+ void addTask (QGCMapTask *task);
+ void cacheTile (UrlFactory::MapType type, int x, int y, int z, const QByteArray& image, const QString& format, qulonglong set = UINT64_MAX);
+ void cacheTile (UrlFactory::MapType type, const QString& hash, const QByteArray& image, const QString& format, qulonglong set = UINT64_MAX);
+ QGCFetchTileTask* createFetchTileTask (UrlFactory::MapType type, int x, int y, int z);
+ QStringList getMapNameList ();
+ const QString userAgent () { return _userAgent; }
+ void setUserAgent (const QString& ua) { _userAgent = ua; }
+ UrlFactory::MapType hashToType (const QString& hash);
+ QString getMapBoxToken ();
+ void setMapBoxToken (const QString& token);
+ quint32 getMaxDiskCache ();
+ void setMaxDiskCache (quint32 size);
+ quint32 getMaxMemCache ();
+ void setMaxMemCache (quint32 size);
+ const QString getCachePath () { return _cachePath; }
+ const QString getCacheFilename () { return _cacheFile; }
+
+ UrlFactory* urlFactory () { return _urlFactory; }
+
+ //-- Tile Math
+ static QGCTileSet getTileCount (int zoom, double topleftLon, double topleftLat, double bottomRightLon, double bottomRightLat, UrlFactory::MapType mapType);
+ static int long2tileX (double lon, int z);
+ static int lat2tileY (double lat, int z);
+ static QString getTileHash (UrlFactory::MapType type, int x, int y, int z);
+ static UrlFactory::MapType getTypeFromName (const QString &name);
+ static QString bigSizeToString (quint64 size);
+ static QString numberToString (quint32 number);
+ static int concurrentDownloads (UrlFactory::MapType type);
+
+private slots:
+ void _updateTotals (quint32 totaltiles, quint64 totalsize, quint32 defaulttiles, quint64 defaultsize);
+ void _pruned ();
+
+signals:
+ void updateTotals (quint32 totaltiles, quint64 totalsize, quint32 defaulttiles, quint64 defaultsize);
+
+private:
+ QGCCacheWorker _worker;
+ QString _cachePath;
+ QString _cacheFile;
+ QString _mapBoxToken;
+ UrlFactory* _urlFactory;
+ QString _userAgent;
+ quint32 _maxDiskCache;
+ quint32 _maxMemCache;
+ bool _prunning;
+};
+
+extern QGCMapEngine* getQGCMapEngine();
+extern void destroyMapEngine();
+
+#endif // QGC_MAP_ENGINE_H
diff --git a/src/QtLocationPlugin/QGCMapEngineData.h b/src/QtLocationPlugin/QGCMapEngineData.h
new file mode 100644
index 0000000000000000000000000000000000000000..507c076b0c3e98a28ff30d7b59cfd2e3a6adff02
--- /dev/null
+++ b/src/QtLocationPlugin/QGCMapEngineData.h
@@ -0,0 +1,371 @@
+/*=====================================================================
+
+QGroundControl Open Source Ground Control Station
+
+(c) 2009, 2016 QGROUNDCONTROL PROJECT
+
+This file is part of the QGROUNDCONTROL project
+
+ QGROUNDCONTROL is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ QGROUNDCONTROL is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QGROUNDCONTROL. If not, see .
+
+======================================================================*/
+
+/**
+ * @file
+ * @brief Map Tile Cache Data
+ *
+ * @author Gus Grubba
+ *
+ */
+
+#ifndef QGC_MAP_ENGINE_DATA_H
+#define QGC_MAP_ENGINE_DATA_H
+
+#include
+#include
+#include
+#include
+
+#include "QGCMapUrlEngine.h"
+
+class QGCCachedTileSet;
+
+//-----------------------------------------------------------------------------
+class QGCTile
+{
+public:
+ QGCTile()
+ : _x(0)
+ , _y(0)
+ , _z(0)
+ , _set(UINT64_MAX)
+ , _type(UrlFactory::Invalid)
+ {
+ }
+
+ enum TyleState {
+ StatePending = 0,
+ StateDownloading,
+ StateError,
+ StateComplete
+ };
+
+ int x () const { return _x; }
+ int y () const { return _y; }
+ int z () const { return _z; }
+ qulonglong set () const { return _set; }
+ const QString hash () const { return _hash; }
+ UrlFactory::MapType type () const { return _type; }
+
+ void setX (int x) { _x = x; }
+ void setY (int y) { _y = y; }
+ void setZ (int z) { _z = z; }
+ void setTileSet (qulonglong set) { _set = set; }
+ void setHash (const QString& hash) { _hash = hash; }
+ void setType (UrlFactory::MapType type) { _type = type; }
+
+private:
+ int _x;
+ int _y;
+ int _z;
+ qulonglong _set;
+ QString _hash;
+ UrlFactory::MapType _type;
+};
+
+//-----------------------------------------------------------------------------
+class QGCCacheTile : public QObject
+{
+ Q_OBJECT
+public:
+ QGCCacheTile (const QString hash, const QByteArray img, const QString format, UrlFactory::MapType type, qulonglong set = UINT64_MAX)
+ : _set(set)
+ , _hash(hash)
+ , _img(img)
+ , _format(format)
+ , _type(type)
+ {
+ }
+ QGCCacheTile (const QString hash, qulonglong set)
+ : _set(set)
+ , _hash(hash)
+ {
+ }
+ qulonglong set () { return _set; }
+ QString hash () { return _hash; }
+ QByteArray img () { return _img; }
+ QString format () { return _format;}
+ UrlFactory::MapType type () { return _type; }
+private:
+ qulonglong _set;
+ QString _hash;
+ QByteArray _img;
+ QString _format;
+ UrlFactory::MapType _type;
+};
+
+//-----------------------------------------------------------------------------
+class QGCMapTask : public QObject
+{
+ Q_OBJECT
+public:
+
+ enum TaskType {
+ taskInit,
+ taskCacheTile,
+ taskFetchTile,
+ taskFetchTileSets,
+ taskCreateTileSet,
+ taskGetTileDownloadList,
+ taskUpdateTileDownloadState,
+ taskDeleteTileSet,
+ taskPruneCache,
+ taskReset
+ };
+
+ QGCMapTask(TaskType type)
+ : _type(type)
+ {}
+ virtual ~QGCMapTask()
+ {}
+
+ virtual TaskType type () { return _type; }
+
+ void setError(QString errorString)
+ {
+ emit error(_type, errorString);
+ }
+
+signals:
+ void error (QGCMapTask::TaskType type, QString errorString);
+
+private:
+ TaskType _type;
+};
+
+//-----------------------------------------------------------------------------
+class QGCFetchTileSetTask : public QGCMapTask
+{
+ Q_OBJECT
+public:
+ QGCFetchTileSetTask()
+ : QGCMapTask(QGCMapTask::taskFetchTileSets)
+ {}
+
+ void setTileSetFetched(QGCCachedTileSet* tileSet)
+ {
+ emit tileSetFetched(tileSet);
+ }
+
+signals:
+ void tileSetFetched (QGCCachedTileSet* tileSet);
+};
+
+//-----------------------------------------------------------------------------
+class QGCCreateTileSetTask : public QGCMapTask
+{
+ Q_OBJECT
+public:
+ QGCCreateTileSetTask(QGCCachedTileSet* tileSet)
+ : QGCMapTask(QGCMapTask::taskCreateTileSet)
+ , _tileSet(tileSet)
+ , _saved(false)
+ {}
+
+ ~QGCCreateTileSetTask();
+
+ QGCCachedTileSet* tileSet () { return _tileSet; }
+
+ void setTileSetSaved()
+ {
+ //-- Flag as saved. Signalee wll maintain it.
+ _saved = true;
+ emit tileSetSaved(_tileSet);
+ }
+
+signals:
+ void tileSetSaved (QGCCachedTileSet* tileSet);
+
+private:
+ QGCCachedTileSet* _tileSet;
+ bool _saved;
+};
+
+//-----------------------------------------------------------------------------
+class QGCFetchTileTask : public QGCMapTask
+{
+ Q_OBJECT
+public:
+ QGCFetchTileTask(const QString hash)
+ : QGCMapTask(QGCMapTask::taskFetchTile)
+ , _hash(hash)
+ {}
+
+ ~QGCFetchTileTask()
+ {
+ }
+
+ void setTileFetched(QGCCacheTile* tile)
+ {
+ emit tileFetched(tile);
+ }
+
+ QString hash() { return _hash; }
+
+signals:
+ void tileFetched (QGCCacheTile* tile);
+
+private:
+ QString _hash;
+};
+
+//-----------------------------------------------------------------------------
+class QGCSaveTileTask : public QGCMapTask
+{
+ Q_OBJECT
+public:
+ QGCSaveTileTask(QGCCacheTile* tile)
+ : QGCMapTask(QGCMapTask::taskCacheTile)
+ , _tile(tile)
+ {}
+
+ ~QGCSaveTileTask()
+ {
+ if(_tile)
+ delete _tile;
+ }
+
+ QGCCacheTile* tile() { return _tile; }
+
+private:
+ QGCCacheTile* _tile;
+};
+
+//-----------------------------------------------------------------------------
+class QGCGetTileDownloadListTask : public QGCMapTask
+{
+ Q_OBJECT
+public:
+ QGCGetTileDownloadListTask(qulonglong setID, int count)
+ : QGCMapTask(QGCMapTask::taskGetTileDownloadList)
+ , _setID(setID)
+ , _count(count)
+ {}
+
+ qulonglong setID() { return _setID; }
+ int count() { return _count; }
+
+ void setTileListFetched(QList tiles)
+ {
+ emit tileListFetched(tiles);
+ }
+
+signals:
+ void tileListFetched (QList tiles);
+
+private:
+ qulonglong _setID;
+ int _count;
+};
+
+//-----------------------------------------------------------------------------
+class QGCUpdateTileDownloadStateTask : public QGCMapTask
+{
+ Q_OBJECT
+public:
+ QGCUpdateTileDownloadStateTask(qulonglong setID, QGCTile::TyleState state, const QString& hash)
+ : QGCMapTask(QGCMapTask::taskUpdateTileDownloadState)
+ , _setID(setID)
+ , _state(state)
+ , _hash(hash)
+ {}
+
+ QString hash () { return _hash; }
+ qulonglong setID () { return _setID; }
+ QGCTile::TyleState state () { return _state; }
+
+private:
+ qulonglong _setID;
+ QGCTile::TyleState _state;
+ QString _hash;
+};
+
+//-----------------------------------------------------------------------------
+class QGCDeleteTileSetTask : public QGCMapTask
+{
+ Q_OBJECT
+public:
+ QGCDeleteTileSetTask(qulonglong setID)
+ : QGCMapTask(QGCMapTask::taskDeleteTileSet)
+ , _setID(setID)
+ {}
+
+ qulonglong setID() { return _setID; }
+
+ void setTileSetDeleted()
+ {
+ emit tileSetDeleted(_setID);
+ }
+
+signals:
+ void tileSetDeleted(qulonglong setID);
+
+private:
+ qulonglong _setID;
+};
+
+//-----------------------------------------------------------------------------
+class QGCPruneCacheTask : public QGCMapTask
+{
+ Q_OBJECT
+public:
+ QGCPruneCacheTask(quint64 amount)
+ : QGCMapTask(QGCMapTask::taskPruneCache)
+ , _amount(amount)
+ {}
+
+ quint64 amount() { return _amount; }
+
+ void setPruned()
+ {
+ emit pruned();
+ }
+
+signals:
+ void pruned();
+
+private:
+ quint64 _amount;
+};
+
+//-----------------------------------------------------------------------------
+class QGCResetTask : public QGCMapTask
+{
+ Q_OBJECT
+public:
+ QGCResetTask()
+ : QGCMapTask(QGCMapTask::taskReset)
+ {}
+
+ void setResetCompleted()
+ {
+ emit resetCompleted();
+ }
+
+signals:
+ void resetCompleted();
+};
+
+
+#endif // QGC_MAP_ENGINE_DATA_H
diff --git a/src/QtLocationPlugin/QGCMapTileSet.cpp b/src/QtLocationPlugin/QGCMapTileSet.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7212614d460dbc793e96bf0d8d2f1ebcb0944a1f
--- /dev/null
+++ b/src/QtLocationPlugin/QGCMapTileSet.cpp
@@ -0,0 +1,327 @@
+/*=====================================================================
+
+QGroundControl Open Source Ground Control Station
+
+(c) 2009, 2016 QGROUNDCONTROL PROJECT
+
+This file is part of the QGROUNDCONTROL project
+
+ QGROUNDCONTROL is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ QGROUNDCONTROL is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QGROUNDCONTROL. If not, see .
+
+======================================================================*/
+
+/**
+ * @file
+ * @brief Map Tile Set
+ *
+ * @author Gus Grubba
+ *
+ */
+
+#include
+#include
+
+#include "QGCMapEngine.h"
+#include "QGCMapTileSet.h"
+#include "QGCMapEngineManager.h"
+
+QGC_LOGGING_CATEGORY(QGCCachedTileSetLog, "QGCCachedTileSetLog")
+
+#define TILE_BATCH_SIZE 256
+
+//-----------------------------------------------------------------------------
+QGCCachedTileSet::QGCCachedTileSet(const QString& name, const QString& description)
+ : _name(name)
+ , _description(description)
+ , _topleftLat(0.0)
+ , _topleftLon(0.0)
+ , _bottomRightLat(0.0)
+ , _bottomRightLon(0.0)
+ , _numTiles(0)
+ , _tilesSize(0)
+ , _savedTiles(0)
+ , _savedSize(0)
+ , _minZoom(3)
+ , _maxZoom(3)
+ , _defaultSet(false)
+ , _deleting(false)
+ , _downloading(false)
+ , _id(0)
+ , _type(UrlFactory::Invalid)
+ , _networkManager(NULL)
+ , _errorCount(0)
+ , _noMoreTiles(false)
+ , _batchRequested(false)
+ , _manager(NULL)
+{
+
+}
+
+//-----------------------------------------------------------------------------
+QGCCachedTileSet::~QGCCachedTileSet()
+{
+ if(_networkManager) {
+ delete _networkManager;
+ }
+}
+
+//-----------------------------------------------------------------------------
+QString
+QGCCachedTileSet::errorCountStr()
+{
+ return QGCMapEngine::numberToString(_errorCount);
+}
+
+//-----------------------------------------------------------------------------
+QString
+QGCCachedTileSet::numTilesStr()
+{
+ return QGCMapEngine::numberToString(_numTiles);
+}
+
+//-----------------------------------------------------------------------------
+QString
+QGCCachedTileSet::tilesSizeStr()
+{
+ return QGCMapEngine::bigSizeToString(_tilesSize);
+}
+
+//-----------------------------------------------------------------------------
+QString
+QGCCachedTileSet::savedTilesStr()
+{
+ return QGCMapEngine::numberToString(_savedTiles);
+}
+
+//-----------------------------------------------------------------------------
+QString
+QGCCachedTileSet::savedSizeStr()
+{
+ return QGCMapEngine::bigSizeToString(_savedSize);
+}
+
+//-----------------------------------------------------------------------------
+QString
+QGCCachedTileSet::downloadStatus()
+{
+ if(_defaultSet) {
+ return tilesSizeStr();
+ }
+ if(_numTiles == _savedTiles) {
+ return savedSizeStr();
+ } else {
+ return savedSizeStr() + " / " + tilesSizeStr();
+ }
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCCachedTileSet::createDownloadTask()
+{
+ if(!_downloading) {
+ _errorCount = 0;
+ _downloading = true;
+ _noMoreTiles = false;
+ emit downloadingChanged();
+ emit errorCountChanged();
+ }
+ QGCGetTileDownloadListTask* task = new QGCGetTileDownloadListTask(_id, TILE_BATCH_SIZE);
+ connect(task, &QGCGetTileDownloadListTask::tileListFetched, this, &QGCCachedTileSet::_tileListFetched);
+ if(_manager)
+ connect(task, &QGCMapTask::error, _manager, &QGCMapEngineManager::taskError);
+ getQGCMapEngine()->addTask(task);
+ emit numTilesChanged();
+ emit tilesSizeChanged();
+ _batchRequested = true;
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCCachedTileSet::resumeDownloadTask()
+{
+ //-- Reset and download error flag (for all tiles)
+ QGCUpdateTileDownloadStateTask* task = new QGCUpdateTileDownloadStateTask(_id, QGCTile::StatePending, "*");
+ getQGCMapEngine()->addTask(task);
+ //-- Start download
+ createDownloadTask();
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCCachedTileSet::cancelDownloadTask()
+{
+ if(_downloading) {
+ _downloading = false;
+ emit downloadingChanged();
+ }
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCCachedTileSet::_tileListFetched(QList tiles)
+{
+ _batchRequested = false;
+ //-- Done?
+ if(tiles.size() < TILE_BATCH_SIZE) {
+ _noMoreTiles = true;
+ }
+ if(!tiles.size()) {
+ return;
+ }
+ //-- If this is the first time, create Network Manager
+ if (!_networkManager) {
+ _networkManager = new QNetworkAccessManager(this);
+ }
+ //-- Add tiles to the list
+ _tilesToDownload += tiles;
+ //-- Kick downloads
+ _prepareDownload();
+}
+
+//-----------------------------------------------------------------------------
+void QGCCachedTileSet::_prepareDownload()
+{
+ if(!_tilesToDownload.count()) {
+ //-- Are we done?
+ if(_noMoreTiles) {
+ if(!_errorCount) {
+ _numTiles = _savedTiles;
+ _tilesSize = _savedSize;
+ }
+ emit numTilesChanged();
+ emit tilesSizeChanged();
+ emit savedSizeChanged();
+ emit savedTilesChanged();
+ _downloading = false;
+ emit downloadingChanged();
+ emit completeChanged();
+ } else {
+ if(!_batchRequested)
+ createDownloadTask();
+ }
+ return;
+ }
+ //-- Prepare queue (QNetworkAccessManager has a limit for concurrent downloads)
+ for(int i = _replies.count(); i < QGCMapEngine::concurrentDownloads(_type); i++) {
+ if(_tilesToDownload.count()) {
+ QGCTile* tile = _tilesToDownload.first();
+ _tilesToDownload.removeFirst();
+ QNetworkRequest request = getQGCMapEngine()->urlFactory()->getTileURL(tile->type(), tile->x(), tile->y(), tile->z(), _networkManager);
+ request.setAttribute(QNetworkRequest::User, tile->hash());
+ QNetworkReply* reply = _networkManager->get(request);
+ reply->setParent(0);
+ connect(reply, &QNetworkReply::finished, this, &QGCCachedTileSet::_networkReplyFinished);
+ connect(reply, static_cast(&QNetworkReply::error), this, &QGCCachedTileSet::_networkReplyError);
+ _replies.insert(tile->hash(), reply);
+ delete tile;
+ //-- Refill queue if running low
+ if(!_batchRequested && !_noMoreTiles && _tilesToDownload.count() < (QGCMapEngine::concurrentDownloads(_type) * 10)) {
+ //-- Request new batch of tiles
+ createDownloadTask();
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCCachedTileSet::_networkReplyFinished()
+{
+ //-- Figure out which reply this is
+ QNetworkReply* reply = qobject_cast(QObject::sender());
+ if(!reply) {
+ qWarning() << "QGCMapEngineManager::networkReplyFinished() NULL Reply";
+ return;
+ }
+ //-- Get tile hash
+ const QString hash = reply->request().attribute(QNetworkRequest::User).toString();
+ if(!hash.isEmpty()) {
+ if(_replies.contains(hash)) {
+ _replies.remove(hash);
+ } else {
+ qWarning() << "QGCMapEngineManager::networkReplyFinished() Reply not in list: " << hash;
+ }
+ if (reply->error() != QNetworkReply::NoError) {
+ qWarning() << "QGCMapEngineManager::networkReplyFinished() Error:" << reply->errorString();
+ return;
+ }
+ qCDebug(QGCCachedTileSetLog) << "Tile fetched" << hash;
+ QByteArray image = reply->readAll();
+ UrlFactory::MapType type = getQGCMapEngine()->hashToType(hash);
+ QString format = getQGCMapEngine()->urlFactory()->getImageFormat(type, image);
+ if(!format.isEmpty()) {
+ //-- Cache tile
+ getQGCMapEngine()->cacheTile(type, hash, image, format, _id);
+ QGCUpdateTileDownloadStateTask* task = new QGCUpdateTileDownloadStateTask(_id, QGCTile::StateComplete, hash);
+ getQGCMapEngine()->addTask(task);
+ //-- Updated cached (downloaded) data
+ _savedSize += image.size();
+ _savedTiles++;
+ emit savedSizeChanged();
+ emit savedTilesChanged();
+ //-- Update estimate
+ if(_savedTiles % 10 == 0) {
+ quint32 avg = _savedSize / _savedTiles;
+ _tilesSize = avg * _numTiles;
+ emit tilesSizeChanged();
+ }
+ }
+ //-- Setup a new download
+ _prepareDownload();
+ } else {
+ qWarning() << "QGCMapEngineManager::networkReplyFinished() Empty Hash";
+ }
+ reply->deleteLater();
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCCachedTileSet::_networkReplyError(QNetworkReply::NetworkError error)
+{
+ //-- Figure out which reply this is
+ QNetworkReply* reply = qobject_cast(QObject::sender());
+ if (!reply) {
+ return;
+ }
+ //-- Upodate error count
+ _errorCount++;
+ emit errorCountChanged();
+ //-- Get tile hash
+ QString hash = reply->request().attribute(QNetworkRequest::User).toString();
+ qCDebug(QGCCachedTileSetLog) << "Error fetching tile" << reply->errorString();
+ if(!hash.isEmpty()) {
+ if(_replies.contains(hash)) {
+ _replies.remove(hash);
+ } else {
+ qWarning() << "QGCMapEngineManager::networkReplyError() Reply not in list: " << hash;
+ }
+ if (error != QNetworkReply::OperationCanceledError) {
+ qWarning() << "QGCMapEngineManager::networkReplyError() Error:" << reply->errorString();
+ }
+ QGCUpdateTileDownloadStateTask* task = new QGCUpdateTileDownloadStateTask(_id, QGCTile::StateError, hash);
+ getQGCMapEngine()->addTask(task);
+ } else {
+ qWarning() << "QGCMapEngineManager::networkReplyError() Empty Hash";
+ }
+ //-- Setup a new download
+ _prepareDownload();
+ reply->deleteLater();
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCCachedTileSet::setManager(QGCMapEngineManager* mgr)
+{
+ _manager = mgr;
+}
diff --git a/src/QtLocationPlugin/QGCMapTileSet.h b/src/QtLocationPlugin/QGCMapTileSet.h
new file mode 100644
index 0000000000000000000000000000000000000000..60d1ae7a775b7a483bd75b777e888c9441083fa1
--- /dev/null
+++ b/src/QtLocationPlugin/QGCMapTileSet.h
@@ -0,0 +1,193 @@
+/*=====================================================================
+
+QGroundControl Open Source Ground Control Station
+
+(c) 2009, 2016 QGROUNDCONTROL PROJECT
+
+This file is part of the QGROUNDCONTROL project
+
+ QGROUNDCONTROL is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ QGROUNDCONTROL is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QGROUNDCONTROL. If not, see .
+
+======================================================================*/
+
+/**
+ * @file
+ * @brief Map Tile Set
+ *
+ * @author Gus Grubba
+ *
+ */
+
+#ifndef QGC_MAP_TILE_SET_H
+#define QGC_MAP_TILE_SET_H
+
+#include
+#include
+#include
+#include
+#include
+
+#include "QGCLoggingCategory.h"
+#include "QGCMapEngineData.h"
+#include "QGCMapUrlEngine.h"
+
+Q_DECLARE_LOGGING_CATEGORY(QGCCachedTileSetLog)
+
+class QGCTile;
+class QGCMapEngineManager;
+
+//-----------------------------------------------------------------------------
+class QGCCachedTileSet : public QObject
+{
+ Q_OBJECT
+public:
+ QGCCachedTileSet (const QString& name, const QString& description);
+ ~QGCCachedTileSet ();
+
+ Q_PROPERTY(QString name READ name CONSTANT)
+ Q_PROPERTY(QString description READ description CONSTANT)
+ Q_PROPERTY(QString mapTypeStr READ mapTypeStr CONSTANT)
+ Q_PROPERTY(double topleftLon READ topleftLon CONSTANT)
+ Q_PROPERTY(double topleftLat READ topleftLat CONSTANT)
+ Q_PROPERTY(double bottomRightLon READ bottomRightLon CONSTANT)
+ Q_PROPERTY(double bottomRightLat READ bottomRightLat CONSTANT)
+ Q_PROPERTY(int minZoom READ minZoom CONSTANT)
+ Q_PROPERTY(int maxZoom READ maxZoom CONSTANT)
+ Q_PROPERTY(quint32 numTiles READ numTiles NOTIFY numTilesChanged)
+ Q_PROPERTY(QString numTilesStr READ numTilesStr NOTIFY numTilesChanged)
+ Q_PROPERTY(quint64 tilesSize READ tilesSize NOTIFY tilesSizeChanged)
+ Q_PROPERTY(QString tilesSizeStr READ tilesSizeStr NOTIFY tilesSizeChanged)
+ Q_PROPERTY(quint32 savedTiles READ savedTiles NOTIFY savedTilesChanged)
+ Q_PROPERTY(QString savedTilesStr READ savedTilesStr NOTIFY savedTilesChanged)
+ Q_PROPERTY(quint64 savedSize READ savedSize NOTIFY savedSizeChanged)
+ Q_PROPERTY(QString savedSizeStr READ savedSizeStr NOTIFY savedSizeChanged)
+ Q_PROPERTY(QString downloadStatus READ downloadStatus NOTIFY savedSizeChanged)
+ Q_PROPERTY(QDateTime creationDate READ creationDate CONSTANT)
+ Q_PROPERTY(bool complete READ complete NOTIFY completeChanged)
+ Q_PROPERTY(bool defaultSet READ defaultSet CONSTANT)
+ Q_PROPERTY(quint64 setID READ setID CONSTANT)
+ Q_PROPERTY(bool deleting READ deleting NOTIFY deletingChanged)
+ Q_PROPERTY(bool downloading READ downloading NOTIFY downloadingChanged)
+ Q_PROPERTY(quint32 errorCount READ errorCount NOTIFY errorCountChanged)
+ Q_PROPERTY(QString errorCountStr READ errorCountStr NOTIFY errorCountChanged)
+ Q_PROPERTY(QImage thumbNail READ thumbNail CONSTANT)
+
+ Q_INVOKABLE void createDownloadTask ();
+ Q_INVOKABLE void resumeDownloadTask ();
+ Q_INVOKABLE void cancelDownloadTask ();
+
+ void setManager (QGCMapEngineManager* mgr);
+
+ QString name () { return _name; }
+ QString description () { return _description; }
+ QString mapTypeStr () { return _mapTypeStr; }
+ double topleftLat () { return _topleftLat; }
+ double topleftLon () { return _topleftLon; }
+ double bottomRightLat () { return _bottomRightLat; }
+ double bottomRightLon () { return _bottomRightLon; }
+ quint32 numTiles () { return (quint32)_numTiles; }
+ QString numTilesStr ();
+ quint64 tilesSize () { return (quint64)_tilesSize; }
+ QString tilesSizeStr ();
+ quint32 savedTiles () { return (quint32)_savedTiles; }
+ QString savedTilesStr ();
+ quint64 savedSize () { return (quint64)_savedSize; }
+ QString savedSizeStr ();
+ QString downloadStatus ();
+ int minZoom () { return _minZoom; }
+ int maxZoom () { return _maxZoom; }
+ QDateTime creationDate () { return _creationDate; }
+ quint64 id () { return _id; }
+ UrlFactory::MapType type () { return _type; }
+ bool complete () { return _defaultSet || (_numTiles == _savedTiles); }
+ bool defaultSet () { return _defaultSet; }
+ quint64 setID () { return _id; }
+ bool deleting () { return _deleting; }
+ bool downloading () { return _downloading; }
+ quint32 errorCount () { return _errorCount; }
+ QString errorCountStr ();
+ QImage thumbNail () { return _thumbNail; }
+
+ void setName (QString name) { _name = name; }
+ void setDescription (QString desc) { _description = desc; }
+ void setMapTypeStr (QString typeStr) { _mapTypeStr = typeStr; }
+ void setTopleftLat (double lat) { _topleftLat = lat; }
+ void setTopleftLon (double lon) { _topleftLon = lon; }
+ void setBottomRightLat (double lat) { _bottomRightLat = lat; }
+ void setBottomRightLon (double lon) { _bottomRightLon = lon; }
+ void setNumTiles (quint32 num) { _numTiles = num; }
+ void setTilesSize (quint64 size) { _tilesSize = size; }
+ void setSavedTiles (quint32 num) { _savedTiles = num; emit savedTilesChanged(); }
+ void setSavedSize (quint64 size) { _savedSize = size; emit savedSizeChanged(); }
+ void setMinZoom (int zoom) { _minZoom = zoom; }
+ void setMaxZoom (int zoom) { _maxZoom = zoom; }
+ void setCreationDate (QDateTime date) { _creationDate = date; }
+ void setId (quint64 id) { _id = id; }
+ void setType (UrlFactory::MapType type) { _type = type; }
+ void setDefaultSet (bool def) { _defaultSet = def; }
+ void setDeleting (bool del) { _deleting = del; emit deletingChanged(); }
+ void setDownloading (bool down) { _downloading = down; }
+ void setThumbNail (const QImage& thumb) { _thumbNail = thumb; }
+
+signals:
+ void deletingChanged ();
+ void downloadingChanged ();
+ void numTilesChanged ();
+ void tilesSizeChanged ();
+ void savedTilesChanged ();
+ void savedSizeChanged ();
+ void completeChanged ();
+ void errorCountChanged ();
+
+private slots:
+ void _tileListFetched (QList tiles);
+ void _networkReplyFinished ();
+ void _networkReplyError (QNetworkReply::NetworkError error);
+
+private:
+ void _prepareDownload ();
+
+private:
+ QString _name;
+ QString _description;
+ QString _mapTypeStr;
+ double _topleftLat;
+ double _topleftLon;
+ double _bottomRightLat;
+ double _bottomRightLon;
+ quint32 _numTiles;
+ quint64 _tilesSize;
+ quint32 _savedTiles;
+ quint64 _savedSize;
+ int _minZoom;
+ int _maxZoom;
+ bool _defaultSet;
+ bool _deleting;
+ bool _downloading;
+ QDateTime _creationDate;
+ quint64 _id;
+ UrlFactory::MapType _type;
+ QNetworkAccessManager* _networkManager;
+ QHash _replies;
+ quint32 _errorCount;
+ //-- Tile download
+ QList _tilesToDownload;
+ bool _noMoreTiles;
+ bool _batchRequested;
+ QGCMapEngineManager* _manager;
+ QImage _thumbNail;
+};
+
+#endif // QGC_MAP_TILE_SET_H
+
diff --git a/src/QtLocationPlugin/QGCMapUrlEngine.cpp b/src/QtLocationPlugin/QGCMapUrlEngine.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0473d26fd887666e9106dc4e1907178b6fc642fa
--- /dev/null
+++ b/src/QtLocationPlugin/QGCMapUrlEngine.cpp
@@ -0,0 +1,513 @@
+/*=====================================================================
+
+QGroundControl Open Source Ground Control Station
+
+(c) 2009, 2015 QGROUNDCONTROL PROJECT
+
+This file is part of the QGROUNDCONTROL project
+
+ QGROUNDCONTROL is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ QGROUNDCONTROL is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QGROUNDCONTROL. If not, see .
+
+======================================================================*/
+
+/**
+ * @file
+ * @author Gus Grubba
+ * Original work: The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "QGCMapEngine.h"
+
+//-----------------------------------------------------------------------------
+UrlFactory::UrlFactory()
+ : _timeout(5 * 1000)
+ , _googleVersionRetrieved(false)
+ , _googleReply(NULL)
+{
+ QStringList langs = QLocale::system().uiLanguages();
+ if (langs.length() > 0) {
+ _language = langs[0];
+ }
+ // Google version strings
+ _versionGoogleMap = "m@336";
+ _versionGoogleSatellite = "194";
+ _versionGoogleLabels = "h@336";
+ _versionGoogleTerrain = "t@132,r@336";
+ _secGoogleWord = "Galileo";
+ // BingMaps
+ _versionBingMaps = "563";
+}
+
+//-----------------------------------------------------------------------------
+UrlFactory::~UrlFactory()
+{
+ if(_googleReply)
+ _googleReply->deleteLater();
+}
+
+
+//-----------------------------------------------------------------------------
+QString
+UrlFactory::getImageFormat(MapType type, const QByteArray& image)
+{
+ QString format;
+ if(image.size() > 2)
+ {
+ if((char)image[0] == (char)0xff && (char)image[1] == (char)0xd8)
+ format = "jpg";
+ else if((char)image[0] == (char)0x89 && (char)image[1] == (char)0x50)
+ format = "png";
+ else {
+ switch (type) {
+ case GoogleMap:
+ case GoogleLabels:
+ case GoogleTerrain:
+ case GoogleHybrid:
+ case BingMap:
+ case OpenStreetMap:
+ format = "png";
+ break;
+ case MapQuestMap:
+ case MapQuestSat:
+ case MapBoxStreets:
+ case MapBoxLight:
+ case MapBoxDark:
+ case MapBoxSatellite:
+ case MapBoxHybrid:
+ case MapBoxWheatPaste:
+ case MapBoxStreetsBasic:
+ case MapBoxComic:
+ case MapBoxOutdoors:
+ case MapBoxRunBikeHike:
+ case MapBoxPencil:
+ case MapBoxPirates:
+ case MapBoxEmerald:
+ case MapBoxHighContrast:
+ case GoogleSatellite:
+ case BingSatellite:
+ case BingHybrid:
+ format = "jpg";
+ break;
+ default:
+ qWarning("UrlFactory::getImageFormat() Unknown map id %d", type);
+ break;
+ }
+ }
+ }
+ return format;
+}
+
+//-----------------------------------------------------------------------------
+QNetworkRequest
+UrlFactory::getTileURL(MapType type, int x, int y, int zoom, QNetworkAccessManager* networkManager)
+{
+ //-- Build URL
+ QNetworkRequest request;
+ QString url = _getURL(type, x, y, zoom, networkManager);
+ if(url.isEmpty())
+ return request;
+ request.setUrl(QUrl(url));
+ request.setRawHeader("Accept", "*/*");
+ request.setRawHeader("User-Agent", _userAgent);
+ switch (type) {
+ case GoogleMap:
+ case GoogleSatellite:
+ case GoogleLabels:
+ case GoogleTerrain:
+ case GoogleHybrid:
+ request.setRawHeader("Referrer", "http://maps.google.com/");
+ break;
+ case BingHybrid:
+ case BingMap:
+ case BingSatellite:
+ request.setRawHeader("Referrer", "http://www.bing.com/maps/");
+ break;
+ /*
+ case OpenStreetMapSurfer:
+ case OpenStreetMapSurferTerrain:
+ request.setRawHeader("Referrer", "http://www.mapsurfer.net/");
+ break;
+ case OpenStreetMap:
+ case OpenStreetOsm:
+ request.setRawHeader("Referrer", "https://www.openstreetmap.org/");
+ break;
+ */
+ default:
+ break;
+ }
+ return request;
+}
+
+//-----------------------------------------------------------------------------
+void
+UrlFactory::_getSecGoogleWords(int x, int y, QString &sec1, QString &sec2)
+{
+ sec1 = ""; // after &x=...
+ sec2 = ""; // after &zoom=...
+ int seclen = ((x * 3) + y) % 8;
+ sec2 = _secGoogleWord.left(seclen);
+ if (y >= 10000 && y < 100000) {
+ sec1 = "&s=";
+ }
+}
+
+//-----------------------------------------------------------------------------
+QString
+UrlFactory::_getURL(MapType type, int x, int y, int zoom, QNetworkAccessManager* networkManager)
+{
+ switch (type) {
+ case GoogleMap:
+ {
+ // http://mt1.google.com/vt/lyrs=m
+ QString server = "mt";
+ QString request = "vt";
+ QString sec1 = ""; // after &x=...
+ QString sec2 = ""; // after &zoom=...
+ _getSecGoogleWords(x, y, sec1, sec2);
+ _tryCorrectGoogleVersions(networkManager);
+ return QString("http://%1%2.google.com/%3/lyrs=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(_getServerNum(x, y, 4)).arg(request).arg(_versionGoogleMap).arg(_language).arg(x).arg(sec1).arg(y).arg(zoom).arg(sec2);
+ }
+ break;
+ case GoogleSatellite:
+ {
+ // http://mt1.google.com/vt/lyrs=s
+ QString server = "khm";
+ QString request = "kh";
+ QString sec1 = ""; // after &x=...
+ QString sec2 = ""; // after &zoom=...
+ _getSecGoogleWords(x, y, sec1, sec2);
+ _tryCorrectGoogleVersions(networkManager);
+ return QString("http://%1%2.google.com/%3/v=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(_getServerNum(x, y, 4)).arg(request).arg(_versionGoogleSatellite).arg(_language).arg(x).arg(sec1).arg(y).arg(zoom).arg(sec2);
+ }
+ break;
+ case GoogleLabels:
+ {
+ QString server = "mts";
+ QString request = "vt";
+ QString sec1 = ""; // after &x=...
+ QString sec2 = ""; // after &zoom=...
+ _getSecGoogleWords(x, y, sec1, sec2);
+ _tryCorrectGoogleVersions(networkManager);
+ return QString("http://%1%2.google.com/%3/lyrs=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(_getServerNum(x, y, 4)).arg(request).arg(_versionGoogleLabels).arg(_language).arg(x).arg(sec1).arg(y).arg(zoom).arg(sec2);
+ }
+ break;
+ case GoogleTerrain:
+ {
+ QString server = "mt";
+ QString request = "vt";
+ QString sec1 = ""; // after &x=...
+ QString sec2 = ""; // after &zoom=...
+ _getSecGoogleWords(x, y, sec1, sec2);
+ _tryCorrectGoogleVersions(networkManager);
+ return QString("http://%1%2.google.com/%3/v=%4&hl=%5&x=%6%7&y=%8&z=%9&s=%10").arg(server).arg(_getServerNum(x, y, 4)).arg(request).arg(_versionGoogleTerrain).arg(_language).arg(x).arg(sec1).arg(y).arg(zoom).arg(sec2);
+ }
+ break;
+ /*
+ case OpenStreetMap:
+ {
+ char letter = "abc"[_getServerNum(x, y, 3)];
+ return QString("https://%1.tile.openstreetmap.org/%2/%3/%4.png").arg(letter).arg(zoom).arg(x).arg(y);
+ }
+ break;
+ case OpenStreetOsm:
+ {
+ char letter = "abc"[_getServerNum(x, y, 3)];
+ return QString("http://%1.tah.openstreetmap.org/Tiles/tile/%2/%3/%4.png").arg(letter).arg(zoom).arg(x).arg(y);
+ }
+ break;
+ case OpenStreetMapSurfer:
+ {
+ // http://tiles1.mapsurfer.net/tms_r.ashx?x=37378&y=20826&z=16
+ return QString("http://tiles1.mapsurfer.net/tms_r.ashx?x=%1&y=%2&z=%3").arg(x).arg(y).arg(zoom);
+ }
+ break;
+ case OpenStreetMapSurferTerrain:
+ {
+ // http://tiles2.mapsurfer.net/tms_t.ashx?x=9346&y=5209&z=14
+ return QString("http://tiles2.mapsurfer.net/tms_t.ashx?x=%1&y=%2&z=%3").arg(x).arg(y).arg(zoom);
+ }
+ break;
+ */
+ case BingMap:
+ {
+ QString key = _tileXYToQuadKey(x, y, zoom);
+ return QString("http://ecn.t%1.tiles.virtualearth.net/tiles/r%2.png?g=%3&mkt=%4").arg(_getServerNum(x, y, 4)).arg(key).arg(_versionBingMaps).arg(_language);
+ }
+ break;
+ case BingSatellite:
+ {
+ QString key = _tileXYToQuadKey(x, y, zoom);
+ return QString("http://ecn.t%1.tiles.virtualearth.net/tiles/a%2.jpeg?g=%3&mkt=%4").arg(_getServerNum(x, y, 4)).arg(key).arg(_versionBingMaps).arg(_language);
+ }
+ break;
+ case BingHybrid:
+ {
+ QString key = _tileXYToQuadKey(x, y, zoom);
+ return QString("http://ecn.t%1.tiles.virtualearth.net/tiles/h%2.jpeg?g=%3&mkt=%4").arg(_getServerNum(x, y, 4)).arg(key).arg(_versionBingMaps).arg(_language);
+ }
+ case MapQuestMap:
+ {
+ char letter = "1234"[_getServerNum(x, y, 4)];
+ return QString("http://otile%1.mqcdn.com/tiles/1.0.0/map/%2/%3/%4.jpg").arg(letter).arg(zoom).arg(x).arg(y);
+ }
+ break;
+ case MapQuestSat:
+ {
+ char letter = "1234"[_getServerNum(x, y, 4)];
+ return QString("http://otile%1.mqcdn.com/tiles/1.0.0/sat/%2/%3/%4.jpg").arg(letter).arg(zoom).arg(x).arg(y);
+ }
+ break;
+
+ case MapBoxStreets:
+ case MapBoxLight:
+ case MapBoxDark:
+ case MapBoxSatellite:
+ case MapBoxHybrid:
+ case MapBoxWheatPaste:
+ case MapBoxStreetsBasic:
+ case MapBoxComic:
+ case MapBoxOutdoors:
+ case MapBoxRunBikeHike:
+ case MapBoxPencil:
+ case MapBoxPirates:
+ case MapBoxEmerald:
+ case MapBoxHighContrast:
+ {
+ QString mapBoxToken = getQGCMapEngine()->getMapBoxToken();
+ if(!mapBoxToken.isEmpty()) {
+ QString server = "https://api.mapbox.com/v4/";
+ switch(type) {
+ case MapBoxStreets:
+ server += "mapbox.streets";
+ break;
+ case MapBoxLight:
+ server += "mapbox.light";
+ break;
+ case MapBoxDark:
+ server += "mapbox.dark";
+ break;
+ case MapBoxSatellite:
+ server += "mapbox.satellite";
+ break;
+ case MapBoxHybrid:
+ server += "mapbox.streets-satellite";
+ break;
+ case MapBoxWheatPaste:
+ server += "mapbox.wheatpaste";
+ break;
+ case MapBoxStreetsBasic:
+ server += "mapbox.streets-basic";
+ break;
+ case MapBoxComic:
+ server += "mapbox.comic";
+ break;
+ case MapBoxOutdoors:
+ server += "mapbox.outdoors";
+ break;
+ case MapBoxRunBikeHike:
+ server += "mapbox.run-bike-hike";
+ break;
+ case MapBoxPencil:
+ server += "mapbox.pencil";
+ break;
+ case MapBoxPirates:
+ server += "mapbox.pirates";
+ break;
+ case MapBoxEmerald:
+ server += "mapbox.emerald";
+ break;
+ case MapBoxHighContrast:
+ server += "mapbox.high-contrast";
+ break;
+ default:
+ return QString::null;
+ }
+ server += QString("/%1/%2/%3.jpg80?access_token=%4").arg(zoom).arg(x).arg(y).arg(mapBoxToken);
+ return server;
+ }
+ }
+ break;
+
+ default:
+ qWarning("Unknown map id %d\n", type);
+ break;
+ }
+ return QString::null;
+}
+
+//-----------------------------------------------------------------------------
+QString
+UrlFactory::_tileXYToQuadKey(int tileX, int tileY, int levelOfDetail)
+{
+ QString quadKey;
+ for (int i = levelOfDetail; i > 0; i--) {
+ char digit = '0';
+ int mask = 1 << (i - 1);
+ if ((tileX & mask) != 0) {
+ digit++;
+ }
+ if ((tileY & mask) != 0) {
+ digit++;
+ digit++;
+ }
+ quadKey.append(digit);
+ }
+ return quadKey;
+}
+
+//-----------------------------------------------------------------------------
+int
+UrlFactory::_getServerNum(int x, int y, int max)
+{
+ return (x + 2 * y) % max;
+}
+
+//-----------------------------------------------------------------------------
+void
+UrlFactory::_networkReplyError(QNetworkReply::NetworkError error)
+{
+ qWarning() << "Could not connect to google maps. Error:" << error;
+ if(_googleReply)
+ {
+ _googleReply->deleteLater();
+ _googleReply = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+void
+UrlFactory::_replyDestroyed()
+{
+ _googleReply = NULL;
+}
+
+//-----------------------------------------------------------------------------
+void
+UrlFactory::_googleVersionCompleted()
+{
+ if (!_googleReply || (_googleReply->error() != QNetworkReply::NoError)) {
+ qDebug() << "Error collecting Google maps version info";
+ return;
+ }
+ QString html = QString(_googleReply->readAll());
+ QRegExp reg("\"*http://mt0.google.com/vt/lyrs=m@(\\d*)",Qt::CaseInsensitive);
+ if (reg.indexIn(html) != -1) {
+ QStringList gc = reg.capturedTexts();
+ _versionGoogleMap = QString("m@%1").arg(gc[1]);
+ }
+ reg = QRegExp("\"*http://mt0.google.com/vt/lyrs=h@(\\d*)",Qt::CaseInsensitive);
+ if (reg.indexIn(html) != -1) {
+ QStringList gc = reg.capturedTexts();
+ _versionGoogleLabels = QString("h@%1").arg(gc[1]);
+ }
+ reg = QRegExp("\"*http://khm\\D?\\d.google.com/kh/v=(\\d*)",Qt::CaseInsensitive);
+ if (reg.indexIn(html) != -1) {
+ QStringList gc = reg.capturedTexts();
+ _versionGoogleSatellite = gc[1];
+ }
+ reg = QRegExp("\"*http://mt0.google.com/vt/lyrs=t@(\\d*),r@(\\d*)",Qt::CaseInsensitive);
+ if (reg.indexIn(html) != -1) {
+ QStringList gc = reg.capturedTexts();
+ _versionGoogleTerrain = QString("t@%1,r@%2").arg(gc[1]).arg(gc[2]);
+ }
+ _googleReply->deleteLater();
+ _googleReply = NULL;
+}
+
+//-----------------------------------------------------------------------------
+void
+UrlFactory::_tryCorrectGoogleVersions(QNetworkAccessManager* networkManager)
+{
+ QMutexLocker locker(&_googleVersionMutex);
+ if (_googleVersionRetrieved) {
+ return;
+ }
+ _googleVersionRetrieved = true;
+ if(networkManager)
+ {
+ QNetworkRequest qheader;
+ QNetworkProxy proxy = networkManager->proxy();
+ QNetworkProxy tProxy;
+ tProxy.setType(QNetworkProxy::NoProxy);
+ networkManager->setProxy(tProxy);
+ QString url = "http://maps.google.com/maps";
+ qheader.setUrl(QUrl(url));
+ QByteArray ua;
+ ua.append(getQGCMapEngine()->userAgent());
+ qheader.setRawHeader("User-Agent", ua);
+ _googleReply = networkManager->get(qheader);
+ connect(_googleReply, &QNetworkReply::finished, this, &UrlFactory::_googleVersionCompleted);
+ connect(_googleReply, &QNetworkReply::destroyed, this, &UrlFactory::_replyDestroyed);
+ connect(_googleReply, static_cast(&QNetworkReply::error),
+ this, &UrlFactory::_networkReplyError);
+ networkManager->setProxy(proxy);
+ }
+}
+
+#define AVERAGE_GOOGLE_STREET_MAP 4913
+#define AVERAGE_GOOGLE_TERRAIN_MAP 19391
+#define AVERAGE_BING_STREET_MAP 1297
+#define AVERAGE_BING_SAT_MAP 19597
+#define AVERAGE_GOOGLE_SAT_MAP 56887
+#define AVERAGE_MAPBOX_SAT_MAP 15739
+#define AVERAGE_MAPBOX_STREET_MAP 5648
+#define AVERAGE_TILE_SIZE 13652
+
+//-----------------------------------------------------------------------------
+quint32
+UrlFactory::averageSizeForType(MapType type)
+{
+ switch (type) {
+ case GoogleMap:
+ return AVERAGE_GOOGLE_STREET_MAP;
+ case BingMap:
+ return AVERAGE_BING_STREET_MAP;
+ case GoogleSatellite:
+ return AVERAGE_GOOGLE_SAT_MAP;
+ case MapBoxSatellite:
+ return AVERAGE_MAPBOX_SAT_MAP;
+ case BingHybrid:
+ case BingSatellite:
+ return AVERAGE_BING_SAT_MAP;
+ case GoogleTerrain:
+ return AVERAGE_GOOGLE_TERRAIN_MAP;
+ case MapBoxStreets:
+ case MapBoxStreetsBasic:
+ case MapBoxRunBikeHike:
+ return AVERAGE_MAPBOX_STREET_MAP;
+ case GoogleLabels:
+ case MapBoxDark:
+ case MapBoxLight:
+ case MapBoxOutdoors:
+ case MapBoxPencil:
+ case OpenStreetMap:
+ case GoogleHybrid:
+ case MapBoxComic:
+ case MapBoxEmerald:
+ case MapBoxHighContrast:
+ case MapBoxHybrid:
+ case MapBoxPirates:
+ case MapBoxWheatPaste:
+ default:
+ break;
+ }
+ return AVERAGE_TILE_SIZE;
+}
diff --git a/src/QtLocationPlugin/QGCMapUrlEngine.h b/src/QtLocationPlugin/QGCMapUrlEngine.h
new file mode 100644
index 0000000000000000000000000000000000000000..57db8512736d103579c6e33204a7d12dacde1075
--- /dev/null
+++ b/src/QtLocationPlugin/QGCMapUrlEngine.h
@@ -0,0 +1,121 @@
+/*=====================================================================
+
+QGroundControl Open Source Ground Control Station
+
+(c) 2009, 2016 QGROUNDCONTROL PROJECT
+
+This file is part of the QGROUNDCONTROL project
+
+ QGROUNDCONTROL is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ QGROUNDCONTROL is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QGROUNDCONTROL. If not, see .
+
+======================================================================*/
+
+/**
+ * @file
+ * @author Gus Grubba
+ */
+
+#ifndef QGC_MAP_URL_ENGINE_H
+#define QGC_MAP_URL_ENGINE_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define MAX_MAP_ZOOM (18.0)
+
+class UrlFactory : public QObject {
+ Q_OBJECT
+public:
+
+ enum MapType
+ {
+ Invalid = -1,
+
+ GoogleMap = 1,
+ GoogleSatellite = 4,
+ GoogleLabels = 8,
+ GoogleTerrain = 16,
+ GoogleHybrid = 20,
+
+ OpenStreetMap = 32,
+ OpenStreetOsm = 33,
+ OpenStreetMapSurfer = 34,
+ OpenStreetMapSurferTerrain=35,
+
+ BingMap = 444,
+ BingSatellite = 555,
+ BingHybrid = 666,
+
+ MapQuestMap = 700,
+ MapQuestSat = 701,
+
+ MapBoxStreets = 6000,
+ MapBoxLight = 6001,
+ MapBoxDark = 6002,
+ MapBoxSatellite = 6003,
+ MapBoxHybrid = 6004,
+ MapBoxWheatPaste = 6005,
+ MapBoxStreetsBasic = 6006,
+ MapBoxComic = 6007,
+ MapBoxOutdoors = 6008,
+ MapBoxRunBikeHike = 6009,
+ MapBoxPencil = 6010,
+ MapBoxPirates = 6011,
+ MapBoxEmerald = 6012,
+ MapBoxHighContrast = 6013
+ };
+
+ UrlFactory ();
+ ~UrlFactory ();
+
+ QNetworkRequest getTileURL (MapType type, int x, int y, int zoom, QNetworkAccessManager* networkManager);
+ QString getImageFormat (MapType type, const QByteArray& image);
+
+ static quint32 averageSizeForType (MapType type);
+
+private slots:
+ void _networkReplyError (QNetworkReply::NetworkError error);
+ void _googleVersionCompleted ();
+ void _replyDestroyed ();
+
+private:
+ QString _getURL (MapType type, int x, int y, int zoom, QNetworkAccessManager* networkManager);
+ void _getSecGoogleWords (int x, int y, QString& sec1, QString& sec2);
+ int _getServerNum (int x, int y, int max);
+ void _tryCorrectGoogleVersions (QNetworkAccessManager* networkManager);
+ QString _tileXYToQuadKey (int tileX, int tileY, int levelOfDetail);
+
+ int _timeout;
+ bool _googleVersionRetrieved;
+ QNetworkReply* _googleReply;
+ QMutex _googleVersionMutex;
+ QByteArray _userAgent;
+ QString _language;
+
+ // Google version strings
+ QString _versionGoogleMap;
+ QString _versionGoogleSatellite;
+ QString _versionGoogleLabels;
+ QString _versionGoogleTerrain;
+ QString _secGoogleWord;
+ // BingMaps
+ QString _versionBingMaps;
+
+};
+
+#endif
diff --git a/src/QtLocationPlugin/QGCTileCacheWorker.cpp b/src/QtLocationPlugin/QGCTileCacheWorker.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c6a9b1f3cd732991edcec4470e3d80cad6b6f70f
--- /dev/null
+++ b/src/QtLocationPlugin/QGCTileCacheWorker.cpp
@@ -0,0 +1,749 @@
+/*=====================================================================
+
+QGroundControl Open Source Ground Control Station
+
+(c) 2009, 2016 QGROUNDCONTROL PROJECT
+
+This file is part of the QGROUNDCONTROL project
+
+ QGROUNDCONTROL is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ QGROUNDCONTROL is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QGROUNDCONTROL. If not, see .
+
+======================================================================*/
+
+/**
+ * @file
+ * @brief Map Tile Cache Worker Thread
+ *
+ * @author Gus Grubba
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "time.h"
+
+#include "QGCMapEngine.h"
+#include "QGCMapTileSet.h"
+
+const char* kDefaultSet = "Default Tile Set";
+const QString kSession = QLatin1String("QGeoTileWorkerSession");
+
+QGC_LOGGING_CATEGORY(QGCTileCacheLog, "QGCTileCacheLog")
+
+//-- Update intervals
+
+#define LONG_TIMEOUT 5
+#define SHORT_TIMEOUT 2
+
+//-----------------------------------------------------------------------------
+QGCCacheWorker::QGCCacheWorker()
+ : _db(NULL)
+ , _valid(false)
+ , _failed(false)
+ , _defaultSet(UINT64_MAX)
+ , _totalSize(0)
+ , _totalCount(0)
+ , _defaultSize(0)
+ , _defaultCount(0)
+ , _lastUpdate(0)
+ , _updateTimeout(SHORT_TIMEOUT)
+{
+
+}
+
+//-----------------------------------------------------------------------------
+QGCCacheWorker::~QGCCacheWorker()
+{
+
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCCacheWorker::setDatabaseFile(const QString& path)
+{
+ _databasePath = path;
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCCacheWorker::quit()
+{
+ _mutex.lock();
+ while(_taskQueue.count()) {
+ QGCMapTask* task = _taskQueue.dequeue();
+ delete task;
+ }
+ _mutex.unlock();
+ if(this->isRunning()) {
+ _waitc.wakeAll();
+ }
+}
+
+//-----------------------------------------------------------------------------
+bool
+QGCCacheWorker::enqueueTask(QGCMapTask* task)
+{
+ //-- If not initialized, the only allowed task is Init
+ if(!_valid && task->type() != QGCMapTask::taskInit) {
+ task->setError("Database Not Initialized");
+ task->deleteLater();
+ return false;
+ }
+ if(!_taskQueue.contains(task))
+ {
+ _mutex.lock();
+ _taskQueue.enqueue(task);
+ _mutex.unlock();
+ if(this->isRunning()) {
+ _waitc.wakeAll();
+ } else {
+ this->start(QThread::NormalPriority);
+ }
+ return true;
+ }
+ //-- Should never happen
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCCacheWorker::run()
+{
+ if(!_valid && !_failed) {
+ _init();
+ }
+ if(_valid) {
+ _db = new QSqlDatabase(QSqlDatabase::addDatabase("QSQLITE", kSession));
+ _db->setDatabaseName(_databasePath);
+ _db->setConnectOptions("QSQLITE_ENABLE_SHARED_CACHE");
+ _valid = _db->open();
+ }
+ while(true) {
+ QGCMapTask* task;
+ if(_taskQueue.count()) {
+ _mutex.lock();
+ task = _taskQueue.dequeue();
+ _mutex.unlock();
+ switch(task->type()) {
+ case QGCMapTask::taskInit:
+ break;
+ case QGCMapTask::taskCacheTile:
+ _saveTile(task);
+ break;
+ case QGCMapTask::taskFetchTile:
+ _getTile(task);
+ break;
+ case QGCMapTask::taskFetchTileSets:
+ _getTileSets(task);
+ break;
+ case QGCMapTask::taskCreateTileSet:
+ _createTileSet(task);
+ break;
+ case QGCMapTask::taskGetTileDownloadList:
+ _getTileDownloadList(task);
+ break;
+ case QGCMapTask::taskUpdateTileDownloadState:
+ _updateTileDownloadState(task);
+ break;
+ case QGCMapTask::taskDeleteTileSet:
+ _deleteTileSet(task);
+ break;
+ case QGCMapTask::taskPruneCache:
+ _pruneCache(task);
+ break;
+ case QGCMapTask::taskReset:
+ _resetCacheDatabase(task);
+ break;
+ }
+ task->deleteLater();
+ //-- Check for update timeout
+ size_t count = _taskQueue.count();
+ if(count > 100) {
+ _updateTimeout = LONG_TIMEOUT;
+ } else if(count < 25) {
+ _updateTimeout = SHORT_TIMEOUT;
+ }
+ if(!count || (time(0) - _lastUpdate > _updateTimeout)) {
+ _updateTotals();
+ }
+ } else {
+ //-- Wait a bit before shutting things down
+ _waitmutex.lock();
+ int timeout = 5000;
+ if(!_waitc.wait(&_waitmutex, timeout))
+ {
+ _waitmutex.unlock();
+ _mutex.lock();
+ //-- If nothing to do, close db and leave thread
+ if(!_taskQueue.count()) {
+ _mutex.unlock();
+ break;
+ }
+ _mutex.unlock();
+ }
+ _waitmutex.unlock();
+ }
+ }
+ if(_db) {
+ delete _db;
+ _db = NULL;
+ QSqlDatabase::removeDatabase(kSession);
+ }
+}
+//-----------------------------------------------------------------------------
+bool
+QGCCacheWorker::_findTileSetID(const QString name, quint64& setID)
+{
+ QSqlQuery query(*_db);
+ QString s = QString("SELECT setID FROM TileSets WHERE name = \"%1\"").arg(name);
+ if(query.exec(s)) {
+ if(query.next()) {
+ setID = query.value(0).toULongLong();
+ return true;
+ }
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+quint64
+QGCCacheWorker::_getDefaultTileSet()
+{
+ if(_defaultSet != UINT64_MAX)
+ return _defaultSet;
+ QSqlQuery query(*_db);
+ QString s = QString("SELECT setID FROM TileSets WHERE defaultSet = 1");
+ if(query.exec(s)) {
+ if(query.next()) {
+ _defaultSet = query.value(0).toULongLong();
+ return _defaultSet;
+ }
+ }
+ return 1L;
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCCacheWorker::_saveTile(QGCMapTask *mtask)
+{
+ if(_valid) {
+ QGCSaveTileTask* task = static_cast(mtask);
+ QSqlQuery query(*_db);
+ query.prepare("INSERT INTO Tiles(hash, format, tile, size, type, date) VALUES(?, ?, ?, ?, ?, ?)");
+ query.addBindValue(task->tile()->hash());
+ query.addBindValue(task->tile()->format());
+ query.addBindValue(task->tile()->img());
+ query.addBindValue(task->tile()->img().size());
+ query.addBindValue(task->tile()->type());
+ query.addBindValue(QDateTime::currentDateTime().toTime_t());
+ if(query.exec()) {
+ quint64 tileID = query.lastInsertId().toULongLong();
+ quint64 setID = task->tile()->set() == UINT64_MAX ? _getDefaultTileSet() : task->tile()->set();
+ QString s = QString("INSERT INTO SetTiles(tileID, setID) VALUES(%1, %2)").arg(tileID).arg(setID);
+ query.prepare(s);
+ if(!query.exec()) {
+ qWarning() << "Map Cache SQL error (add tile into SetTiles):" << query.lastError().text();
+ }
+ qCDebug(QGCTileCacheLog) << "_saveTile() HASH:" << task->tile()->hash();
+ } else {
+ //-- Tile was already there.
+ // QtLocation some times requests the same tile twice in a row. The first is saved, the second is already there.
+ }
+ } else {
+ qWarning() << "Map Cache SQL error (saveTile() open db):" << _db->lastError();
+ }
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCCacheWorker::_getTile(QGCMapTask* mtask)
+{
+ if(!_valid) {
+ mtask->setError("No Cache Database");
+ return;
+ }
+ bool found = false;
+ QGCFetchTileTask* task = static_cast(mtask);
+ QSqlQuery query(*_db);
+ QString s = QString("SELECT tile, format, type FROM Tiles WHERE hash = \"%1\"").arg(task->hash());
+ if(query.exec(s)) {
+ if(query.next()) {
+ QByteArray ar = query.value(0).toByteArray();
+ QString format = query.value(1).toString();
+ UrlFactory::MapType type = (UrlFactory::MapType)query.value(2).toInt();
+ qCDebug(QGCTileCacheLog) << "_getTile() (Found in DB) HASH:" << task->hash();
+ QGCCacheTile* tile = new QGCCacheTile(task->hash(), ar, format, type);
+ task->setTileFetched(tile);
+ found = true;
+ }
+ }
+ if(!found) {
+ qCDebug(QGCTileCacheLog) << "_getTile() (NOT in DB) HASH:" << task->hash();
+ task->setError("Tile not in cache database");
+ }
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCCacheWorker::_getTileSets(QGCMapTask* mtask)
+{
+ if(!_valid) {
+ mtask->setError("No Cache Database");
+ return;
+ }
+ QGCFetchTileSetTask* task = static_cast(mtask);
+ QSqlQuery query(*_db);
+ QString s = QString("SELECT * FROM TileSets ORDER BY defaultSet DESC, name ASC");
+ if(query.exec(s)) {
+ while(query.next()) {
+ QString name = query.value("name").toString();
+ QString desc = query.value("description").toString();
+ QGCCachedTileSet* set = new QGCCachedTileSet(name, desc);
+ set->setId(query.value("setID").toULongLong());
+ set->setMapTypeStr(query.value("typeStr").toString());
+ set->setTopleftLat(query.value("topleftLat").toDouble());
+ set->setTopleftLon(query.value("topleftLon").toDouble());
+ set->setBottomRightLat(query.value("bottomRightLat").toDouble());
+ set->setBottomRightLon(query.value("bottomRightLon").toDouble());
+ set->setMinZoom(query.value("minZoom").toInt());
+ set->setMaxZoom(query.value("maxZoom").toInt());
+ set->setType((UrlFactory::MapType)query.value("type").toInt());
+ set->setNumTiles(query.value("numTiles").toUInt());
+ set->setTilesSize(query.value("tilesSize").toULongLong());
+ set->setDefaultSet(query.value("defaultSet").toInt() != 0);
+ set->setCreationDate(QDateTime::fromTime_t(query.value("date").toUInt()));
+ //-- Load thumbnail (if not default set)
+ if(!set->defaultSet()) {
+ int w = query.value("thumbW").toInt();
+ int h = query.value("thumbH").toInt();
+ if(w && h) {
+ QByteArray ba = query.value("thumbNail").toByteArray();
+ set->setThumbNail(QImage((uchar*)(void*)ba.data(), w, h, QImage::Format_RGB32));
+ }
+ }
+ _updateSetTotals(set);
+ //-- Object created here must be moved to app thread to be used there
+ set->moveToThread(QApplication::instance()->thread());
+ task->tileSetFetched(set);
+ }
+ } else {
+ task->setError("No tile set in database");
+ }
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCCacheWorker::_updateSetTotals(QGCCachedTileSet* set)
+{
+ if(set->defaultSet()) {
+ _updateTotals();
+ set->setSavedTiles(_totalCount);
+ set->setSavedSize(_totalSize);
+ set->setNumTiles(_defaultCount);
+ set->setTilesSize(_defaultSize);
+ return;
+ }
+ QSqlQuery subquery(*_db);
+ QString sq = QString("SELECT COUNT(size), SUM(size) FROM Tiles A INNER JOIN SetTiles B on A.tileID = B.tileID WHERE B.setID = %1").arg(set->id());
+ if(subquery.exec(sq)) {
+ if(subquery.next()) {
+ set->setSavedTiles(subquery.value(0).toUInt());
+ set->setSavedSize(subquery.value(1).toULongLong());
+ //-- Update estimated size
+ if(set->savedTiles() > 10 && set->savedSize()) {
+ quint32 avg = set->savedSize() / set->savedTiles();
+ set->setTilesSize(avg * set->numTiles());
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCCacheWorker::_updateTotals()
+{
+ QSqlQuery query(*_db);
+ QString s;
+ s = QString("SELECT COUNT(size), SUM(size) FROM Tiles");
+ if(query.exec(s)) {
+ if(query.next()) {
+ _totalCount = query.value(0).toUInt();
+ _totalSize = query.value(1).toULongLong();
+ }
+ }
+ s = QString("SELECT COUNT(size), SUM(size) FROM Tiles A INNER JOIN SetTiles B on A.tileID = B.tileID WHERE B.setID = %1").arg(_getDefaultTileSet());
+ if(query.exec(s)) {
+ if(query.next()) {
+ _defaultCount = query.value(0).toUInt();
+ _defaultSize = query.value(1).toULongLong();
+ }
+ }
+ emit updateTotals(_totalCount, _totalSize, _defaultCount, _defaultSize);
+ _lastUpdate = time(0);
+}
+
+//-----------------------------------------------------------------------------
+bool
+QGCCacheWorker::_findTile(const QString hash)
+{
+ QSqlQuery query(*_db);
+ QString s = QString("SELECT type FROM Tiles WHERE hash = \"%1\"").arg(hash);
+ if(query.exec(s)) {
+ if(query.next()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCCacheWorker::_createTileSet(QGCMapTask *mtask)
+{
+ if(_valid) {
+ //-- Create Tile Set
+ quint32 actual_count = 0;
+ QGCCreateTileSetTask* task = static_cast(mtask);
+ QSqlQuery query(*_db);
+ query.prepare("INSERT INTO TileSets("
+ "name, description, typeStr, topleftLat, topleftLon, bottomRightLat, bottomRightLon, minZoom, maxZoom, type, numTiles, tilesSize, thumbNail, thumbW, thumbH, date"
+ ") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
+ query.addBindValue(task->tileSet()->name());
+ query.addBindValue(task->tileSet()->description());
+ query.addBindValue(task->tileSet()->mapTypeStr());
+ query.addBindValue(task->tileSet()->topleftLat());
+ query.addBindValue(task->tileSet()->topleftLon());
+ query.addBindValue(task->tileSet()->bottomRightLat());
+ query.addBindValue(task->tileSet()->bottomRightLon());
+ query.addBindValue(task->tileSet()->minZoom());
+ query.addBindValue(task->tileSet()->maxZoom());
+ query.addBindValue(task->tileSet()->type());
+ query.addBindValue(task->tileSet()->numTiles());
+ query.addBindValue(task->tileSet()->tilesSize());
+ if(task->tileSet()->thumbNail().isNull()) {
+ query.addBindValue(QByteArray(1,'\0'));
+ query.addBindValue(0);
+ query.addBindValue(0);
+ } else {
+ query.addBindValue(QByteArray((const char *)(void*)task->tileSet()->thumbNail().convertToFormat(QImage::Format_RGB32).bits(), task->tileSet()->thumbNail().byteCount()));
+ query.addBindValue(task->tileSet()->thumbNail().width());
+ query.addBindValue(task->tileSet()->thumbNail().height());
+ }
+ query.addBindValue(QDateTime::currentDateTime().toTime_t());
+ if(!query.exec()) {
+ qWarning() << "Map Cache SQL error (add tileSet into TileSets):" << query.lastError().text();
+ } else {
+ //-- Get just creted (auto-incremented) setID
+ quint64 setID = query.lastInsertId().toULongLong();
+ task->tileSet()->setId(setID);
+ //-- Prepare Download List
+ for(int z = task->tileSet()->minZoom(); z <= task->tileSet()->maxZoom(); z++) {
+ QGCTileSet set = QGCMapEngine::getTileCount(z,
+ task->tileSet()->topleftLon(), task->tileSet()->topleftLat(),
+ task->tileSet()->bottomRightLon(), task->tileSet()->bottomRightLat(), task->tileSet()->type());
+ UrlFactory::MapType type = task->tileSet()->type();
+ for(int x = set.tileX0; x <= set.tileX1; x++) {
+ for(int y = set.tileY0; y <= set.tileY1; y++) {
+ //-- See if tile is already downloaded
+ QString hash = QGCMapEngine::getTileHash(type, x, y, z);
+ if(!_findTile(hash)) {
+ //-- Set to download
+ query.prepare("INSERT OR IGNORE INTO TilesDownload(setID, hash, type, x, y, z, state) VALUES(?, ?, ?, ?, ? ,? ,?)");
+ query.addBindValue(setID);
+ query.addBindValue(hash);
+ query.addBindValue(type);
+ query.addBindValue(x);
+ query.addBindValue(y);
+ query.addBindValue(z);
+ query.addBindValue(0);
+ if(!query.exec()) {
+ qWarning() << "Map Cache SQL error (add tile into TilesDownload):" << query.lastError().text();
+ mtask->setError("Error creating tile set download list");
+ return;
+ } else
+ actual_count++;
+ }
+ }
+ }
+ }
+ //-- Now update how many tiles we actually have to download
+ quint64 actual_size = actual_count * UrlFactory::averageSizeForType(task->tileSet()->type());
+ QString s = QString("UPDATE TileSets SET numTiles = %1, tilesSize = %2 WHERE setID = %3").arg(actual_count).arg(actual_size).arg(task->tileSet()->setID());
+ if(!query.exec(s)) {
+ qWarning() << "Map Cache SQL error (set TilesDownload state):" << query.lastError().text();
+ }
+ //-- Done
+ _updateSetTotals(task->tileSet());
+ task->setTileSetSaved();
+ return;
+ }
+ }
+ mtask->setError("Error saving tile set");
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCCacheWorker::_getTileDownloadList(QGCMapTask* mtask)
+{
+ if(!_valid) {
+ mtask->setError("No Cache Database");
+ return;
+ }
+ QList tiles;
+ QGCGetTileDownloadListTask* task = static_cast(mtask);
+ QSqlQuery query(*_db);
+ QString s = QString("SELECT hash, type, x, y, z FROM TilesDownload WHERE setID = %1 AND state = 0 LIMIT %2").arg(task->setID()).arg(task->count());
+ if(query.exec(s)) {
+ while(query.next()) {
+ QGCTile* tile = new QGCTile;
+ tile->setHash(query.value("hash").toString());
+ tile->setType((UrlFactory::MapType)query.value("type").toInt());
+ tile->setX(query.value("x").toInt());
+ tile->setY(query.value("y").toInt());
+ tile->setZ(query.value("z").toInt());
+ tiles.append(tile);
+ }
+ for(int i = 0; i < tiles.size(); i++) {
+ s = QString("UPDATE TilesDownload SET state = %1 WHERE setID = %2 and hash = \"%3\"").arg((int)QGCTile::StateDownloading).arg(task->setID()).arg(tiles[i]->hash());
+ if(!query.exec(s)) {
+ qWarning() << "Map Cache SQL error (set TilesDownload state):" << query.lastError().text();
+ }
+ }
+ }
+ task->setTileListFetched(tiles);
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCCacheWorker::_updateTileDownloadState(QGCMapTask* mtask)
+{
+ if(!_valid) {
+ mtask->setError("No Cache Database");
+ return;
+ }
+ QGCUpdateTileDownloadStateTask* task = static_cast(mtask);
+ QSqlQuery query(*_db);
+ QString s;
+ if(task->state() == QGCTile::StateComplete) {
+ s = QString("DELETE FROM TilesDownload WHERE setID = %1 AND hash = \"%2\"").arg(task->setID()).arg(task->hash());
+ } else {
+ if(task->hash() == "*") {
+ s = QString("UPDATE TilesDownload SET state = %1 WHERE setID = %2").arg((int)task->state()).arg(task->setID());
+ } else {
+ s = QString("UPDATE TilesDownload SET state = %1 WHERE setID = %2 AND hash = \"%3\"").arg((int)task->state()).arg(task->setID()).arg(task->hash());
+ }
+ }
+ if(!query.exec(s)) {
+ qWarning() << "QGCCacheWorker::_updateTileDownloadState() Error:" << query.lastError().text();
+ }
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCCacheWorker::_pruneCache(QGCMapTask* mtask)
+{
+ if(!_valid) {
+ mtask->setError("No Cache Database");
+ return;
+ }
+ QGCPruneCacheTask* task = static_cast(mtask);
+ QSqlQuery query(*_db);
+ QString s;
+ s = QString("SELECT tileID, size, hash FROM Tiles WHERE tileID IN (SELECT tileID FROM SetTiles WHERE setID = %1) ORDER BY DATE ASC LIMIT 128").arg(_getDefaultTileSet());
+ qint64 amount = (qint64)task->amount();
+ QList tlist;
+ if(query.exec(s)) {
+ while(query.next() && amount >= 0) {
+ tlist << query.value(0).toULongLong();
+ amount -= query.value(1).toULongLong();
+ qCDebug(QGCTileCacheLog) << "_pruneCache() HASH:" << query.value(2).toString();
+ }
+ while(tlist.count()) {
+ s = QString("DELETE FROM Tiles WHERE tileID = %1").arg(tlist[0]);
+ tlist.removeFirst();
+ if(!query.exec(s))
+ break;
+ }
+ task->setPruned();
+ }
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCCacheWorker::_deleteTileSet(QGCMapTask* mtask)
+{
+ if(!_valid) {
+ mtask->setError("No Cache Database");
+ return;
+ }
+ QGCDeleteTileSetTask* task = static_cast(mtask);
+ QSqlQuery query(*_db);
+ QString s;
+ s = QString("DELETE FROM Tiles WHERE tileID IN (SELECT tileID FROM SetTiles WHERE setID = %1)").arg(task->setID());
+ query.exec(s);
+ s = QString("DELETE FROM TilesDownload WHERE setID = %1").arg(task->setID());
+ query.exec(s);
+ s = QString("DELETE FROM TileSets WHERE setID = %1").arg(task->setID());
+ query.exec(s);
+ s = QString("DELETE FROM SetTiles WHERE setID = %1").arg(task->setID());
+ query.exec(s);
+ _updateTotals();
+ task->setTileSetDeleted();
+}
+//-----------------------------------------------------------------------------
+void
+QGCCacheWorker::_resetCacheDatabase(QGCMapTask* mtask)
+{
+ if(!_valid) {
+ mtask->setError("No Cache Database");
+ return;
+ }
+ QGCResetTask* task = static_cast(mtask);
+ QSqlQuery query(*_db);
+ QString s;
+ s = QString("DROP TABLE Tiles");
+ query.exec(s);
+ s = QString("DROP TABLE TileSets");
+ query.exec(s);
+ s = QString("DROP TABLE SetTiles");
+ query.exec(s);
+ s = QString("DROP TABLE TilesDownload");
+ query.exec(s);
+ _createDB();
+ task->setResetCompleted();
+}
+
+//-----------------------------------------------------------------------------
+bool
+QGCCacheWorker::_init()
+{
+ _failed = false;
+ if(!_databasePath.isEmpty()) {
+ qCDebug(QGCTileCacheLog) << "Mapping cache directory:" << _databasePath;
+ //-- Initialize Database
+ _db = new QSqlDatabase(QSqlDatabase::addDatabase("QSQLITE", kSession));
+ _db->setDatabaseName(_databasePath);
+ _db->setConnectOptions("QSQLITE_ENABLE_SHARED_CACHE");
+ if (_db->open()) {
+ _createDB();
+ } else {
+ qCritical() << "Map Cache SQL error (init() open db):" << _db->lastError();
+ _failed = true;
+ }
+ delete _db;
+ _db = NULL;
+ QSqlDatabase::removeDatabase(kSession);
+ } else {
+ qCritical() << "Could not find suitable cache directory.";
+ _failed = true;
+ }
+ return _failed;
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCCacheWorker::_createDB()
+{
+ QSqlQuery query(*_db);
+ if(!query.exec(
+ "CREATE TABLE IF NOT EXISTS Tiles ("
+ "tileID INTEGER PRIMARY KEY NOT NULL, "
+ "hash TEXT NOT NULL UNIQUE, "
+ "format TEXT NOT NULL, "
+ "tile BLOB NULL, "
+ "size INTEGER, "
+ "type INTEGER, "
+ "date INTEGER DEFAULT 0)"))
+ {
+ qWarning() << "Map Cache SQL error (create Tiles db):" << query.lastError().text();
+ } else {
+ if(!query.exec(
+ "CREATE TABLE IF NOT EXISTS TileSets ("
+ "setID INTEGER PRIMARY KEY NOT NULL, "
+ "name TEXT NOT NULL UNIQUE, "
+ "description TEXT NOT NULL, "
+ "typeStr TEXT, "
+ "topleftLat REAL DEFAULT 0.0, "
+ "topleftLon REAL DEFAULT 0.0, "
+ "bottomRightLat REAL DEFAULT 0.0, "
+ "bottomRightLon REAL DEFAULT 0.0, "
+ "minZoom INTEGER DEFAULT 3, "
+ "maxZoom INTEGER DEFAULT 3, "
+ "type INTEGER DEFAULT -1, "
+ "numTiles INTEGER DEFAULT 0, "
+ "tilesSize INTEGER DEFAULT 0, "
+ "defaultSet INTEGER DEFAULT 0, "
+ "thumbNail BLOB NULL, "
+ "thumbW INTEGER DEFAULT 0, "
+ "thumbH INTEGER DEFAULT 0, "
+ "date INTEGER DEFAULT 0)"))
+ {
+ qWarning() << "Map Cache SQL error (create TileSets db):" << query.lastError().text();
+ } else {
+ if(!query.exec(
+ "CREATE TABLE IF NOT EXISTS SetTiles ("
+ "setID INTEGER, "
+ "tileID INTEGER)"))
+ {
+ qWarning() << "Map Cache SQL error (create SetTiles db):" << query.lastError().text();
+ } else {
+ if(!query.exec(
+ "CREATE TABLE IF NOT EXISTS TilesDownload ("
+ "setID INTEGER, "
+ "hash TEXT NOT NULL UNIQUE, "
+ "type INTEGER, "
+ "x INTEGER, "
+ "y INTEGER, "
+ "z INTEGER, "
+ "state INTEGER DEFAULT 0)"))
+ {
+ qWarning() << "Map Cache SQL error (create TilesDownload db):" << query.lastError().text();
+ } else {
+ //-- Database it ready for use
+ _valid = true;
+ }
+ }
+ }
+ }
+ //-- Create default tile set
+ if(_valid) {
+ QString s = QString("SELECT name FROM TileSets WHERE name = \"%1\"").arg(kDefaultSet);
+ if(query.exec(s)) {
+ if(!query.next()) {
+ query.prepare("INSERT INTO TileSets(name, description, defaultSet, date) VALUES(?, ?, ?, ?)");
+ query.addBindValue(kDefaultSet);
+ query.addBindValue("System wide tile cache");
+ 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;
+ }
+ }
+ } else {
+ qWarning() << "Map Cache SQL error (Looking for default tile set):" << _db->lastError();
+ }
+ }
+ if(!_valid) {
+ QFile file(_databasePath);
+ file.remove();
+ }
+ _failed = !_valid;
+}
diff --git a/src/QtLocationPlugin/QGCTileCacheWorker.h b/src/QtLocationPlugin/QGCTileCacheWorker.h
new file mode 100644
index 0000000000000000000000000000000000000000..646f761e5838ab038d74bb43f67681ab3034c528
--- /dev/null
+++ b/src/QtLocationPlugin/QGCTileCacheWorker.h
@@ -0,0 +1,105 @@
+/*=====================================================================
+
+QGroundControl Open Source Ground Control Station
+
+(c) 2009, 2016 QGROUNDCONTROL PROJECT
+
+This file is part of the QGROUNDCONTROL project
+
+ QGROUNDCONTROL is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ QGROUNDCONTROL is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QGROUNDCONTROL. If not, see .
+
+======================================================================*/
+
+/**
+ * @file
+ * @brief Map Tile Cache Worker Thread
+ *
+ * @author Gus Grubba
+ *
+ */
+
+#ifndef QGC_TILE_CACHE_WORKER_H
+#define QGC_TILE_CACHE_WORKER_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "QGCLoggingCategory.h"
+
+Q_DECLARE_LOGGING_CATEGORY(QGCTileCacheLog)
+
+class QGCMapTask;
+class QGCCachedTileSet;
+
+//-----------------------------------------------------------------------------
+class QGCCacheWorker : public QThread
+{
+ Q_OBJECT
+public:
+ QGCCacheWorker ();
+ ~QGCCacheWorker ();
+
+ void quit ();
+ bool enqueueTask (QGCMapTask* task);
+ void setDatabaseFile (const QString& path);
+
+protected:
+ void run ();
+
+private:
+ void _saveTile (QGCMapTask* mtask);
+ void _getTile (QGCMapTask* mtask);
+ void _getTileSets (QGCMapTask* mtask);
+ void _createTileSet (QGCMapTask* mtask);
+ void _getTileDownloadList (QGCMapTask* mtask);
+ void _updateTileDownloadState(QGCMapTask* mtask);
+ void _deleteTileSet (QGCMapTask* mtask);
+ void _resetCacheDatabase (QGCMapTask* mtask);
+ void _pruneCache (QGCMapTask* mtask);
+
+ bool _findTile (const QString hash);
+ bool _findTileSetID (const QString name, quint64& setID);
+ void _updateSetTotals (QGCCachedTileSet* set);
+ bool _init ();
+ void _createDB ();
+ quint64 _getDefaultTileSet ();
+ void _updateTotals ();
+
+signals:
+ void updateTotals (quint32 totaltiles, quint64 totalsize, quint32 defaulttiles, quint64 defaultsize);
+
+private:
+ QQueue _taskQueue;
+ QMutex _mutex;
+ QMutex _waitmutex;
+ QWaitCondition _waitc;
+ QString _databasePath;
+ QSqlDatabase* _db;
+ bool _valid;
+ bool _failed;
+ quint64 _defaultSet;
+ quint64 _totalSize;
+ quint32 _totalCount;
+ quint64 _defaultSize;
+ quint32 _defaultCount;
+ time_t _lastUpdate;
+ int _updateTimeout;
+};
+
+#endif // QGC_TILE_CACHE_WORKER_H
diff --git a/src/QtLocationPlugin/qgeocodereplyqgc.cpp b/src/QtLocationPlugin/QGeoCodeReplyQGC.cpp
similarity index 99%
rename from src/QtLocationPlugin/qgeocodereplyqgc.cpp
rename to src/QtLocationPlugin/QGeoCodeReplyQGC.cpp
index 48f6af56f9e6ff588718e2b5eb2073b2fc829de7..aeca6d4b5862e63ffe4e673914038b40f6121d6e 100644
--- a/src/QtLocationPlugin/qgeocodereplyqgc.cpp
+++ b/src/QtLocationPlugin/QGeoCodeReplyQGC.cpp
@@ -54,7 +54,7 @@
#include
#include
-#include "qgeocodereplyqgc.h"
+#include "QGeoCodeReplyQGC.h"
enum QGeoCodeTypeGoogle {
GeoCodeTypeUnknown,
diff --git a/src/QtLocationPlugin/qgeocodereplyqgc.h b/src/QtLocationPlugin/QGeoCodeReplyQGC.h
similarity index 96%
rename from src/QtLocationPlugin/qgeocodereplyqgc.h
rename to src/QtLocationPlugin/QGeoCodeReplyQGC.h
index b53b1726c85f6a04c15bb31fe56189ff8e3cf62f..4a94ce3baa2721b4d866737612be1998e6d8ced1 100644
--- a/src/QtLocationPlugin/qgeocodereplyqgc.h
+++ b/src/QtLocationPlugin/QGeoCodeReplyQGC.h
@@ -44,8 +44,8 @@
**
****************************************************************************/
-#ifndef QGEOCODEREPLYGOOGLE_H
-#define QGEOCODEREPLYGOOGLE_H
+#ifndef QGEOCODEREPLYQGC_H
+#define QGEOCODEREPLYQGC_H
#include
#include
@@ -68,4 +68,4 @@ private:
QNetworkReply *m_reply;
};
-#endif // QGEOCODEREPLYGOOGLE_H
+#endif // QGEOCODEREPLYQGC_H
diff --git a/src/QtLocationPlugin/qgeocodingmanagerengineqgc.cpp b/src/QtLocationPlugin/QGeoCodingManagerEngineQGC.cpp
similarity index 98%
rename from src/QtLocationPlugin/qgeocodingmanagerengineqgc.cpp
rename to src/QtLocationPlugin/QGeoCodingManagerEngineQGC.cpp
index 567c329902723841d6d0173329bb071a358d52cc..384c1ac18705c691933c90349fb31dadcc43b079 100644
--- a/src/QtLocationPlugin/qgeocodingmanagerengineqgc.cpp
+++ b/src/QtLocationPlugin/QGeoCodingManagerEngineQGC.cpp
@@ -57,8 +57,8 @@
#include
#include
-#include "qgeocodingmanagerengineqgc.h"
-#include "qgeocodereplyqgc.h"
+#include "QGeoCodingManagerEngineQGC.h"
+#include "QGeoCodeReplyQGC.h"
static QString addressToQuery(const QGeoAddress &address)
{
diff --git a/src/QtLocationPlugin/qgeocodingmanagerengineqgc.h b/src/QtLocationPlugin/QGeoCodingManagerEngineQGC.h
similarity index 96%
rename from src/QtLocationPlugin/qgeocodingmanagerengineqgc.h
rename to src/QtLocationPlugin/QGeoCodingManagerEngineQGC.h
index 56040f4cdbf5eaf360573f10aed755c6cbe48023..14697c0f4cfa7fb01ce11faec949951fcaf1fd93 100644
--- a/src/QtLocationPlugin/qgeocodingmanagerengineqgc.h
+++ b/src/QtLocationPlugin/QGeoCodingManagerEngineQGC.h
@@ -44,8 +44,8 @@
**
****************************************************************************/
-#ifndef QGEOCODINGMANAGERENGINEGOOGLE_H
-#define QGEOCODINGMANAGERENGINEGOOGLE_H
+#ifndef QGEOCODINGMANAGERENGINEQGC_H
+#define QGEOCODINGMANAGERENGINEQGC_H
#include
#include
@@ -78,4 +78,4 @@ private:
QT_END_NAMESPACE
-#endif // QGEOCODINGMANAGERENGINEGOOGLE_H
+#endif // QGEOCODINGMANAGERENGINEQGC_H
diff --git a/src/QtLocationPlugin/QGeoMapReplyQGC.cpp b/src/QtLocationPlugin/QGeoMapReplyQGC.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..30d69e919cde031f224c5e0f7bda4ef89331a257
--- /dev/null
+++ b/src/QtLocationPlugin/QGeoMapReplyQGC.cpp
@@ -0,0 +1,171 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Aaron McCarthy
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+** 2015.4.4
+** Adapted for use with QGroundControl
+**
+** Gus Grubba
+**
+****************************************************************************/
+
+#include
+#include
+#include
+
+#include "QGCMapEngine.h"
+#include "QGeoMapReplyQGC.h"
+
+//-----------------------------------------------------------------------------
+QGeoTiledMapReplyQGC::QGeoTiledMapReplyQGC(QNetworkAccessManager *networkManager, const QNetworkRequest &request, const QGeoTileSpec &spec, QObject *parent)
+ : QGeoTiledMapReply(spec, parent)
+ , _reply(NULL)
+ , _request(request)
+ , _networkManager(networkManager)
+{
+ if(_request.url().isEmpty()) {
+ if(!_badMapBox.size()) {
+ QFile b(":/res/notile.png");
+ if(b.open(QFile::ReadOnly))
+ _badMapBox = b.readAll();
+ }
+ setMapImageData(_badMapBox);
+ setMapImageFormat("png");
+ setFinished(true);
+ setCached(false);
+ } else {
+ QGCFetchTileTask* task = getQGCMapEngine()->createFetchTileTask((UrlFactory::MapType)spec.mapId(), spec.x(), spec.y(), spec.zoom());
+ connect(task, &QGCFetchTileTask::tileFetched, this, &QGeoTiledMapReplyQGC::cacheReply);
+ connect(task, &QGCMapTask::error, this, &QGeoTiledMapReplyQGC::cacheError);
+ getQGCMapEngine()->addTask(task);
+ }
+}
+
+//-----------------------------------------------------------------------------
+QGeoTiledMapReplyQGC::~QGeoTiledMapReplyQGC()
+{
+ if (_reply) {
+ _reply->deleteLater();
+ _reply = 0;
+ }
+}
+//-----------------------------------------------------------------------------
+void
+QGeoTiledMapReplyQGC::abort()
+{
+ if (_reply)
+ _reply->abort();
+}
+
+//-----------------------------------------------------------------------------
+void
+QGeoTiledMapReplyQGC::replyDestroyed()
+{
+ _reply = 0;
+}
+
+//-----------------------------------------------------------------------------
+void
+QGeoTiledMapReplyQGC::networkReplyFinished()
+{
+ if (!_reply) {
+ return;
+ }
+ if (_reply->error() != QNetworkReply::NoError) {
+ return;
+ }
+ QByteArray a = _reply->readAll();
+ setMapImageData(a);
+ QString format = getQGCMapEngine()->urlFactory()->getImageFormat((UrlFactory::MapType)tileSpec().mapId(), a);
+ if(!format.isEmpty()) {
+ setMapImageFormat(format);
+ getQGCMapEngine()->cacheTile((UrlFactory::MapType)tileSpec().mapId(), tileSpec().x(), tileSpec().y(), tileSpec().zoom(), a, format);
+ }
+ setFinished(true);
+ _reply->deleteLater();
+ _reply = 0;
+}
+
+//-----------------------------------------------------------------------------
+void
+QGeoTiledMapReplyQGC::networkReplyError(QNetworkReply::NetworkError error)
+{
+ if (!_reply) {
+ return;
+ }
+ if (error != QNetworkReply::OperationCanceledError) {
+ qWarning() << "Fetch tile error:" << _reply->errorString();
+ }
+ _reply->deleteLater();
+ _reply = 0;
+ if(!_badTile.size()) {
+ QFile b(":/res/notile.png");
+ if(b.open(QFile::ReadOnly))
+ _badTile = b.readAll();
+ }
+ setMapImageData(_badTile);
+ setMapImageFormat("png");
+ setFinished(true);
+ setCached(false);
+}
+
+//-----------------------------------------------------------------------------
+void
+QGeoTiledMapReplyQGC::cacheError(QGCMapTask::TaskType type, QString /*errorString*/)
+{
+ if(type != QGCMapTask::taskFetchTile) {
+ qWarning() << "QGeoTiledMapReplyQGC::cacheError() for wrong task";
+ }
+ //-- Tile not in cache. Get it off the Internet.
+ _reply = _networkManager->get(_request);
+ _reply->setParent(0);
+ connect(_reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
+ connect(_reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(networkReplyError(QNetworkReply::NetworkError)));
+ connect(_reply, SIGNAL(destroyed()), this, SLOT(replyDestroyed()));
+}
+
+//-----------------------------------------------------------------------------
+void
+QGeoTiledMapReplyQGC::cacheReply(QGCCacheTile* tile)
+{
+ setMapImageData(tile->img());
+ setMapImageFormat(tile->format());
+ setFinished(true);
+ setCached(true);
+ tile->deleteLater();
+}
diff --git a/src/QtLocationPlugin/qgeomapreplyqgc.h b/src/QtLocationPlugin/QGeoMapReplyQGC.h
similarity index 77%
rename from src/QtLocationPlugin/qgeomapreplyqgc.h
rename to src/QtLocationPlugin/QGeoMapReplyQGC.h
index 90d85583cd18a0bc37e1cec472e2f60a5c08c980..b66791090344cd64801a144e567f91bead548209 100644
--- a/src/QtLocationPlugin/qgeomapreplyqgc.h
+++ b/src/QtLocationPlugin/QGeoMapReplyQGC.h
@@ -44,31 +44,35 @@
**
****************************************************************************/
-#ifndef QGEOMAPREPLYGOOGLE_H
-#define QGEOMAPREPLYGOOGLE_H
+#ifndef QGEOMAPREPLYQGC_H
+#define QGEOMAPREPLYQGC_H
#include
#include
-class QGeoMapReplyQGC : public QGeoTiledMapReply
+#include "QGCMapEngineData.h"
+
+class QGeoTiledMapReplyQGC : public QGeoTiledMapReply
{
Q_OBJECT
-
public:
- explicit QGeoMapReplyQGC(QNetworkReply *reply, const QGeoTileSpec &spec, QObject *parent = 0);
- ~QGeoMapReplyQGC();
-
+ QGeoTiledMapReplyQGC(QNetworkAccessManager* networkManager, const QNetworkRequest& request, const QGeoTileSpec &spec, QObject *parent = 0);
+ ~QGeoTiledMapReplyQGC();
void abort();
- QNetworkReply *networkReply() const;
-
-private Q_SLOTS:
+private slots:
void replyDestroyed ();
void networkReplyFinished ();
void networkReplyError (QNetworkReply::NetworkError error);
+ void cacheReply (QGCCacheTile* tile);
+ void cacheError (QGCMapTask::TaskType type, QString errorString);
private:
- QNetworkReply* m_reply;
+ QNetworkReply* _reply;
+ QNetworkRequest _request;
+ QNetworkAccessManager* _networkManager;
+ QByteArray _badMapBox;
+ QByteArray _badTile;
};
-#endif // QGEOMAPREPLYGOOGLE_H
+#endif // QGEOMAPREPLYQGC_H
diff --git a/src/QtLocationPlugin/qgeoserviceproviderpluginqgc.cpp b/src/QtLocationPlugin/QGeoServiceProviderPluginQGC.cpp
similarity index 78%
rename from src/QtLocationPlugin/qgeoserviceproviderpluginqgc.cpp
rename to src/QtLocationPlugin/QGeoServiceProviderPluginQGC.cpp
index bead3e336e8c235155077aa9c967d10e6924db5c..1b24429ebfe357207ce82e6d645bbd600bf6b911 100644
--- a/src/QtLocationPlugin/qgeoserviceproviderpluginqgc.cpp
+++ b/src/QtLocationPlugin/QGeoServiceProviderPluginQGC.cpp
@@ -47,38 +47,48 @@
#include
#include "qdebug.h"
-#include "qgeoserviceproviderpluginqgc.h"
-#include "qgeotiledmappingmanagerengineqgc.h"
-#include "qgeocodingmanagerengineqgc.h"
+#include "QGeoServiceProviderPluginQGC.h"
+#include "QGeoTiledMappingManagerEngineQGC.h"
+#include "QGeoCodingManagerEngineQGC.h"
Q_EXTERN_C Q_DECL_EXPORT const char *qt_plugin_query_metadata();
Q_EXTERN_C Q_DECL_EXPORT QT_PREPEND_NAMESPACE(QObject) *qt_plugin_instance();
+
+//-----------------------------------------------------------------------------
const QT_PREPEND_NAMESPACE(QStaticPlugin) qt_static_plugin_QGeoServiceProviderFactoryQGC()
{
QT_PREPEND_NAMESPACE(QStaticPlugin) plugin = { qt_plugin_instance, qt_plugin_query_metadata};
return plugin;
}
-QGeoCodingManagerEngine *QGeoServiceProviderFactoryQGC::createGeocodingManagerEngine(
+//-----------------------------------------------------------------------------
+QGeoCodingManagerEngine*
+QGeoServiceProviderFactoryQGC::createGeocodingManagerEngine(
const QVariantMap ¶meters, QGeoServiceProvider::Error *error, QString *errorString) const
{
return new QGeoCodingManagerEngineQGC(parameters, error, errorString);
}
-QGeoMappingManagerEngine *QGeoServiceProviderFactoryQGC::createMappingManagerEngine(
+//-----------------------------------------------------------------------------
+QGeoMappingManagerEngine*
+QGeoServiceProviderFactoryQGC::createMappingManagerEngine(
const QVariantMap ¶meters, QGeoServiceProvider::Error *error, QString *errorString) const
{
return new QGeoTiledMappingManagerEngineQGC(parameters, error, errorString);
}
-QGeoRoutingManagerEngine *QGeoServiceProviderFactoryQGC::createRoutingManagerEngine(
+//-----------------------------------------------------------------------------
+QGeoRoutingManagerEngine*
+QGeoServiceProviderFactoryQGC::createRoutingManagerEngine(
const QVariantMap &, QGeoServiceProvider::Error *, QString *) const
{
// Not implemented for QGC
return NULL;
}
-QPlaceManagerEngine *QGeoServiceProviderFactoryQGC::createPlaceManagerEngine(
+//-----------------------------------------------------------------------------
+QPlaceManagerEngine*
+QGeoServiceProviderFactoryQGC::createPlaceManagerEngine(
const QVariantMap &, QGeoServiceProvider::Error *, QString *) const
{
// Not implemented for QGC
diff --git a/src/QtLocationPlugin/qgeoserviceproviderpluginqgc.h b/src/QtLocationPlugin/QGeoServiceProviderPluginQGC.h
similarity index 96%
rename from src/QtLocationPlugin/qgeoserviceproviderpluginqgc.h
rename to src/QtLocationPlugin/QGeoServiceProviderPluginQGC.h
index 49f598b2376a4d13c47fb432a3aca613dead44f1..4f1659f049f5bd1e21c12bf9c506c69f86ceb05c 100644
--- a/src/QtLocationPlugin/qgeoserviceproviderpluginqgc.h
+++ b/src/QtLocationPlugin/QGeoServiceProviderPluginQGC.h
@@ -44,8 +44,8 @@
**
****************************************************************************/
-#ifndef QGEOSERVICEPROVIDER_GOOGLE_H
-#define QGEOSERVICEPROVIDER_GOOGLE_H
+#ifndef QGEOSERVICEPROVIDERQGC_H
+#define QGEOSERVICEPROVIDERQGC_H
#include
#include
@@ -64,4 +64,4 @@ public:
QPlaceManagerEngine* createPlaceManagerEngine (const QVariantMap ¶meters, QGeoServiceProvider::Error *error, QString *errorString) const;
};
-#endif // QGEOSERVICEPROVIDER_GOOGLE_H
+#endif // QGEOSERVICEPROVIDERQGC_H
diff --git a/src/QtLocationPlugin/QGeoTileFetcherQGC.cpp b/src/QtLocationPlugin/QGeoTileFetcherQGC.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c9e34958a23c4612d8f78b3d5541199ea30a25d9
--- /dev/null
+++ b/src/QtLocationPlugin/QGeoTileFetcherQGC.cpp
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Aaron McCarthy
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+** 2015.4.4
+** Adapted for use with QGroundControl
+**
+** Gus Grubba
+**
+****************************************************************************/
+
+#include
+#include
+#include
+
+#include "QGCMapEngine.h"
+#include "QGeoTileFetcherQGC.h"
+#include "QGeoMapReplyQGC.h"
+
+//-----------------------------------------------------------------------------
+QGeoTileFetcherQGC::QGeoTileFetcherQGC(QGeoTiledMappingManagerEngine *parent)
+ : QGeoTileFetcher(parent)
+ , _networkManager(new QNetworkAccessManager(this))
+{
+}
+
+//-----------------------------------------------------------------------------
+QGeoTileFetcherQGC::~QGeoTileFetcherQGC()
+{
+
+}
+
+//-----------------------------------------------------------------------------
+QGeoTiledMapReply*
+QGeoTileFetcherQGC::getTileImage(const QGeoTileSpec &spec)
+{
+ //-- Build URL
+ QNetworkRequest request = getQGCMapEngine()->urlFactory()->getTileURL((UrlFactory::MapType)spec.mapId(), spec.x(), spec.y(), spec.zoom(), _networkManager);
+ return new QGeoTiledMapReplyQGC(_networkManager, request, spec);
+}
diff --git a/src/QtLocationPlugin/qgeotilefetcherqgc.h b/src/QtLocationPlugin/QGeoTileFetcherQGC.h
similarity index 82%
rename from src/QtLocationPlugin/qgeotilefetcherqgc.h
rename to src/QtLocationPlugin/QGeoTileFetcherQGC.h
index 5f3dfab8df9ab1ff0a5ad681dfb5c39837e86b9a..846306351f68635f707f821fa3c5b8b282ef739c 100644
--- a/src/QtLocationPlugin/qgeotilefetcherqgc.h
+++ b/src/QtLocationPlugin/QGeoTileFetcherQGC.h
@@ -44,12 +44,12 @@
**
****************************************************************************/
-#ifndef QGEOTILEFETCHERGOOGLE_H
-#define QGEOTILEFETCHERGOOGLE_H
+#ifndef QGEOTILEFETCHERQGC_H
+#define QGEOTILEFETCHERQGC_H
#include
#include
-#include "OpenPilotMaps.h"
+#include "QGCMapUrlEngine.h"
class QGeoTiledMappingManagerEngine;
class QNetworkAccessManager;
@@ -57,19 +57,13 @@ class QNetworkAccessManager;
class QGeoTileFetcherQGC : public QGeoTileFetcher
{
Q_OBJECT
-
public:
- explicit QGeoTileFetcherQGC(QGeoTiledMappingManagerEngine *parent = 0);
+ explicit QGeoTileFetcherQGC (QGeoTiledMappingManagerEngine *parent = 0);
~QGeoTileFetcherQGC();
-
- void setUserAgent(const QByteArray &userAgent);
-
private:
- QGeoTiledMapReply* getTileImage(const QGeoTileSpec &spec);
- QNetworkAccessManager* m_networkManager;
- QByteArray m_userAgent;
- OpenPilot::UrlFactory* m_UrlFactory;
- QString m_Language;
+ QGeoTiledMapReply* getTileImage (const QGeoTileSpec &spec);
+private:
+ QNetworkAccessManager* _networkManager;
};
-#endif // QGEOTILEFETCHERGOOGLE_H
+#endif // QGEOTILEFETCHERQGC_H
diff --git a/src/QtLocationPlugin/QGeoTiledMappingManagerEngineQGC.cpp b/src/QtLocationPlugin/QGeoTiledMappingManagerEngineQGC.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c762f84235b39a7a580fbd6dab13683f34a9d12a
--- /dev/null
+++ b/src/QtLocationPlugin/QGeoTiledMappingManagerEngineQGC.cpp
@@ -0,0 +1,239 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Aaron McCarthy
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+** 2015.4.4
+** Adapted for use with QGroundControl
+**
+** Gus Grubba
+**
+****************************************************************************/
+
+#include
+#include
+#if QT_VERSION < 0x050500
+#include
+#else
+#include
+#endif
+#include
+#include
+
+#include "QGCMapEngine.h"
+#include "QGeoTiledMappingManagerEngineQGC.h"
+#include "QGeoTileFetcherQGC.h"
+
+#if QT_VERSION >= 0x050500
+//-----------------------------------------------------------------------------
+QGeoTiledMapQGC::QGeoTiledMapQGC(QGeoTiledMappingManagerEngine *engine, QObject *parent)
+ : QGeoTiledMap(engine, parent)
+{
+
+}
+#endif
+
+//-----------------------------------------------------------------------------
+QGeoTiledMappingManagerEngineQGC::QGeoTiledMappingManagerEngineQGC(const QVariantMap ¶meters, QGeoServiceProvider::Error *error, QString *errorString)
+: QGeoTiledMappingManagerEngine()
+{
+
+ QGeoCameraCapabilities cameraCaps;
+ cameraCaps.setMinimumZoomLevel(2.0);
+ cameraCaps.setMaximumZoomLevel(MAX_MAP_ZOOM);
+ cameraCaps.setSupportsBearing(true);
+ setCameraCapabilities(cameraCaps);
+
+ setTileSize(QSize(256, 256));
+
+ /*
+ * Most of these don't seem kosher at all. This was based on original code from OpenPilot and heavily modified to be used in QGC.
+ */
+
+
+ //-- IMPORTANT
+ // Changes here must reflect those in QGCMapEngine.cpp
+
+ QList mapTypes;
+ mapTypes << QGeoMapType(QGeoMapType::StreetMap, "Google Street Map", "Google street map", false, false, UrlFactory::GoogleMap);
+ mapTypes << QGeoMapType(QGeoMapType::SatelliteMapDay, "Google Satellite Map", "Google satellite map", false, false, UrlFactory::GoogleSatellite);
+ mapTypes << QGeoMapType(QGeoMapType::TerrainMap, "Google Terrain Map", "Google terrain map", false, false, UrlFactory::GoogleTerrain);
+
+ /* TODO:
+ * Proper google hybrid maps requires collecting two separate bimaps and overlaying them.
+ *
+ * mapTypes << QGeoMapType(QGeoMapType::HybridMap, "Google Hybrid Map", "Google hybrid map", false, false, UrlFactory::GoogleHybrid);
+ *
+ */
+
+ // Bing
+ mapTypes << QGeoMapType(QGeoMapType::StreetMap, "Bing Street Map", "Bing street map", false, false, UrlFactory::BingMap);
+ mapTypes << QGeoMapType(QGeoMapType::SatelliteMapDay, "Bing Satellite Map", "Bing satellite map", false, false, UrlFactory::BingSatellite);
+ mapTypes << QGeoMapType(QGeoMapType::HybridMap, "Bing Hybrid Map", "Bing hybrid map", false, false, UrlFactory::BingHybrid);
+
+ /* See: https://wiki.openstreetmap.org/wiki/Tile_usage_policy
+ mapTypes << QGeoMapType(QGeoMapType::StreetMap, "Open Street Map", "Open Street map", false, false, UrlFactory::OpenStreetMap);
+ */
+
+ // MapQuest
+ mapTypes << QGeoMapType(QGeoMapType::StreetMap, "MapQuest Street Map", "MapQuest street map", false, false, UrlFactory::MapQuestMap);
+ mapTypes << QGeoMapType(QGeoMapType::SatelliteMapDay, "MapQuest Satellite Map", "MapQuest satellite map", false, false, UrlFactory::MapQuestSat);
+
+ /*
+ * These are OK as you need your own token for accessing it. Out-of-the box, QGC does not even offer these unless you enter a proper MapBox token.
+ */
+
+ mapTypes << QGeoMapType(QGeoMapType::StreetMap, "MapBox Street Map", "MapBox Street Map", false, false, UrlFactory::MapBoxStreets);
+ mapTypes << QGeoMapType(QGeoMapType::SatelliteMapDay, "MapBox Satellite Map", "MapBox Satellite Map", false, false, UrlFactory::MapBoxSatellite);
+ mapTypes << QGeoMapType(QGeoMapType::CustomMap, "MapBox High Contrast Map", "MapBox High Contrast Map", false, false, UrlFactory::MapBoxHighContrast);
+ mapTypes << QGeoMapType(QGeoMapType::CustomMap, "MapBox Light Map", "MapBox Light Map", false, false, UrlFactory::MapBoxLight);
+ mapTypes << QGeoMapType(QGeoMapType::CustomMap, "MapBox Dark Map", "MapBox Dark Map", false, false, UrlFactory::MapBoxDark);
+ mapTypes << QGeoMapType(QGeoMapType::HybridMap, "MapBox Hybrid Map", "MapBox Hybrid Map", false, false, UrlFactory::MapBoxHybrid);
+ mapTypes << QGeoMapType(QGeoMapType::CustomMap, "MapBox Wheat Paste Map", "MapBox Wheat Paste Map", false, false, UrlFactory::MapBoxWheatPaste);
+ mapTypes << QGeoMapType(QGeoMapType::StreetMap, "MapBox Streets Basic Map", "MapBox Streets Basic Map", false, false, UrlFactory::MapBoxStreetsBasic);
+ mapTypes << QGeoMapType(QGeoMapType::CustomMap, "MapBox Comic Map", "MapBox Comic Map", false, false, UrlFactory::MapBoxComic);
+ mapTypes << QGeoMapType(QGeoMapType::CustomMap, "MapBox Outdoors Map", "MapBox Outdoors Map", false, false, UrlFactory::MapBoxOutdoors);
+ mapTypes << QGeoMapType(QGeoMapType::CycleMap, "MapBox Run, Byke and Hike Map", "MapBox Run, Byke and Hike Map", false, false, UrlFactory::MapBoxRunBikeHike);
+ mapTypes << QGeoMapType(QGeoMapType::CustomMap, "MapBox Pencil Map", "MapBox Pencil Map", false, false, UrlFactory::MapBoxPencil);
+ mapTypes << QGeoMapType(QGeoMapType::CustomMap, "MapBox Pirates Map", "MapBox Pirates Map", false, false, UrlFactory::MapBoxPirates);
+ mapTypes << QGeoMapType(QGeoMapType::CustomMap, "MapBox Emerald Map", "MapBox Emerald Map", false, false, UrlFactory::MapBoxEmerald);
+
+ setSupportedMapTypes(mapTypes);
+
+ //-- Users (QML code) can define a different user agent
+ if (parameters.contains(QStringLiteral("useragent"))) {
+ getQGCMapEngine()->setUserAgent(parameters.value(QStringLiteral("useragent")).toString().toLatin1());
+ }
+
+#if QT_VERSION >= 0x050500
+ _setCache(parameters);
+#endif
+
+ setTileFetcher(new QGeoTileFetcherQGC(this));
+
+ *error = QGeoServiceProvider::NoError;
+ errorString->clear();
+
+#if QT_VERSION >= 0x050500
+ if (parameters.contains(QStringLiteral("mapping.copyright")))
+ m_customCopyright = parameters.value(QStringLiteral("mapping.copyright")).toString().toLatin1();
+#endif
+}
+
+//-----------------------------------------------------------------------------
+QGeoTiledMappingManagerEngineQGC::~QGeoTiledMappingManagerEngineQGC()
+{
+}
+
+#if QT_VERSION < 0x050500
+
+//-----------------------------------------------------------------------------
+QGeoMapData *QGeoTiledMappingManagerEngineQGC::createMapData()
+{
+ return new QGeoTiledMapData(this, 0);
+}
+
+#else
+
+//-----------------------------------------------------------------------------
+QGeoMap*
+QGeoTiledMappingManagerEngineQGC::createMap()
+{
+ return new QGeoTiledMapQGC(this);
+}
+
+//-----------------------------------------------------------------------------
+QString
+QGeoTiledMappingManagerEngineQGC::customCopyright() const
+{
+ return m_customCopyright;
+}
+
+#endif
+
+#if QT_VERSION >= 0x050500
+//-----------------------------------------------------------------------------
+void
+QGeoTiledMappingManagerEngineQGC::_setCache(const QVariantMap ¶meters)
+{
+ QString cacheDir;
+ if (parameters.contains(QStringLiteral("mapping.cache.directory")))
+ cacheDir = parameters.value(QStringLiteral("mapping.cache.directory")).toString();
+ else {
+ cacheDir = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + QLatin1String("/QGCMapCache55");
+ if(!QDir::root().mkpath(cacheDir)) {
+ qWarning() << "Could not create mapping disk cache directory: " << cacheDir;
+ cacheDir = QDir::homePath() + QLatin1String("/.qgcmapscache/");
+ }
+ }
+ if(!QFileInfo(cacheDir).exists()) {
+ if(!QDir::root().mkpath(cacheDir)) {
+ qWarning() << "Could not create mapping disk cache directory: " << cacheDir;
+ cacheDir.clear();
+ }
+ }
+ //-- Memory Cache
+ uint32_t memLimit = 0;
+ if (parameters.contains(QStringLiteral("mapping.cache.memory.size"))) {
+ bool ok = false;
+ memLimit = parameters.value(QStringLiteral("mapping.cache.memory.size")).toString().toUInt(&ok);
+ if (!ok)
+ memLimit = 0;
+ }
+ if(!memLimit)
+ {
+ //-- Value saved in MB
+ memLimit = getQGCMapEngine()->getMaxMemCache() * (1024 * 1024);
+ }
+ //-- It won't work with less than 1M of memory cache
+ if(memLimit < 1024 * 1024)
+ memLimit = 1024 * 1024;
+ //-- Disable Qt's disk cache (set memory cache otherwise Qtlocation won't work)
+ QGeoTileCache* pTileCache = createTileCacheWithDir(cacheDir);
+ if(pTileCache)
+ {
+ //-- We're basically telling it to use 1kb (100k for Windows) of disk for cache. It doesn't like
+ // values smaller than that and I could not find a way to make it NOT cache.
+#ifdef Q_OS_WIN
+ pTileCache->setMaxDiskUsage(1024 * 100);
+#else
+ pTileCache->setMaxDiskUsage(1024);
+#endif
+ pTileCache->setMaxMemoryUsage(memLimit);
+ }
+}
+#endif
diff --git a/src/QtLocationPlugin/qgeotiledmappingmanagerengineqgc.h b/src/QtLocationPlugin/QGeoTiledMappingManagerEngineQGC.h
similarity index 94%
rename from src/QtLocationPlugin/qgeotiledmappingmanagerengineqgc.h
rename to src/QtLocationPlugin/QGeoTiledMappingManagerEngineQGC.h
index 6bc8447d9202049be783121d93bb957e9968d05d..2d6d1dc63401d92a1f92bc90eee32ec53627496b 100644
--- a/src/QtLocationPlugin/qgeotiledmappingmanagerengineqgc.h
+++ b/src/QtLocationPlugin/QGeoTiledMappingManagerEngineQGC.h
@@ -44,8 +44,8 @@
**
****************************************************************************/
-#ifndef QGEOTILEDMAPPINGMANAGERENGINEGOOGLE_H
-#define QGEOTILEDMAPPINGMANAGERENGINEGOOGLE_H
+#ifndef QGEOTILEDMAPPINGMANAGERENGINEQGC_H
+#define QGEOTILEDMAPPINGMANAGERENGINEQGC_H
#include
#if QT_VERSION >= 0x050500
@@ -62,6 +62,8 @@ public:
};
#endif
+class QGeoTileFetcherQGC;
+
class QGeoTiledMappingManagerEngineQGC : public QGeoTiledMappingManagerEngine
{
Q_OBJECT
@@ -81,4 +83,4 @@ private:
#endif
};
-#endif // QGEOTILEDMAPPINGMANAGERENGINEGOOGLE_H
+#endif // QGEOTILEDMAPPINGMANAGERENGINEQGC_H
diff --git a/src/QtLocationPlugin/QMLControl/OfflineMap.qml b/src/QtLocationPlugin/QMLControl/OfflineMap.qml
new file mode 100644
index 0000000000000000000000000000000000000000..ae245db8533bd75ec04b4706f13bdec781643163
--- /dev/null
+++ b/src/QtLocationPlugin/QMLControl/OfflineMap.qml
@@ -0,0 +1,909 @@
+/*=====================================================================
+
+ QGroundControl Open Source Ground Control Station
+
+ (c) 2009 - 2015 QGROUNDCONTROL PROJECT
+
+ This file is part of the QGROUNDCONTROL project
+
+ QGROUNDCONTROL is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ QGROUNDCONTROL is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QGROUNDCONTROL. If not, see .
+
+ ======================================================================*/
+
+import QtQuick 2.5
+import QtQuick.Controls 1.2
+import QtQuick.Controls.Styles 1.2
+import QtQuick.Dialogs 1.1
+import QtQuick.Layouts 1.2
+import QtLocation 5.3
+import QtPositioning 5.3
+
+import QGroundControl 1.0
+import QGroundControl.Controls 1.0
+import QGroundControl.ScreenTools 1.0
+import QGroundControl.Palette 1.0
+
+Rectangle {
+ id: _offlineMapRoot
+ color: __qgcPal.window
+ anchors.fill: parent
+ anchors.margins: ScreenTools.defaultFontPixelWidth
+
+ property var _currentSelection: null
+
+ property string mapKey: "lastMapType"
+
+ property string mapType: QGroundControl.mapEngineManager.loadSetting(mapKey, "Google Street Map")
+ property int mapMargin: (ScreenTools.defaultFontPixelHeight * 0.2).toFixed(0)
+ property real infoWidth: Math.max(Math.max(nameLabel.width, descLabel.width), (ScreenTools.defaultFontPixelWidth * 40))
+ property bool isDefaultSet: _offlineMapRoot._currentSelection && _offlineMapRoot._currentSelection.defaultSet
+
+ property real oldlon0: 0
+ property real oldlon1: 0
+ property real oldlat0: 0
+ property real oldlat1: 0
+ property int oldz0: 0
+ property int oldz1: 0
+
+ Component.onCompleted: {
+ QGroundControl.mapEngineManager.loadTileSets()
+ updateMap()
+ }
+
+ Connections {
+ target: QGroundControl.mapEngineManager
+ onTileSetsChanged: {
+ setName.text = QGroundControl.mapEngineManager.getUniqueName()
+ }
+ onErrorMessageChanged: {
+ errorDialog.visible = true
+ }
+ }
+
+ ExclusiveGroup { id: setGroup }
+
+ function handleChanges() {
+ var xl = mapMargin
+ var yl = mapMargin
+ var xr = _map.width.toFixed(0) - mapMargin
+ var yr = _map.height.toFixed(0) - mapMargin
+ var c0 = _map.toCoordinate(Qt.point(xl, yl))
+ var c1 = _map.toCoordinate(Qt.point(xr, yr))
+ if(oldlon0 !== c0.longitude || oldlat0 !== c0.latitude || oldlon1 !== c1.longitude || oldlat1 !== c1.latitude || oldz0 !== _slider0.value || oldz1 !== _slider1.value) {
+ QGroundControl.mapEngineManager.updateForCurrentView(c0.longitude, c0.latitude, c1.longitude, c1.latitude, _slider0.value, _slider1.value, mapType)
+ }
+ }
+
+ function checkSanity() {
+ if(QGroundControl.mapEngineManager.crazySize) {
+ _slider1.value = _slider1.value - 1
+ handleChanges()
+ }
+ }
+
+ function updateMap() {
+ for (var i = 0; i < _map.supportedMapTypes.length; i++) {
+ if (mapType === _map.supportedMapTypes[i].name) {
+ _map.activeMapType = _map.supportedMapTypes[i]
+ handleChanges()
+ return
+ }
+ }
+ }
+
+ function showOptions() {
+ _tileSetList.visible = false
+ _infoView.visible = false
+ _mapView.visible = false
+ _optionsView.visible = true
+ }
+
+ function showMap() {
+ _tileSetList.visible = false
+ _infoView.visible = false
+ _mapView.visible = true
+ _optionsView.visible = false
+ }
+
+ function showList() {
+ _tileSetList.visible = true
+ _infoView.visible = false
+ _mapView.visible = false
+ _optionsView.visible = false
+ }
+
+ function showInfo() {
+ if(_currentSelection && !_offlineMapRoot._currentSelection.deleting) {
+ _tileSetList.visible = false
+ _mapView.visible = false
+ _infoView.visible = true
+ _optionsView.visible = false
+ } else
+ showList()
+ }
+
+ ExclusiveGroup {
+ id: _dropButtonsExclusiveGroup
+ }
+
+ onMapTypeChanged: {
+ updateMap()
+ QGroundControl.mapEngineManager.saveSetting(mapKey, mapType)
+ }
+
+ MessageDialog {
+ id: errorDialog
+ visible: false
+ text: QGroundControl.mapEngineManager.errorMessage
+ icon: StandardIcon.Critical
+ standardButtons: StandardButton.Ok
+ title: "Errror Message"
+ onYes: {
+ errorDialog.visible = false
+ }
+ }
+ Rectangle {
+ id: _offlineMapTopRect
+ width: parent.width
+ height: labelTitle.height + ScreenTools.defaultFontPixelHeight
+ color: __qgcPal.window
+ anchors.top: parent.top
+ Row {
+ spacing: ScreenTools.defaultFontPixelHeight * 2
+ anchors.verticalCenter: parent.verticalCenter
+ QGCLabel {
+ id: labelTitle
+ text: "Offline Maps"
+ font.pixelSize: ScreenTools.mediumFontPixelSize
+ anchors.verticalCenter: parent.verticalCenter
+ }
+ QGCCheckBox {
+ id: showTilePreview
+ text: "Show tile min/max zoom level preview"
+ checked: false
+ visible: _mapView.visible
+ anchors.verticalCenter: parent.verticalCenter
+ }
+ }
+ }
+ QGCFlickable {
+ id: _tileSetList
+ clip: true
+ anchors.top: _offlineMapTopRect.bottom
+ width: parent.width
+ height: parent.height - _offlineMapTopRect.height
+ contentHeight: _cacheList.height
+ contentWidth: parent.width
+ flickableDirection: Flickable.VerticalFlick
+ Column {
+ id: _cacheList
+ width: _offlineMapRoot.width
+ anchors.margins: ScreenTools.defaultFontPixelWidth
+ spacing: (ScreenTools.defaultFontPixelHeight * 0.5).toFixed(0)
+ OfflineMapButton {
+ text: "Add new set"
+ width: (ScreenTools.defaultFontPixelWidth * 50).toFixed(0)
+ height: (ScreenTools.defaultFontPixelHeight * 2).toFixed(0)
+ anchors.horizontalCenter: parent.horizontalCenter
+ onClicked: {
+ _offlineMapRoot._currentSelection = null
+ showMap()
+ }
+ }
+ Repeater {
+ model: QGroundControl.mapEngineManager.tileSets
+ delegate: OfflineMapButton {
+ text: object.name
+ size: object.downloadStatus
+ complete: object.complete
+ width: (ScreenTools.defaultFontPixelWidth * 50).toFixed(0)
+ height: (ScreenTools.defaultFontPixelHeight * 2).toFixed(0)
+ anchors.horizontalCenter: parent.horizontalCenter
+ onClicked: {
+ _offlineMapRoot._currentSelection = object
+ showInfo()
+ }
+ }
+ }
+ }
+ }
+ QGCButton {
+ id: _optionsButton
+ text: "Options"
+ width: ScreenTools.defaultFontPixelWidth * 10
+ visible: _tileSetList.visible
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+ anchors.margins: ScreenTools.defaultFontPixelWidth
+ onClicked: showOptions()
+ }
+ //-- Offline Map Definition
+ Rectangle {
+ id: _mapView
+ color: __qgcPal.window
+ width: parent.width
+ anchors.top: _offlineMapTopRect.bottom
+ anchors.bottom: parent.bottom
+ anchors.margins: ScreenTools.defaultFontPixelWidth
+ visible: false
+
+ Rectangle {
+ width: parent.width
+ anchors.top: parent.top
+ anchors.bottom: bottomRect.top
+ color: (__qgcPal.globalTheme === QGCPalette.Light) ? "black" : "#98aca4"
+ Map {
+ id: _map
+ anchors.fill: parent
+ anchors.margins: ScreenTools.defaultFontPixelHeight * 0.15
+ zoomLevel: 10
+ center: QGroundControl.defaultMapPosition
+ gesture.flickDeceleration: 3000
+ gesture.activeGestures: MapGestureArea.ZoomGesture | MapGestureArea.PanGesture | MapGestureArea.FlickGesture
+ plugin: Plugin { name: "QGroundControl" }
+ onCenterChanged: {
+ handleChanges()
+ checkSanity()
+ }
+ onZoomLevelChanged: {
+ handleChanges()
+ checkSanity()
+ }
+ onWidthChanged: {
+ handleChanges()
+ checkSanity()
+ }
+ onHeightChanged: {
+ handleChanges()
+ checkSanity()
+ }
+ // Used to make pinch zoom work
+ MouseArea {
+ anchors.fill: parent
+ }
+ }
+ Rectangle {
+ width: ScreenTools.defaultFontPixelHeight * 16
+ height: ScreenTools.defaultFontPixelHeight * 9
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.margins: ScreenTools.defaultFontPixelHeight
+ color: "black"
+ visible: showTilePreview.checked
+ Map {
+ id: _mapMin
+ anchors.fill: parent
+ anchors.margins: 2
+ zoomLevel: _slider0.value
+ center: _map.center
+ gesture.enabled: false
+ activeMapType: _map.activeMapType
+ plugin: Plugin { name: "QGroundControl" }
+ }
+ }
+ Rectangle {
+ width: ScreenTools.defaultFontPixelHeight * 16
+ height: ScreenTools.defaultFontPixelHeight * 9
+ anchors.top: parent.top
+ anchors.right: parent.right
+ anchors.margins: ScreenTools.defaultFontPixelHeight
+ color: "black"
+ visible: showTilePreview.checked
+ Map {
+ id: _mapMax
+ anchors.fill: parent
+ anchors.margins: 2
+ zoomLevel: _slider1.value
+ center: _map.center
+ gesture.enabled: false
+ activeMapType: _map.activeMapType
+ plugin: Plugin { name: "QGroundControl" }
+ }
+ }
+ }
+ Rectangle {
+ id: bottomRect
+ width: parent.width
+ height: _controlRow.height + (ScreenTools.defaultFontPixelHeight * 2)
+ color: __qgcPal.window
+ anchors.bottom: parent.bottom
+ Row {
+ id: _controlRow
+ anchors.centerIn: parent
+ spacing: ScreenTools.defaultFontPixelWidth * 0.5
+ Rectangle {
+ height: _zoomRow.height + ScreenTools.defaultFontPixelHeight * 1.5
+ width: _zoomRow.width + ScreenTools.defaultFontPixelWidth
+ color: "#98aca4"
+ border.color: "black"
+ border.width: 2
+ radius: ScreenTools.defaultFontPixelWidth * 0.5
+ anchors.verticalCenter: parent.verticalCenter
+ Row {
+ id: _zoomRow
+ anchors.centerIn: parent
+ Column {
+ spacing: ScreenTools.defaultFontPixelHeight * 0.5
+ anchors.verticalCenter: parent.verticalCenter
+ Row {
+ spacing: ScreenTools.defaultFontPixelWidth * 0.5
+ Column {
+ anchors.verticalCenter: parent.verticalCenter
+ Label {
+ text: "Min"
+ color: "black"
+ width: ScreenTools.defaultFontPixelWidth * 5
+ font.pixelSize: ScreenTools.smallFontPixelSize
+ horizontalAlignment: Text.AlignHCenter
+ }
+ Label {
+ text: "Zoom"
+ color: "black"
+ width: ScreenTools.defaultFontPixelWidth * 5
+ font.pixelSize: ScreenTools.smallFontPixelSize
+ horizontalAlignment: Text.AlignHCenter
+ }
+ }
+ Slider {
+ id: _slider0
+ minimumValue: 3
+ maximumValue: 18
+ stepSize: 1
+ tickmarksEnabled: false
+ orientation: Qt.Horizontal
+ updateValueWhileDragging: true
+ anchors.verticalCenter: parent.verticalCenter
+ style: SliderStyle {
+ groove: Rectangle {
+ implicitWidth: ScreenTools.defaultFontPixelWidth * 12
+ implicitHeight: 4
+ color: "gray"
+ radius: 4
+ }
+ handle: Rectangle {
+ anchors.centerIn: parent
+ color: control.pressed ? "white" : "lightgray"
+ border.color: "gray"
+ border.width: 2
+ implicitWidth: ScreenTools.isAndroid ? 60 : 30
+ implicitHeight: ScreenTools.isAndroid ? 60 : 30
+ radius: 10
+ Label {
+ text: _slider0.value
+ anchors.centerIn: parent
+ }
+ }
+ }
+ Component.onCompleted: {
+ _slider0.value = _map.zoomLevel - 2
+ }
+ onValueChanged: {
+ if(_slider1) {
+ if(_slider0.value > _slider1.value)
+ _slider1.value = _slider0.value
+ else {
+ handleChanges()
+ checkSanity()
+ }
+ }
+ }
+ }
+ }
+ Row {
+ spacing: ScreenTools.defaultFontPixelWidth * 0.5
+ Column {
+ anchors.verticalCenter: parent.verticalCenter
+ Label {
+ text: "Max"
+ color: "black"
+ width: ScreenTools.defaultFontPixelWidth * 5
+ font.pixelSize: ScreenTools.smallFontPixelSize
+ horizontalAlignment: Text.AlignHCenter
+ }
+ Label {
+ text: "Zoom"
+ color: "black"
+ width: ScreenTools.defaultFontPixelWidth * 5
+ font.pixelSize: ScreenTools.smallFontPixelSize
+ horizontalAlignment: Text.AlignHCenter
+ }
+ }
+ Slider {
+ id: _slider1
+ minimumValue: 3
+ maximumValue: 18
+ stepSize: 1
+ tickmarksEnabled: false
+ orientation: Qt.Horizontal
+ updateValueWhileDragging: true
+ anchors.verticalCenter: parent.verticalCenter
+ style: SliderStyle {
+ groove: Rectangle {
+ implicitWidth: ScreenTools.defaultFontPixelWidth * 12
+ implicitHeight: 4
+ color: "gray"
+ radius: 4
+ }
+ handle: Rectangle {
+ anchors.centerIn: parent
+ color: control.pressed ? "white" : "lightgray"
+ border.color: "gray"
+ border.width: 2
+ implicitWidth: ScreenTools.isAndroid ? 60 : 30
+ implicitHeight: ScreenTools.isAndroid ? 60 : 30
+ radius: 10
+ Label {
+ text: _slider1.value
+ anchors.centerIn: parent
+ }
+ }
+ }
+ Component.onCompleted: {
+ _slider1.value = _map.zoomLevel + 2
+ }
+ onValueChanged: {
+ if(_slider1.value < _slider0.value)
+ _slider0.value = _slider1.value
+ else {
+ handleChanges()
+ checkSanity()
+ }
+ }
+ }
+ }
+ }
+ Column {
+ spacing: ScreenTools.defaultFontPixelHeight * 0.5
+ anchors.verticalCenter: parent.verticalCenter
+ Label {
+ text: "Tile Count"
+ color: "black"
+ width: ScreenTools.defaultFontPixelWidth * 12
+ font.pixelSize: ScreenTools.smallFontPixelSize
+ horizontalAlignment: Text.AlignHCenter
+ }
+ Label {
+ text: QGroundControl.mapEngineManager.tileCountStr
+ color: "black"
+ width: ScreenTools.defaultFontPixelWidth * 12
+ horizontalAlignment: Text.AlignHCenter
+ }
+ Label {
+ text: "Set Size (Est)"
+ color: "black"
+ width: ScreenTools.defaultFontPixelWidth * 12
+ font.pixelSize: ScreenTools.smallFontPixelSize
+ horizontalAlignment: Text.AlignHCenter
+ }
+ Label {
+ text: QGroundControl.mapEngineManager.tileSizeStr
+ color: "black"
+ width: ScreenTools.defaultFontPixelWidth * 12
+ horizontalAlignment: Text.AlignHCenter
+ }
+ }
+ }
+ }
+ Column {
+ anchors.verticalCenter: parent.verticalCenter
+ spacing: ScreenTools.defaultFontPixelHeight * 0.5
+ Row {
+ spacing: ScreenTools.defaultFontPixelWidth * 2
+ QGCLabel {
+ text: "Name:"
+ width: ScreenTools.defaultFontPixelWidth * 10
+ anchors.verticalCenter: parent.verticalCenter
+ horizontalAlignment: Text.AlignRight
+ }
+ QGCTextField {
+ id: setName
+ width: ScreenTools.defaultFontPixelWidth * 24
+ anchors.verticalCenter: parent.verticalCenter
+ }
+ }
+ Row {
+ spacing: ScreenTools.defaultFontPixelWidth * 2
+ QGCLabel {
+ text: "Description:"
+ width: ScreenTools.defaultFontPixelWidth * 10
+ anchors.verticalCenter: parent.verticalCenter
+ horizontalAlignment: Text.AlignRight
+ }
+ QGCTextField {
+ id: setDescription
+ text: "Description"
+ width: ScreenTools.defaultFontPixelWidth * 24
+ anchors.verticalCenter: parent.verticalCenter
+ }
+ }
+ Row {
+ spacing: ScreenTools.defaultFontPixelWidth * 2
+ QGCLabel {
+ text: "Map Type:"
+ width: ScreenTools.defaultFontPixelWidth * 10
+ anchors.verticalCenter: parent.verticalCenter
+ horizontalAlignment: Text.AlignRight
+ }
+ QGCComboBox {
+ id: mapCombo
+ width: ScreenTools.defaultFontPixelWidth * 24
+ model: QGroundControl.mapEngineManager.mapList
+ onActivated: {
+ mapType = textAt(index)
+ if(_dropButtonsExclusiveGroup.current)
+ _dropButtonsExclusiveGroup.current.checked = false
+ _dropButtonsExclusiveGroup.current = null
+ }
+ Component.onCompleted: {
+ var index = mapCombo.find(mapType)
+ if (index === -1) {
+ console.warn("Active map name not in combo", mapType)
+ } else {
+ mapCombo.currentIndex = index
+ }
+ }
+ }
+ }
+ }
+ Item {
+ height: 1
+ width: ScreenTools.defaultFontPixelWidth * 1.5
+ }
+ Column {
+ anchors.verticalCenter: parent.verticalCenter
+ spacing: ScreenTools.defaultFontPixelHeight * 0.5
+ QGCButton {
+ text: "Download"
+ enabled: setName.text.length > 0
+ width: ScreenTools.defaultFontPixelWidth * 10
+ onClicked: {
+ if(QGroundControl.mapEngineManager.findName(setName.text)) {
+ duplicateName.visible = true
+ } else {
+ /* This does not work if hosted by QQuickWidget. Waiting until we're 100% QtQuick
+ var mapImage
+ _map.grabToImage(function(result) { mapImage = result; })
+ QGroundControl.mapEngineManager.startDownload(setName.text, setDescription.text, mapType, mapImage);
+ */
+ QGroundControl.mapEngineManager.startDownload(setName.text, setDescription.text, mapType);
+ showList()
+ }
+ }
+ }
+ QGCButton {
+ text: "Cancel"
+ width: ScreenTools.defaultFontPixelWidth * 10
+ onClicked: {
+ showList()
+ }
+ }
+ MessageDialog {
+ id: duplicateName
+ visible: false
+ icon: StandardIcon.Warning
+ standardButtons: StandardButton.Ok
+ title: "Tile Set Already Exists"
+ text: "Tile Set \"" + setName.text + "\" already exists.\nPlease select a different name."
+ onYes: {
+ duplicateName.visible = false
+ }
+ }
+ }
+ }
+ }
+ }
+ Rectangle {
+ id: _infoView
+ color: __qgcPal.windowShade
+ width: parent.width
+ anchors.top: _offlineMapTopRect.bottom
+ anchors.bottom: parent.bottom
+ anchors.margins: ScreenTools.defaultFontPixelWidth
+ visible: false
+
+ Column {
+ width: parent.width
+ spacing: ScreenTools.defaultFontPixelHeight
+ Item {
+ height: ScreenTools.defaultFontPixelHeight * 0.5
+ width: 1
+ }
+ Rectangle {
+ width: infoWidth
+ height: nameLabel.height + (ScreenTools.defaultFontPixelHeight * 2)
+ color: __qgcPal.window
+ radius: ScreenTools.defaultFontPixelHeight * 0.5
+ anchors.horizontalCenter: parent.horizontalCenter
+ QGCLabel {
+ id: nameLabel
+ text: _offlineMapRoot._currentSelection ? _offlineMapRoot._currentSelection.name : ""
+ font.pixelSize: ScreenTools.isAndroid ? ScreenTools.mediumFontPixelSize : ScreenTools.largeFontPixelSize
+ anchors.centerIn: parent
+ }
+ }
+ QGCLabel {
+ id: descLabel
+ text: _offlineMapRoot._currentSelection ? _offlineMapRoot._currentSelection.description : ""
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+ Rectangle {
+ id: infoRect
+ width: infoWidth
+ height: infoGrid.height + (ScreenTools.defaultFontPixelHeight * 4)
+ color: __qgcPal.window
+ radius: ScreenTools.defaultFontPixelHeight * 0.5
+ anchors.horizontalCenter: parent.horizontalCenter
+ GridLayout {
+ id: infoGrid
+ columns: 2
+ anchors.centerIn: parent
+ anchors.margins: ScreenTools.defaultFontPixelWidth * 2
+ rowSpacing: ScreenTools.defaultFontPixelWidth
+ columnSpacing: ScreenTools.defaultFontPixelHeight * 2
+ QGCLabel {
+ text: "Map Type:"
+ visible: !isDefaultSet
+ }
+ QGCLabel {
+ text: _offlineMapRoot._currentSelection ? _offlineMapRoot._currentSelection.mapTypeStr : ""
+ visible: !isDefaultSet
+ }
+ QGCLabel {
+ text: "Min Zoom:"
+ visible: !isDefaultSet
+ }
+ QGCLabel {
+ text: _offlineMapRoot._currentSelection ? _offlineMapRoot._currentSelection.minZoom : ""
+ visible: !isDefaultSet
+ }
+ QGCLabel {
+ text: "Max Zoom:"
+ visible: !isDefaultSet
+ }
+ QGCLabel {
+ text: _offlineMapRoot._currentSelection ? _offlineMapRoot._currentSelection.maxZoom : ""
+ visible: !isDefaultSet
+ }
+ QGCLabel {
+ text: isDefaultSet ? "Default Set Size:" : "Total Size:"
+ }
+ QGCLabel {
+ text: _offlineMapRoot._currentSelection ? _offlineMapRoot._currentSelection.tilesSizeStr : ""
+ }
+ QGCLabel {
+ text: isDefaultSet ? "Default Set Tile Count:" : "Total Tile Count:"
+ }
+ QGCLabel {
+ text: _offlineMapRoot._currentSelection ? _offlineMapRoot._currentSelection.numTilesStr : ""
+ }
+ QGCLabel {
+ text: isDefaultSet ? "Total Size (All Sets):" : "Downloaded Size:"
+ }
+ QGCLabel {
+ text: _offlineMapRoot._currentSelection ? _offlineMapRoot._currentSelection.savedSizeStr : ""
+ }
+ QGCLabel {
+ text: isDefaultSet ? "Total Count (All Sets):" : "Downloaded Count:"
+ }
+ QGCLabel {
+ text: _offlineMapRoot._currentSelection ? _offlineMapRoot._currentSelection.savedTilesStr : ""
+ }
+ QGCLabel {
+ text: "Error Count:"
+ visible: !isDefaultSet && _offlineMapRoot._currentSelection && !_offlineMapRoot._currentSelection.complete
+ }
+ QGCLabel {
+ text: _offlineMapRoot._currentSelection ? _offlineMapRoot._currentSelection.errorCountStr : ""
+ visible: !isDefaultSet && _offlineMapRoot._currentSelection && !_offlineMapRoot._currentSelection.complete
+ }
+ }
+ }
+ Item {
+ height: ScreenTools.defaultFontPixelHeight * 0.5
+ width: 1
+ }
+ Row {
+ anchors.horizontalCenter: parent.horizontalCenter
+ spacing: ScreenTools.defaultFontPixelWidth
+ QGCButton {
+ width: ScreenTools.defaultFontPixelWidth * 18
+ text: "Delete"
+ enabled: _offlineMapRoot._currentSelection && (!_offlineMapRoot._currentSelection.deleting)
+ onClicked: {
+ if(_offlineMapRoot._currentSelection)
+ deleteDialog.visible = true
+ }
+ MessageDialog {
+ id: deleteDialog
+ visible: false
+ icon: StandardIcon.Warning
+ standardButtons: StandardButton.Yes | StandardButton.No
+ title: "Delete Tile Set"
+ text: {
+ if(_offlineMapRoot._currentSelection) {
+ var blurb = "Delete " + _offlineMapRoot._currentSelection.name + " and all its tiles.\nIs this really what you want?"
+ if(_offlineMapRoot._currentSelection.defaultSet)
+ return blurb + "\nNote that deleteting the Default Set deletes all tiles from all sets."
+ else
+ return blurb
+ }
+ return ""
+ }
+ onYes: {
+ if(_offlineMapRoot._currentSelection)
+ QGroundControl.mapEngineManager.deleteTileSet(_offlineMapRoot._currentSelection)
+ deleteDialog.visible = false
+ showList()
+ }
+ onNo: {
+ deleteDialog.visible = false
+ }
+ }
+ }
+ QGCButton {
+ text: "Resume Download"
+ width: ScreenTools.defaultFontPixelWidth * 18
+ enabled: _offlineMapRoot._currentSelection && (!_offlineMapRoot._currentSelection.deleting && !_offlineMapRoot._currentSelection.downloading)
+ visible: !isDefaultSet && _offlineMapRoot._currentSelection && (!_offlineMapRoot._currentSelection.complete && !_offlineMapRoot._currentSelection.downloading)
+ onClicked: {
+ if(_offlineMapRoot._currentSelection)
+ _offlineMapRoot._currentSelection.resumeDownloadTask()
+ }
+ }
+ QGCButton {
+ text: "Cancel Download"
+ width: ScreenTools.defaultFontPixelWidth * 18
+ enabled: _offlineMapRoot._currentSelection && (!_offlineMapRoot._currentSelection.deleting && _offlineMapRoot._currentSelection.downloading)
+ visible: !isDefaultSet && _offlineMapRoot._currentSelection && (!_offlineMapRoot._currentSelection.complete && _offlineMapRoot._currentSelection.downloading)
+ onClicked: {
+ if(_offlineMapRoot._currentSelection)
+ _offlineMapRoot._currentSelection.cancelDownloadTask()
+ }
+ }
+ QGCButton {
+ text: "Back"
+ width: ScreenTools.defaultFontPixelWidth * 18
+ onClicked: showList()
+ }
+ }
+ }
+ }
+ Rectangle {
+ id: _optionsView
+ color: __qgcPal.windowShade
+ width: parent.width
+ anchors.top: _offlineMapTopRect.bottom
+ anchors.bottom: parent.bottom
+ anchors.margins: ScreenTools.defaultFontPixelWidth
+ visible: false
+ onVisibleChanged: {
+ if(_optionsView.visible) {
+ mapBoxToken.text = QGroundControl.mapEngineManager.mapboxToken
+ maxCacheSize.text = QGroundControl.mapEngineManager.maxDiskCache
+ maxCacheMemSize.text = QGroundControl.mapEngineManager.maxMemCache
+ }
+ }
+ Column {
+ width: parent.width
+ spacing: ScreenTools.defaultFontPixelHeight
+ Item {
+ height: ScreenTools.defaultFontPixelHeight
+ width: 1
+ }
+ Rectangle {
+ width: infoWidth
+ height: optionsLabel.height + (ScreenTools.defaultFontPixelHeight * 2)
+ color: __qgcPal.window
+ radius: ScreenTools.defaultFontPixelHeight * 0.5
+ anchors.horizontalCenter: parent.horizontalCenter
+ QGCLabel {
+ id: optionsLabel
+ text: "Offline Map Options"
+ font.pixelSize: ScreenTools.isAndroid ? ScreenTools.mediumFontPixelSize : ScreenTools.largeFontPixelSize
+ anchors.centerIn: parent
+ }
+ }
+ Rectangle {
+ id: optionsRect
+ width: optionsGrid.width + (ScreenTools.defaultFontPixelWidth * 4)
+ height: optionsGrid.height + (ScreenTools.defaultFontPixelHeight * 4)
+ color: __qgcPal.window
+ radius: ScreenTools.defaultFontPixelHeight * 0.5
+ anchors.horizontalCenter: parent.horizontalCenter
+ GridLayout {
+ id: optionsGrid
+ columns: 2
+ anchors.centerIn: parent
+ anchors.margins: ScreenTools.defaultFontPixelWidth * 2
+ rowSpacing: ScreenTools.defaultFontPixelWidth * 1.5
+ columnSpacing: ScreenTools.defaultFontPixelHeight * 2
+ QGCLabel {
+ text: "Max Cache Disk Size (MB):"
+ }
+ QGCTextField {
+ id: maxCacheSize
+ maximumLength: 6
+ inputMethodHints: Qt.ImhDigitsOnly
+ validator: IntValidator {bottom: 1; top: 262144;}
+ }
+ QGCLabel {
+ text: "Max Cache Memory Size (MB):"
+ }
+ QGCTextField {
+ id: maxCacheMemSize
+ maximumLength: 4
+ inputMethodHints: Qt.ImhDigitsOnly
+ validator: IntValidator {bottom: 1; top: 4096;}
+ }
+ Item {
+ Layout.columnSpan: 2
+ Layout.fillWidth: true
+ implicitHeight: ScreenTools.defaultFontPixelHeight * 1.5
+ QGCLabel {
+ anchors.centerIn: parent
+ text: "Memory cache changes require a restart to take effect."
+ font.pixelSize: ScreenTools.defaultFontPixelSize * 0.85
+ }
+ }
+ Rectangle {
+ Layout.columnSpan: 2
+ Layout.fillWidth: true
+ implicitHeight: 1
+ color: __qgcPal.text
+ }
+ QGCLabel {
+ text: "MapBox Access Token"
+ }
+ QGCTextField {
+ id: mapBoxToken
+ Layout.fillWidth: true
+ maximumLength: 256
+ implicitWidth : ScreenTools.defaultFontPixelWidth * 30
+ }
+ Item {
+ Layout.columnSpan: 2
+ Layout.fillWidth: true
+ implicitHeight: ScreenTools.defaultFontPixelHeight * 1.5
+ QGCLabel {
+ anchors.centerIn: parent
+ text: "With an access token, you can use MapBox Maps."
+ font.pixelSize: ScreenTools.defaultFontPixelSize * 0.85
+ }
+ }
+ }
+ }
+ Row {
+ anchors.horizontalCenter: parent.horizontalCenter
+ spacing: ScreenTools.defaultFontPixelWidth
+ QGCButton {
+ text: "Save"
+ width: ScreenTools.defaultFontPixelWidth * 18
+ onClicked: {
+ QGroundControl.mapEngineManager.mapboxToken = mapBoxToken.text
+ QGroundControl.mapEngineManager.maxDiskCache = parseInt(maxCacheSize.text)
+ QGroundControl.mapEngineManager.maxMemCache = parseInt(maxCacheMemSize.text)
+ showList()
+ }
+ }
+ QGCButton {
+ text: "Cancel"
+ width: ScreenTools.defaultFontPixelWidth * 18
+ onClicked: {
+ showList()
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/QtLocationPlugin/QMLControl/QGCMapEngineManager.cc b/src/QtLocationPlugin/QMLControl/QGCMapEngineManager.cc
new file mode 100644
index 0000000000000000000000000000000000000000..e506dcb42eb3ddeaef669014e79d9ce7f1e2662f
--- /dev/null
+++ b/src/QtLocationPlugin/QMLControl/QGCMapEngineManager.cc
@@ -0,0 +1,405 @@
+/*=====================================================================
+
+ QGroundControl Open Source Ground Control Station
+
+ (c) 2009 - 2016 QGROUNDCONTROL PROJECT
+
+ This file is part of the QGROUNDCONTROL project
+
+ QGROUNDCONTROL is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ QGROUNDCONTROL is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QGROUNDCONTROL. If not, see .
+
+ ======================================================================*/
+
+/// @file
+/// @author Gus Grubba
+
+#include "QGCMapEngineManager.h"
+#include "QGCApplication.h"
+#include
+#include "QGCMapTileSet.h"
+#include "QGCMapUrlEngine.h"
+#include
+#include
+
+QGC_LOGGING_CATEGORY(QGCMapEngineManagerLog, "QGCMapEngineManagerLog")
+
+static const char* kQmlOfflineMapKeyName = "QGCOfflineMap";
+
+//-----------------------------------------------------------------------------
+QGCMapEngineManager::QGCMapEngineManager(QGCApplication* app)
+ : QGCTool(app)
+ , _topleftLat(0.0)
+ , _topleftLon(0.0)
+ , _bottomRightLat(0.0)
+ , _bottomRightLon(0.0)
+ , _minZoom(0)
+ , _maxZoom(0)
+ , _setID(UINT64_MAX)
+ , _freeDiskSpace(0)
+ , _diskSpace(0)
+{
+
+}
+
+//-----------------------------------------------------------------------------
+QGCMapEngineManager::~QGCMapEngineManager()
+{
+ _tileSets.clear();
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCMapEngineManager::setToolbox(QGCToolbox *toolbox)
+{
+ QGCTool::setToolbox(toolbox);
+ QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
+ qmlRegisterUncreatableType("QGroundControl.QGCMapEngineManager", 1, 0, "QGCMapEngineManager", "Reference only");
+ connect(getQGCMapEngine(), &QGCMapEngine::updateTotals, this, &QGCMapEngineManager::_updateTotals);
+ _updateDiskFreeSpace();
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCMapEngineManager::updateForCurrentView(double lon0, double lat0, double lon1, double lat1, int minZoom, int maxZoom, const QString& mapName)
+{
+ UrlFactory::MapType mapType = QGCMapEngine::getTypeFromName(mapName);
+
+ _topleftLat = lat0;
+ _topleftLon = lon0;
+ _bottomRightLat = lat1;
+ _bottomRightLon = lon1;
+ _minZoom = minZoom;
+ _maxZoom = maxZoom;
+ _totalSet.clear();
+ for(int z = minZoom; z <= maxZoom; z++) {
+ QGCTileSet set = QGCMapEngine::getTileCount(z, lon0, lat0, lon1, lat1, mapType);
+ _totalSet += set;
+ }
+ //-- Beyond 100,000,000 tiles is just nuts
+ if(_totalSet.tileCount > 100 * 1000 * 1000) {
+ _crazySize = true;
+ emit crazySizeChanged();
+ } else {
+ _crazySize = false;
+ emit crazySizeChanged();
+ emit tileX0Changed();
+ emit tileX1Changed();
+ emit tileY0Changed();
+ emit tileY1Changed();
+ emit tileCountChanged();
+ emit tileSizeChanged();
+ }
+}
+
+//-----------------------------------------------------------------------------
+QString
+QGCMapEngineManager::tileCountStr()
+{
+ return QGCMapEngine::numberToString(_totalSet.tileCount);
+}
+
+//-----------------------------------------------------------------------------
+QString
+QGCMapEngineManager::tileSizeStr()
+{
+ return QGCMapEngine::bigSizeToString(_totalSet.tileSize);
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCMapEngineManager::loadTileSets()
+{
+ if(_tileSets.count()) {
+ _tileSets.clear();
+ emit tileSetsChanged();
+ }
+ QGCFetchTileSetTask* task = new QGCFetchTileSetTask();
+ connect(task, &QGCFetchTileSetTask::tileSetFetched, this, &QGCMapEngineManager::_tileSetFetched);
+ connect(task, &QGCMapTask::error, this, &QGCMapEngineManager::taskError);
+ getQGCMapEngine()->addTask(task);
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCMapEngineManager::_tileSetFetched(QGCCachedTileSet* tileSet)
+{
+ //-- A blank (default) type means it uses various types and not just one
+ if(tileSet->type() == UrlFactory::Invalid) {
+ tileSet->setMapTypeStr("Various");
+ }
+ _tileSets.append(tileSet);
+ tileSet->setManager(this);
+ emit tileSetsChanged();
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCMapEngineManager::startDownload(const QString& name, const QString& description, const QString& mapType, const QImage& image)
+{
+ if(_totalSet.tileSize) {
+ QGCCachedTileSet* set = new QGCCachedTileSet(name, description);
+ set->setMapTypeStr(mapType);
+ set->setTopleftLat(_topleftLat);
+ set->setTopleftLon(_topleftLon);
+ set->setBottomRightLat(_bottomRightLat);
+ set->setBottomRightLon(_bottomRightLon);
+ set->setMinZoom(_minZoom);
+ set->setMaxZoom(_maxZoom);
+ set->setTilesSize(_totalSet.tileSize);
+ set->setNumTiles(_totalSet.tileCount);
+ set->setType(QGCMapEngine::getTypeFromName(mapType));
+ if(!image.isNull())
+ set->setThumbNail(image);
+ QGCCreateTileSetTask* task = new QGCCreateTileSetTask(set);
+ //-- Create Tile Set (it will also create a list of tiles to download)
+ connect(task, &QGCCreateTileSetTask::tileSetSaved, this, &QGCMapEngineManager::_tileSetSaved);
+ connect(task, &QGCMapTask::error, this, &QGCMapEngineManager::taskError);
+ getQGCMapEngine()->addTask(task);
+ } else {
+ qWarning() << "QGCMapEngineManager::startDownload() No Tiles to save";
+ }
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCMapEngineManager::_tileSetSaved(QGCCachedTileSet *set)
+{
+ qCDebug(QGCMapEngineManagerLog) << "New tile set saved (" << set->name() << "). Starting download...";
+ _tileSets.append(set);
+ emit tileSetsChanged();
+ //-- Start downloading tiles
+ set->createDownloadTask();
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCMapEngineManager::saveSetting (const QString& key, const QString& value)
+{
+ QSettings settings;
+ settings.beginGroup(kQmlOfflineMapKeyName);
+ settings.setValue(key, value);
+}
+
+//-----------------------------------------------------------------------------
+QString
+QGCMapEngineManager::loadSetting (const QString& key, const QString& defaultValue)
+{
+ QSettings settings;
+ settings.beginGroup(kQmlOfflineMapKeyName);
+ return settings.value(key, defaultValue).toString();
+}
+
+//-----------------------------------------------------------------------------
+QStringList
+QGCMapEngineManager::mapList()
+{
+ return getQGCMapEngine()->getMapNameList();
+}
+
+//-----------------------------------------------------------------------------
+QString
+QGCMapEngineManager::mapboxToken()
+{
+ return getQGCMapEngine()->getMapBoxToken();
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCMapEngineManager::setMapboxToken(QString token)
+{
+ getQGCMapEngine()->setMapBoxToken(token);
+}
+
+//-----------------------------------------------------------------------------
+quint32
+QGCMapEngineManager::maxMemCache()
+{
+ return getQGCMapEngine()->getMaxMemCache();
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCMapEngineManager::setMaxMemCache(quint32 size)
+{
+ getQGCMapEngine()->setMaxMemCache(size);
+}
+
+//-----------------------------------------------------------------------------
+quint32
+QGCMapEngineManager::maxDiskCache()
+{
+ return getQGCMapEngine()->getMaxDiskCache();
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCMapEngineManager::setMaxDiskCache(quint32 size)
+{
+ getQGCMapEngine()->setMaxDiskCache(size);
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCMapEngineManager::deleteTileSet(QGCCachedTileSet* tileSet)
+{
+ qCDebug(QGCMapEngineManagerLog) << "Deleting tile set " << tileSet->name();
+ //-- If deleting default set, delete it all
+ if(tileSet->defaultSet()) {
+ for(int i = 0; i < _tileSets.count(); i++ ) {
+ QGCCachedTileSet* set = qobject_cast(_tileSets.get(i));
+ Q_ASSERT(set);
+ set->setDeleting(true);
+ }
+ QGCResetTask* task = new QGCResetTask();
+ connect(task, &QGCResetTask::resetCompleted, this, &QGCMapEngineManager::_resetCompleted);
+ connect(task, &QGCMapTask::error, this, &QGCMapEngineManager::taskError);
+ getQGCMapEngine()->addTask(task);
+ } else {
+ tileSet->setDeleting(true);
+ QGCDeleteTileSetTask* task = new QGCDeleteTileSetTask(tileSet->setID());
+ connect(task, &QGCDeleteTileSetTask::tileSetDeleted, this, &QGCMapEngineManager::_tileSetDeleted);
+ connect(task, &QGCMapTask::error, this, &QGCMapEngineManager::taskError);
+ getQGCMapEngine()->addTask(task);
+ }
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCMapEngineManager::_resetCompleted()
+{
+ //-- Reload sets
+ loadTileSets();
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCMapEngineManager::_tileSetDeleted(quint64 setID)
+{
+ //-- Tile Set successfully deleted
+ QGCCachedTileSet* setToDelete = NULL;
+ int i = 0;
+ for(i = 0; i < _tileSets.count(); i++ ) {
+ QGCCachedTileSet* set = qobject_cast(_tileSets.get(i));
+ Q_ASSERT(set);
+ if (set->setID() == setID) {
+ setToDelete = set;
+ break;
+ }
+ }
+ if(setToDelete) {
+ _tileSets.removeAt(i);
+ delete setToDelete;
+ }
+ emit tileSetsChanged();
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCMapEngineManager::taskError(QGCMapTask::TaskType type, QString error)
+{
+ QString task;
+ switch(type) {
+ case QGCMapTask::taskFetchTileSets:
+ task = "Fetch Tile Set";
+ break;
+ case QGCMapTask::taskCreateTileSet:
+ task = "Create Tile Set";
+ break;
+ case QGCMapTask::taskGetTileDownloadList:
+ task = "Get Tile Download List";
+ break;
+ case QGCMapTask::taskUpdateTileDownloadState:
+ task = "Update Tile Download Status";
+ break;
+ case QGCMapTask::taskDeleteTileSet:
+ task = "Delete Tile Set";
+ break;
+ case QGCMapTask::taskReset:
+ task = "Reset Tile Sets";
+ break;
+ default:
+ task = "Database Error";
+ break;
+ }
+ QString serror = "Error in task: " + task;
+ serror += "\nError description:\n";
+ serror += error;
+ qWarning() << "QGCMapEngineManager::_taskError()";
+ setErrorMessage(serror);
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCMapEngineManager::_updateTotals(quint32 totaltiles, quint64 totalsize, quint32 defaulttiles, quint64 defaultsize)
+{
+ for(int i = 0; i < _tileSets.count(); i++ ) {
+ QGCCachedTileSet* set = qobject_cast(_tileSets.get(i));
+ Q_ASSERT(set);
+ if (set->defaultSet()) {
+ set->setSavedSize(totalsize);
+ set->setSavedTiles(totaltiles);
+ set->setNumTiles(defaulttiles);
+ set->setTilesSize(defaultsize);
+ return;
+ }
+ }
+ _updateDiskFreeSpace();
+}
+
+//-----------------------------------------------------------------------------
+bool
+QGCMapEngineManager::findName(const QString& name)
+{
+ for(int i = 0; i < _tileSets.count(); i++ ) {
+ QGCCachedTileSet* set = qobject_cast(_tileSets.get(i));
+ Q_ASSERT(set);
+ if (set->name() == name) {
+ return true;
+ }
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+QString
+QGCMapEngineManager::getUniqueName()
+{
+ QString test = "Tile Set ";
+ QString name;
+ int count = 1;
+ while (true) {
+ name = test;
+ name += QString().sprintf("%03d", count++);
+ if(!findName(name))
+ return name;
+ }
+}
+
+//-----------------------------------------------------------------------------
+void
+QGCMapEngineManager::_updateDiskFreeSpace()
+{
+ QString path = getQGCMapEngine()->getCachePath();
+ if(!path.isEmpty()) {
+ QStorageInfo info(path);
+ quint32 total = (quint32)(info.bytesTotal() / 1024);
+ quint32 free = (quint32)(info.bytesFree() / 1024);
+ qCDebug(QGCMapEngineManagerLog) << info.rootPath() << "has" << free << "Mbytes available.";
+ if(_freeDiskSpace != free) {
+ _freeDiskSpace = free;
+ _diskSpace = total;
+ emit freeDiskSpaceChanged();
+ }
+ }
+}
diff --git a/src/QtLocationPlugin/QMLControl/QGCMapEngineManager.h b/src/QtLocationPlugin/QMLControl/QGCMapEngineManager.h
new file mode 100644
index 0000000000000000000000000000000000000000..9a354019cc4266614a86f72fc592800fc056739a
--- /dev/null
+++ b/src/QtLocationPlugin/QMLControl/QGCMapEngineManager.h
@@ -0,0 +1,144 @@
+/*=====================================================================
+
+ QGroundControl Open Source Ground Control Station
+
+ (c) 2009 - 2016 QGROUNDCONTROL PROJECT
+
+ This file is part of the QGROUNDCONTROL project
+
+ QGROUNDCONTROL is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ QGROUNDCONTROL is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QGROUNDCONTROL. If not, see .
+
+ ======================================================================*/
+
+/// @file
+/// @author Gus Grubba
+
+#ifndef OfflineMapsManager_H
+#define OfflineMapsManager_H
+
+#include "QmlObjectListModel.h"
+#include "QGCToolbox.h"
+#include "QGCLoggingCategory.h"
+#include "QGCMapEngine.h"
+#include "QGCMapTileSet.h"
+
+Q_DECLARE_LOGGING_CATEGORY(QGCMapEngineManagerLog)
+
+class QGCMapEngineManager : public QGCTool
+{
+ Q_OBJECT
+public:
+ QGCMapEngineManager(QGCApplication* app);
+ ~QGCMapEngineManager();
+
+ Q_PROPERTY(int tileX0 READ tileX0 NOTIFY tileX0Changed)
+ Q_PROPERTY(int tileX1 READ tileX1 NOTIFY tileX1Changed)
+ Q_PROPERTY(int tileY0 READ tileY0 NOTIFY tileY0Changed)
+ Q_PROPERTY(int tileY1 READ tileY1 NOTIFY tileY1Changed)
+ Q_PROPERTY(quint64 tileCount READ tileCount NOTIFY tileCountChanged)
+ Q_PROPERTY(QString tileCountStr READ tileCountStr NOTIFY tileCountChanged)
+ Q_PROPERTY(quint64 tileSize READ tileSize NOTIFY tileSizeChanged)
+ Q_PROPERTY(QString tileSizeStr READ tileSizeStr NOTIFY tileSizeChanged)
+ Q_PROPERTY(bool crazySize READ crazySize NOTIFY crazySizeChanged)
+ Q_PROPERTY(QmlObjectListModel* tileSets READ tileSets NOTIFY tileSetsChanged)
+ Q_PROPERTY(QStringList mapList READ mapList CONSTANT)
+ Q_PROPERTY(QString mapboxToken READ mapboxToken WRITE setMapboxToken NOTIFY mapboxTokenChanged)
+ Q_PROPERTY(quint32 maxMemCache READ maxMemCache WRITE setMaxMemCache NOTIFY maxMemCacheChanged)
+ Q_PROPERTY(quint32 maxDiskCache READ maxDiskCache WRITE setMaxDiskCache NOTIFY maxDiskCacheChanged)
+ Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY errorMessageChanged)
+ //-- Disk Space in MB
+ Q_PROPERTY(quint32 freeDiskSpace READ freeDiskSpace NOTIFY freeDiskSpaceChanged)
+ Q_PROPERTY(quint32 diskSpace READ diskSpace CONSTANT)
+
+ Q_INVOKABLE void loadTileSets ();
+ Q_INVOKABLE void updateForCurrentView (double lon0, double lat0, double lon1, double lat1, int minZoom, int maxZoom, const QString& mapName);
+ Q_INVOKABLE void startDownload (const QString& name, const QString& description, const QString& mapType, const QImage& image = QImage());
+ Q_INVOKABLE void saveSetting (const QString& key, const QString& value);
+ Q_INVOKABLE QString loadSetting (const QString& key, const QString& defaultValue);
+ Q_INVOKABLE void deleteTileSet (QGCCachedTileSet* tileSet);
+ Q_INVOKABLE QString getUniqueName ();
+ Q_INVOKABLE bool findName (const QString& name);
+
+ int tileX0 () { return _totalSet.tileX0; }
+ int tileX1 () { return _totalSet.tileX1; }
+ int tileY0 () { return _totalSet.tileY0; }
+ int tileY1 () { return _totalSet.tileY1; }
+ quint64 tileCount () { return _totalSet.tileCount; }
+ QString tileCountStr ();
+ quint64 tileSize () { return _totalSet.tileSize; }
+ QString tileSizeStr ();
+ bool crazySize () { return _crazySize; }
+ QStringList mapList ();
+ QString mapboxToken ();
+ QmlObjectListModel* tileSets () { return &_tileSets; }
+ quint32 maxMemCache ();
+ quint32 maxDiskCache ();
+ QString errorMessage () { return _errorMessage; }
+ quint64 freeDiskSpace () { return _freeDiskSpace; }
+ quint64 diskSpace () { return _diskSpace; }
+
+ void setMapboxToken (QString token);
+ void setMaxMemCache (quint32 size);
+ void setMaxDiskCache (quint32 size);
+
+ void setErrorMessage (const QString& error) { _errorMessage = error; emit errorMessageChanged(); }
+
+ // Override from QGCTool
+ void setToolbox(QGCToolbox *toolbox);
+
+signals:
+ void tileX0Changed ();
+ void tileX1Changed ();
+ void tileY0Changed ();
+ void tileY1Changed ();
+ void tileCountChanged ();
+ void tileSizeChanged ();
+ void crazySizeChanged ();
+ void mapboxTokenChanged ();
+ void tileSetsChanged ();
+ void maxMemCacheChanged ();
+ void maxDiskCacheChanged ();
+ void errorMessageChanged ();
+ void freeDiskSpaceChanged ();
+
+public slots:
+ void taskError (QGCMapTask::TaskType type, QString error);
+
+private slots:
+ void _tileSetSaved (QGCCachedTileSet* set);
+ void _tileSetFetched (QGCCachedTileSet* tileSets);
+ void _tileSetDeleted (quint64 setID);
+ void _updateTotals (quint32 totaltiles, quint64 totalsize, quint32 defaulttiles, quint64 defaultsize);
+ void _resetCompleted ();
+
+private:
+ void _updateDiskFreeSpace ();
+
+private:
+ QGCTileSet _totalSet;
+ bool _crazySize;
+ double _topleftLat;
+ double _topleftLon;
+ double _bottomRightLat;
+ double _bottomRightLon;
+ int _minZoom;
+ int _maxZoom;
+ quint64 _setID;
+ quint32 _freeDiskSpace;
+ quint32 _diskSpace;
+ QmlObjectListModel _tileSets;
+ QString _errorMessage;
+};
+
+#endif
diff --git a/src/QtLocationPlugin/qgeomapreplyqgc.cpp b/src/QtLocationPlugin/qgeomapreplyqgc.cpp
deleted file mode 100644
index 298bca0626e462373f9abf9d44a68285ea069534..0000000000000000000000000000000000000000
--- a/src/QtLocationPlugin/qgeomapreplyqgc.cpp
+++ /dev/null
@@ -1,158 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Aaron McCarthy
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtLocation module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 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 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-** 2015.4.4
-** Adapted for use with QGroundControl
-**
-** Gus Grubba
-**
-****************************************************************************/
-
-#include
-
-#include "qgeomapreplyqgc.h"
-#include "OpenPilotMaps.h"
-
-QGeoMapReplyQGC::QGeoMapReplyQGC(QNetworkReply *reply, const QGeoTileSpec &spec, QObject *parent)
- : QGeoTiledMapReply(spec, parent)
- , m_reply(reply)
-{
- if(!reply)
- {
- setError(QGeoTiledMapReply::UnknownError, "Invalid tile request");
- setFinished(true);
- }
- else
- {
- connect(m_reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
- connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(networkReplyError(QNetworkReply::NetworkError)));
- connect(m_reply, SIGNAL(destroyed()), this, SLOT(replyDestroyed()));
- }
-}
-
-QGeoMapReplyQGC::~QGeoMapReplyQGC()
-{
- if (m_reply) {
- m_reply->deleteLater();
- m_reply = 0;
- }
-}
-
-void QGeoMapReplyQGC::abort()
-{
- if (!m_reply)
- return;
- m_reply->abort();
-}
-
-QNetworkReply *QGeoMapReplyQGC::networkReply() const
-{
- return m_reply;
-}
-
-void QGeoMapReplyQGC::replyDestroyed()
-{
- m_reply = 0;
-}
-
-void QGeoMapReplyQGC::networkReplyFinished()
-{
- if (!m_reply)
- {
- return;
- }
-
- if (m_reply->error() != QNetworkReply::NoError)
- {
- return;
- }
-
- QByteArray a = m_reply->readAll();
- setMapImageData(a);
-
- if(a.size() > 2)
- {
- if((char)a[0] == (char)0xff && (char)a[1] == (char)0xd8)
- setMapImageFormat("jpg");
- else if((char)a[0] == (char)0x89 && (char)a[1] == (char)0x50)
- setMapImageFormat("png");
- else
- {
- switch ((OpenPilot::MapType)tileSpec().mapId()) {
- case OpenPilot::GoogleMap:
- case OpenPilot::GoogleLabels:
- case OpenPilot::GoogleTerrain:
- case OpenPilot::GoogleHybrid:
- case OpenPilot::BingMap:
- case OpenPilot::OpenStreetMap:
- setMapImageFormat("png");
- break;
- case OpenPilot::GoogleSatellite:
- case OpenPilot::BingSatellite:
- case OpenPilot::BingHybrid:
- setMapImageFormat("jpg");
- break;
- default:
- qWarning("Unknown map id %d", tileSpec().mapId());
- break;
- }
- }
- }
-
- setFinished(true);
- m_reply->deleteLater();
- m_reply = 0;
-}
-
-void QGeoMapReplyQGC::networkReplyError(QNetworkReply::NetworkError error)
-{
- if (!m_reply)
- {
- return;
- }
-
- if (error != QNetworkReply::OperationCanceledError)
- {
- setError(QGeoTiledMapReply::CommunicationError, m_reply->errorString());
- }
-
- setFinished(true);
- m_reply->deleteLater();
- m_reply = 0;
-}
diff --git a/src/QtLocationPlugin/qgeotiledmappingmanagerengineqgc.cpp b/src/QtLocationPlugin/qgeotiledmappingmanagerengineqgc.cpp
deleted file mode 100644
index 37d359d2c35d4fb2b63616736973bb8c7c56adef..0000000000000000000000000000000000000000
--- a/src/QtLocationPlugin/qgeotiledmappingmanagerengineqgc.cpp
+++ /dev/null
@@ -1,211 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Aaron McCarthy
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtLocation module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 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 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-** 2015.4.4
-** Adapted for use with QGroundControl
-**
-** Gus Grubba
-**
-****************************************************************************/
-
-#include
-#include
-#if QT_VERSION < 0x050500
-#include
-#else
-#include
-#endif
-#include
-#include
-
-#include "qgeotiledmappingmanagerengineqgc.h"
-#include "qgeotilefetcherqgc.h"
-#include "OpenPilotMaps.h"
-
-#if QT_VERSION >= 0x050500
-QGeoTiledMapQGC::QGeoTiledMapQGC(QGeoTiledMappingManagerEngine *engine, QObject *parent)
- : QGeoTiledMap(engine, parent)
-{
-
-}
-#endif
-
-QGeoTiledMappingManagerEngineQGC::QGeoTiledMappingManagerEngineQGC(const QVariantMap ¶meters, QGeoServiceProvider::Error *error, QString *errorString)
-: QGeoTiledMappingManagerEngine()
-{
- QGeoCameraCapabilities cameraCaps;
- cameraCaps.setMinimumZoomLevel(2.0);
- cameraCaps.setMaximumZoomLevel(MAX_MAP_ZOOM);
- cameraCaps.setSupportsBearing(true);
- setCameraCapabilities(cameraCaps);
-
- setTileSize(QSize(256, 256));
-
- QList mapTypes;
- mapTypes << QGeoMapType(QGeoMapType::StreetMap, tr("Google Street Map"), tr("Google street map"), false, false, OpenPilot::GoogleMap);
- mapTypes << QGeoMapType(QGeoMapType::SatelliteMapDay, tr("Google Satellite Map"),tr("Google satellite map"), false, false, OpenPilot::GoogleSatellite);
- mapTypes << QGeoMapType(QGeoMapType::TerrainMap, tr("Google Terrain Map"), tr("Google terrain map"), false, false, OpenPilot::GoogleTerrain);
- // TODO:
- // Proper google hybrid maps requires collecting two separate bimaps and overlaying them.
- //mapTypes << QGeoMapType(QGeoMapType::HybridMap, tr("Google Hybrid Map"), tr("Google hybrid map"), false, false, OpenPilot::GoogleHybrid);
- // Bing
- mapTypes << QGeoMapType(QGeoMapType::StreetMap, tr("Bing Street Map"), tr("Bing street map"), false, false, OpenPilot::BingMap);
- mapTypes << QGeoMapType(QGeoMapType::SatelliteMapDay, tr("Bing Satellite Map"), tr("Bing satellite map"), false, false, OpenPilot::BingSatellite);
- mapTypes << QGeoMapType(QGeoMapType::HybridMap, tr("Bing Hybrid Map"), tr("Bing hybrid map"), false, false, OpenPilot::BingHybrid);
- mapTypes << QGeoMapType(QGeoMapType::StreetMap, tr("Open Street Map"), tr("Open Street map"), false, false, OpenPilot::OpenStreetMap);
- setSupportedMapTypes(mapTypes);
-
- QGeoTileFetcherQGC *tileFetcher = new QGeoTileFetcherQGC(this);
- if (parameters.contains(QStringLiteral("useragent"))) {
- const QByteArray ua = parameters.value(QStringLiteral("useragent")).toString().toLatin1();
- tileFetcher->setUserAgent(ua);
- } else
- // QGC Default
- tileFetcher->setUserAgent("Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7");
-
-#if QT_VERSION >= 0x050500
- _setCache(parameters);
-#endif
- setTileFetcher(tileFetcher);
-
- *error = QGeoServiceProvider::NoError;
- errorString->clear();
-
-#if QT_VERSION >= 0x050500
- if (parameters.contains(QStringLiteral("mapping.copyright")))
- m_customCopyright = parameters.value(QStringLiteral("mapping.copyright")).toString().toLatin1();
-#endif
-}
-
-QGeoTiledMappingManagerEngineQGC::~QGeoTiledMappingManagerEngineQGC()
-{
-}
-
-#if QT_VERSION < 0x050500
-
-QGeoMapData *QGeoTiledMappingManagerEngineQGC::createMapData()
-{
- return new QGeoTiledMapData(this, 0);
-}
-
-#else
-
-QGeoMap *QGeoTiledMappingManagerEngineQGC::createMap()
-{
- return new QGeoTiledMapQGC(this);
-}
-
-QString QGeoTiledMappingManagerEngineQGC::customCopyright() const
-{
- return m_customCopyright;
-}
-
-#endif
-
-#if QT_VERSION >= 0x050500
-void QGeoTiledMappingManagerEngineQGC::_setCache(const QVariantMap ¶meters)
-{
-
- QString cacheDir = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + QLatin1String("/QGCMapCache");
- //-- Clear old cache
- QDir baseDir(cacheDir);
- if (baseDir.exists()) {
- const QStringList oldCacheFiles = baseDir.entryList(QDir::Files);
- foreach (const QString& file, oldCacheFiles)
- baseDir.remove(file);
- }
-
- if (parameters.contains(QStringLiteral("mapping.cache.directory")))
- cacheDir = parameters.value(QStringLiteral("mapping.cache.directory")).toString();
- else {
- cacheDir = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + QLatin1String("/QGCMapCache55");
- if(!QDir::root().mkpath(cacheDir)) {
- qWarning() << "Could not create mapping disk cache directory: " << cacheDir;
- cacheDir = QDir::homePath() + QLatin1String("/.qgcmapscache/");
- }
- }
-
- if(!QDir::root().mkpath(cacheDir))
- {
- qWarning() << "Could not create mapping disk cache directory: " << cacheDir;
- cacheDir.clear();
- }
- else {
- qDebug() << "Mapping cache directory:" << cacheDir;
- }
- QGeoTileCache* pTileCache = createTileCacheWithDir(cacheDir);
- if(pTileCache)
- {
- int cacheLimit = 0;
- //-- Disk Cache
- if (parameters.contains(QStringLiteral("mapping.cache.disk.size"))) {
- bool ok = false;
- cacheLimit = parameters.value(QStringLiteral("mapping.cache.disk.size")).toString().toInt(&ok);
- if (!ok)
- cacheLimit = 0;
- }
- if(!cacheLimit)
- {
-#ifdef __mobile__
- cacheLimit = 128 * 1024 * 1024;
-#else
- cacheLimit = 1024 * 1024 * 1024;
-#endif
- }
- pTileCache->setMaxDiskUsage(cacheLimit);
- //-- Memory Cache
- cacheLimit = 0;
- if (parameters.contains(QStringLiteral("mapping.cache.memory.size"))) {
- bool ok = false;
- cacheLimit = parameters.value(QStringLiteral("mapping.cache.memory.size")).toString().toInt(&ok);
- if (!ok)
- cacheLimit = 0;
- }
- if(!cacheLimit)
- {
-#ifdef __mobile__
- cacheLimit = 16 * 1024 * 1024;
-#else
- cacheLimit = 128 * 1024 * 1024;
-#endif
- }
- pTileCache->setMaxMemoryUsage(cacheLimit);
- }
-}
-#endif
diff --git a/src/QtLocationPlugin/qgeotilefetcherqgc.cpp b/src/QtLocationPlugin/qgeotilefetcherqgc.cpp
deleted file mode 100644
index 54c32d0be107ddde87a0b70f96f611a4dc3b44d5..0000000000000000000000000000000000000000
--- a/src/QtLocationPlugin/qgeotilefetcherqgc.cpp
+++ /dev/null
@@ -1,160 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Aaron McCarthy
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtLocation module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 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 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-** 2015.4.4
-** Adapted for use with QGroundControl
-**
-** Gus Grubba
-**
-****************************************************************************/
-
-#include
-#include
-#include
-#include
-
-#include "qgeotilefetcherqgc.h"
-#include "qgeomapreplyqgc.h"
-
-QGeoTileFetcherQGC::QGeoTileFetcherQGC(QGeoTiledMappingManagerEngine *parent)
- : QGeoTileFetcher(parent)
- , m_networkManager(new QNetworkAccessManager(this))
-#if defined Q_OS_MAC
- , m_userAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:21.0) Gecko/20100101 Firefox/21.0")
-#elif defined Q_OS_WIN32
- , m_userAgent("Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7")
-#else
- , m_userAgent("Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:21.0) Gecko/20130331 Firefox/21.0")
-#endif
- , m_UrlFactory(NULL)
-{
- QStringList langs = QLocale::system().uiLanguages();
- if (langs.length() > 0) {
- m_Language = langs[0];
- }
- m_UrlFactory = new OpenPilot::UrlFactory(m_networkManager);
-}
-
-QGeoTileFetcherQGC::~QGeoTileFetcherQGC()
-{
- if(m_UrlFactory)
- delete m_UrlFactory;
-}
-
-void QGeoTileFetcherQGC::setUserAgent(const QByteArray &userAgent)
-{
- m_userAgent = userAgent;
-}
-
-QGeoTiledMapReply *QGeoTileFetcherQGC::getTileImage(const QGeoTileSpec &spec)
-{
- QNetworkRequest request;
- QString url = m_UrlFactory->makeImageUrl((OpenPilot::MapType)spec.mapId(), QPoint(spec.x(), spec.y()), spec.zoom(), m_Language);
-
- request.setUrl(QUrl(url));
- request.setRawHeader("User-Agent", m_userAgent);
- request.setRawHeader("Accept", "*/*");
- switch ((OpenPilot::MapType)spec.mapId()) {
- case OpenPilot::GoogleMap:
- case OpenPilot::GoogleSatellite:
- case OpenPilot::GoogleLabels:
- case OpenPilot::GoogleTerrain:
- case OpenPilot::GoogleHybrid:
- {
- request.setRawHeader("Referrer", "http://maps.google.com/");
- }
- break;
- case OpenPilot::GoogleMapChina:
- case OpenPilot::GoogleSatelliteChina:
- case OpenPilot::GoogleLabelsChina:
- case OpenPilot::GoogleTerrainChina:
- case OpenPilot::GoogleHybridChina:
- {
- request.setRawHeader("Referrer", "http://ditu.google.cn/");
- }
- break;
- case OpenPilot::BingHybrid:
- case OpenPilot::BingMap:
- case OpenPilot::BingSatellite:
- {
- request.setRawHeader("Referrer", "http://www.bing.com/maps/");
- }
- break;
- case OpenPilot::YahooHybrid:
- case OpenPilot::YahooLabels:
- case OpenPilot::YahooMap:
- case OpenPilot::YahooSatellite:
- {
- request.setRawHeader("Referrer", "http://maps.yahoo.com/");
- }
- break;
- case OpenPilot::ArcGIS_MapsLT_Map_Labels:
- case OpenPilot::ArcGIS_MapsLT_Map:
- case OpenPilot::ArcGIS_MapsLT_OrtoFoto:
- case OpenPilot::ArcGIS_MapsLT_Map_Hybrid:
- {
- request.setRawHeader("Referrer", "http://www.maps.lt/map_beta/");
- }
- break;
- case OpenPilot::OpenStreetMapSurfer:
- case OpenPilot::OpenStreetMapSurferTerrain:
- {
- request.setRawHeader("Referrer", "http://www.mapsurfer.net/");
- }
- break;
- case OpenPilot::OpenStreetMap:
- case OpenPilot::OpenStreetOsm:
- {
- request.setRawHeader("Referrer", "http://www.openstreetmap.org/");
- }
- break;
- case OpenPilot::YandexMapRu:
- {
- request.setRawHeader("Referrer", "http://maps.yandex.ru/");
- }
- break;
- default:
- break;
- }
-
- QNetworkReply *reply = m_networkManager->get(request);
- reply->setParent(0);
- return new QGeoMapReplyQGC(reply, spec);
-
-}
diff --git a/src/main.cc b/src/main.cc
index c2cdbf4802b7a1a02c66cd36d90443d77952d8e2..95bd955d5369521000eed26dfcfbf11578e40c60 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -56,6 +56,7 @@ This file is part of the QGROUNDCONTROL project
#endif
#include
+#include "QGCMapEngine.h"
/* SDL does ugly things to main() */
#ifdef main
@@ -234,6 +235,8 @@ int main(int argc, char *argv[])
qRegisterMetaType > >();
app->_initCommon();
+ //-- Initialize Cache System
+ getQGCMapEngine()->init();
int exitCode = 0;
@@ -267,6 +270,8 @@ int main(int argc, char *argv[])
}
delete app;
+ //-- Shutdown Cache System
+ destroyMapEngine();
qDebug() << "After app delete";
diff --git a/src/ui/MainWindowLeftPanel.qml b/src/ui/MainWindowLeftPanel.qml
index b508ba6c0be0cd897a1e9849436610d950b4943d..d83f724fc34db85ea8493862b413dbb2498e351e 100644
--- a/src/ui/MainWindowLeftPanel.qml
+++ b/src/ui/MainWindowLeftPanel.qml
@@ -174,6 +174,19 @@ Item {
checked = true
}
}
+ QGCButton {
+ width: parent.width * 0.85
+ height: ScreenTools.defaultFontPixelHeight * 2.5
+ text: "Offline Maps"
+ exclusiveGroup: panelActionGroup
+ anchors.horizontalCenter: parent.horizontalCenter
+ onClicked: {
+ if(__rightPanel.source != "OfflineMap.qml") {
+ __rightPanel.source = "OfflineMap.qml"
+ }
+ checked = true
+ }
+ }
QGCButton {
width: parent.width * 0.85
height: ScreenTools.defaultFontPixelHeight * 2.5
diff --git a/src/ui/preferences/GeneralSettings.qml b/src/ui/preferences/GeneralSettings.qml
index 7762d23481941885914a47e2015959167aa32a70..450f4d4f0d088310720cc9bb3ba11dfd32c0eaaf 100644
--- a/src/ui/preferences/GeneralSettings.qml
+++ b/src/ui/preferences/GeneralSettings.qml
@@ -133,7 +133,6 @@ Rectangle {
height: ScreenTools.defaultFontPixelHeight / 2
width: parent.width
}
-
//-----------------------------------------------------------------
//-- Map Providers
Row {