1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-22 08:04:49 -05:00

ADS-B: Allow plugin to be compiled as static lib. Allow building without texttospeech, location or process.

VOR localizer: Allow plugin to be compiled as static lib.
SID feature: Allow plugin to be compiled as static lib.
Satellite Tracker: Allow building without texttospeech or timezone.
Map: Allow plugin to be compiled as static lib. Allow building without SSL.
APT: Allow plugin to be compiled as static lib.
Radio Astronomy: Allow plugin to be compiled as static lib. Allow building without process.
ChannelWebAPIUtils: Fix memory leaks.
DeviceSampleSource: Add signals that indicate when the position or direction of a device (or it's antenna) has changed. This is to support per device position, which is useful for remote devices not at My Position.
This commit is contained in:
srcejon 2024-09-17 09:47:45 +01:00 committed by f4exb
parent 1f8cf3261d
commit 246735918b
38 changed files with 1015 additions and 157 deletions

View File

@ -728,8 +728,27 @@ if (BUILD_GUI)
endif()
endif()
# List of static plugins to link with - This is appended to by each pluging CMakeLists.txt
set_property(GLOBAL PROPERTY STATIC_PLUGINS_PROPERTY "")
if(Qt${QT_DEFAULT_MAJOR_VERSION}Positioning_FOUND)
add_compile_definitions(QT_POSITIONING_FOUND)
endif()
if(Qt${QT_DEFAULT_MAJOR_VERSION}Location_FOUND)
add_compile_definitions(QT_LOCATION_FOUND)
endif()
if(Qt${QT_DEFAULT_MAJOR_VERSION}Charts_FOUND)
add_compile_definitions(QT_CHARTS_FOUND)
endif()
if(Qt${QT_DEFAULT_MAJOR_VERSION}TextToSpeech_FOUND)
add_compile_definitions(QT_TEXTTOSPEECH_FOUND)
endif()
if(BUILD_SHARED_LIBS)
add_compile_definitions(BUILD_SHARED_LIBS)
endif()
# other requirements
if(NOT ANDROID)
if(NOT ANDROID AND NOT EMSCRIPTEN)
find_package(PkgConfig REQUIRED)
endif()

View File

@ -43,10 +43,10 @@ if(NOT SERVER_MODE)
adsbdemodnotificationdialog.cpp
adsbdemodnotificationdialog.ui
adsbosmtemplateserver.cpp
adsbdemodmap.qrc
adsbdemodicons.qrc
airlinelogos.qrc
flags.qrc
map.qrc
icons.qrc
)
set(adsb_HEADERS
${adsb_HEADERS}
@ -60,7 +60,13 @@ if(NOT SERVER_MODE)
)
set(TARGET_NAME ${PLUGINS_PREFIX}demodadsb)
set(TARGET_LIB Qt::Widgets Qt::Quick Qt::QuickWidgets Qt::Positioning Qt::Location Qt::TextToSpeech)
set(TARGET_LIB Qt::Widgets Qt::Quick Qt::QuickWidgets Qt::Positioning)
if(Qt${QT_DEFAULT_MAJOR_VERSION}Location_FOUND)
list(APPEND TARGET_LIB Qt::Location)
endif()
if(Qt${QT_DEFAULT_MAJOR_VERSION}TextToSpeech_FOUND)
list(APPEND TARGET_LIB Qt::TextToSpeech)
endif()
set(TARGET_LIB_GUI "sdrgui")
set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR})
else()
@ -70,15 +76,21 @@ else()
set(INSTALL_FOLDER ${INSTALL_PLUGINSSRV_DIR})
endif()
add_library(${TARGET_NAME} SHARED
${adsb_SOURCES}
)
if(NOT Qt6_FOUND)
add_library(${TARGET_NAME} ${adsb_SOURCES})
else()
qt_add_plugin(${TARGET_NAME} CLASS_NAME ADSBPlugin ${adsb_SOURCES})
endif()
if(NOT BUILD_SHARED_LIBS)
set_property(GLOBAL APPEND PROPERTY STATIC_PLUGINS_PROPERTY ${TARGET_NAME})
endif()
if (NOT WIN32)
link_directories(${Boost_LIBRARY_DIRS})
endif()
target_link_libraries(${TARGET_NAME}
target_link_libraries(${TARGET_NAME} PRIVATE
Boost::disable_autolinking
Qt::Core
${TARGET_LIB}

View File

@ -157,7 +157,9 @@ void ADSBDemod::stop()
m_basebandSink->stopWork();
m_worker->stopWork();
m_thread->exit();
#ifndef __EMSCRIPTEN__
m_thread->wait();
#endif
}
bool ADSBDemod::handleMessage(const Message& cmd)

View File

@ -16,7 +16,9 @@
///////////////////////////////////////////////////////////////////////////////////
#include <QFontDialog>
#ifdef QT_LOCATION_FOUND
#include <QGeoServiceProvider>
#endif
#include <QDebug>
#include "adsbdemoddisplaydialog.h"
@ -30,6 +32,7 @@ ADSBDemodDisplayDialog::ADSBDemodDisplayDialog(ADSBDemodSettings *settings, QWid
{
ui->setupUi(this);
#ifdef QT_LOCATION_FOUND
QStringList mapProviders = QGeoServiceProvider::availableServiceProviders();
if (!mapProviders.contains("osm")) {
ui->mapProvider->removeItem(ui->mapProvider->findText("osm"));
@ -37,6 +40,9 @@ ADSBDemodDisplayDialog::ADSBDemodDisplayDialog(ADSBDemodSettings *settings, QWid
if (!mapProviders.contains("mapboxgl")) {
ui->mapProvider->removeItem(ui->mapProvider->findText("mapboxgl"));
}
#else
QStringList mapProviders;
#endif
ui->timeout->setValue(settings->m_removeTimeout);
ui->aircraftMinZoom->setValue(settings->m_aircraftMinZoom);

View File

@ -1,6 +1,6 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// Copyright (C) 2020-2024 Jon Beniston, M7RCE //
// //
// 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 //
@ -34,10 +34,13 @@
#include <QQmlProperty>
#include <QJsonDocument>
#include <QJsonObject>
#ifdef QT_LOCATION_FOUND
#include <QGeoServiceProvider>
#endif
#include "ui_adsbdemodgui.h"
#include "device/deviceapi.h"
#include "dsp/devicesamplesource.h"
#include "channel/channelwebapiutils.h"
#include "feature/featurewebapiutils.h"
#include "plugin/pluginapi.h"
@ -3323,6 +3326,7 @@ void ADSBDemodGUI::checkDynamicNotification(Aircraft *aircraft)
// has speech notifications configured
void ADSBDemodGUI::enableSpeechIfNeeded()
{
#ifdef QT_TEXTTOSPEECH_FOUND
if (m_speech) {
return;
}
@ -3335,19 +3339,25 @@ void ADSBDemodGUI::enableSpeechIfNeeded()
return;
}
}
#endif
}
void ADSBDemodGUI::speechNotification(Aircraft *aircraft, const QString &speech)
{
#ifdef QT_TEXTTOSPEECH_FOUND
if (m_speech) {
m_speech->say(subAircraftString(aircraft, speech));
} else {
qDebug() << "ADSBDemodGUI::speechNotification: Unable to say " << speech;
qWarning() << "ADSBDemodGUI::speechNotification: Unable to say " << speech;
}
#else
qWarning() << "ADSBDemodGUI::speechNotification: TextToSpeech not supported. Unable to say " << speech;
#endif
}
void ADSBDemodGUI::commandNotification(Aircraft *aircraft, const QString &command)
{
#if QT_CONFIG(process)
QString commandLine = subAircraftString(aircraft, command);
QStringList allArgs = QProcess::splitCommand(commandLine);
@ -3357,6 +3367,9 @@ void ADSBDemodGUI::commandNotification(Aircraft *aircraft, const QString &comman
allArgs.pop_front();
QProcess::startDetached(program, allArgs);
}
#else
qWarning() << "ADSBDemodGUI::commandNotification: QProcess not supported. Can't run: " << command;
#endif
}
QString ADSBDemodGUI::subAircraftString(Aircraft *aircraft, const QString &string)
@ -3606,6 +3619,7 @@ void ADSBDemodGUI::on_findOnMapFeature_clicked()
// Find aircraft on channel map
void ADSBDemodGUI::findOnChannelMap(Aircraft *aircraft)
{
#ifdef QT_LOCATION_FOUND
if (aircraft->m_positionValid)
{
QQuickItem *item = ui->map->rootObject();
@ -3618,6 +3632,7 @@ void ADSBDemodGUI::findOnChannelMap(Aircraft *aircraft)
object->setProperty("center", QVariant::fromValue(geocoord));
}
}
#endif
}
void ADSBDemodGUI::adsbData_customContextMenuRequested(QPoint pos)
@ -4682,6 +4697,7 @@ void ADSBDemodGUI::on_displaySettings_clicked()
{
bool oldSiUnits = m_settings.m_siUnits;
ADSBDemodDisplayDialog dialog(&m_settings);
new DialogPositioner(&dialog, true);
if (dialog.exec() == QDialog::Accepted)
{
bool unitsChanged = m_settings.m_siUnits != oldSiUnits;
@ -4695,6 +4711,7 @@ void ADSBDemodGUI::on_displaySettings_clicked()
void ADSBDemodGUI::applyMapSettings()
{
#ifdef QT_LOCATION_FOUND
Real stationLatitude = MainCore::instance()->getSettings().getLatitude();
Real stationLongitude = MainCore::instance()->getSettings().getLongitude();
Real stationAltitude = MainCore::instance()->getSettings().getAltitude();
@ -4743,8 +4760,13 @@ void ADSBDemodGUI::applyMapSettings()
if (mapProvider == "osm")
{
#ifdef __EMSCRIPTEN__
// Default is http://maps-redirect.qt.io/osm/5.8/ and Emscripten needs https
parameters["osm.mapping.providersrepository.address"] = QString("https://sdrangel.beniston.com/sdrangel/maps/");
#else
// Use our repo, so we can append API key and redefine transmit maps
parameters["osm.mapping.providersrepository.address"] = QString("http://127.0.0.1:%1/").arg(m_osmPort);
#endif
// Use ADS-B specific cache, as we use different transmit maps
QString cachePath = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + "/QtLocation/5.8/tiles/osm/sdrangel_adsb";
parameters["osm.mapping.cache.directory"] = cachePath;
@ -4831,6 +4853,7 @@ void ADSBDemodGUI::applyMapSettings()
{
qDebug() << "ADSBDemodGUI::applyMapSettings - createMap returned a nullptr";
}
#endif // QT_LOCATION_FOUND
}
// Called from QML when empty space clicked
@ -4875,12 +4898,15 @@ ADSBDemodGUI::ADSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb
{
QSurfaceFormat format;
format.setSamples(multisamples);
#ifdef QT_LOCATION_FOUND
ui->map->setFormat(format);
#endif
}
m_osmPort = 0; // Pick a free port
m_templateServer = new ADSBOSMTemplateServer("q2RVNAe3eFKCH4XsrE3r", m_osmPort);
#ifdef QT_LOCATION_FOUND
ui->map->setAttribute(Qt::WA_AcceptTouchEvents, true);
ui->map->rootContext()->setContextProperty("aircraftModel", &m_aircraftModel);
@ -4889,9 +4915,17 @@ ADSBDemodGUI::ADSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb
ui->map->rootContext()->setContextProperty("navAidModel", &m_navAidModel);
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
ui->map->setSource(QUrl(QStringLiteral("qrc:/map/map.qml")));
#elif defined(__EMSCRIPTEN__)
// No Qt5Compat.GraphicalEffects
ui->map->setSource(QUrl(QStringLiteral("qrc:/map/map_6_strict.qml")));
#else
ui->map->setSource(QUrl(QStringLiteral("qrc:/map/map_6.qml")));
ui->map->setSource(QUrl(QStringLiteral("qrc:/map/map_6_strict.qml")));
#endif
ui->map->installEventFilter(this);
#else
ui->map->hide();
#endif
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &)));
m_adsbDemod = reinterpret_cast<ADSBDemod*>(rxChannel); //new ADSBDemod(m_deviceUISet->m_deviceSourceAPI);
@ -4991,12 +5025,15 @@ ADSBDemodGUI::ADSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb
m_azEl.setLocation(stationLatitude, stationLongitude, stationAltitude);
// These are the default values in sdrbase/settings/preferences.cpp
if ((stationLatitude == (float)49.012423) && (stationLongitude == (float)8.418125)) {
if ((stationLatitude == 49.012423f) && (stationLongitude == 8.418125f)) {
ui->warning->setText("Please set your antenna location under Preferences > My Position");
}
// Get updated when position changes
connect(&MainCore::instance()->getSettings(), &MainSettings::preferenceChanged, this, &ADSBDemodGUI::preferenceChanged);
if (m_deviceUISet->m_deviceAPI->getSampleSource()) {
connect(m_deviceUISet->m_deviceAPI->getSampleSource(), &DeviceSampleSource::positionChanged, this, &ADSBDemodGUI::devicePositionChanged);
}
// Get airport weather when requested
connect(&m_airportModel, &AirportModel::requestMetar, this, &ADSBDemodGUI::requestMetar);
@ -5034,7 +5071,6 @@ ADSBDemodGUI::ADSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb
connect(&m_redrawMapTimer, &QTimer::timeout, this, &ADSBDemodGUI::redrawMap);
m_redrawMapTimer.setSingleShot(true);
ui->map->installEventFilter(this);
DialPopup::addPopupsToChildDials(this);
m_resizer.enableChildMouseTracking();
}
@ -5194,12 +5230,19 @@ void ADSBDemodGUI::displaySettings()
initFlightInformation();
initAviationWeather();
applyMapSettings();
applyImportSettings();
getRollupContents()->restoreState(m_rollupState);
blockApplySettings(false);
enableSpeechIfNeeded();
#ifdef __EMSCRIPTEN__
// FIXME: If we don't have this delay, tile server requests get deleted
QTimer::singleShot(250, [this] {
applyMapSettings();
});
#else
applyMapSettings();
#endif
}
void ADSBDemodGUI::leaveEvent(QEvent* event)
@ -5752,6 +5795,7 @@ int ADSBDemodGUI::grayToBinary(int gray, int bits) const
void ADSBDemodGUI::redrawMap()
{
#ifdef QT_LOCATION_FOUND
// An awful workaround for https://bugreports.qt.io/browse/QTBUG-100333
// Also used in Map feature
QQuickItem *item = ui->map->rootObject();
@ -5765,6 +5809,7 @@ void ADSBDemodGUI::redrawMap()
object->setProperty("zoomLevel", QVariant::fromValue(zoom));
}
}
#endif
}
void ADSBDemodGUI::showEvent(QShowEvent *event)
@ -5976,54 +6021,70 @@ void ADSBDemodGUI::handleImportReply(QNetworkReply* reply)
}
}
void ADSBDemodGUI::updatePosition(float latitude, float longitude, float altitude)
{
// Use device postion in preference to My Position
ChannelWebAPIUtils::getDevicePosition(getDeviceSetIndex(), latitude, longitude, altitude);
QGeoCoordinate stationPosition(latitude, longitude, altitude);
QGeoCoordinate previousPosition(m_azEl.getLocationSpherical().m_latitude, m_azEl.getLocationSpherical().m_longitude, m_azEl.getLocationSpherical().m_altitude);
if (stationPosition != previousPosition)
{
m_azEl.setLocation(latitude, longitude, altitude);
// Update distances and what is visible, but only do it if position has changed significantly
if (!m_lastFullUpdatePosition.isValid() || (stationPosition.distanceTo(m_lastFullUpdatePosition) >= 1000))
{
updateAirports();
updateAirspaces();
updateNavAids();
m_lastFullUpdatePosition = stationPosition;
}
#ifdef QT_LOCATION_FOUND
// Update icon position on Map
QQuickItem *item = ui->map->rootObject();
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
QObject *map = item->findChild<QObject*>("map");
#else
QObject *map = item->findChild<QObject*>("mapView");
#endif
if (map != nullptr)
{
QObject *stationObject = map->findChild<QObject*>("station");
if(stationObject != NULL)
{
QGeoCoordinate coords = stationObject->property("coordinate").value<QGeoCoordinate>();
coords.setLatitude(latitude);
coords.setLongitude(longitude);
coords.setAltitude(altitude);
stationObject->setProperty("coordinate", QVariant::fromValue(coords));
}
}
#endif
}
}
void ADSBDemodGUI::devicePositionChanged(float latitude, float longitude, float altitude)
{
updatePosition(latitude, longitude, altitude);
}
void ADSBDemodGUI::preferenceChanged(int elementType)
{
Preferences::ElementType pref = (Preferences::ElementType)elementType;
if ((pref == Preferences::Latitude) || (pref == Preferences::Longitude) || (pref == Preferences::Altitude))
{
Real stationLatitude = MainCore::instance()->getSettings().getLatitude();
Real stationLongitude = MainCore::instance()->getSettings().getLongitude();
Real stationAltitude = MainCore::instance()->getSettings().getAltitude();
Real myLatitude = MainCore::instance()->getSettings().getLatitude();
Real myLongitude = MainCore::instance()->getSettings().getLongitude();
Real myAltitude = MainCore::instance()->getSettings().getAltitude();
QGeoCoordinate stationPosition(stationLatitude, stationLongitude, stationAltitude);
QGeoCoordinate previousPosition(m_azEl.getLocationSpherical().m_latitude, m_azEl.getLocationSpherical().m_longitude, m_azEl.getLocationSpherical().m_altitude);
if (stationPosition != previousPosition)
{
m_azEl.setLocation(stationLatitude, stationLongitude, stationAltitude);
// Update distances and what is visible, but only do it if position has changed significantly
if (!m_lastFullUpdatePosition.isValid() || (stationPosition.distanceTo(m_lastFullUpdatePosition) >= 1000))
{
updateAirports();
updateAirspaces();
updateNavAids();
m_lastFullUpdatePosition = stationPosition;
}
// Update icon position on Map
QQuickItem *item = ui->map->rootObject();
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
QObject *map = item->findChild<QObject*>("map");
#else
QObject *map = item->findChild<QObject*>("mapView");
#endif
if (map != nullptr)
{
QObject *stationObject = map->findChild<QObject*>("station");
if(stationObject != NULL)
{
QGeoCoordinate coords = stationObject->property("coordinate").value<QGeoCoordinate>();
coords.setLatitude(stationLatitude);
coords.setLongitude(stationLongitude);
coords.setAltitude(stationAltitude);
stationObject->setProperty("coordinate", QVariant::fromValue(coords));
}
}
}
updatePosition(myLatitude, myLongitude, myAltitude);
}
else if (pref == Preferences::StationName)
{
#ifdef QT_LOCATION_FOUND
// Update icon label on Map
QQuickItem *item = ui->map->rootObject();
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
@ -6038,11 +6099,14 @@ void ADSBDemodGUI::preferenceChanged(int elementType)
stationObject->setProperty("stationName", QVariant::fromValue(MainCore::instance()->getSettings().getStationName()));
}
}
#endif
}
else if (pref == Preferences::MapSmoothing)
{
#ifdef QT_LOCATION_FOUND
QQuickItem *item = ui->map->rootObject();
QQmlProperty::write(item, "smoothing", MainCore::instance()->getSettings().getMapSmoothing());
#endif
}
}

