///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2021 Jon Beniston, M7RCE //
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program 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 as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program 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 V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see . //
///////////////////////////////////////////////////////////////////////////////////
#include
#include
#include
#include
#include
#include
#include
#ifdef QT_WEBENGINE_FOUND
#include
#include
#include
#endif
#include "feature/featureuiset.h"
#include "gui/basicfeaturesettingsdialog.h"
#include "gui/dialogpositioner.h"
#include "mainwindow.h"
#include "device/deviceuiset.h"
#include "util/units.h"
#include "util/maidenhead.h"
#include "util/morse.h"
#include "maplocationdialog.h"
#include "mapmaidenheaddialog.h"
#include "mapsettingsdialog.h"
#include "ibpbeacon.h"
#include "ui_mapgui.h"
#include "map.h"
#include "mapgui.h"
#include "SWGMapItem.h"
#include "SWGTargetAzimuthElevation.h"
MapGUI* MapGUI::create(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature)
{
MapGUI* gui = new MapGUI(pluginAPI, featureUISet, feature);
return gui;
}
void MapGUI::destroy()
{
delete this;
}
void MapGUI::resetToDefaults()
{
m_settings.resetToDefaults();
displaySettings();
applySettings(true);
}
QByteArray MapGUI::serialize() const
{
return m_settings.serialize();
}
bool MapGUI::deserialize(const QByteArray& data)
{
if (m_settings.deserialize(data))
{
m_feature->setWorkspaceIndex(m_settings.m_workspaceIndex);
displaySettings();
applySettings(true);
return true;
}
else
{
resetToDefaults();
return false;
}
}
bool MapGUI::handleMessage(const Message& message)
{
if (Map::MsgConfigureMap::match(message))
{
qDebug("MapGUI::handleMessage: Map::MsgConfigureMap");
const Map::MsgConfigureMap& cfg = (Map::MsgConfigureMap&) message;
if (cfg.getForce()) {
m_settings = cfg.getSettings();
} else {
m_settings.applySettings(cfg.getSettingsKeys(), cfg.getSettings());
}
blockApplySettings(true);
displaySettings();
blockApplySettings(false);
return true;
}
else if (Map::MsgReportAvailableChannelOrFeatures::match(message))
{
Map::MsgReportAvailableChannelOrFeatures& report = (Map::MsgReportAvailableChannelOrFeatures&) message;
m_availableChannelOrFeatures = report.getItems();
return true;
}
else if (Map::MsgFind::match(message))
{
Map::MsgFind& msgFind = (Map::MsgFind&) message;
find(msgFind.getTarget());
return true;
}
else if (Map::MsgSetDateTime::match(message))
{
Map::MsgSetDateTime& msgSetDateTime = (Map::MsgSetDateTime&) message;
if (m_cesium) {
m_cesium->setDateTime(msgSetDateTime.getDateTime());
}
return true;
}
else if (MainCore::MsgMapItem::match(message))
{
MainCore::MsgMapItem& msgMapItem = (MainCore::MsgMapItem&) message;
SWGSDRangel::SWGMapItem *swgMapItem = msgMapItem.getSWGMapItem();
// TODO: Could have this in SWGMapItem so plugins can create additional groups
QString group;
for (int i = 0; i < m_availableChannelOrFeatures.size(); i++)
{
if (m_availableChannelOrFeatures[i].m_source == msgMapItem.getPipeSource())
{
for (int j = 0; j < MapSettings::m_pipeTypes.size(); j++)
{
if (m_availableChannelOrFeatures[i].m_type == MapSettings::m_pipeTypes[j]) {
group = m_availableChannelOrFeatures[i].m_type;
}
}
}
}
update(msgMapItem.getPipeSource(), swgMapItem, group);
return true;
}
return false;
}
void MapGUI::handleInputMessages()
{
Message* message;
while ((message = getInputMessageQueue()->pop()))
{
if (handleMessage(*message)) {
delete message;
}
}
}
void MapGUI::onWidgetRolled(QWidget* widget, bool rollDown)
{
(void) widget;
(void) rollDown;
getRollupContents()->saveState(m_rollupState);
}
MapGUI::MapGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent) :
FeatureGUI(parent),
ui(new Ui::MapGUI),
m_pluginAPI(pluginAPI),
m_featureUISet(featureUISet),
m_doApplySettings(true),
m_objectMapModel(this),
m_imageMapModel(this),
m_polygonMapModel(this),
m_polylineMapModel(this),
m_beacons(nullptr),
m_beaconDialog(this),
m_ibpBeaconDialog(this),
m_radioTimeDialog(this),
m_cesium(nullptr)
{
m_feature = feature;
setAttribute(Qt::WA_DeleteOnClose, true);
m_helpURL = "plugins/feature/map/readme.md";
RollupContents *rollupContents = getRollupContents();
ui->setupUi(rollupContents);
setSizePolicy(rollupContents->sizePolicy());
rollupContents->arrangeRollups();
connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool)));
// Enable MSAA antialiasing on 2D map
// This can be much faster than using layer.smooth in the QML, when there are many items
// However, only seems to work when set to 16, and doesn't seem to be supported on all graphics cards
int multisamples = MainCore::instance()->getSettings().getMapMultisampling();
if (multisamples > 0)
{
QSurfaceFormat format;
format.setSamples(multisamples);
ui->map->setFormat(format);
}
m_osmPort = 0;
m_templateServer = new OSMTemplateServer(thunderforestAPIKey(), maptilerAPIKey(), m_osmPort);
// Web server to serve dynamic files from QResources
m_webPort = 0;
m_webServer = new WebServer(m_webPort);
ui->map->setAttribute(Qt::WA_AcceptTouchEvents, true);
m_objectMapFilter.setSourceModel(&m_objectMapModel);
m_imageMapFilter.setSourceModel(&m_imageMapModel);
m_polygonMapFilter.setSourceModel(&m_polygonMapModel);
m_polylineMapFilter.setSourceModel(&m_polylineMapModel);
ui->map->rootContext()->setContextProperty("mapModelFiltered", &m_objectMapFilter);
ui->map->rootContext()->setContextProperty("mapModel", &m_objectMapModel);
ui->map->rootContext()->setContextProperty("imageModelFiltered", &m_imageMapFilter);
ui->map->rootContext()->setContextProperty("polygonModelFiltered", &m_polygonMapFilter);
ui->map->rootContext()->setContextProperty("polylineModelFiltered", &m_polylineMapFilter);
ui->map->setSource(QUrl(QStringLiteral("qrc:/map/map/map.qml")));
m_settings.m_modelURL = QString("http://127.0.0.1:%1/3d/").arg(m_webPort);
m_webServer->addPathSubstitution("3d", m_settings.m_modelDir);
m_map = reinterpret_cast