From 851c6b773374de1d3280eefd5106627a85f0e42e Mon Sep 17 00:00:00 2001 From: Kyle Boyle Date: Wed, 13 Nov 2024 19:43:09 -0400 Subject: [PATCH] Adds time of day and better qso mapping to statistics (reporting) window --- res/map/onlinemap.html | 33 +++++++++++++++-- ui/MapWebChannelHandler.cpp | 12 +++++- ui/MapWebChannelHandler.h | 3 +- ui/StatisticsWidget.cpp | 32 ++++++++++------ ui/StatisticsWidget.ui | 74 ++++++++++++++++++++----------------- 5 files changed, 103 insertions(+), 51 deletions(-) diff --git a/res/map/onlinemap.html b/res/map/onlinemap.html index de2b3d80..0b69e5af 100644 --- a/res/map/onlinemap.html +++ b/res/map/onlinemap.html @@ -89,6 +89,14 @@ popupAnchor: [1, -34], shadowSize: [41, 41] }); + const greenIconSmall = new L.Icon({ + iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-green.png', + shadowUrl: 'https://unpkg.com/leaflet@1.7.1/dist/images/marker-shadow.png', + iconSize: [14, 23], + iconAnchor: [7, 23], + popupAnchor: [1, -18], + shadowSize: [23, 23] + }); // yellow Icon definition. It is usually used for generic QSOs or generic point const yellowIcon = new L.Icon({ @@ -100,12 +108,21 @@ shadowSize: [41, 41] }); + const yellowIconSmall = new L.Icon({ + iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-gold.png', + shadowUrl: 'https://unpkg.com/leaflet@1.7.1/dist/images/marker-shadow.png', + iconSize: [14, 23], + iconAnchor: [7, 23], + popupAnchor: [1, -18], + shadowSize: [23, 23] + }); + // home Icon definition. It is usually used for own location const homeIcon = new L.Icon({ iconUrl: 'https://img.icons8.com/officel/30/000000/radio-tower.png', - iconSize: [50, 50], - iconAnchor: [12, 41], - popupAnchor: [1, -34] + iconSize: [30, 30], + iconAnchor: [15, 25], + popupAnchor: [1, -14] }); @@ -178,7 +195,15 @@ return; geodesic.setLatLngs([points[0], points[1]]); map.fitBounds(geodesic.getBounds(), {animate:false}); - //map.panTo(geodesic.getBounds().getCenter(), {animate:false}); + } + + function drawShortPaths(coords) { + pathLayer.clearLayers(); + coords.forEach(function(coord) { + let geodesic = new L.Geodesic([],{ wrap: true, 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]}]); + }); } // function computes a destination point based on distance and azimuth diff --git a/ui/MapWebChannelHandler.cpp b/ui/MapWebChannelHandler.cpp index d7a4eb02..997ab258 100644 --- a/ui/MapWebChannelHandler.cpp +++ b/ui/MapWebChannelHandler.cpp @@ -58,6 +58,9 @@ void MapWebChannelHandler::connectWebChannel(QWebEnginePage *page) " case '" + tr("WSJTX - CQ") + "': " " foo.handleLayerSelectionChanged('wsjtxStationsLayer', 'on'); " " break; " + " case '" + tr("Paths") + "': " + " foo.handleLayerSelectionChanged('pathLayer', 'on'); " + " break; " " } " "});" "map.on('overlayremove', function(e){ " @@ -87,6 +90,9 @@ void MapWebChannelHandler::connectWebChannel(QWebEnginePage *page) " case '" + tr("WSJTX - CQ") + "': " " foo.handleLayerSelectionChanged('wsjtxStationsLayer', 'off'); " " break; " + " case '" + tr("Paths") + "': " + " foo.handleLayerSelectionChanged('pathLayer', 'off'); " + " break; " " } " "});"; page->runJavaScript(js); @@ -124,7 +130,8 @@ QString MapWebChannelHandler::generateMapMenuJS(bool gridLayer, bool ibp, bool antpath, bool chatStations, - bool wsjtxStations) + bool wsjtxStations, + bool paths) { FCT_IDENTIFICATION; QStringList options; @@ -153,6 +160,9 @@ QString MapWebChannelHandler::generateMapMenuJS(bool gridLayer, if ( wsjtxStations ) options << "\"" + tr("WSJTX - CQ") + "\": wsjtxStationsLayer"; + if ( paths ) + options << "\"" + tr("Paths") + "\": pathLayer"; + QString ret = QString("var layerControl = new L.Control.Layers(null," "{ %1 },{}).addTo(map);").arg(options.join(",")); diff --git a/ui/MapWebChannelHandler.h b/ui/MapWebChannelHandler.h index f338f97f..4c69f179 100644 --- a/ui/MapWebChannelHandler.h +++ b/ui/MapWebChannelHandler.h @@ -18,7 +18,8 @@ class MapWebChannelHandler : public QObject bool ibp = false, bool antpath = false, bool chatStations = false, - bool wsjtxStations = false); + bool wsjtxStations = false, + bool paths = false); signals: void chatCallsignPressed(QString); diff --git a/ui/StatisticsWidget.cpp b/ui/StatisticsWidget.cpp index 0d2f6bb0..05779d54 100644 --- a/ui/StatisticsWidget.cpp +++ b/ui/StatisticsWidget.cpp @@ -86,8 +86,8 @@ void StatisticsWidget::refreshGraph() genericFilter << " (band = '" + ui->bandCombo->currentText() + "') "; if ( ui->useDateRangeCheckBox->isChecked() ) - genericFilter << " (date(start_time) BETWEEN date('" + ui->startDateEdit->date().toString("yyyy-MM-dd") - + " 00:00:00') AND date('" + ui->endDateEdit->date().toString("yyyy-MM-dd") + " 23:59:59') ) "; + genericFilter << " (datetime(start_time) BETWEEN datetime('" + ui->startDateEdit->dateTime().toString("yyyy-MM-dd HH:mm:ss") + + "') AND datetime('" + ui->endDateEdit->dateTime().toString("yyyy-MM-dd HH:mm:ss") + "') ) "; qCDebug(runtime) << "main " << ui->statTypeMainCombo->currentIndex() << " secondary " << ui->statTypeSecCombo->currentIndex(); @@ -316,15 +316,15 @@ void StatisticsWidget::refreshGraph() { case 0: case 1: - stmt = "SELECT callsign, gridsquare, SUM(confirmed) FROM (SELECT callsign, gridsquare, " + stmt = "SELECT callsign, gridsquare, my_gridsquare, SUM(confirmed) FROM (SELECT callsign, gridsquare, my_gridsquare," + innerCase +" AS confirmed FROM contacts WHERE gridsquare is not NULL AND " - + genericFilter.join(" AND ") +" ) GROUP BY callsign, gridsquare"; + + genericFilter.join(" AND ") +" ) GROUP BY callsign, gridsquare, my_gridsquare"; break; case 2: QString unit; Gridsquare::distance2localeUnitDistance(0, unit); QString distCoef = QString::number(Gridsquare::localeDistanceCoef()); - QString sel = QString("SELECT callsign || '
' || CAST(ROUND(distance * %1,0) AS INT) || ' %2', gridsquare, ").arg(distCoef, unit); + QString sel = QString("SELECT callsign || '
' || CAST(ROUND(distance * %1,0) AS INT) || ' %2', gridsquare, my_gridsquare, ").arg(distCoef, unit); stmt = sel + innerCase + " AS confirmed FROM contacts WHERE " + genericFilter.join(" AND ") + " AND distance = (SELECT MAX(distance) FROM contacts WHERE " @@ -376,7 +376,7 @@ void StatisticsWidget::mapLoaded(bool) isMainPageLoaded = true; /* which layers will be active */ - postponedScripts += layerControlHandler.generateMapMenuJS(); + postponedScripts += layerControlHandler.generateMapMenuJS(true, false, false, false, false, false, false, false, true); main_page->runJavaScript(postponedScripts); layerControlHandler.restoreLayerControlStates(main_page); @@ -418,10 +418,12 @@ StatisticsWidget::StatisticsWidget(QWidget *parent) : ui->myAntennaCombo->setModel(new QStringListModel(this)); ui->bandCombo->setModel(new QStringListModel(this)); - ui->startDateEdit->setDisplayFormat(locale.formatDateShortWithYYYY()); + ui->startDateEdit->setDisplayFormat(locale.formatDateTimeShortWithYYYY()); ui->startDateEdit->setDate(QDate::currentDate().addDays(DEFAULT_STAT_RANGE)); - ui->endDateEdit->setDisplayFormat(locale.formatDateShortWithYYYY()); + ui->startDateEdit->setTime(QTime::fromMSecsSinceStartOfDay(0)); + ui->endDateEdit->setDisplayFormat(locale.formatDateTimeShortWithYYYY()); ui->endDateEdit->setDate(QDate::currentDate()); + ui->endDateEdit->setTime(QTime::fromMSecsSinceStartOfDay(86399999)); ui->graphView->setRenderHint(QPainter::Antialiasing); ui->graphView->setChart(new QChart()); @@ -575,13 +577,14 @@ void StatisticsWidget::drawPointsOnMap(QSqlQuery &query) return; QList stations; + QList shortPaths; qulonglong count = 0; while ( query.next() ) { const Gridsquare stationGrid(query.value(1).toString()); - + const Gridsquare myStationGrid(query.value(2).toString()); if ( stationGrid.isValid() ) { count++; @@ -590,7 +593,12 @@ void StatisticsWidget::drawPointsOnMap(QSqlQuery &query) stations.append(QString("[\"%1\", %2, %3, %4]").arg(query.value(0).toString()) .arg(lat) .arg(lon) - .arg((query.value(2).toInt()) > 0 ? "greenIcon" : "yellowIcon")); + .arg((query.value(3).toInt()) > 0 ? "greenIconSmall" : "yellowIconSmall")); + shortPaths.append(QString("[%1, %2, %3, %4]") + .arg(myStationGrid.getLatitude()) + .arg(myStationGrid.getLongitude()) + .arg(lat) + .arg(lon)); } } @@ -607,7 +615,8 @@ void StatisticsWidget::drawPointsOnMap(QSqlQuery &query) QString javaScript = QString("grids_confirmed = [];" "grids_worked = [];" "drawPoints([%1]);" - "maidenheadConfWorked.redraw();").arg(stations.join(",")); + "drawShortPaths([%2]);" + "maidenheadConfWorked.redraw();").arg(stations.join(",")).arg(shortPaths.join(",")); qCDebug(runtime) << javaScript; @@ -639,6 +648,7 @@ void StatisticsWidget::drawFilledGridsOnMap(QSqlQuery &query) "grids_worked = [ %2 ];" "mylocations = [];" "drawPoints([]);" + "drawShortPaths([]);" "maidenheadConfWorked.redraw();").arg(confirmedGrids.join(","), workedGrids.join(",")); qCDebug(runtime) << javaScript; diff --git a/ui/StatisticsWidget.ui b/ui/StatisticsWidget.ui index 2a4d4aea..b5095255 100644 --- a/ui/StatisticsWidget.ui +++ b/ui/StatisticsWidget.ui @@ -35,7 +35,7 @@ Options - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter false @@ -68,7 +68,7 @@ - Qt::ClickFocus + Qt::FocusPolicy::ClickFocus @@ -84,7 +84,7 @@ My Antenna - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter @@ -94,14 +94,14 @@ My Gridsquare - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter - Qt::ClickFocus + Qt::FocusPolicy::ClickFocus @@ -114,13 +114,13 @@ - Qt::ClickFocus + Qt::FocusPolicy::ClickFocus - Qt::RightToLeft + Qt::LayoutDirection::RightToLeft - QComboBox::NoInsert + QComboBox::InsertPolicy::NoInsert @@ -158,14 +158,14 @@ - Qt::ClickFocus + Qt::FocusPolicy::ClickFocus - Qt::ClickFocus + Qt::FocusPolicy::ClickFocus @@ -177,7 +177,7 @@ Graph Type - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter @@ -188,7 +188,7 @@ - Qt::ClickFocus + Qt::FocusPolicy::ClickFocus @@ -199,7 +199,7 @@ - + false @@ -210,10 +210,10 @@ - Qt::ClickFocus + Qt::FocusPolicy::ClickFocus - QAbstractSpinBox::UpDownArrows + QAbstractSpinBox::ButtonSymbols::UpDownArrows @@ -224,17 +224,20 @@ false + + yyyy-MM-dd HH:mm + true - Qt::UTC + Qt::TimeSpec::UTC 1999 12 - 31 + 28 @@ -253,7 +256,7 @@ - + false @@ -264,7 +267,7 @@ - Qt::ClickFocus + Qt::FocusPolicy::ClickFocus false @@ -278,11 +281,14 @@ false + + yyyy-MM-dd HH:mm + true - Qt::UTC + Qt::TimeSpec::UTC @@ -300,7 +306,7 @@ My Rig - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter @@ -310,7 +316,7 @@ My Callsign - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter @@ -320,7 +326,7 @@ Band - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter @@ -333,7 +339,7 @@ - Qt::ClickFocus + Qt::FocusPolicy::ClickFocus @@ -343,14 +349,14 @@ Date Range - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter - Qt::ClickFocus + Qt::FocusPolicy::ClickFocus @@ -365,7 +371,7 @@ Confirmed by: - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter @@ -375,7 +381,7 @@ false - Qt::ClickFocus + Qt::FocusPolicy::ClickFocus LoTW @@ -388,7 +394,7 @@ false - Qt::ClickFocus + Qt::FocusPolicy::ClickFocus eQSL @@ -401,7 +407,7 @@ false - Qt::ClickFocus + Qt::FocusPolicy::ClickFocus Paper @@ -458,11 +464,11 @@ 2 - + - Qt::NoContextMenu + Qt::ContextMenuPolicy::NoContextMenu - + about:blank @@ -603,7 +609,7 @@ startDateEdit - userDateChanged(QDate) + dateTimeChanged(QDateTime) StatisticsWidget refreshGraph()