Date: Sun, 10 May 2026 22:11:14 +0200
Subject: [PATCH 029/104] OnlineMap Controller: Refactor online map bridge
handling
---
QLog.pro | 5 +-
res/map/onlinemap.html | 185 ++++++++++---
ui/MapLayer.h | 26 ++
ui/MapPageController.cpp | 519 ++++++++++++++++++++++++++++++++++++
ui/MapPageController.h | 169 ++++++++++++
ui/MapWebChannelHandler.cpp | 199 --------------
ui/MapWebChannelHandler.h | 42 ---
ui/OnlineMapWidget.cpp | 158 ++++-------
ui/OnlineMapWidget.h | 15 +-
ui/QSODetailDialog.cpp | 120 +++------
ui/QSODetailDialog.h | 13 +-
ui/StatisticsWidget.cpp | 146 ++++------
ui/StatisticsWidget.h | 12 +-
13 files changed, 1020 insertions(+), 589 deletions(-)
create mode 100644 ui/MapLayer.h
create mode 100644 ui/MapPageController.cpp
create mode 100644 ui/MapPageController.h
delete mode 100644 ui/MapWebChannelHandler.cpp
delete mode 100644 ui/MapWebChannelHandler.h
diff --git a/QLog.pro b/QLog.pro
index 7beaf1f6..2a66f336 100644
--- a/QLog.pro
+++ b/QLog.pro
@@ -200,7 +200,7 @@ SOURCES += \
ui/KSTHighlighterSettingDialog.cpp \
ui/LogbookWidget.cpp \
ui/MainWindow.cpp \
- ui/MapWebChannelHandler.cpp \
+ ui/MapPageController.cpp \
ui/MapWidget.cpp \
ui/ModeSelectionController.cpp \
ui/NewContactWidget.cpp \
@@ -396,7 +396,8 @@ HEADERS += \
ui/KSTHighlighterSettingDialog.h \
ui/LogbookWidget.h \
ui/MainWindow.h \
- ui/MapWebChannelHandler.h \
+ ui/MapLayer.h \
+ ui/MapPageController.h \
ui/MapWidget.h \
ui/ModeSelectionController.h \
ui/NewContactWidget.h \
diff --git a/res/map/onlinemap.html b/res/map/onlinemap.html
index a69bf98f..8d3778ab 100644
--- a/res/map/onlinemap.html
+++ b/res/map/onlinemap.html
@@ -105,6 +105,80 @@
var staticMapTime = null;
var map = L.map('map', {center: [0,0], zoom: 2, minZoom: 1});
+ var layerControl = null;
+ var mapBridge = null;
+ const qlogLayerStateKeys = new Map();
+ let qlogLayerStateBridgeConnected = false;
+
+ function mapLayerByKey(key) {
+ return window[key] || null;
+ }
+
+ function sendToQt(method) {
+ if (!window.mapBridge || typeof window.mapBridge[method] !== 'function')
+ return;
+
+ window.mapBridge[method].apply(window.mapBridge, Array.prototype.slice.call(arguments, 1));
+ }
+
+ function setQLogLayerVisibility(key, visible) {
+ const layer = mapLayerByKey(key);
+ if (!layer)
+ return;
+
+ if (visible)
+ map.addLayer(layer);
+ else
+ map.removeLayer(layer);
+ }
+
+ function restoreQLogLayerStates(states) {
+ states.forEach(function(state) {
+ setQLogLayerVisibility(state.key, state.visible);
+ });
+ }
+
+ function configureLayerControl(layers) {
+ const overlays = {};
+ qlogLayerStateKeys.clear();
+
+ layers.forEach(function(layerSpec) {
+ const layer = mapLayerByKey(layerSpec.key);
+ if (!layer)
+ return;
+
+ overlays[layerSpec.label] = layer;
+ qlogLayerStateKeys.set(layer, layerSpec.key);
+ });
+
+ if (layerControl)
+ map.removeControl(layerControl);
+
+ layerControl = new L.Control.Layers(null, overlays, {}).addTo(map);
+ }
+
+ function handleQLogLayerStateChanged(layer, state) {
+ const key = qlogLayerStateKeys.get(layer);
+ if (!key)
+ return;
+
+ sendToQt('handleLayerSelectionChanged', key, state);
+ }
+
+ function connectQtMapBridge(handler) {
+ window.mapBridge = handler;
+
+ if (qlogLayerStateBridgeConnected)
+ return;
+
+ map.on('overlayadd', function(e) {
+ handleQLogLayerStateChanged(e.layer, 'on');
+ });
+ map.on('overlayremove', function(e) {
+ handleQLogLayerStateChanged(e.layer, 'off');
+ });
+ qlogLayerStateBridgeConnected = true;
+ }
map.createPane('lowestPane');
map.getPane('lowestPane').style.zIndex = 200;
@@ -156,6 +230,47 @@
popupAnchor: [1, -14]
});
+ const mapIcons = {
+ greenIcon: greenIcon,
+ greenIconSmall: greenIconSmall,
+ yellowIcon: yellowIcon,
+ yellowIconSmall: yellowIconSmall,
+ homeIcon: homeIcon
+ };
+
+ function resolveIcon(icon) {
+ return mapIcons[icon] || null;
+ }
+
+ function normalizePoint(point) {
+ if (Array.isArray(point)) {
+ return {
+ label: point[0],
+ lat: point[1],
+ lng: point[2],
+ icon: point[3]
+ };
+ }
+
+ return point;
+ }
+
+ function markerOptions(point) {
+ const icon = resolveIcon(point.icon);
+ return icon ? {icon: icon} : {};
+ }
+
+ function normalizePath(path) {
+ if (Array.isArray(path)) {
+ return {
+ from: {lat: path[0], lng: path[1]},
+ to: {lat: path[2], lng: path[3]}
+ };
+ }
+
+ return path;
+ }
+
var language = navigator.language || navigator.userLanguage;
var mapUrl;
@@ -256,10 +371,11 @@
function drawShortPaths(coords) {
pathLayer.clearLayers();
- coords.forEach(function(coord) {
+ coords.forEach(function(rawPath) {
+ const path = normalizePath(rawPath);
let geodesic = new L.Geodesic([],{ wrap: false, color: "#cc2e41", steps: 5, opacity: 0.7, weight: 1});
pathLayer.addLayer(geodesic);
- geodesic.setLatLngs([{lat: coord[0], lng: coord[1]}, {lat: coord[2], lng: coord[3]}]);
+ geodesic.setLatLngs([path.from, path.to]);
});
}
@@ -308,15 +424,19 @@
var markersLayer = L.layerGroup().addTo(map);
- // generic function to render point on the map
- function drawPoints(points) {
- markersLayer.clearLayers();
+ function drawPointMarkers(layer, points) {
+ layer.clearLayers();
points.forEach(function(point) {
- let marker = L.marker([point[1], point[2]], {
- icon: point[3]})
- .bindPopup(point[0]);
- markersLayer.addLayer(marker);
+ const mapPoint = normalizePoint(point);
+ let marker = L.marker([mapPoint.lat, mapPoint.lng], markerOptions(mapPoint))
+ .bindPopup(mapPoint.label);
+ layer.addLayer(marker);
});
+ }
+
+ // generic function to render point on the map
+ function drawPoints(points) {
+ drawPointMarkers(markersLayer, points);
}
function drawPointsBusy(points, text) {
@@ -325,7 +445,8 @@
// generic function for flying to the point
function flyToPoint(point, zoom) {
- map.flyTo([point[1], point[2]],zoom);
+ const mapPoint = normalizePoint(point);
+ map.flyTo([mapPoint.lat, mapPoint.lng], zoom);
}
var markersLayer2 = L.layerGroup().addTo(map);
@@ -333,13 +454,7 @@
// generic function to render the sencond layer of the points
// It is usually used to render My QTHs
function drawPointsGroup2(points) {
- markersLayer2.clearLayers();
- points.forEach(function(point) {
- let marker = L.marker([point[1], point[2]], {
- icon: point[3]})
- .bindPopup(point[0]);
- markersLayer2.addLayer(marker);
- });
+ drawPointMarkers(markersLayer2, points);
}
// compute 3-color gradient
@@ -400,13 +515,14 @@
mufLayer.clearLayers();
points.forEach(function(point) {
- let marker = new L.marker([point[1], point[2]], {opacity: 0.001 });
- marker.bindTooltip(point[0], {permanent: true, direction : 'bottom', offset: [-16, 8], className: 'muf-tooltip' });
+ const mapPoint = normalizePoint(point);
+ let marker = new L.marker([mapPoint.lat, mapPoint.lng], {opacity: 0.001 });
+ marker.bindTooltip(mapPoint.label, {permanent: true, direction : 'bottom', offset: [-16, 8], className: 'muf-tooltip' });
// color gradient is calculated for number interval 0 - 1.
// MUF value is a fgrequency. Threfore is it needed to recalculate Freq to interval 0 - 1
// QLog currently recalculate the interval 0 - 50 MHz. This is due to the fact that
// most of the values move in this interval and it is easy to see the individual frequency ranges
- const oldValue = parseFloat(point[0]);
+ const oldValue = parseFloat(mapPoint.label);
const oldMin = 0; const oldMax = 50; //frequency input range (0 - 50MHz)
const newMin = 0; const newMax = 1; //mapped to range 0 - 1
const newValue = (oldValue - oldMin) / (oldMax - oldMin) * (newMax - newMin) + newMin;
@@ -449,7 +565,10 @@
function IBPCallsignPressed(e) {
let currentIndex = band.findIndex(object => {return object.band_name === currentBand;});
- foo.IBPCallsignClicked(this.callsign, band[currentIndex].freq);
+ if (currentIndex === -1)
+ return;
+
+ sendToQt('IBPCallsignClicked', this.callsign, band[currentIndex].freq);
}
// render IPB Beacon Point
@@ -512,7 +631,7 @@
var chatStationsLayer = L.layerGroup().addTo(map);
function chatCallsignPressed(e) {
- foo.chatCallsignClicked(this.callsign);
+ sendToQt('chatCallsignClicked', this.callsign);
}
// generic function to render the third layer of the points
@@ -520,10 +639,11 @@
function drawPointsGroup3(points) {
chatStationsLayer.clearLayers();
points.forEach(function(point) {
- let marker = new L.marker([point[1], point[2]], {opacity: 0.001 });
- marker.bindTooltip(point[0], {pane: 'lowestPane', permanent: true, direction : 'bottom', offset: [-16, 8], className: 'chat-tooltip' });
+ const mapPoint = normalizePoint(point);
+ let marker = new L.marker([mapPoint.lat, mapPoint.lng], {opacity: 0.001 });
+ marker.bindTooltip(mapPoint.label, {pane: 'lowestPane', permanent: true, direction : 'bottom', offset: [-16, 8], className: 'chat-tooltip' });
marker.on('dblclick', chatCallsignPressed);
- marker.callsign = point[0];
+ marker.callsign = mapPoint.label;
marker.getTooltip().setContent(`${marker.getTooltip().getContent()}
`);
chatStationsLayer.addLayer(marker);
});
@@ -532,13 +652,14 @@
setInterval(function(){updateBeacon()}, 250);
function wsjtxCallsignPressed(e) {
- foo.wsjtxCallsignClicked(this.callsign);
+ sendToQt('wsjtxCallsignClicked', this.callsign);
}
var wsjtxStationsLayer = L.layerGroup();
// this function show WSJTX spots
- function addWSJTXSpot(lat, lng, callsign, color) {
+ function addWSJTXSpot(point, color) {
+ const spot = normalizePoint(point);
const fadeSchedule = [
{ timeout: 30000, className: 'fade-out75' },
{ timeout: 45000, className: 'fade-out50' },
@@ -549,9 +670,9 @@
function createSpotMarker(latitude, longitude) {
const marker = new L.marker([latitude, longitude], { opacity: 0.001 });
- marker.callsign = callsign;
+ marker.callsign = spot.label;
- marker.bindTooltip(callsign, {
+ marker.bindTooltip(spot.label, {
pane: 'lowestPane',
permanent: true,
direction: 'bottom',
@@ -568,11 +689,11 @@
}
// the main marker
- const marker = createSpotMarker(lat, lng);
+ const marker = createSpotMarker(spot.lat, spot.lng);
// mirror marker
- const mirrorLon = lng >= 0 ? lng - 360 : lng + 360;
- const markerMirror = createSpotMarker(lat, mirrorLon);
+ const mirrorLon = spot.lng >= 0 ? spot.lng - 360 : spot.lng + 360;
+ const markerMirror = createSpotMarker(spot.lat, mirrorLon);
wsjtxStationsLayer.addLayer(marker);
wsjtxStationsLayer.addLayer(markerMirror);
diff --git a/ui/MapLayer.h b/ui/MapLayer.h
new file mode 100644
index 00000000..9f5291dc
--- /dev/null
+++ b/ui/MapLayer.h
@@ -0,0 +1,26 @@
+#ifndef QLOG_UI_MAPLAYER_H
+#define QLOG_UI_MAPLAYER_H
+
+#include
+
+class MapLayer
+{
+public:
+ enum Layer
+ {
+ Grid = 0x0001,
+ Grayline = 0x0002,
+ Aurora = 0x0004,
+ Muf = 0x0008,
+ Ibp = 0x0010,
+ Beam = 0x0020,
+ Chat = 0x0040,
+ Wsjtx = 0x0080,
+ Path = 0x0100
+ };
+ Q_DECLARE_FLAGS(Layers, Layer)
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(MapLayer::Layers)
+
+#endif // QLOG_UI_MAPLAYER_H
diff --git a/ui/MapPageController.cpp b/ui/MapPageController.cpp
new file mode 100644
index 00000000..498b09b7
--- /dev/null
+++ b/ui/MapPageController.cpp
@@ -0,0 +1,519 @@
+#include "MapPageController.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "core/debug.h"
+#include "core/LogParam.h"
+#include "ui/WebEnginePage.h"
+
+MODULE_IDENTIFICATION("qlog.ui.mappagecontroller");
+
+QString MapPageController::jsonArray(const QJsonArray &array)
+{
+ return QString::fromUtf8(QJsonDocument(array).toJson(QJsonDocument::Compact));
+}
+
+QString MapPageController::jsonObject(const QJsonObject &object)
+{
+ return QString::fromUtf8(QJsonDocument(object).toJson(QJsonDocument::Compact));
+}
+
+QString MapPageController::jsonString(const QString &string)
+{
+ QJsonArray array;
+ array.append(string);
+
+ QString ret = jsonArray(array);
+ ret.remove(0, 1);
+ ret.chop(1);
+ return ret;
+}
+
+QJsonObject MapPageController::coordinateObject(const MapCoordinate &coordinate)
+{
+ QJsonObject object;
+ object.insert(QStringLiteral("lat"), coordinate.latitude);
+ object.insert(QStringLiteral("lng"), coordinate.longitude);
+ return object;
+}
+
+QJsonObject MapPageController::pointObject(const MapPoint &point)
+{
+ QJsonObject object;
+ object.insert(QStringLiteral("label"), point.label);
+ object.insert(QStringLiteral("lat"), point.coordinate.latitude);
+ object.insert(QStringLiteral("lng"), point.coordinate.longitude);
+ object.insert(QStringLiteral("icon"), point.icon);
+ return object;
+}
+
+QJsonArray MapPageController::coordinateArray(const MapCoordinate &coordinate)
+{
+ QJsonArray array;
+ array.append(coordinate.latitude);
+ array.append(coordinate.longitude);
+ return array;
+}
+
+QJsonArray MapPageController::pointsArray(const QList &points)
+{
+ QJsonArray array;
+
+ for ( const MapPoint &point : points )
+ array.append(pointObject(point));
+
+ return array;
+}
+
+QJsonArray MapPageController::coordinatesArray(const QList &coordinates)
+{
+ QJsonArray array;
+
+ for ( const MapCoordinate &coordinate : coordinates )
+ array.append(coordinateArray(coordinate));
+
+ return array;
+}
+
+QJsonArray MapPageController::pathsArray(const QList &paths)
+{
+ QJsonArray array;
+
+ for ( const MapPath &path : paths )
+ {
+ QJsonObject item;
+ item.insert(QStringLiteral("from"), coordinateObject(path.from));
+ item.insert(QStringLiteral("to"), coordinateObject(path.to));
+ array.append(item);
+ }
+
+ return array;
+}
+
+QJsonArray MapPageController::stringArray(const QStringList &strings)
+{
+ QJsonArray array;
+
+ for ( const QString &string : strings )
+ array.append(string);
+
+ return array;
+}
+
+QJsonArray MapPageController::heatPointsArray(const QList &points)
+{
+ QJsonArray array;
+
+ for ( const MapHeatPoint &point : points )
+ {
+ QJsonObject item;
+ item.insert(QStringLiteral("lat"), point.coordinate.latitude);
+ item.insert(QStringLiteral("lng"), point.coordinate.longitude);
+ item.insert(QStringLiteral("count"), point.value);
+ array.append(item);
+ }
+
+ return array;
+}
+
+MapPageController::MapPageController(const QString &configID,
+ QObject *parent)
+ : QObject(parent),
+ configID(configID),
+ mainPage(new WebEnginePage(this)),
+ pageLoaded(false)
+{
+ channel.registerObject("mapBridge", this);
+}
+
+MapPageController::~MapPageController()
+{
+ if ( attachedView && attachedView->page() == mainPage )
+ attachedView->setPage(nullptr);
+
+ if ( mainPage )
+ mainPage->setWebChannel(nullptr);
+
+ channel.deregisterObject(this);
+}
+
+void MapPageController::attach(QWebEngineView *view,
+ MapLayer::Layers layers)
+{
+ FCT_IDENTIFICATION;
+
+ if ( !view )
+ return;
+
+ if ( attachedView )
+ {
+ disconnect(attachedView.data(), &QWebEngineView::loadFinished,
+ this, &MapPageController::finishLoading);
+ if ( attachedView->page() == mainPage )
+ attachedView->setPage(nullptr);
+ }
+
+ attachedView = view;
+ mapLayers = layers;
+ mainPage->setWebChannel(&channel);
+ view->setPage(mainPage);
+ connect(view, &QWebEngineView::loadFinished,
+ this, &MapPageController::finishLoading,
+ Qt::UniqueConnection);
+ mainPage->load(QUrl(QStringLiteral("qrc:/res/map/onlinemap.html")));
+ view->setFocusPolicy(Qt::ClickFocus);
+}
+
+void MapPageController::runJavaScript(const QString &js)
+{
+ FCT_IDENTIFICATION;
+
+ qCDebug(function_parameters) << js;
+
+ if ( !pageLoaded )
+ postponedScripts.append(js);
+ else
+ mainPage->runJavaScript(js);
+}
+
+void MapPageController::setDarkTheme(bool isDark)
+{
+ FCT_IDENTIFICATION;
+
+ const QString js = isDark
+ ? QLatin1String("map.getPanes().tilePane.style.webkitFilter=\"brightness(0.6) invert(1) contrast(3) hue-rotate(200deg) saturate(0.3) brightness(0.9)\";")
+ : QLatin1String("map.getPanes().tilePane.style.webkitFilter=\"\";");
+ runJavaScript(js);
+}
+
+void MapPageController::setStaticMapTime(const QDateTime &dateTime)
+{
+ FCT_IDENTIFICATION;
+
+ runJavaScript(QStringLiteral("setStaticMapTime(new Date(%1));")
+ .arg(dateTime.toMSecsSinceEpoch()));
+}
+
+void MapPageController::drawPoints(const QList &points)
+{
+ FCT_IDENTIFICATION;
+
+ runJavaScript(QStringLiteral("drawPoints(%1);")
+ .arg(jsonArray(pointsArray(points))));
+}
+
+void MapPageController::drawPointsBusy(const QList &points,
+ const QString &text)
+{
+ FCT_IDENTIFICATION;
+
+ runJavaScript(QStringLiteral("drawPointsBusy(%1, %2);")
+ .arg(jsonArray(pointsArray(points)),
+ jsonString(text)));
+}
+
+void MapPageController::drawHomePoints(const QList &points)
+{
+ FCT_IDENTIFICATION;
+
+ runJavaScript(QStringLiteral("drawPointsGroup2(%1);")
+ .arg(jsonArray(pointsArray(points))));
+}
+
+void MapPageController::drawChatPoints(const QList &points)
+{
+ FCT_IDENTIFICATION;
+
+ runJavaScript(QStringLiteral("drawPointsGroup3(%1);")
+ .arg(jsonArray(pointsArray(points))));
+}
+
+void MapPageController::flyToPoint(const MapPoint &point, int zoom)
+{
+ FCT_IDENTIFICATION;
+
+ runJavaScript(QStringLiteral("flyToPoint(%1, %2);")
+ .arg(jsonObject(pointObject(point)))
+ .arg(zoom));
+}
+
+void MapPageController::drawPath(const QList &points)
+{
+ FCT_IDENTIFICATION;
+
+ runJavaScript(QStringLiteral("drawPath(%1);")
+ .arg(jsonArray(coordinatesArray(points))));
+}
+
+void MapPageController::clearPath()
+{
+ FCT_IDENTIFICATION;
+
+ drawPath(QList());
+}
+
+void MapPageController::drawShortPaths(const QList &paths)
+{
+ FCT_IDENTIFICATION;
+
+ runJavaScript(QStringLiteral("drawShortPaths(%1);")
+ .arg(jsonArray(pathsArray(paths))));
+}
+
+void MapPageController::drawShortPathsBusy(const QList &paths,
+ const QString &text)
+{
+ FCT_IDENTIFICATION;
+
+ runJavaScript(QStringLiteral("drawShortPathsBusy(%1, %2);")
+ .arg(jsonArray(pathsArray(paths)),
+ jsonString(text)));
+}
+
+void MapPageController::drawAntPath(const MapCoordinate &from,
+ double distance,
+ double azimuth,
+ double antAngle)
+{
+ FCT_IDENTIFICATION;
+
+ runJavaScript(QStringLiteral("drawAntPath(%1, %2, %3, %4);")
+ .arg(jsonObject(coordinateObject(from)))
+ .arg(distance)
+ .arg(azimuth)
+ .arg(antAngle));
+}
+
+void MapPageController::clearAntPath()
+{
+ FCT_IDENTIFICATION;
+
+ runJavaScript(QLatin1String("drawAntPath({}, 0, 0, 0);"));
+}
+
+void MapPageController::setGridLayers(const QStringList &confirmedGrids,
+ const QStringList &workedGrids)
+{
+ FCT_IDENTIFICATION;
+
+ runJavaScript(QStringLiteral("grids_confirmed = %1;"
+ "grids_worked = %2;")
+ .arg(jsonArray(stringArray(confirmedGrids)),
+ jsonArray(stringArray(workedGrids))));
+}
+
+void MapPageController::clearGridLayers()
+{
+ FCT_IDENTIFICATION;
+
+ setGridLayers(QStringList(), QStringList());
+}
+
+void MapPageController::redrawGridLayer()
+{
+ FCT_IDENTIFICATION;
+
+ runJavaScript(QLatin1String("maidenheadConfWorked.redraw();"));
+}
+
+void MapPageController::panToBoundsLongitudeCenter(const QList &coordinates)
+{
+ FCT_IDENTIFICATION;
+
+ if ( coordinates.isEmpty() )
+ return;
+
+ runJavaScript(QStringLiteral("map.panTo([0, L.latLngBounds(%1).getCenter().lng]);")
+ .arg(jsonArray(coordinatesArray(coordinates))));
+}
+
+void MapPageController::setAuroraData(const QList &points)
+{
+ FCT_IDENTIFICATION;
+
+ runJavaScript(QStringLiteral("auroraLayer.setData({max: 100, data:%1});")
+ .arg(jsonArray(heatPointsArray(points))));
+}
+
+void MapPageController::drawMuf(const QList &points)
+{
+ FCT_IDENTIFICATION;
+
+ runJavaScript(QStringLiteral("drawMuf(%1);")
+ .arg(jsonArray(pointsArray(points))));
+}
+
+void MapPageController::setCurrentBand(const QString &band)
+{
+ FCT_IDENTIFICATION;
+
+ runJavaScript(QStringLiteral("currentBand=%1;")
+ .arg(jsonString(band)));
+}
+
+void MapPageController::addWsjtxSpot(const MapPoint &point,
+ const QString &color)
+{
+ FCT_IDENTIFICATION;
+
+ runJavaScript(QStringLiteral("addWSJTXSpot(%1, %2);")
+ .arg(jsonObject(pointObject(point)),
+ jsonString(color)));
+}
+
+void MapPageController::clearWsjtxSpots()
+{
+ FCT_IDENTIFICATION;
+
+ runJavaScript(QLatin1String("clearWSJTXSpots();"));
+}
+
+QString MapPageController::generateLayerControlJS(MapLayer::Layers layers)
+{
+ FCT_IDENTIFICATION;
+ QJsonArray options;
+
+ auto appendOption = [&options, layers](MapLayer::Layer layer,
+ const QString &label,
+ const QString &key)
+ {
+ if ( !layers.testFlag(layer) )
+ return;
+
+ QJsonObject option;
+ option.insert(QStringLiteral("label"), label);
+ option.insert(QStringLiteral("key"), key);
+ options.append(option);
+ };
+
+ appendOption(MapLayer::Aurora, tr("Aurora"), QStringLiteral("auroraLayer"));
+
+ appendOption(MapLayer::Beam, tr("Beam"), QStringLiteral("antPathLayer"));
+
+ appendOption(MapLayer::Chat, tr("Chat"), QStringLiteral("chatStationsLayer"));
+
+ appendOption(MapLayer::Grid, tr("Grid"), QStringLiteral("maidenheadConfWorked"));
+
+ appendOption(MapLayer::Grayline, tr("Gray-Line"), QStringLiteral("grayline"));
+
+ appendOption(MapLayer::Ibp, tr("IBP"), QStringLiteral("IBPLayer"));
+
+ appendOption(MapLayer::Muf, tr("MUF"), QStringLiteral("mufLayer"));
+
+ appendOption(MapLayer::Wsjtx, tr("WSJTX - CQ"), QStringLiteral("wsjtxStationsLayer"));
+
+ appendOption(MapLayer::Path, tr("Path"), QStringLiteral("pathLayer"));
+
+ QString ret = QStringLiteral("configureLayerControl(%1);")
+ .arg(jsonArray(options));
+
+ qCDebug(runtime) << ret;
+
+ return ret;
+}
+
+void MapPageController::restoreLayerControlStates()
+{
+ FCT_IDENTIFICATION;
+
+ QJsonArray layerStates;
+
+ const QStringList &keys = LogParam::getMapLayerStates(configID);
+
+ for ( const QString &key : keys )
+ {
+ qCDebug(runtime) << "key:" << key << "value:" << LogParam::getMapLayerState(configID, key);
+
+ QJsonObject layerState;
+ layerState.insert(QStringLiteral("key"), key);
+ layerState.insert(QStringLiteral("visible"), LogParam::getMapLayerState(configID, key));
+ layerStates.append(layerState);
+ }
+
+ const QString js = QStringLiteral("restoreQLogLayerStates(%1);")
+ .arg(jsonArray(layerStates));
+ qCDebug(runtime) << js;
+
+ mainPage->runJavaScript(js);
+
+ connectWebChannel();
+}
+
+void MapPageController::connectWebChannel()
+{
+ FCT_IDENTIFICATION;
+
+ QFile file(":/qtwebchannel/qwebchannel.js");
+
+ if ( !file.open(QIODevice::ReadOnly) )
+ {
+ qCInfo(runtime) << "Cannot read qwebchannel.js";
+ return;
+ }
+
+ QTextStream stream(&file);
+ QString js;
+
+ js.append(stream.readAll());
+ js += " var webChannel = new QWebChannel(qt.webChannelTransport, function(channel) "
+ "{ "
+ " window.mapBridge = channel.objects.mapBridge; "
+ " if (window.connectQtMapBridge) "
+ " window.connectQtMapBridge(window.mapBridge); "
+ "});";
+ mainPage->runJavaScript(js);
+}
+
+void MapPageController::handleLayerSelectionChanged(const QVariant &data, const QVariant &state)
+{
+ FCT_IDENTIFICATION;
+
+ qCDebug(function_parameters) << data << state;
+
+ LogParam::setMapLayerState(configID, data.toString(),
+ (state.toString().toLower() == "on") ? true : false);
+}
+
+void MapPageController::chatCallsignClicked(const QVariant &data)
+{
+ FCT_IDENTIFICATION;
+
+ emit chatCallsignPressed(data.toString());
+}
+
+void MapPageController::wsjtxCallsignClicked(const QVariant &data)
+{
+ FCT_IDENTIFICATION;
+
+ emit wsjtxCallsignPressed(data.toString());
+}
+
+void MapPageController::IBPCallsignClicked(const QVariant &callsign, const QVariant &freq)
+{
+ FCT_IDENTIFICATION;
+
+ emit IBPPressed(callsign.toString(), freq.toDouble());
+}
+
+void MapPageController::finishLoading(bool ok)
+{
+ FCT_IDENTIFICATION;
+
+ if ( pageLoaded || !ok )
+ return;
+
+ pageLoaded = true;
+ postponedScripts.append(generateLayerControlJS(mapLayers));
+ mainPage->runJavaScript(postponedScripts.join(QLatin1Char('\n')));
+ postponedScripts.clear();
+
+ restoreLayerControlStates();
+ emit loaded();
+}
diff --git a/ui/MapPageController.h b/ui/MapPageController.h
new file mode 100644
index 00000000..28a848b5
--- /dev/null
+++ b/ui/MapPageController.h
@@ -0,0 +1,169 @@
+#ifndef QLOG_UI_MAPPAGECONTROLLER_H
+#define QLOG_UI_MAPPAGECONTROLLER_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "ui/MapLayer.h"
+
+class WebEnginePage;
+class QJsonArray;
+class QJsonObject;
+class QWebEngineView;
+
+struct MapCoordinate
+{
+ MapCoordinate() = default;
+ MapCoordinate(double inLatitude, double inLongitude)
+ : latitude(inLatitude),
+ longitude(inLongitude)
+ {
+ }
+
+ double latitude = 0.0;
+ double longitude = 0.0;
+};
+
+struct MapPoint
+{
+ MapPoint() = default;
+ MapPoint(const QString &inLabel,
+ double inLatitude,
+ double inLongitude,
+ const QString &inIcon = QString())
+ : label(inLabel),
+ coordinate(inLatitude, inLongitude),
+ icon(inIcon)
+ {
+ }
+
+ QString label;
+ MapCoordinate coordinate;
+ QString icon;
+};
+
+struct MapPath
+{
+ MapPath() = default;
+ MapPath(const MapCoordinate &inFrom,
+ const MapCoordinate &inTo)
+ : from(inFrom),
+ to(inTo)
+ {
+ }
+
+ MapCoordinate from;
+ MapCoordinate to;
+};
+
+struct MapHeatPoint
+{
+ MapHeatPoint() = default;
+ MapHeatPoint(double inLatitude,
+ double inLongitude,
+ double inValue)
+ : coordinate(inLatitude, inLongitude),
+ value(inValue)
+ {
+ }
+
+ MapCoordinate coordinate;
+ double value = 0.0;
+};
+
+class MapPageController : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit MapPageController(const QString &configID,
+ QObject *parent = nullptr);
+ ~MapPageController() override;
+
+ void attach(QWebEngineView *view,
+ MapLayer::Layers layers);
+
+ void setDarkTheme(bool isDark);
+ void setStaticMapTime(const QDateTime &dateTime);
+
+ void drawPoints(const QList &points);
+ void drawPointsBusy(const QList &points,
+ const QString &text);
+ void drawHomePoints(const QList &points);
+ void drawChatPoints(const QList &points);
+ void flyToPoint(const MapPoint &point, int zoom);
+
+ void drawPath(const QList &points);
+ void clearPath();
+ void drawShortPaths(const QList &paths);
+ void drawShortPathsBusy(const QList &paths,
+ const QString &text);
+ void drawAntPath(const MapCoordinate &from,
+ double distance,
+ double azimuth,
+ double antAngle);
+ void clearAntPath();
+
+ void setGridLayers(const QStringList &confirmedGrids,
+ const QStringList &workedGrids);
+ void clearGridLayers();
+ void redrawGridLayer();
+ void panToBoundsLongitudeCenter(const QList &coordinates);
+
+ void setAuroraData(const QList &points);
+ void drawMuf(const QList &points);
+ void setCurrentBand(const QString &band);
+
+ void addWsjtxSpot(const MapPoint &point,
+ const QString &color);
+ void clearWsjtxSpots();
+
+signals:
+ void loaded();
+ void chatCallsignPressed(QString callsign);
+ void wsjtxCallsignPressed(QString callsign);
+ void IBPPressed(QString callsign, double frequency);
+
+public slots:
+ void handleLayerSelectionChanged(const QVariant &data,
+ const QVariant &state);
+ void chatCallsignClicked(const QVariant &data);
+ void wsjtxCallsignClicked(const QVariant &data);
+ void IBPCallsignClicked(const QVariant &callsign,
+ const QVariant &freq);
+
+private:
+ static QString jsonArray(const QJsonArray &array);
+ static QString jsonObject(const QJsonObject &object);
+ static QString jsonString(const QString &string);
+ static QJsonObject pointObject(const MapPoint &point);
+ static QJsonObject coordinateObject(const MapCoordinate &coordinate);
+ static QJsonArray coordinateArray(const MapCoordinate &coordinate);
+ static QJsonArray pointsArray(const QList &points);
+ static QJsonArray coordinatesArray(const QList &coordinates);
+ static QJsonArray pathsArray(const QList &paths);
+ static QJsonArray stringArray(const QStringList &strings);
+ static QJsonArray heatPointsArray(const QList &points);
+
+ QString generateLayerControlJS(MapLayer::Layers layers);
+ void restoreLayerControlStates();
+ void connectWebChannel();
+ void finishLoading(bool ok);
+ void runJavaScript(const QString &js);
+
+ QString configID;
+ WebEnginePage *mainPage;
+ QPointer attachedView;
+ bool pageLoaded;
+ QStringList postponedScripts;
+ QWebChannel channel;
+ MapLayer::Layers mapLayers;
+};
+
+#endif // QLOG_UI_MAPPAGECONTROLLER_H
diff --git a/ui/MapWebChannelHandler.cpp b/ui/MapWebChannelHandler.cpp
deleted file mode 100644
index 4d0e04c2..00000000
--- a/ui/MapWebChannelHandler.cpp
+++ /dev/null
@@ -1,199 +0,0 @@
-#include
-
-#include "MapWebChannelHandler.h"
-#include "core/debug.h"
-#include "core/LogParam.h"
-
-MODULE_IDENTIFICATION("qlog.ui.maplayercontrolhandler");
-
-MapWebChannelHandler::MapWebChannelHandler(const QString &configID,
- QObject *parent)
- : QObject(parent), configID(configID)
-{
-}
-
-void MapWebChannelHandler::connectWebChannel(QWebEnginePage *page)
-{
- FCT_IDENTIFICATION;
-
- QFile file(":/qtwebchannel/qwebchannel.js");
-
- if (!file.open(QIODevice::ReadOnly))
- {
- qCInfo(runtime) << "Cannot read qwebchannel.js";
- return;
- }
-
- QTextStream stream(&file);
- QString js;
-
- js.append(stream.readAll());
- js += " var webChannel = new QWebChannel(qt.webChannelTransport, function(channel) "
- "{ window.foo = channel.objects.layerControlHandler; });"
- " map.on('overlayadd', function(e){ "
- " switch (e.name) "
- " { "
- " case '" + tr("Grid") + "': "
- " foo.handleLayerSelectionChanged('maidenheadConfWorked', 'on'); "
- " break; "
- " case '" + tr("Gray-Line") + "': "
- " foo.handleLayerSelectionChanged('grayline', 'on'); "
- " break; "
- " case '" + tr("Beam") + "': "
- " foo.handleLayerSelectionChanged('antPathLayer', 'on'); "
- " break; "
- " case '" + tr("Aurora") + "': "
- " foo.handleLayerSelectionChanged('auroraLayer', 'on'); "
- " break; "
- " case '" + tr("MUF") + "': "
- " foo.handleLayerSelectionChanged('mufLayer', 'on'); "
- " break; "
- " case '" + tr("IBP") + "': "
- " foo.handleLayerSelectionChanged('IBPLayer', 'on'); "
- " break; "
- " case '" + tr("Chat") + "': "
- " foo.handleLayerSelectionChanged('chatStationsLayer', 'on'); "
- " break; "
- " case '" + tr("WSJTX - CQ") + "': "
- " foo.handleLayerSelectionChanged('wsjtxStationsLayer', 'on'); "
- " break; "
- " case '" + tr("Path") + "': "
- " foo.handleLayerSelectionChanged('pathLayer', 'on'); "
- " break; "
- " } "
- "});"
- "map.on('overlayremove', function(e){ "
- " switch (e.name) "
- " { "
- " case '" + tr("Grid") + "': "
- " foo.handleLayerSelectionChanged('maidenheadConfWorked', 'off'); "
- " break; "
- " case '" + tr("Gray-Line") + "': "
- " foo.handleLayerSelectionChanged('grayline', 'off'); "
- " break; "
- " case '" + tr("Beam") + "': "
- " foo.handleLayerSelectionChanged('antPathLayer', 'off'); "
- " break; "
- " case '" + tr("Aurora") + "': "
- " foo.handleLayerSelectionChanged('auroraLayer', 'off'); "
- " break; "
- " case '" + tr("MUF") + "': "
- " foo.handleLayerSelectionChanged('mufLayer', 'off'); "
- " break; "
- " case '" + tr("IBP") + "': "
- " foo.handleLayerSelectionChanged('IBPLayer', 'off'); "
- " break; "
- " case '" + tr("Chat") + "': "
- " foo.handleLayerSelectionChanged('chatStationsLayer', 'off'); "
- " break; "
- " case '" + tr("WSJTX - CQ") + "': "
- " foo.handleLayerSelectionChanged('wsjtxStationsLayer', 'off'); "
- " break; "
- " case '" + tr("Path") + "': "
- " foo.handleLayerSelectionChanged('pathLayer', 'off'); "
- " break; "
- " } "
- "});";
- page->runJavaScript(js);
-}
-
-void MapWebChannelHandler::restoreLayerControlStates(QWebEnginePage *page)
-{
- FCT_IDENTIFICATION;
-
- QString js;
-
- const QStringList &keys = LogParam::getMapLayerStates(configID);
-
- for ( const QString &key : keys)
- {
- qCDebug(runtime) << "key:" << key << "value:" << LogParam::getMapLayerState(configID, key);
-
- js += ( LogParam::getMapLayerState(configID, key) ) ? QString("map.addLayer(%1);").arg(key)
- : QString("map.removeLayer(%1);").arg(key);
- }
- qCDebug(runtime) << js;
-
- page->runJavaScript(js);
-
- connectWebChannel(page);
-}
-
-QString MapWebChannelHandler::generateMapMenuJS(bool gridLayer,
- bool grayline,
- bool aurora,
- bool muf,
- bool ibp,
- bool antpath,
- bool chatStations,
- bool wsjtxStations,
- bool paths)
-{
- FCT_IDENTIFICATION;
- QStringList options;
-
- if ( aurora )
- options << "\"" + tr("Aurora") + "\": auroraLayer";
-
- if ( antpath )
- options << "\"" + tr("Beam") + "\": antPathLayer";
-
- if ( chatStations )
- options << "\"" + tr("Chat") + "\": chatStationsLayer";
-
- if ( gridLayer )
- options << "\"" + tr("Grid") + "\": maidenheadConfWorked";
-
- if ( grayline )
- options << "\"" + tr("Gray-Line") + "\": grayline";
-
- if ( ibp )
- options << "\"" + tr("IBP") + "\": IBPLayer";
-
- if ( muf )
- options << "\"" + tr("MUF") + "\": mufLayer";
-
- if ( wsjtxStations )
- options << "\"" + tr("WSJTX - CQ") + "\": wsjtxStationsLayer";
-
- if ( paths )
- options << "\"" + tr("Path") + "\": pathLayer";
-
- QString ret = QString("var layerControl = new L.Control.Layers(null,"
- "{ %1 },{}).addTo(map);").arg(options.join(","));
-
- qCDebug(runtime) << ret;
-
- return ret;
-}
-
-void MapWebChannelHandler::handleLayerSelectionChanged(const QVariant &data, const QVariant &state)
-{
- FCT_IDENTIFICATION;
-
- qCDebug(function_parameters) << data << state;
-
- LogParam::setMapLayerState(configID, data.toString(),
- (state.toString().toLower() == "on") ? true : false);
-}
-
-void MapWebChannelHandler::chatCallsignClicked(const QVariant &data)
-{
- FCT_IDENTIFICATION;
-
- emit chatCallsignPressed(data.toString());
-}
-
-void MapWebChannelHandler::wsjtxCallsignClicked(const QVariant &data)
-{
- FCT_IDENTIFICATION;
-
- emit wsjtxCallsignPressed(data.toString());
-}
-
-void MapWebChannelHandler::IBPCallsignClicked(const QVariant &callsign, const QVariant &freq)
-{
- FCT_IDENTIFICATION;
-
- emit IBPPressed(callsign.toString(), freq.toDouble());
-}
diff --git a/ui/MapWebChannelHandler.h b/ui/MapWebChannelHandler.h
deleted file mode 100644
index c29032a2..00000000
--- a/ui/MapWebChannelHandler.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef QLOG_UI_MAPWEBCHANNELHANDLER_H
-#define QLOG_UI_MAPWEBCHANNELHANDLER_H
-
-#include
-#include
-
-class MapWebChannelHandler : public QObject
-{
- Q_OBJECT
-public:
- explicit MapWebChannelHandler(const QString &configID,
- QObject *parent = nullptr);
- void restoreLayerControlStates(QWebEnginePage *page);
- QString generateMapMenuJS(bool gridLayer = true,
- bool grayline = false,
- bool aurora = false,
- bool muf = false,
- bool ibp = false,
- bool antpath = false,
- bool chatStations = false,
- bool wsjtxStations = false,
- bool paths = false);
-
-signals:
- void chatCallsignPressed(QString);
- void wsjtxCallsignPressed(QString);
- void IBPPressed(QString, double);
-
-public slots:
- void handleLayerSelectionChanged(const QVariant &data,
- const QVariant &state);
- void chatCallsignClicked(const QVariant &data);
- void wsjtxCallsignClicked(const QVariant &data);
- void IBPCallsignClicked(const QVariant &callsign,
- const QVariant &freq);
-private:
- QString configID;
-
- void connectWebChannel(QWebEnginePage *page);
-};
-
-#endif // QLOG_UI_MAPWEBCHANNELHANDLER_H
diff --git a/ui/OnlineMapWidget.cpp b/ui/OnlineMapWidget.cpp
index 827bc194..066e56b4 100644
--- a/ui/OnlineMapWidget.cpp
+++ b/ui/OnlineMapWidget.cpp
@@ -25,9 +25,7 @@ MODULE_IDENTIFICATION("qlog.ui.onlinemapwidget");
OnlineMapWidget::OnlineMapWidget(QWidget *parent):
QWebEngineView(parent),
- main_page(new WebEnginePage(this)),
- isMainPageLoaded(false),
- webChannelHandler("onlinemap",parent),
+ mapController(new MapPageController(QStringLiteral("onlinemap"), this)),
prop_cond(nullptr),
contact(nullptr),
lastSeenAzimuth(0.0),
@@ -36,24 +34,28 @@ OnlineMapWidget::OnlineMapWidget(QWidget *parent):
{
FCT_IDENTIFICATION;
- main_page->setWebChannel(&channel);
-
- setPage(main_page);
- main_page->load(QUrl(QLatin1String("qrc:/res/map/onlinemap.html")));
- connect(this, &OnlineMapWidget::loadFinished, this, &OnlineMapWidget::finishLoading);
-
+ mapController->attach(this,
+ MapLayer::Grid
+ | MapLayer::Grayline
+ | MapLayer::Aurora
+ | MapLayer::Muf
+ | MapLayer::Ibp
+ | MapLayer::Beam
+ | MapLayer::Chat
+ | MapLayer::Wsjtx);
+ connect(mapController.data(), &MapPageController::loaded,
+ this, &OnlineMapWidget::finishLoading);
setFocusPolicy(Qt::ClickFocus);
setContextMenuPolicy(Qt::NoContextMenu);
- channel.registerObject("layerControlHandler", &webChannelHandler);
double freq = LogParam::getNewContactFreq();
freq += RigProfilesManager::instance()->getCurProfile1().ritOffset;
setIBPBand(VFO1, 0.0, freq, 0.0);
- connect(&webChannelHandler, &MapWebChannelHandler::chatCallsignPressed, this, &OnlineMapWidget::chatCallsignTrigger);
- connect(&webChannelHandler, &MapWebChannelHandler::wsjtxCallsignPressed, this, &OnlineMapWidget::wsjtxCallsignTrigger);
- connect(&webChannelHandler, &MapWebChannelHandler::IBPPressed, this, &OnlineMapWidget::IBPCallsignTrigger);
+ connect(mapController.data(), &MapPageController::chatCallsignPressed, this, &OnlineMapWidget::chatCallsignTrigger);
+ connect(mapController.data(), &MapPageController::wsjtxCallsignPressed, this, &OnlineMapWidget::wsjtxCallsignTrigger);
+ connect(mapController.data(), &MapPageController::IBPPressed, this, &OnlineMapWidget::IBPCallsignTrigger);
}
void OnlineMapWidget::setTarget(double lat, double lon)
@@ -62,8 +64,6 @@ void OnlineMapWidget::setTarget(double lat, double lon)
qCDebug(function_parameters) << lat << " " << lon;
- QString targetJavaScript;
-
if ( ! qIsNaN(lat) && ! qIsNaN(lon) )
{
/* Draw a new path */
@@ -71,16 +71,19 @@ void OnlineMapWidget::setTarget(double lat, double lon)
if ( myGrid.isValid() )
{
- targetJavaScript += QString("drawPath([{lat: %1, lng: %2}, {lat: %3, lng: %4}]);").arg(myGrid.getLatitude())
- .arg(myGrid.getLongitude())
- .arg(lat)
- .arg(lon);
+ mapController->drawPath(QList()
+ << MapCoordinate(myGrid.getLatitude(), myGrid.getLongitude())
+ << MapCoordinate(lat, lon));
+ }
+ else
+ {
+ mapController->clearPath();
}
}
else
- targetJavaScript = QLatin1String("drawPath([]);");
-
- runJavaScript(targetJavaScript);
+ {
+ mapController->clearPath();
+ }
// redraw ant path because QSO distance can change
antPositionChanged(lastSeenAzimuth, lastSeenElevation);
@@ -92,24 +95,15 @@ void OnlineMapWidget::changeTheme(int theme, bool isDark)
qCDebug(function_parameters) << theme << isDark;
- QString themeJavaScript;
-
//theme == 1 dart
- themeJavaScript
- = (isDark == 1)
- ? QLatin1String(
- "map.getPanes().tilePane.style.webkitFilter=\"brightness(0.6) invert(1) "
- "contrast(3) hue-rotate(200deg) saturate(0.3) brightness(0.9)\";")
- : QLatin1String("map.getPanes().tilePane.style.webkitFilter=\"\";");
-
- runJavaScript(themeJavaScript);
+ mapController->setDarkTheme(isDark);
}
void OnlineMapWidget::auroraDataUpdate()
{
FCT_IDENTIFICATION;
- QStringList mapPoints;
+ QList mapPoints;
if ( !prop_cond ) return;
@@ -121,24 +115,20 @@ void OnlineMapWidget::auroraDataUpdate()
{
if ( point.value > 10 )
{
- mapPoints << QString("{lat: %1, lng: %2, count: %3}").arg(point.latitude)
- .arg(point.longitude)
- .arg(point.value)
- << QString("{lat: %1, lng: %2, count: %3}").arg(point.latitude)
- .arg(point.longitude - 360)
- .arg(point.value);
+ mapPoints << MapHeatPoint(point.latitude, point.longitude, point.value)
+ << MapHeatPoint(point.latitude, point.longitude - 360, point.value);
}
}
}
- runJavaScript(QString(" auroraLayer.setData({max: 100, data:[%1]});").arg(mapPoints.join(",")));
+ mapController->setAuroraData(mapPoints);
}
void OnlineMapWidget::mufDataUpdate()
{
FCT_IDENTIFICATION;
- QStringList mapPoints;
+ QList mapPoints;
if ( !prop_cond ) return;
@@ -148,16 +138,13 @@ void OnlineMapWidget::mufDataUpdate()
for ( const GenericValueMap::MapPoint &point : points )
{
- mapPoints << QString("['%1', %2, %3]").arg(QString::number(point.value,'f',0))
- .arg(point.latitude)
- .arg(point.longitude)
- << QString("['%1', %2, %3]").arg(QString::number(point.value,'f',0))
- .arg(point.latitude)
- .arg(point.longitude - 360);
+ const QString label = QString::number(point.value, 'f', 0);
+ mapPoints << MapPoint(label, point.latitude, point.longitude)
+ << MapPoint(label, point.latitude, point.longitude - 360);
}
}
- runJavaScript(QString(" drawMuf([%1]);").arg(mapPoints.join(",")));
+ mapController->drawMuf(mapPoints);
}
void OnlineMapWidget::setIBPBand(VFOID vfoid, double, double ritFreq, double)
@@ -168,7 +155,7 @@ void OnlineMapWidget::setIBPBand(VFOID vfoid, double, double ritFreq, double)
if ( vfoid == VFO2 )
return;
- runJavaScript(QString("currentBand=\"%1\";").arg(BandPlan::freq2Band(ritFreq).name));
+ mapController->setCurrentBand(BandPlan::freq2Band(ritFreq).name);
}
void OnlineMapWidget::antPositionChanged(double in_azimuth, double in_elevation)
@@ -180,7 +167,6 @@ void OnlineMapWidget::antPositionChanged(double in_azimuth, double in_elevation)
if ( ! isRotConnected )
return;
- QString targetJavaScript;
lastSeenAzimuth = in_azimuth;
lastSeenElevation = in_elevation;
@@ -200,19 +186,16 @@ void OnlineMapWidget::antPositionChanged(double in_azimuth, double in_elevation)
beamLen = newBeamLen;
}
}
- targetJavaScript += QString("drawAntPath({lat: %1, lng: %2}, %3, %4, %5);").arg(myGrid.getLatitude())
- .arg(myGrid.getLongitude())
- .arg(beamLen)
- .arg(in_azimuth)
- .arg(azimuthBeamWidth);
+ mapController->drawAntPath(MapCoordinate(myGrid.getLatitude(), myGrid.getLongitude()),
+ beamLen,
+ in_azimuth,
+ azimuthBeamWidth);
}
else
{
// clean paths
- targetJavaScript = QLatin1String("drawAntPath({}, 0, 0, 0);");
+ mapController->clearAntPath();
}
-
- runJavaScript(targetJavaScript);
}
void OnlineMapWidget::rotConnected()
@@ -230,25 +213,13 @@ void OnlineMapWidget::rotDisconnected()
isRotConnected = false;
// clear the Ant Path
- runJavaScript(QLatin1String("drawAntPath({}, 0, 0, 0);"));
+ mapController->clearAntPath();
}
-void OnlineMapWidget::finishLoading(bool)
+void OnlineMapWidget::finishLoading()
{
FCT_IDENTIFICATION;
- if ( isMainPageLoaded )
- return;
-
- isMainPageLoaded = true;
-
- /* which layers will be active */
- postponedScripts += webChannelHandler.generateMapMenuJS(true, true, true, true, true, true, true, true);
- main_page->runJavaScript(postponedScripts);
- postponedScripts = QString();
-
- webChannelHandler.restoreLayerControlStates(main_page);
-
flyToMyQTH();
auroraDataUpdate();
}
@@ -281,18 +252,6 @@ void OnlineMapWidget::IBPCallsignTrigger(const QString &callsign, double freq)
Rig::instance()->setMode("CW", QString());
}
-void OnlineMapWidget::runJavaScript(const QString &js)
-{
- FCT_IDENTIFICATION;
-
- qCDebug(function_parameters) << js;
-
- if ( !isMainPageLoaded )
- postponedScripts.append(js);
- else
- main_page->runJavaScript(js);
-}
-
void OnlineMapWidget::flyToMyQTH()
{
FCT_IDENTIFICATION;
@@ -302,9 +261,11 @@ void OnlineMapWidget::flyToMyQTH()
if ( myGrid.isValid() )
{
- QString currentProfilePosition(QString("[\"\", %1, %2, yellowIcon]").arg(myGrid.getLatitude())
- .arg(myGrid.getLongitude()));
- runJavaScript(QString("flyToPoint(%1, 4);").arg(currentProfilePosition));
+ mapController->flyToPoint(MapPoint(QString(),
+ myGrid.getLatitude(),
+ myGrid.getLongitude(),
+ QStringLiteral("yellowIcon")),
+ 4);
}
// redraw ant path because QSO distance can change
antPositionChanged(lastSeenAzimuth, lastSeenElevation);
@@ -314,20 +275,20 @@ void OnlineMapWidget::drawChatUsers(const QList &list)
{
FCT_IDENTIFICATION;
- QList chatUsers;
+ QList chatUsers;
for ( const KSTUsersInfo &user : list )
{
if ( user.grid.isValid() )
{
- chatUsers.append(QString("[\"%1\", %2, %3, %4]").arg(user.callsign)
- .arg(user.grid.getLatitude())
- .arg(user.grid.getLongitude())
- .arg("yellowIcon"));
+ chatUsers << MapPoint(user.callsign,
+ user.grid.getLatitude(),
+ user.grid.getLongitude(),
+ QStringLiteral("yellowIcon"));
}
}
- runJavaScript(QString("drawPointsGroup3([%1]);").arg(chatUsers.join(",")));
+ mapController->drawChatPoints(chatUsers);
}
void OnlineMapWidget::drawWSJTXSpot(const WsjtxEntry &spot)
@@ -338,9 +299,10 @@ void OnlineMapWidget::drawWSJTXSpot(const WsjtxEntry &spot)
if ( spotGrid.isValid() )
{
- runJavaScript(QString("addWSJTXSpot(%1, %2, \"%3\", \"%4\");").arg(spotGrid.getLatitude())
- .arg(spotGrid.getLongitude())
- .arg(spot.callsign, Data::colorToHTMLColor(Data::statusToColor(spot.status, spot.dupeCount, QColor(Qt::white)))));
+ mapController->addWsjtxSpot(MapPoint(spot.callsign,
+ spotGrid.getLatitude(),
+ spotGrid.getLongitude()),
+ Data::colorToHTMLColor(Data::statusToColor(spot.status, spot.dupeCount, QColor(Qt::white))));
}
}
@@ -348,14 +310,12 @@ void OnlineMapWidget::clearWSJTXSpots()
{
FCT_IDENTIFICATION;
- runJavaScript(QLatin1String("clearWSJTXSpots();"));
+ mapController->clearWsjtxSpots();
}
OnlineMapWidget::~OnlineMapWidget()
{
FCT_IDENTIFICATION;
-
- main_page->deleteLater();
}
void OnlineMapWidget::assignPropConditions(PropConditions *conditions)
diff --git a/ui/OnlineMapWidget.h b/ui/OnlineMapWidget.h
index b6bb1057..0e89eccd 100644
--- a/ui/OnlineMapWidget.h
+++ b/ui/OnlineMapWidget.h
@@ -3,10 +3,9 @@
#include
#include
-#include
-#include "ui/MapWebChannelHandler.h"
+#include
+#include "ui/MapPageController.h"
#include "core/PropConditions.h"
-#include "ui/WebEnginePage.h"
#include "rig/Rig.h"
#include "ui/NewContactWidget.h"
#include "service/kstchat/KSTChat.h"
@@ -46,24 +45,18 @@ public slots:
void clearWSJTXSpots();
protected slots:
- void finishLoading(bool);
+ void finishLoading();
void chatCallsignTrigger(const QString&);
void wsjtxCallsignTrigger(const QString&);
void IBPCallsignTrigger(const QString&, double);
private:
- WebEnginePage *main_page;
- bool isMainPageLoaded;
- QString postponedScripts;
- QWebChannel channel;
- MapWebChannelHandler webChannelHandler;
+ QScopedPointer mapController;
PropConditions *prop_cond;
const NewContactWidget *contact;
double lastSeenAzimuth, lastSeenElevation;
bool isRotConnected;
-
- void runJavaScript(const QString &);
};
#endif // QLOG_UI_ONLINEMAPWIDGET_H
diff --git a/ui/QSODetailDialog.cpp b/ui/QSODetailDialog.cpp
index b64f5c5f..eda24f9b 100644
--- a/ui/QSODetailDialog.cpp
+++ b/ui/QSODetailDialog.cpp
@@ -34,9 +34,7 @@ QSODetailDialog::QSODetailDialog(const QSqlRecord &qso,
mapper(new QDataWidgetMapper(this)),
model(new LogbookModelPrivate(this)),
editedRecord(new QSqlRecord(qso)),
- isMainPageLoaded(false),
- main_page(new WebEnginePage(this)),
- layerControlHandler("qsodetail", parent)
+ mapController(new MapPageController(QStringLiteral("qsodetail"), this))
{
FCT_IDENTIFICATION;
@@ -48,12 +46,12 @@ QSODetailDialog::QSODetailDialog(const QSqlRecord &qso,
connect(model, &QSqlTableModel::beforeUpdate, this, &QSODetailDialog::handleBeforeUpdate);
/* mapView setting */
- main_page->setWebChannel(&channel);
- ui->mapView->setPage(main_page);
- main_page->load(QUrl(QStringLiteral("qrc:/res/map/onlinemap.html")));
- ui->mapView->setFocusPolicy(Qt::ClickFocus);
- connect(ui->mapView, &QWebEngineView::loadFinished, this, &QSODetailDialog::mapLoaded);
- channel.registerObject("layerControlHandler", &layerControlHandler);
+ mapController->attach(ui->mapView,
+ MapLayer::Grid
+ | MapLayer::Grayline
+ | MapLayer::Path);
+ connect(mapController.data(), &MapPageController::loaded,
+ this, &QSODetailDialog::mapLoaded);
/* Edit Button */
editButton = new QPushButton(getButtonText(EDIT_BUTTON_TEXT));
@@ -1090,37 +1088,16 @@ void QSODetailDialog::doValidationDouble(double)
doValidation();
}
-void QSODetailDialog::mapLoaded(bool)
+void QSODetailDialog::mapLoaded()
{
FCT_IDENTIFICATION;
- isMainPageLoaded = true;
-
- /* which layers will be active */
- postponedScripts += layerControlHandler.generateMapMenuJS(true,
- true,
- false,
- false,
- false,
- false,
- false,
- false,
- true);
-
- main_page->runJavaScript(postponedScripts);
-
const QPalette &defaultPalette = this->palette();
const QColor &text = defaultPalette.color(QPalette::WindowText);
const QColor &window = defaultPalette.color(QPalette::Window);
bool isDark = text.lightness() > window.lightness();
- if ( isDark )
- {
- QString themeJavaScript = "map.getPanes().tilePane.style.webkitFilter=\"brightness(0.6) invert(1) contrast(3) hue-rotate(200deg) saturate(0.3) brightness(0.9)\";";
- main_page->runJavaScript(themeJavaScript);
- }
-
- layerControlHandler.restoreLayerControlStates(main_page);
+ mapController->setDarkTheme(isDark);
}
void QSODetailDialog::myGridChanged(const QString &newGrid)
@@ -1404,39 +1381,28 @@ void QSODetailDialog::drawDXOnMap(const QString &label, const Gridsquare &dxGrid
double lat = dxGrid.getLatitude();
double lon = dxGrid.getLongitude();
- // do not wrap the points
- double delta = lon - myGrid.getLongitude();
- if ( delta > 180 )
- lon -= 360;
- if ( delta < -180 )
- lon += 360;
-
- stationString.append(QString("[[\"%1\", %2, %3, yellowIcon]]").arg(popupString).arg(lat).arg(lon));
- QString shortPath = QString("[%1, %2, %3, %4]")
- .arg(myGrid.getLatitude())
- .arg(myGrid.getLongitude())
- .arg(lat)
- .arg(lon);
+ QList shortPaths;
- QString javaScript = QString("grids_confirmed = [];"
- "grids_worked = [];"
- "drawPoints(%1);"
- "drawShortPaths([%2]);"
- "maidenheadConfWorked.redraw();"
- "flyToPoint(%3[0], 6);")
- .arg(stationString, shortPath, stationString);
-
- qCDebug(runtime) << javaScript;
-
- if ( !isMainPageLoaded )
- {
- postponedScripts.append(javaScript);
- }
- else
+ if ( myGrid.isValid() )
{
- main_page->runJavaScript(javaScript);
+ // do not wrap the points
+ double delta = lon - myGrid.getLongitude();
+ if ( delta > 180 )
+ lon -= 360;
+ if ( delta < -180 )
+ lon += 360;
+
+ shortPaths << MapPath(MapCoordinate(myGrid.getLatitude(), myGrid.getLongitude()),
+ MapCoordinate(lat, lon));
}
+
+ const MapPoint dxPoint(popupString, lat, lon, QStringLiteral("yellowIcon"));
+ mapController->clearGridLayers();
+ mapController->drawPoints(QList() << dxPoint);
+ mapController->drawShortPaths(shortPaths);
+ mapController->redrawGridLayer();
+ mapController->flyToPoint(dxPoint, 6);
}
void QSODetailDialog::drawMyQTHOnMap(const QString &label, const Gridsquare &myGrid)
@@ -1450,26 +1416,12 @@ void QSODetailDialog::drawMyQTHOnMap(const QString &label, const Gridsquare &myG
return;
}
- QString stationString;
double lat = myGrid.getLatitude();
double lon = myGrid.getLongitude();
- stationString.append(QString("[[\"%1\", %2, %3, homeIcon]]").arg(label).arg(lat).arg(lon));
-
- QString javaScript = QString("grids_confirmed = [];"
- "grids_worked = [];"
- "drawPointsGroup2(%1);"
- "maidenheadConfWorked.redraw();").arg(stationString);
-
- qCDebug(runtime) << javaScript;
-
- if ( !isMainPageLoaded )
- {
- postponedScripts.append(javaScript);
- }
- else
- {
- main_page->runJavaScript(javaScript);
- }
+ const MapPoint myPoint(label, lat, lon, QStringLiteral("homeIcon"));
+ mapController->clearGridLayers();
+ mapController->drawHomePoints(QList() << myPoint);
+ mapController->redrawGridLayer();
}
void QSODetailDialog::setStaticMapTime(const QDateTime &dateTime)
@@ -1478,15 +1430,7 @@ void QSODetailDialog::setStaticMapTime(const QDateTime &dateTime)
qCDebug(function_parameters) << dateTime;
- QString javaScript = QString("setStaticMapTime(new Date(%1));").arg(dateTime.toMSecsSinceEpoch());
-
- qCDebug(runtime) << javaScript;
-
- if (!isMainPageLoaded) {
- postponedScripts.append(javaScript);
- } else {
- main_page->runJavaScript(javaScript);
- }
+ mapController->setStaticMapTime(dateTime);
}
void QSODetailDialog::enableWidgetChangeHandlers()
diff --git a/ui/QSODetailDialog.h b/ui/QSODetailDialog.h
index bf2178d0..f09131ca 100644
--- a/ui/QSODetailDialog.h
+++ b/ui/QSODetailDialog.h
@@ -7,13 +7,12 @@
#include
#include
#include
-#include
+#include
#include "models/LogbookModel.h"
#include "data/Gridsquare.h"
#include "core/CallbookManager.h"
-#include "ui/MapWebChannelHandler.h"
-#include "ui/WebEnginePage.h"
+#include "ui/MapPageController.h"
#include "core/MembershipQE.h"
#include "core/LogLocale.h"
#include "ui/component/MultiselectCompleter.h"
@@ -78,7 +77,7 @@ private slots:
bool doValidation();
void doValidationDateTime(const QDateTime&);
void doValidationDouble(double);
- void mapLoaded(bool);
+ void mapLoaded();
void myGridChanged(const QString&);
void DXGridChanged(const QString&);
void callsignFound(const CallbookResponseData &data);
@@ -141,9 +140,7 @@ private slots:
QPointer lookupButtonMovie;
qint64 timeLockDiff;
double freqLockDiff;
- bool isMainPageLoaded;
- QPointer main_page;
- QString postponedScripts;
+ QScopedPointer mapController;
CallbookManager callbookManager;
QScopedPointer iotaCompleter;
QScopedPointer myIotaCompleter;
@@ -156,8 +153,6 @@ private slots:
QScopedPointer sigCompleter;
QScopedPointer countyCompleter;
QScopedPointer modeController;
- QWebChannel channel;
- MapWebChannelHandler layerControlHandler;
LogLocale locale;
};
diff --git a/ui/StatisticsWidget.cpp b/ui/StatisticsWidget.cpp
index dabc21ca..0277abf8 100644
--- a/ui/StatisticsWidget.cpp
+++ b/ui/StatisticsWidget.cpp
@@ -386,44 +386,19 @@ void StatisticsWidget::dateRangeCheckBoxChanged(int)
refreshGraph();
}
-void StatisticsWidget::mapLoaded(bool)
-{
- FCT_IDENTIFICATION;
-
- isMainPageLoaded = true;
-
- /* which layers will be active */
- postponedScripts += layerControlHandler.generateMapMenuJS(true, false, false, false, false, false, false, false, true);
- main_page->runJavaScript(postponedScripts);
-
- layerControlHandler.restoreLayerControlStates(main_page);
-}
-
void StatisticsWidget::changeTheme(int theme, bool isDark)
{
FCT_IDENTIFICATION;
qCDebug(function_parameters) << theme << isDark;
- QString themeJavaScript;
-
- if (isDark) /* dark mode */
- themeJavaScript = "map.getPanes().tilePane.style.webkitFilter=\"brightness(0.6) invert(1) contrast(3) hue-rotate(200deg) saturate(0.3) brightness(0.9)\";";
- else
- themeJavaScript = "map.getPanes().tilePane.style.webkitFilter=\"\";";
-
- if ( !isMainPageLoaded )
- postponedScripts.append(themeJavaScript);
- else
- main_page->runJavaScript(themeJavaScript);
+ mapController->setDarkTheme(isDark);
}
StatisticsWidget::StatisticsWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::StatisticsWidget),
- main_page(new WebEnginePage(this)),
- isMainPageLoaded(false),
- layerControlHandler("statistics", parent)
+ mapController(new MapPageController(QStringLiteral("statistics"), this))
{
FCT_IDENTIFICATION;
@@ -447,18 +422,14 @@ StatisticsWidget::StatisticsWidget(QWidget *parent) :
ui->graphView->setRenderHint(QPainter::Antialiasing);
ui->graphView->setChart(new QChart());
- main_page->setWebChannel(&channel);
- ui->mapView->setPage(main_page);
- connect(ui->mapView, &QWebEngineView::loadFinished, this, &StatisticsWidget::mapLoaded);
- main_page->load(QUrl(QStringLiteral("qrc:/res/map/onlinemap.html")));
- ui->mapView->setFocusPolicy(Qt::ClickFocus);
- channel.registerObject("layerControlHandler", &layerControlHandler);
+ mapController->attach(ui->mapView,
+ MapLayer::Grid
+ | MapLayer::Path);
}
StatisticsWidget::~StatisticsWidget()
{
FCT_IDENTIFICATION;
- main_page->deleteLater();
delete ui;
}
@@ -563,8 +534,8 @@ void StatisticsWidget::drawMyLocationsOnMap(QSqlQuery &query)
if ( query.lastQuery().isEmpty() )
return;
- QStringList locationIcons;
- QStringList rawLocationsPoint;
+ QList locationIcons;
+ QList rawLocationsPoint;
while ( query.next() )
{
@@ -575,23 +546,15 @@ void StatisticsWidget::drawMyLocationsOnMap(QSqlQuery &query)
{
double lat = stationGrid.getLatitude();
double lon = stationGrid.getLongitude();
- locationIcons.append(QString("[\"%1\", %2, %3, homeIcon]").arg(stationGrid.getGrid()).arg(lat).arg(lon));
- rawLocationsPoint.append(QString("[%1, %2]").arg(lat).arg(lon));
+ locationIcons << MapPoint(stationGrid.getGrid(), lat, lon, QStringLiteral("homeIcon"));
+ rawLocationsPoint << MapCoordinate(lat, lon);
}
}
- QString javaScript = QString("grids_confirmed = [];"
- "grids_worked = [];"
- "drawPointsGroup2([%1]);"
- "maidenheadConfWorked.redraw();"
- "map.panTo([0, L.latLngBounds([%2]).getCenter().lng]);").arg(locationIcons.join(","), rawLocationsPoint.join(","));
-
- qCDebug(runtime) << javaScript;
-
- if ( !isMainPageLoaded )
- postponedScripts.append(javaScript);
- else
- main_page->runJavaScript(javaScript);
+ mapController->clearGridLayers();
+ mapController->drawHomePoints(locationIcons);
+ mapController->redrawGridLayer();
+ mapController->panToBoundsLongitudeCenter(rawLocationsPoint);
}
void StatisticsWidget::drawPointsOnMap(QSqlQuery &query)
@@ -601,8 +564,8 @@ void StatisticsWidget::drawPointsOnMap(QSqlQuery &query)
if ( query.lastQuery().isEmpty() )
return;
- QList stations;
- QList