View File

@ -941,7 +941,9 @@ private:
ADSBDemodSettings::AirportType m_currentAirportMinimumSize;
bool m_currentDisplayHeliports;
#ifdef QT_TEXTTOSPEECH_FOUND
QTextToSpeech *m_speech;
#endif
QMenu *menu; // Column select context menu
FlightInformation *m_flightInformation;
PlaneSpotters m_planeSpotters;
@ -1039,6 +1041,7 @@ private:
void redrawMap();
void applyImportSettings();
void sendAircraftReport();
void updatePosition(float latitude, float longitude, float altitude);
void leaveEvent(QEvent*);
void enterEvent(EnterEventType*);
@ -1092,6 +1095,7 @@ private slots:
void import();
void handleImportReply(QNetworkReply* reply);
void preferenceChanged(int elementType);
void devicePositionChanged(float latitude, float longitude, float altitude);
void requestMetar(const QString& icao);
void weatherUpdated(const AviationWeather::METAR &metar);

View File

@ -0,0 +1,31 @@
<RCC>
<qresource prefix="/">
<file>map/map.qml</file>
<file>map/map_6.qml</file>
<file>map/map_6_strict.qml</file>
<file>map/ModifiedMapView.qml</file>
<file>map/MapStation.qml</file>
<file>map/aircraft_2engine.png</file>
<file>map/aircraft_2enginesmall.png</file>
<file>map/aircraft_4engine.png</file>
<file>map/aircraft_helicopter.png</file>
<file>map/aircraft_light.png</file>
<file>map/aircraft_space.png</file>
<file>map/aircraft_drone.png</file>
<file>map/aircraft_fighter.png</file>
<file>map/airport_large.png</file>
<file>map/airport_medium.png</file>
<file>map/airport_small.png</file>
<file>map/heliport.png</file>
<file>map/antenna.png</file>
<file>map/truck.png</file>
<file>map/VOR.png</file>
<file>map/VOR-DME.png</file>
<file>map/VORTAC.png</file>
<file>map/DVOR.png</file>
<file>map/DVOR-DME.png</file>
<file>map/DVORTAC.png</file>
<file>map/NDB.png</file>
<file>map/DME.png</file>
</qresource>
</RCC>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -1,30 +0,0 @@
<RCC>
<qresource prefix="/">
<file>map/map.qml</file>
<file>map/map_6.qml</file>
<file>map/ModifiedMapView.qml</file>
<file>map/MapStation.qml</file>
<file>map/aircraft_2engine.png</file>
<file>map/aircraft_2enginesmall.png</file>
<file>map/aircraft_4engine.png</file>
<file>map/aircraft_helicopter.png</file>
<file>map/aircraft_light.png</file>
<file>map/aircraft_space.png</file>
<file>map/aircraft_drone.png</file>
<file>map/aircraft_fighter.png</file>
<file>map/airport_large.png</file>
<file>map/airport_medium.png</file>
<file>map/airport_small.png</file>
<file>map/heliport.png</file>
<file>map/antenna.png</file>
<file>map/truck.png</file>
<file>map/VOR.png</file>
<file>map/VOR-DME.png</file>
<file>map/VORTAC.png</file>
<file>map/DVOR.png</file>
<file>map/DVOR-DME.png</file>
<file>map/DVORTAC.png</file>
<file>map/NDB.png</file>
<file>map/DME.png</file>
</qresource>
</RCC>

View File

@ -0,0 +1,539 @@
import QtQuick 2.14
import QtQuick.Window 2.14
import QtQuick.Controls 2.14
import QtPositioning 6.5
import QtLocation 6.5
import QtQuick.Effects
Item {
id: qmlMap
property int aircraftZoomLevel: 11
property int aircraftMinZoomLevel: 11
property int airportZoomLevel: 11
property string mapProvider: "osm"
property variant mapPtr
property string requestedMapType
property bool lightIcons
property variant guiPtr
property bool smoothing
function createMap(pluginParameters, requestedMap, gui) {
requestedMapType = requestedMap
guiPtr = gui
var paramString = ""
for (var prop in pluginParameters) {
var parameter = 'PluginParameter { name: "' + prop + '"; value: "' + pluginParameters[prop] + '"}'
paramString = paramString + parameter
}
var pluginString = 'import QtLocation 6.5; Plugin{ name:"' + mapProvider + '"; ' + paramString + '}'
var plugin = Qt.createQmlObject (pluginString, qmlMap)
if (mapPtr) {
// Objects aren't destroyed immediately, so don't call findChild("map")
mapPtr.destroy()
mapPtr = null
}
mapPtr = actualMapComponent.createObject(page)
mapPtr.map.plugin = plugin
mapPtr.map.forceActiveFocus()
return mapPtr
}
Item {
id: page
anchors.fill: parent
}
Component {
id: actualMapComponent
ModifiedMapView {
id: mapView
objectName: "mapView"
anchors.fill: parent
map.center: QtPositioning.coordinate(51.5, 0.125) // London
map.zoomLevel: 10
map.objectName: "map"
// not in 6
//gesture.enabled: true
//gesture.acceptedGestures: MapGestureArea.PinchGesture | MapGestureArea.PanGesture
MouseArea {
anchors.fill: parent
propagateComposedEvents: true
onClicked: {
// Unhighlight current aircraft
guiPtr.clearHighlighted()
mouse.accepted = false
}
}
MapStation {
id: station
objectName: "station"
stationName: "Home"
parent: mapView.map
}
MapItemView {
model: airspaceModel
delegate: airspaceComponent
parent: mapView.map
}
MapItemView {
model: navAidModel
delegate: navAidComponent
parent: mapView.map
}
MapItemView {
model: airspaceModel
delegate: airspaceNameComponent
parent: mapView.map
}
MapItemView {
model: airportModel
delegate: airportComponent
parent: mapView.map
}
// This needs to be before aircraftComponent MapItemView, so it's drawn underneath
MapItemView {
model: aircraftModel
delegate: aircraftPathComponent
parent: mapView.map
}
MapItemView {
model: aircraftModel
delegate: aircraftComponent
parent: mapView.map
}
map.onZoomLevelChanged: {
if (map.zoomLevel > aircraftMinZoomLevel) {
aircraftZoomLevel = map.zoomLevel
} else {
aircraftZoomLevel = aircraftMinZoomLevel
}
if (map.zoomLevel > 11) {
station.zoomLevel = map.zoomLevel
airportZoomLevel = map.zoomLevel
} else {
station.zoomLevel = 11
airportZoomLevel = 11
}
}
map.onSupportedMapTypesChanged : {
for (var i = 0; i < map.supportedMapTypes.length; i++) {
if (requestedMapType == map.supportedMapTypes[i].name) {
map.activeMapType = map.supportedMapTypes[i]
}
}
lightIcons = (requestedMapType == "Night Transit Map") || (requestedMapType == "mapbox://styles/mapbox/dark-v9")
}
}
}
Component {
id: navAidComponent
MapQuickItem {
id: navAid
anchorPoint.x: image.width/2
anchorPoint.y: image.height/2
coordinate: position
zoomLevel: airportZoomLevel
sourceItem: Grid {
columns: 1
Grid {
horizontalItemAlignment: Grid.AlignHCenter
columnSpacing: 5
layer.enabled: smoothing
layer.smooth: smoothing
Image {
id: image
source: navAidImage
visible: !lightIcons
MouseArea {
anchors.fill: parent
onClicked: (mouse) => {
selected = !selected
}
}
}
MultiEffect {
width: image.width
height: image.height
source: image
brightness: 1.0
colorization: 1.0
colorizationColor: "#c0ffffff"
visible: lightIcons
}
Rectangle {
id: bubble
color: bubbleColour
border.width: 1
width: text.width + 5
height: text.height + 5
radius: 5
Text {
id: text
anchors.centerIn: parent
text: navAidData
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onClicked: (mouse) => {
selected = !selected
}
}
}
}
}
}
}
Component {
id: airspaceComponent
MapPolygon {
border.width: 1
border.color: airspaceBorderColor
color: airspaceFillColor
path: airspacePolygon
}
}
Component {
id: airspaceNameComponent
MapQuickItem {
coordinate: position
anchorPoint.x: airspaceText.width/2
anchorPoint.y: airspaceText.height/2
zoomLevel: airportZoomLevel
sourceItem: Grid {
columns: 1
Grid {
layer.enabled: smoothing
layer.smooth: smoothing
horizontalItemAlignment: Grid.AlignHCenter
Text {
id: airspaceText
text: details
}
}
}
}
}
Component {
id: aircraftPathComponent
MapPolyline {
line.width: 2
line.color: 'gray'
path: aircraftPath
}
}
Component {
id: aircraftComponent
MapQuickItem {
id: aircraft
anchorPoint.x: image.width/2
anchorPoint.y: image.height/2
coordinate: position
zoomLevel: aircraftZoomLevel
sourceItem: Grid {
columns: 1
Grid {
layer.enabled: smoothing
layer.smooth: smoothing
horizontalItemAlignment: Grid.AlignHCenter
Image {
id: image
rotation: heading
source: aircraftImage
visible: !lightIcons
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: {
if (mouse.button === Qt.LeftButton) {
highlighted = true
console.log("z=" + aircraft.sourceItem.z)
aircraft.sourceItem.z = aircraft.sourceItem.z + 1
} else if (mouse.button === Qt.RightButton) {
contextMenu.popup()
}
}
onDoubleClicked: {
target = true
}
}
}
MultiEffect {
width: image.width
height: image.height
rotation: heading
source: image
brightness: 1.0
colorization: 1.0
colorizationColor: "#c0ffffff"
visible: lightIcons
MouseArea {
anchors.fill: parent
onClicked: {
highlighted = true
}
onDoubleClicked: {
target = true
}
}
}
Rectangle {
id: bubble
color: bubbleColour
border.width: 1
width: text.width * 1.1
height: text.height * 1.1
radius: 5
Text {
id: text
anchors.centerIn: parent
text: adsbData
textFormat: TextEdit.RichText
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: {
if (mouse.button === Qt.LeftButton) {
showAll = !showAll
} else if (mouse.button === Qt.RightButton) {
contextMenu.popup()
}
}
Menu {
id: contextMenu
MenuItem {
text: "Set as target"
onTriggered: target = true
}
MenuItem {
text: "Find on feature map"
onTriggered: aircraftModel.findOnMap(index)
}
}
}
}
}
}
}
}
Component {
id: airportComponent
MapItemGroup {
MapItemGroup {
property var groupVisible: false
id: rangeGroup
MapCircle {
id: circle5nm
center: position
color: "transparent"
border.color: "gray"
radius: 9260 // 5nm in metres
visible: rangeGroup.groupVisible
}
MapCircle {
id: circle10nm
center: position
color: "transparent"
border.color: "gray"
radius: 18520
visible: rangeGroup.groupVisible
}
MapCircle {
id: circle15nm
center: airport.coordinate
color: "transparent"
border.color: "gray"
radius: 27780
visible: rangeGroup.groupVisible
}
MapQuickItem {
id: text5nm
coordinate {
latitude: position.latitude
longitude: position.longitude + (5/60)/Math.cos(Math.abs(position.latitude)*Math.PI/180)
}
anchorPoint.x: 0
anchorPoint.y: height/2
sourceItem: Text {
color: "grey"
text: "5nm"
}
visible: rangeGroup.groupVisible
}
MapQuickItem {
id: text10nm
coordinate {
latitude: position.latitude
longitude: position.longitude + (10/60)/Math.cos(Math.abs(position.latitude)*Math.PI/180)
}
anchorPoint.x: 0
anchorPoint.y: height/2
sourceItem: Text {
color: "grey"
text: "10nm"
}
visible: rangeGroup.groupVisible
}
MapQuickItem {
id: text15nm
coordinate {
latitude: position.latitude
longitude: position.longitude + (15/60)/Math.cos(Math.abs(position.latitude)*Math.PI/180)
}
anchorPoint.x: 0
anchorPoint.y: height/2
sourceItem: Text {
color: "grey"
text: "15nm"
}
visible: rangeGroup.groupVisible
}
}
MapQuickItem {
id: airport
anchorPoint.x: image.width/2
anchorPoint.y: image.height/2
coordinate: position
zoomLevel: airportZoomLevel
sourceItem: Grid {
columns: 1
Grid {
horizontalItemAlignment: Grid.AlignHCenter
layer.enabled: smoothing
layer.smooth: smoothing
Image {
id: image
source: airportImage
visible: !lightIcons
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: (mouse) => {
if (mouse.button === Qt.RightButton) {
showRangeItem.visible = !rangeGroup.groupVisible
hideRangeItem.visible = rangeGroup.groupVisible
menuItems.clear()
var scanners = airportModel.getFreqScanners()
for (var i = 0; i < scanners.length; i++) {
menuItems.append({
text: "Send to Frequency Scanner " + scanners[i],
airport: index,
scanner: scanners[i]
})
}
contextMenu.popup()
}
}
onDoubleClicked: (mouse) => {
rangeGroup.groupVisible = !rangeGroup.groupVisible
}
ListModel {
id: menuItems
}
Menu {
id: contextMenu
MenuItem {
id: showRangeItem
text: "Show range rings"
onTriggered: rangeGroup.groupVisible = true
height: visible ? implicitHeight : 0
}
MenuItem {
id: hideRangeItem
text: "Hide range rings"
onTriggered: rangeGroup.groupVisible = false
height: visible ? implicitHeight : 0
}
Instantiator {
model: menuItems
MenuItem {
text: model.text
onTriggered: airportModel.sendToFreqScanner(model.airport, model.scanner)
}
onObjectAdded: function(index, object) {
contextMenu.insertItem(index, object)
}
onObjectRemoved: function(index, object) {
contextMenu.removeItem(object)
}
}
}
}
}
MultiEffect {
width: image.width
height: image.height
source: image
brightness: 1.0
colorization: 1.0
colorizationColor: "#c0ffffff"
visible: lightIcons
}
Rectangle {
id: bubble
color: bubbleColour
border.width: 1
width: text.width + 5
height: text.height + 5
radius: 5
Text {
id: text
anchors.centerIn: parent
text: airportData
}
MouseArea {
anchors.fill: parent
onClicked: (mouse) => {
if (showFreq) {
var freqIdx = Math.floor((mouse.y-5)/((height-10)/airportDataRows))
if (freqIdx == 0) {
showFreq = false
}
} else {
showFreq = true
}
}
onDoubleClicked: (mouse) => {
if (showFreq) {
var freqIdx = Math.floor((mouse.y-5)/((height-10)/airportDataRows))
if (freqIdx != 0) {
selectedFreq = freqIdx - 1
}
}
}
}
}
}
}
}
}
}
}

View File

@ -35,7 +35,7 @@ if(NOT SERVER_MODE)
aptdemodsettingsdialog.ui
aptdemodselectdialog.cpp
aptdemodselectdialog.ui
icons.qrc
aptdemodicons.qrc
)
set(demodapt_HEADERS
${demodapt_HEADERS}
@ -55,9 +55,15 @@ else()
set(INSTALL_FOLDER ${INSTALL_PLUGINSSRV_DIR})
endif()
add_library(${TARGET_NAME} SHARED
${demodapt_SOURCES}
)
if(NOT Qt6_FOUND)
add_library(${TARGET_NAME} ${demodapt_SOURCES})
else()
qt_add_plugin(${TARGET_NAME} CLASS_NAME APTDemodPlugin ${demodapt_SOURCES})
endif()
if(NOT BUILD_SHARED_LIBS)
set_property(GLOBAL APPEND PROPERTY STATIC_PLUGINS_PROPERTY ${TARGET_NAME})
endif()
if(APT_EXTERNAL)
add_dependencies(${TARGET_NAME} apt)
@ -67,7 +73,7 @@ if(SGP4_EXTERNAL)
add_dependencies(${TARGET_NAME} sgp4)
endif()
target_link_libraries(${TARGET_NAME}
target_link_libraries(${TARGET_NAME} PRIVATE
Qt::Core
${TARGET_LIB}
sdrbase

View File

@ -33,7 +33,7 @@ if(NOT SERVER_MODE)
radioastronomycalibrationdialog.ui
radioastronomysensordialog.cpp
radioastronomysensordialog.ui
icons.qrc
radioastronomyicons.qrc
)
set(radioastronomy_HEADERS
${radioastronomy_HEADERS}
@ -53,11 +53,17 @@ else()
set(INSTALL_FOLDER ${INSTALL_PLUGINSSRV_DIR})
endif()
add_library(${TARGET_NAME} SHARED
${radioastronomy_SOURCES}
)
if(NOT Qt6_FOUND)
add_library(${TARGET_NAME} ${radioastronomy_SOURCES})
else()
qt_add_plugin(${TARGET_NAME} CLASS_NAME RadioAstronomyPlugin ${radioastronomy_SOURCES})
endif()
target_link_libraries(${TARGET_NAME}
if(NOT BUILD_SHARED_LIBS)
set_property(GLOBAL APPEND PROPERTY STATIC_PLUGINS_PROPERTY ${TARGET_NAME})
endif()
target_link_libraries(${TARGET_NAME} PRIVATE
Qt::Core
${TARGET_LIB}
sdrbase

View File

@ -382,6 +382,7 @@ void RadioAstronomy::startCal(bool hot)
// Execute command to enable calibration
if (!m_settings.m_startCalCommand.isEmpty())
{
#if QT_CONFIG(process)
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
QStringList allArgs = m_settings.m_startCalCommand.split(" ", Qt::SkipEmptyParts);
#else
@ -390,6 +391,9 @@ void RadioAstronomy::startCal(bool hot)
QString program = allArgs[0];
allArgs.pop_front();
QProcess::startDetached(program, allArgs);
#else
qWarning() << "RadioAstronomy::startCal: QProcess not supported. Can't run: " << m_settings.m_startCalCommand;
#endif
}
// Start calibration after requested delay
@ -423,6 +427,7 @@ void RadioAstronomy::calComplete(MsgCalComplete* report)
// Execute command to disable calibration
if (!m_settings.m_stopCalCommand.isEmpty())
{
#if QT_CONFIG(process)
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
QStringList allArgs = m_settings.m_stopCalCommand.split(" ", Qt::SkipEmptyParts);
#else
@ -431,6 +436,9 @@ void RadioAstronomy::calComplete(MsgCalComplete* report)
QString program = allArgs[0];
allArgs.pop_front();
QProcess::startDetached(program, allArgs);
#else
qWarning() << "RadioAstronomy::calComplete: QProcess not supported. Can't run: " << m_settings.m_startCalCommand;
#endif
}
// Send calibration result to GUI

View File

@ -41,7 +41,7 @@ if(NOT SERVER_MODE)
set(map_SOURCES
${map_SOURCES}
mapgui.cpp
${CMAKE_CURRENT_BINARY_DIR}/mapgui.ui
#${CMAKE_CURRENT_BINARY_DIR}/mapgui.ui
maplocationdialog.cpp
maplocationdialog.ui
mapmaidenheaddialog.cpp
@ -61,9 +61,9 @@ if(NOT SERVER_MODE)
cesiuminterface.cpp
czml.cpp
map.qrc
icons.qrc
mapicons.qrc
cesium.qrc
data.qrc
mapdata.qrc
)
set(map_HEADERS
${map_HEADERS}
@ -91,7 +91,7 @@ if(NOT SERVER_MODE)
set(TARGET_LIB ${TARGET_LIB} Qt::WebEngine Qt::WebEngineCore Qt::WebEngineWidgets)
elseif(Qt${QT_DEFAULT_MAJOR_VERSION}WebEngineCore_FOUND)
set(TARGET_LIB ${TARGET_LIB} Qt::SvgWidgets Qt::WebEngineCore Qt::WebEngineWidgets)
elseif(ANDROID)
else()
set(TARGET_LIB ${TARGET_LIB} Qt::SvgWidgets)
endif()
else()
@ -101,11 +101,17 @@ else()
set(INSTALL_FOLDER ${INSTALL_PLUGINSSRV_DIR})
endif()
add_library(${TARGET_NAME} SHARED
${map_SOURCES}
)
if(NOT Qt6_FOUND)
add_library(${TARGET_NAME} ${map_SOURCES})
else()
qt_add_plugin(${TARGET_NAME} CLASS_NAME MapPlugin ${map_SOURCES})
endif()
target_link_libraries(${TARGET_NAME}
if(NOT BUILD_SHARED_LIBS)
set_property(GLOBAL APPEND PROPERTY STATIC_PLUGINS_PROPERTY ${TARGET_NAME})
endif()
target_link_libraries(${TARGET_NAME} PRIVATE
Qt::Core
${TARGET_LIB}
sdrbase

View File

@ -8,6 +8,7 @@
<file>map/antennadab.png</file>
<file>map/antennafm.png</file>
<file>map/antennaam.png</file>
<file>map/antennaangel.png</file>
<file>map/antennakiwi.png</file>
<file>map/antennaspyserver.png</file>
<file>map/ionosonde.png</file>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>491</width>
<width>1031</width>
<height>507</height>
</rect>
</property>
@ -39,7 +39,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>480</width>
<width>751</width>
<height>41</height>
</rect>
</property>
@ -171,6 +171,20 @@
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="layersMenu">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="icons.qrc">
<normaloff>:/map/icons/layers.png</normaloff>:/map/icons/layers.png</iconset>
</property>
<property name="popupMode">
<enum>QToolButton::InstantPopup</enum>
</property>
</widget>
</item>
<item>
<widget class="ButtonSwitch" name="displayRain">
<property name="toolTip">
@ -351,6 +365,20 @@
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="save">
<property name="toolTip">
<string>Save to .kml</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../sdrgui/resources/res.qrc">
<normaloff>:/save.png</normaloff>:/save.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="deleteAll">
<property name="toolTip">
@ -379,6 +407,71 @@
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="nasaGlobalImageryOpacityText">
<property name="minimumSize">
<size>
<width>34</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>100%</string>
</property>
</widget>
</item>
<item>
<widget class="ButtonSwitch" name="displayNASAGlobalImagery">
<property name="toolTip">
<string>Display NASA GIBS data</string>
</property>
<property name="text">
<string>^</string>
</property>
<property name="icon">
<iconset resource="icons.qrc">
<normaloff>:/map/icons/earthsat.png</normaloff>:/map/icons/earthsat.png</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QDial" name="nasaGlobalImageryOpacity">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>NASA GIBS image opacity (3D only)</string>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>100</number>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="nasaGlobalImageryIdentifier">
<property name="minimumSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>NASA GIBS data</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>

View File

@ -15,8 +15,6 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QRegExp>
#include "mapitem.h"
MapItem::MapItem(const QObject *sourcePipe, const QString &group, MapSettings::MapItemSettings *itemSettings, SWGSDRangel::SWGMapItem *mapItem) :

View File

@ -181,7 +181,9 @@ public:
}
QNetworkReply *reply = m_manager.get(request);
#ifndef QT_NO_OPENSSL
connect(reply, &QNetworkReply::sslErrors, this, &MapTileServer::sslErrors);
#endif
//qDebug() << "MapTileServer: Downloading from " << url;
return reply;
}
@ -407,6 +409,7 @@ private slots:
m_replies.remove(reply);
}
#ifndef QT_NO_OPENSSL
void sslErrors(const QList<QSslError> &sslErrors)
{
for (const QSslError &error : sslErrors)
@ -425,6 +428,7 @@ private slots:
#endif
}
}
#endif
};

View File

@ -20,7 +20,6 @@
#include <cmath>
#include <QMessageBox>
#include <QLineEdit>
#include <QRegExp>
#include <QtCharts/QChartView>
#include <QtCharts/QLineSeries>
@ -334,7 +333,9 @@ SatelliteTrackerGUI::SatelliteTrackerGUI(PluginAPI* pluginAPI, FeatureUISet *fea
connect(ui->satTable->horizontalHeader(), SIGNAL(sectionMoved(int, int, int)), SLOT(satTable_sectionMoved(int, int, int)));
connect(ui->satTable->horizontalHeader(), SIGNAL(sectionResized(int, int, int)), SLOT(satTable_sectionResized(int, int, int)));
#ifdef QT_TEXTTOSPEECH_FOUND
m_speech = new QTextToSpeech(this);
#endif
displaySettings();
applySettings(true);
@ -441,16 +442,26 @@ void SatelliteTrackerGUI::aos(const QString &speech)
// Call plotChart() to start the periodic updates with sat position in polar chart
plotChart();
// Give speech notification of pass
if (!speech.isEmpty()) {
if (!speech.isEmpty())
{
#ifdef QT_TEXTTOSPEECH_FOUND
m_speech->say(speech);
#else
qWarning() << "SatelliteTrackerGUI::aos: No TextToSpeech: " << speech;
#endif
}
}
void SatelliteTrackerGUI::los(const QString &speech)
{
// Give speech notification of end of pass
if (!speech.isEmpty()) {
if (!speech.isEmpty())
{
#ifdef QT_TEXTTOSPEECH_FOUND
m_speech->say(speech);
#else
qWarning() << "SatelliteTrackerGUI::los: No TextToSpeech: " << speech;
#endif
}
}

View File

@ -92,7 +92,9 @@ private:
QDateTime m_nextTargetLOS;
bool m_geostationarySatVisible;
#ifdef QT_TEXTTOSPEECH_FOUND
QTextToSpeech *m_speech;
#endif
QMenu *menu; // Column select context menu
enum SatCol {

View File

@ -65,7 +65,11 @@ void getGroundTrack(QDateTime dateTime,
// For 3D map, we want to quantize to minutes, so we replace previous
// position data, rather than insert additional positions alongside the old
// which can result is the camera view jumping around
#if QT_CONFIG(timezone)
dateTime = QDateTime(dateTime.date(), QTime(dateTime.time().hour(), dateTime.time().minute()), dateTime.timeZone());
#else
dateTime = QDateTime(dateTime.date(), QTime(dateTime.time().hour(), dateTime.time().minute()));
#endif
// Note 2D map doesn't support paths wrapping around Earth several times
// So we just have a slight overlap here, with the future track being longer

View File

@ -668,6 +668,7 @@ void SatelliteTrackerWorker::executeCommand(const QString &command, const QStrin
{
if (!command.isEmpty())
{
#if QT_CONFIG(process)
// Replace variables
QString cmd = substituteVariables(command, satelliteName);
QStringList allArgs = QProcess::splitCommand(cmd);
@ -675,6 +676,9 @@ void SatelliteTrackerWorker::executeCommand(const QString &command, const QStrin
QString program = allArgs[0];
allArgs.pop_front();
QProcess::startDetached(program, allArgs);
#else
qWarning() << "SatelliteTrackerWorker::executeCommand: QProcess not supported. Can't run: " << command;
#endif
}
}

View File

@ -29,7 +29,7 @@ if(NOT SERVER_MODE)
sidsettingsdialog.ui
sidaddchannelsdialog.cpp
sidaddchannelsdialog.ui
icons.qrc
sidicons.qrc
)
set(sid_HEADERS
${sid_HEADERS}
@ -49,11 +49,17 @@ else()
set(INSTALL_FOLDER ${INSTALL_PLUGINSSRV_DIR})
endif()
add_library(${TARGET_NAME} SHARED
${sid_SOURCES}
)
if(NOT Qt6_FOUND)
add_library(${TARGET_NAME} ${sid_SOURCES})
else()
qt_add_plugin(${TARGET_NAME} CLASS_NAME SIDPlugin ${sid_SOURCES})
endif()
target_link_libraries(${TARGET_NAME}
if(NOT BUILD_SHARED_LIBS)
set_property(GLOBAL APPEND PROPERTY STATIC_PLUGINS_PROPERTY ${TARGET_NAME})
endif()
target_link_libraries(${TARGET_NAME} PRIVATE
Qt::Core
${TARGET_LIB}
sdrbase

View File

@ -211,11 +211,11 @@ When clicked, the X-axis is set 1 day later than the current setting, at the sam
<h3>27: Start Time</h3>
Displays/sets the current start time of the chart (X-axis minimum). It's possible to scroll through hours/days/months by clicking on the relevant segment and using the mouse scroll wheel.
Displays/sets the current local start time of the chart (X-axis minimum). It's possible to scroll through hours/days/months by clicking on the relevant segment and using the mouse scroll wheel.
<h3>28: End Time</h3>
Displays/sets the current end time of the chart (X-axis maximum). It's possible to scroll through hours/days/months by clicking on the relevant segment and using the mouse scroll wheel.
Displays/sets the current local end time of the chart (X-axis maximum). It's possible to scroll through hours/days/months by clicking on the relevant segment and using the mouse scroll wheel.
<h3>29: Min</h3>
@ -231,7 +231,7 @@ When checked, the latest SDO imagery is displayed. When unchecked, you can enter
<h3>32: Date Time</h3>
Specifies the date and time for which SDO imagery should be displayed. Images are updated every 15 minutes. The date and time can also be set by clicking on the chart.
Specifies the local date and time for which SDO imagery should be displayed. Images are updated every 15 minutes. The date and time can also be set by clicking on the chart.
<h3>33: Map</h3>

View File

@ -2035,7 +2035,15 @@ void SIDGUI::on_showPaths_clicked()
{
// Get position of device, defaulting to My Position
QGeoCoordinate rxPosition;
if (!ChannelWebAPIUtils::getDevicePosition(deviceSetIndex, rxPosition))
float latitude, longitude, altitude;
if (ChannelWebAPIUtils::getDevicePosition(deviceSetIndex, latitude, longitude, altitude))
{
rxPosition.setLatitude(latitude);
rxPosition.setLongitude(longitude);
rxPosition.setAltitude(altitude);
}
else
{
rxPosition.setLatitude(MainCore::instance()->getSettings().getLatitude());
rxPosition.setLongitude(MainCore::instance()->getSettings().getLongitude());

View File

@ -28,8 +28,8 @@ if(NOT SERVER_MODE)
${vor_SOURCES}
vorlocalizergui.cpp
vorlocalizergui.ui
map.qrc
icons.qrc
vorlocalizermap.qrc
vorlocalizericons.qrc
)
set(vor_HEADERS
${vor_HEADERS}
@ -47,11 +47,17 @@ else()
set(INSTALL_FOLDER ${INSTALL_PLUGINSSRV_DIR})
endif()
add_library(${TARGET_NAME} SHARED
${vor_SOURCES}
)
if(NOT Qt6_FOUND)
add_library(${TARGET_NAME} ${vor_SOURCES})
else()
qt_add_plugin(${TARGET_NAME} CLASS_NAME VORLocalizerPlugin ${vor_SOURCES})
endif()
target_link_libraries(${TARGET_NAME}
if(NOT BUILD_SHARED_LIBS)
set_property(GLOBAL APPEND PROPERTY STATIC_PLUGINS_PROPERTY ${TARGET_NAME})
endif()
target_link_libraries(${TARGET_NAME} PRIVATE
Qt::Core
${TARGET_LIB}
sdrbase

View File

@ -369,6 +369,7 @@ bool ChannelWebAPIUtils::setCenterFrequency(unsigned int deviceIndex, double fre
deviceSettingsResponse.init();
deviceSettingsResponse.fromJsonObject(*jsonObj);
SWGSDRangel::SWGErrorResponse errorResponse2;
delete jsonObj;
DeviceSampleSource *source = deviceSet->m_deviceAPI->getSampleSource();
if (source) {
@ -910,7 +911,9 @@ bool ChannelWebAPIUtils::getFrequencyOffset(unsigned int deviceIndex, int channe
}
jsonObj = channelSettingsResponse.asJsonObject();
if (WebAPIUtils::getSubObjectDouble(*jsonObj, "inputFrequencyOffset", offsetD))
bool result = WebAPIUtils::getSubObjectDouble(*jsonObj, "inputFrequencyOffset", offsetD);
delete jsonObj;
if (result)
{
offset = (int)offsetD;
return true;
@ -946,6 +949,7 @@ bool ChannelWebAPIUtils::setFrequencyOffset(unsigned int deviceIndex, int channe
keys.append("inputFrequencyOffset");
channelSettingsResponse.init();
channelSettingsResponse.fromJsonObject(*jsonObj);
delete jsonObj;
httpRC = channel->webapiSettingsPutPatch(false, keys, channelSettingsResponse, errorResponse);
if (httpRC/100 != 2)
{
@ -956,6 +960,7 @@ bool ChannelWebAPIUtils::setFrequencyOffset(unsigned int deviceIndex, int channe
return true;
}
delete jsonObj;
}
return false;
}
@ -986,6 +991,7 @@ bool ChannelWebAPIUtils::setAudioMute(unsigned int deviceIndex, int channelIndex
keys.append("audioMute");
channelSettingsResponse.init();
channelSettingsResponse.fromJsonObject(*jsonObj);
delete jsonObj;
httpRC = channel->webapiSettingsPutPatch(false, keys, channelSettingsResponse, errorResponse);
if (httpRC / 100 != 2)
{
@ -996,6 +1002,7 @@ bool ChannelWebAPIUtils::setAudioMute(unsigned int deviceIndex, int channelIndex
return true;
}
delete jsonObj;
}
return false;
}
@ -1120,7 +1127,9 @@ bool ChannelWebAPIUtils::getDeviceSetting(unsigned int deviceIndex, const QStrin
if (getDeviceSettings(deviceIndex, deviceSettingsResponse, deviceSet))
{
QJsonObject *jsonObj = deviceSettingsResponse.asJsonObject();
return WebAPIUtils::getSubObjectInt(*jsonObj, setting, value);
bool result = WebAPIUtils::getSubObjectInt(*jsonObj, setting, value);
delete jsonObj;
return result;
}
else
{
@ -1136,7 +1145,9 @@ bool ChannelWebAPIUtils::getDeviceReportValue(unsigned int deviceIndex, const QS
{
// Get value of requested key
QJsonObject *jsonObj = deviceReport.asJsonObject();
if (WebAPIUtils::getSubObjectString(*jsonObj, key, value))
bool result = WebAPIUtils::getSubObjectString(*jsonObj, key, value);
delete jsonObj;
if (result)
{
// Done
return true;
@ -1158,7 +1169,9 @@ bool ChannelWebAPIUtils::getDeviceReportList(unsigned int deviceIndex, const QSt
{
// Get value of requested key
QJsonObject *jsonObj = deviceReport.asJsonObject();
if (WebAPIUtils::getSubObjectIntList(*jsonObj, key, subKey, values))
bool result = WebAPIUtils::getSubObjectIntList(*jsonObj, key, subKey, values);
delete jsonObj;
if (result)
{
// Done
return true;
@ -1173,29 +1186,27 @@ bool ChannelWebAPIUtils::getDeviceReportList(unsigned int deviceIndex, const QSt
}
bool ChannelWebAPIUtils::getDevicePosition(unsigned int deviceIndex, QGeoCoordinate& position)
bool ChannelWebAPIUtils::getDevicePosition(unsigned int deviceIndex, float& latitude, float& longitude, float& altitude)
{
SWGSDRangel::SWGDeviceReport deviceReport;
if (getDeviceReport(deviceIndex, deviceReport))
{
QJsonObject *jsonObj = deviceReport.asJsonObject();
double latitude, longitude, altitude;
if (WebAPIUtils::getSubObjectDouble(*jsonObj, "latitude", latitude)
&& WebAPIUtils::getSubObjectDouble(*jsonObj, "longitude", longitude)
&& WebAPIUtils::getSubObjectDouble(*jsonObj, "altitude", altitude))
double latitudeDouble, longitudeDouble, altitudeDouble;
bool result = WebAPIUtils::getSubObjectDouble(*jsonObj, "latitude", latitudeDouble)
&& WebAPIUtils::getSubObjectDouble(*jsonObj, "longitude", longitudeDouble)
&& WebAPIUtils::getSubObjectDouble(*jsonObj, "altitude", altitudeDouble);
delete jsonObj;
if (result)
{
position.setLatitude(latitude);
position.setLongitude(longitude);
position.setAltitude(altitude);
// Done
return true;
}
else
{
//qWarning("ChannelWebAPIUtils::getDevicePosition: no latitude/longitude/altitude in device report");
return false;
if (!std::isnan(latitudeDouble) && !std::isnan(longitudeDouble) && !std::isnan(altitudeDouble))
{
latitude = (float) latitudeDouble;
longitude = (float) longitudeDouble;
altitude = (float) altitudeDouble;
return true;
}
}
}
return false;
@ -1305,6 +1316,7 @@ bool ChannelWebAPIUtils::patchDeviceSetting(unsigned int deviceIndex, const QStr
deviceSettingsResponse.init();
deviceSettingsResponse.fromJsonObject(*jsonObj);
SWGSDRangel::SWGErrorResponse errorResponse2;
delete jsonObj;
DeviceSampleSource *source = deviceSet->m_deviceAPI->getSampleSource();
@ -1324,6 +1336,7 @@ bool ChannelWebAPIUtils::patchDeviceSetting(unsigned int deviceIndex, const QStr
}
else
{
delete jsonObj;
qWarning("ChannelWebAPIUtils::patchDeviceSetting: no key %s in device settings", qPrintable(setting));
return false;
}
@ -1354,6 +1367,7 @@ bool ChannelWebAPIUtils::patchFeatureSetting(unsigned int featureSetIndex, unsig
featureSettingsResponse.init();
featureSettingsResponse.fromJsonObject(*jsonObj);
SWGSDRangel::SWGErrorResponse errorResponse2;
delete jsonObj;
httpRC = feature->webapiSettingsPutPatch(false, featureSettingsKeys, featureSettingsResponse, *errorResponse2.getMessage());
@ -1371,6 +1385,7 @@ bool ChannelWebAPIUtils::patchFeatureSetting(unsigned int featureSetIndex, unsig
}
else
{
delete jsonObj;
qWarning("ChannelWebAPIUtils::patchFeatureSetting: no key %s in feature settings", qPrintable(setting));
return false;
}
@ -1401,6 +1416,7 @@ bool ChannelWebAPIUtils::patchFeatureSetting(unsigned int featureSetIndex, unsig
featureSettingsResponse.init();
featureSettingsResponse.fromJsonObject(*jsonObj);
SWGSDRangel::SWGErrorResponse errorResponse2;
delete jsonObj;
httpRC = feature->webapiSettingsPutPatch(false, featureSettingsKeys, featureSettingsResponse, *errorResponse2.getMessage());
@ -1418,6 +1434,7 @@ bool ChannelWebAPIUtils::patchFeatureSetting(unsigned int featureSetIndex, unsig
}
else
{
delete jsonObj;
qWarning("ChannelWebAPIUtils::patchFeatureSetting: no key %s in feature settings", qPrintable(setting));
return false;
}
@ -1480,6 +1497,7 @@ bool ChannelWebAPIUtils::patchFeatureSetting(unsigned int featureSetIndex, unsig
featureSettingsResponse.init();
featureSettingsResponse.fromJsonObject(*jsonObj);
SWGSDRangel::SWGErrorResponse errorResponse2;
delete jsonObj;
httpRC = feature->webapiSettingsPutPatch(false, featureSettingsKeys, featureSettingsResponse, *errorResponse2.getMessage());
@ -1519,6 +1537,7 @@ bool ChannelWebAPIUtils::patchChannelSetting(ChannelAPI *channel, const QString
channelSettingsResponse.init();
channelSettingsResponse.fromJsonObject(*jsonObj);
SWGSDRangel::SWGErrorResponse errorResponse2;
delete jsonObj;
httpRC = channel->webapiSettingsPutPatch(false, channelSettingsKeys, channelSettingsResponse, *errorResponse2.getMessage());
@ -1536,6 +1555,7 @@ bool ChannelWebAPIUtils::patchChannelSetting(ChannelAPI *channel, const QString
}
else
{
delete jsonObj;
qWarning("ChannelWebAPIUtils::patchChannelSetting: no key %s in channel settings", qPrintable(setting));
return false;
}
@ -1631,6 +1651,7 @@ bool ChannelWebAPIUtils::patchChannelSetting(unsigned int deviceSetIndex, unsign
channelSettingsResponse.init();
channelSettingsResponse.fromJsonObject(*jsonObj);
SWGSDRangel::SWGErrorResponse errorResponse2;
delete jsonObj;
httpRC = channel->webapiSettingsPutPatch(false, channelSettingsKeys, channelSettingsResponse, *errorResponse2.getMessage());
@ -1660,7 +1681,9 @@ bool ChannelWebAPIUtils::getFeatureSetting(unsigned int featureSetIndex, unsign
if (getFeatureSettings(featureSetIndex, featureIndex, featureSettingsResponse, feature))
{
QJsonObject *jsonObj = featureSettingsResponse.asJsonObject();
return WebAPIUtils::getSubObjectInt(*jsonObj, setting, value);
bool result = WebAPIUtils::getSubObjectInt(*jsonObj, setting, value);
delete jsonObj;
return result;
}
else
{
@ -1676,7 +1699,9 @@ bool ChannelWebAPIUtils::getFeatureSetting(unsigned int featureSetIndex, unsign
if (getFeatureSettings(featureSetIndex, featureIndex, featureSettingsResponse, feature))
{
QJsonObject *jsonObj = featureSettingsResponse.asJsonObject();
return WebAPIUtils::getSubObjectDouble(*jsonObj, setting, value);
bool result = WebAPIUtils::getSubObjectDouble(*jsonObj, setting, value);
delete jsonObj;
return result;
}
else
{
@ -1692,7 +1717,9 @@ bool ChannelWebAPIUtils::getFeatureSetting(unsigned int featureSetIndex, unsign
if (getFeatureSettings(featureSetIndex, featureIndex, featureSettingsResponse, feature))
{
QJsonObject *jsonObj = featureSettingsResponse.asJsonObject();
return WebAPIUtils::getSubObjectString(*jsonObj, setting, value);
bool result = WebAPIUtils::getSubObjectString(*jsonObj, setting, value);
delete jsonObj;
return result;
}
else
{
@ -1708,7 +1735,9 @@ bool ChannelWebAPIUtils::getChannelSetting(unsigned int deviceSetIndex, unsigne
if (getChannelSettings(deviceSetIndex, channelIndex, channelSettingsResponse, channel))
{
QJsonObject *jsonObj = channelSettingsResponse.asJsonObject();
return WebAPIUtils::getSubObjectInt(*jsonObj, setting, value);
bool result = WebAPIUtils::getSubObjectInt(*jsonObj, setting, value);
delete jsonObj;
return result;
}
else
{
@ -1724,7 +1753,9 @@ bool ChannelWebAPIUtils::getChannelSetting(unsigned int deviceSetIndex, unsigne
if (getChannelSettings(deviceSetIndex, channelIndex, channelSettingsResponse, channel))
{
QJsonObject *jsonObj = channelSettingsResponse.asJsonObject();
return WebAPIUtils::getSubObjectDouble(*jsonObj, setting, value);
bool result = WebAPIUtils::getSubObjectDouble(*jsonObj, setting, value);
delete jsonObj;
return result;
}
else
{
@ -1740,7 +1771,9 @@ bool ChannelWebAPIUtils::getChannelSetting(unsigned int deviceSetIndex, unsigne
if (getChannelSettings(deviceSetIndex, channelIndex, channelSettingsResponse, channel))
{
QJsonObject *jsonObj = channelSettingsResponse.asJsonObject();
return WebAPIUtils::getSubObjectString(*jsonObj, setting, value);
bool result = WebAPIUtils::getSubObjectString(*jsonObj, setting, value);
delete jsonObj;
return result;
}
else
{
@ -1756,7 +1789,9 @@ bool ChannelWebAPIUtils::getFeatureReportValue(unsigned int featureSetIndex, uns
{
// Get value of requested key
QJsonObject *jsonObj = featureReport.asJsonObject();
if (WebAPIUtils::getSubObjectInt(*jsonObj, key, value))
bool result = WebAPIUtils::getSubObjectInt(*jsonObj, key, value);
delete jsonObj;
if (result)
{
// Done
return true;
@ -1778,7 +1813,9 @@ bool ChannelWebAPIUtils::getFeatureReportValue(unsigned int featureSetIndex, uns
{
// Get value of requested key
QJsonObject *jsonObj = featureReport.asJsonObject();
if (WebAPIUtils::getSubObjectDouble(*jsonObj, key, value))
bool result = WebAPIUtils::getSubObjectDouble(*jsonObj, key, value);
delete jsonObj;
if (result)
{
// Done
return true;
@ -1800,7 +1837,9 @@ bool ChannelWebAPIUtils::getFeatureReportValue(unsigned int featureSetIndex, uns
{
// Get value of requested key
QJsonObject *jsonObj = featureReport.asJsonObject();
if (WebAPIUtils::getSubObjectString(*jsonObj, key, value))
bool result = WebAPIUtils::getSubObjectString(*jsonObj, key, value);
delete jsonObj;
if (result)
{
// Done
return true;
@ -1823,7 +1862,9 @@ bool ChannelWebAPIUtils::getChannelReportValue(unsigned int deviceIndex, unsigne
{
// Get value of requested key
QJsonObject *jsonObj = channelReport.asJsonObject();
if (WebAPIUtils::getSubObjectInt(*jsonObj, key, value))
bool result = WebAPIUtils::getSubObjectInt(*jsonObj, key, value);
delete jsonObj;
if (result)
{
// Done
return true;
@ -1845,7 +1886,9 @@ bool ChannelWebAPIUtils::getChannelReportValue(unsigned int deviceIndex, unsigne
{
// Get value of requested key
QJsonObject *jsonObj = channelReport.asJsonObject();
if (WebAPIUtils::getSubObjectDouble(*jsonObj, key, value))
bool result = WebAPIUtils::getSubObjectDouble(*jsonObj, key, value);
delete jsonObj;
if (result)
{
// Done
return true;
@ -1867,7 +1910,9 @@ bool ChannelWebAPIUtils::getChannelReportValue(unsigned int deviceIndex, unsigne
{
// Get value of requested key
QJsonObject *jsonObj = channelReport.asJsonObject();
if (WebAPIUtils::getSubObjectString(*jsonObj, key, value))
bool result = WebAPIUtils::getSubObjectString(*jsonObj, key, value);
delete jsonObj;
if (result)
{
// Done
return true;

View File

@ -23,7 +23,6 @@
#include <QString>
#include <QJsonArray>
#include <QGeoCoordinate>
#include "SWGDeviceSettings.h"
#include "SWGDeviceReport.h"
@ -72,7 +71,7 @@ public:
static bool getDeviceSetting(unsigned int deviceIndex, const QString &setting, int &value);
static bool getDeviceReportValue(unsigned int deviceIndex, const QString &key, QString &value);
static bool getDeviceReportList(unsigned int deviceIndex, const QString &key, const QString &subKey, QList<int> &values);
static bool getDevicePosition(unsigned int deviceIndex, QGeoCoordinate& position);
static bool getDevicePosition(unsigned int deviceIndex, float& latitude, float& longitude, float& altitude);
static bool patchDeviceSetting(unsigned int deviceIndex, const QString &setting, int value);
static bool runFeature(unsigned int featureSetIndex, unsigned int featureIndex);
static bool stopFeature(unsigned int featureSetIndex, unsigned int featureIndex);

View File

@ -165,6 +165,10 @@ public:
protected slots:
void handleInputMessages();
signals:
void positionChanged(float latitude, float longitude, float altitude);
void directionChanged(bool isotropic, float azimuth, float elevation);
protected:
SampleSinkFifo m_sampleFifo;
MessageQueue m_inputMessageQueue; //!< Input queue to the source