Allow sampling devices to be refreshed while SDRangel is running.

(Possibly need to add a mutex for MainCore::getPluginManager, so only
can be used by one thread)
Add option to automatically update My Position based on GPS. This is
started in MainCore, so we get position as soon as possible.
Don't set QFileDialog::DontUseNativeDialog on Android, as Qt's file
dialog can't access user storage. Set globally for Linux/Windows, rather
than for each dialog.

 MainWindow:
 - Add welcome dialog for Android.
 - Don't show menu bar or status bar on Android to save screen space.
 - On Android, change tab position when screen orientation changes.
 - Load default configurations and presets first time SDRangel is run.
 - Change loadConfiguration to use a QProgressDialog rather than
   QMessageBox, as the latter was crashing on Android.
   - Use DialogPositioner to ensure dialogs are on screen.
This commit is contained in:
Jon Beniston 2022-12-20 21:06:39 +00:00
parent cedd7c20d1
commit 68603fec43
34 changed files with 1125 additions and 416 deletions

View File

@ -26,6 +26,9 @@
#include <QGLFormat>
#include <QSurfaceFormat>
#endif
#ifdef ANDROID
#include "util/android.h"
#endif
#include "loggerwithfile.h"
#include "mainwindow.h"
@ -49,6 +52,9 @@ static int runQtApplication(int argc, char* argv[], qtwebapp::LoggerWithFile *lo
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) && (QT_VERSION <= QT_VERSION_CHECK(6, 0, 0))
QApplication::setAttribute(Qt::AA_DisableWindowContextHelpButton);
#endif
#ifndef ANDROID
QApplication::setAttribute(Qt::AA_DontUseNativeDialogs); // Don't use on Android, otherwise we can't access files on internal storage
#endif
QApplication a(argc, argv);
@ -111,6 +117,20 @@ static int runQtApplication(int argc, char* argv[], qtwebapp::LoggerWithFile *lo
#endif
#endif
#ifdef ANDROID
// Default sized sliders can be hard to move using touch GUIs, so increase szie
// FIXME: How can we do a double border around the handle, as Fusion style seems to use?
// Dialog borders are hard to see as is (perhaps as Android doesn't have a title bar), so use same color as for MDI
qApp->setStyleSheet("QSlider {min-height: 20px; } "
"QSlider::groove:horizontal { border: 1px solid #2e2e2e; height: 1px; background: #444444; margin: 1px 0;}"
"QSlider::handle:horizontal { background: #585858; border: 1px double #676767; width: 16px; margin: -8px 0px; border-radius: 3px;}"
"QSlider::sub-page {background: #ff8c00; border: 1px solid #2e2e2e;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-top-left-radius: 5px;border-bottom-left-radius: 5px;}"
"QSlider::add-page {background: #444444; border: 1px solid #2e2e2e;border-top-right-radius: 5px;border-bottom-right-radius: 5px;border-top-left-radius: 0px;border-bottom-left-radius: 0px;}"
"QDialog { border: 1px solid #ff8c00;}"
);
#endif
MainParser parser;
parser.parse(*qApp);
@ -160,10 +180,18 @@ int main(int argc, char* argv[])
QSurfaceFormat::setDefaultFormat(sfc);
#endif
qtwebapp::LoggerWithFile *logger = new qtwebapp::LoggerWithFile(qApp);
#ifdef ANDROID
qtwebapp::LoggerWithFile *logger = nullptr;
qInstallMessageHandler(Android::messageHandler);
#else
qtwebapp::LoggerWithFile *logger = new qtwebapp::LoggerWithFile(qApp);
logger->installMsgHandler();
#endif
int res = runQtApplication(argc, argv, logger);
delete logger;
qWarning("SDRangel quit.");
return res;
}

View File

@ -1,6 +1,7 @@
project (sdrbase)
if(WIN32)
# This should probably be in ../CMakeLists.txt with the other variables like it
set(OPUS_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/external/windows/libopus/include")
set(OPUS_LIBRARIES "${CMAKE_SOURCE_DIR}/external/windows/libopus/lib/x64/libopus.lib")
endif()
@ -45,10 +46,11 @@ if (LIBSIGMF_FOUND AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(sdrbase_LIBSIGMF_LIB ${LIBSIGMF_LIBRARIES})
endif()
# serialdv now required
add_definitions(-DDSD_USE_SERIALDV)
include_directories(${LIBSERIALDV_INCLUDE_DIR})
set(sdrbase_SERIALDV_LIB ${LIBSERIALDV_LIBRARY})
if (LIBSERIALDV_FOUND)
add_definitions(-DDSD_USE_SERIALDV)
include_directories(${LIBSERIALDV_INCLUDE_DIR})
set(sdrbase_SERIALDV_LIB ${LIBSERIALDV_LIBRARY})
endif()
set(sdrbase_SOURCES
${sdrbase_SOURCES}
@ -168,6 +170,7 @@ set(sdrbase_SOURCES
settings/rollupstate.cpp
util/ais.cpp
util/android.cpp
util/aviationweather.cpp
util/ax25.cpp
util/aprs.cpp
@ -388,6 +391,7 @@ set(sdrbase_HEADERS
settings/rollupstate.h
util/ais.h
util/android.h
util/aviationweather.h
util/ax25.h
util/aprs.h
@ -491,6 +495,7 @@ target_link_libraries(sdrbase
Qt::Core
Qt::Multimedia
Qt::WebSockets
Qt::Positioning
httpserver
logging
qrtplib
@ -499,8 +504,15 @@ target_link_libraries(sdrbase
if (Qt6_FOUND)
target_link_libraries(sdrbase
Qt::Core5Compat
Qt::CorePrivate
)
endif()
if(ANDROID AND NOT ENABLE_QT6)
target_link_libraries(sdrbase Qt::AndroidExtras)
endif()
if(ANDROID)
target_link_libraries(sdrbase log)
endif()
install(TARGETS sdrbase DESTINATION ${INSTALL_LIB_DIR})

View File

@ -17,8 +17,6 @@
#include <QGlobalStatic>
#include "plugin/pluginmanager.h"
#include "deviceenumerator.h"
Q_GLOBAL_STATIC(DeviceEnumerator, deviceEnumerator)
@ -246,89 +244,101 @@ bool DeviceEnumerator::isMIMOEnumerated(const QString& deviceHwId, int deviceSeq
return false;
}
void DeviceEnumerator::enumerateRxDevices(PluginManager *pluginManager)
void DeviceEnumerator::enumerateDevices(PluginAPI::SamplingDeviceRegistrations& deviceRegistrations, DevicesEnumeration& enumeration, PluginInterface::SamplingDevice::StreamType type)
{
m_rxEnumeration.clear();
PluginAPI::SamplingDeviceRegistrations& rxDeviceRegistrations = pluginManager->getSourceDeviceRegistrations();
int index = 0;
DevicesEnumeration tempEnumeration;
PluginInterface::OriginDevices originDevices;
QStringList originDevicesHwIds;
for (int i = 0; i < rxDeviceRegistrations.count(); i++)
for (int i = 0; i < deviceRegistrations.count(); i++)
{
qDebug("DeviceEnumerator::enumerateRxDevices: %s", qPrintable(rxDeviceRegistrations[i].m_deviceId));
rxDeviceRegistrations[i].m_plugin->enumOriginDevices(m_originDevicesHwIds, m_originDevices);
PluginInterface::SamplingDevices samplingDevices = rxDeviceRegistrations[i].m_plugin->enumSampleSources(m_originDevices);
qDebug("DeviceEnumerator::enumerateDevices: %s", qPrintable(deviceRegistrations[i].m_deviceId));
deviceRegistrations[i].m_plugin->enumOriginDevices(originDevicesHwIds, originDevices);
PluginInterface::SamplingDevices samplingDevices;
if (type == PluginInterface::SamplingDevice::StreamSingleRx) {
samplingDevices = deviceRegistrations[i].m_plugin->enumSampleSources(originDevices);
} else if (type == PluginInterface::SamplingDevice::StreamSingleTx) {
samplingDevices = deviceRegistrations[i].m_plugin->enumSampleSinks(originDevices);
} else {
samplingDevices = deviceRegistrations[i].m_plugin->enumSampleMIMO(originDevices);
}
for (int j = 0; j < samplingDevices.count(); j++)
{
m_rxEnumeration.push_back(
tempEnumeration.push_back(
DeviceEnumeration(
samplingDevices[j],
rxDeviceRegistrations[i].m_plugin,
index
deviceRegistrations[i].m_plugin,
0 // Index will be set when adding to enumeration below
)
);
index++;
}
}
// We don't remove devices that are no-longer found from the enumeration list, in case their
// index is referenced in some other object (E.g. DeviceGUI)
// Instead we mark as removed. If later re-added, then we re-use the same index
for (DevicesEnumeration::iterator it = enumeration.begin(); it != enumeration.end(); ++it)
{
bool found = false;
for (DevicesEnumeration::iterator it2 = tempEnumeration.begin(); it2 != tempEnumeration.end(); ++it2)
{
if (it->m_samplingDevice == it2->m_samplingDevice)
{
found = true;
break;
}
}
if (!found) {
it->m_samplingDevice.removed = true;
}
}
// Add new entries and update existing (in case re-added or sequence number has changed)
int index = enumeration.size();
for (DevicesEnumeration::iterator it = tempEnumeration.begin(); it != tempEnumeration.end(); ++it)
{
bool found = false;
for (DevicesEnumeration::iterator it2 = enumeration.begin(); it2 != enumeration.end(); ++it2)
{
if (it->m_samplingDevice == it2->m_samplingDevice)
{
it2->m_samplingDevice.removed = false;
it2->m_samplingDevice.displayedName = it->m_samplingDevice.displayedName;
found = true;
break;
}
}
if (!found)
{
it->m_index = index++;
enumeration.push_back(*it);
}
}
}
void DeviceEnumerator::enumerateRxDevices(PluginManager *pluginManager)
{
enumerateDevices(pluginManager->getSourceDeviceRegistrations(), m_rxEnumeration, PluginInterface::SamplingDevice::StreamSingleRx);
}
void DeviceEnumerator::enumerateTxDevices(PluginManager *pluginManager)
{
m_txEnumeration.clear();
PluginAPI::SamplingDeviceRegistrations& txDeviceRegistrations = pluginManager->getSinkDeviceRegistrations();
int index = 0;
for (int i = 0; i < txDeviceRegistrations.count(); i++)
{
qDebug("DeviceEnumerator::enumerateTxDevices: %s", qPrintable(txDeviceRegistrations[i].m_deviceId));
txDeviceRegistrations[i].m_plugin->enumOriginDevices(m_originDevicesHwIds, m_originDevices);
PluginInterface::SamplingDevices samplingDevices = txDeviceRegistrations[i].m_plugin->enumSampleSinks(m_originDevices);
for (int j = 0; j < samplingDevices.count(); j++)
{
m_txEnumeration.push_back(
DeviceEnumeration(
samplingDevices[j],
txDeviceRegistrations[i].m_plugin,
index
)
);
index++;
}
}
enumerateDevices(pluginManager->getSinkDeviceRegistrations(), m_txEnumeration, PluginInterface::SamplingDevice::StreamSingleTx);
}
void DeviceEnumerator::enumerateMIMODevices(PluginManager *pluginManager)
{
m_mimoEnumeration.clear();
PluginAPI::SamplingDeviceRegistrations& mimoDeviceRegistrations = pluginManager->getMIMODeviceRegistrations();
int index = 0;
for (int i = 0; i < mimoDeviceRegistrations.count(); i++)
{
qDebug("DeviceEnumerator::enumerateMIMODevices: %s", qPrintable(mimoDeviceRegistrations[i].m_deviceId));
mimoDeviceRegistrations[i].m_plugin->enumOriginDevices(m_originDevicesHwIds, m_originDevices);
PluginInterface::SamplingDevices samplingDevices = mimoDeviceRegistrations[i].m_plugin->enumSampleMIMO(m_originDevices);
for (int j = 0; j < samplingDevices.count(); j++)
{
m_mimoEnumeration.push_back(
DeviceEnumeration(
samplingDevices[j],
mimoDeviceRegistrations[i].m_plugin,
index
)
);
index++;
}
}
enumerateDevices(pluginManager->getMIMODeviceRegistrations(), m_mimoEnumeration, PluginInterface::SamplingDevice::StreamMIMO);
}
void DeviceEnumerator::listRxDeviceNames(QList<QString>& list, std::vector<int>& indexes) const
{
for (DevicesEnumeration::const_iterator it = m_rxEnumeration.begin(); it != m_rxEnumeration.end(); ++it)
{
if ((it->m_samplingDevice.claimed < 0) || (it->m_samplingDevice.type == PluginInterface::SamplingDevice::BuiltInDevice))
if (((it->m_samplingDevice.claimed < 0) && (!it->m_samplingDevice.removed)) || (it->m_samplingDevice.type == PluginInterface::SamplingDevice::BuiltInDevice))
{
list.append(it->m_samplingDevice.displayedName);
indexes.push_back(it->m_index);
@ -340,7 +350,7 @@ void DeviceEnumerator::listTxDeviceNames(QList<QString>& list, std::vector<int>&
{
for (DevicesEnumeration::const_iterator it = m_txEnumeration.begin(); it != m_txEnumeration.end(); ++it)
{
if ((it->m_samplingDevice.claimed < 0) || (it->m_samplingDevice.type == PluginInterface::SamplingDevice::BuiltInDevice))
if (((it->m_samplingDevice.claimed < 0) && (!it->m_samplingDevice.removed)) || (it->m_samplingDevice.type == PluginInterface::SamplingDevice::BuiltInDevice))
{
list.append(it->m_samplingDevice.displayedName);
indexes.push_back(it->m_index);
@ -352,7 +362,7 @@ void DeviceEnumerator::listMIMODeviceNames(QList<QString>& list, std::vector<int
{
for (DevicesEnumeration::const_iterator it = m_mimoEnumeration.begin(); it != m_mimoEnumeration.end(); ++it)
{
if ((it->m_samplingDevice.claimed < 0) || (it->m_samplingDevice.type == PluginInterface::SamplingDevice::BuiltInDevice))
if (((it->m_samplingDevice.claimed < 0) && (!it->m_samplingDevice.removed)) || (it->m_samplingDevice.type == PluginInterface::SamplingDevice::BuiltInDevice))
{
list.append(it->m_samplingDevice.displayedName);
indexes.push_back(it->m_index);

View File

@ -21,6 +21,7 @@
#include <vector>
#include "plugin/plugininterface.h"
#include "plugin/pluginmanager.h"
#include "device/deviceuserargs.h"
#include "export.h"
@ -85,9 +86,8 @@ private:
DevicesEnumeration m_rxEnumeration;
DevicesEnumeration m_txEnumeration;
DevicesEnumeration m_mimoEnumeration;
PluginInterface::OriginDevices m_originDevices;
QStringList m_originDevicesHwIds;
void enumerateDevices(PluginAPI::SamplingDeviceRegistrations& deviceRegistrations, DevicesEnumeration& enumeration, PluginInterface::SamplingDevice::StreamType type);
PluginInterface *getRxRegisteredPlugin(PluginManager *pluginManager, const QString& deviceHwId);
PluginInterface *getTxRegisteredPlugin(PluginManager *pluginManager, const QString& deviceHwId);
PluginInterface *getMIMORegisteredPlugin(PluginManager *pluginManager, const QString& deviceHwId);

View File

@ -18,6 +18,8 @@
#include <QGlobalStatic>
#include <QCoreApplication>
#include <QString>
#include <QDebug>
#include <QGeoPositionInfoSource>
#include "loggerwithfile.h"
#include "dsp/dsptypes.h"
@ -71,6 +73,8 @@ MainCore::MainCore()
m_masterTimer.start(50);
m_startMsecsSinceEpoch = QDateTime::currentMSecsSinceEpoch();
m_masterElapsedTimer.start();
// Position can take a while to determine, so we start updates at program startup
initPosition();
}
MainCore::~MainCore()
@ -335,3 +339,36 @@ void MainCore::debugMaps()
feIt.value()->getIndex(), feIt.key()->getIndexInFeatureSet(), qPrintable(feIt.key()->getURI()), qPrintable(feIt.key()->getName()));
}
}
void MainCore::initPosition()
{
m_positionSource = QGeoPositionInfoSource::createDefaultSource(this);
if (m_positionSource)
{
connect(m_positionSource, &QGeoPositionInfoSource::positionUpdated, this, &MainCore::positionUpdated);
m_positionSource->startUpdates();
}
else
{
qDebug() << "MainCore::initPosition: No position source.";
}
}
const QGeoPositionInfo& MainCore::getPosition() const
{
return m_position;
}
void MainCore::positionUpdated(const QGeoPositionInfo &info)
{
if (info.isValid())
{
m_position = info;
if (m_settings.getAutoUpdatePosition())
{
m_settings.setLatitude(m_position.coordinate().latitude());
m_settings.setLongitude(m_position.coordinate().longitude());
m_settings.setAltitude(m_position.coordinate().altitude());
}
}
}

View File

@ -25,6 +25,7 @@
#include <QElapsedTimer>
#include <QDateTime>
#include <QObject>
#include <QGeoPositionInfo>
#include "export.h"
#include "settings/mainsettings.h"
@ -38,6 +39,7 @@ class FeatureSet;
class Feature;
class PluginManager;
class MessageQueue;
class QGeoPositionInfoSource;
namespace qtwebapp {
class LoggerWithFile;
@ -846,7 +848,7 @@ public:
qint64 getStartMsecsSinceEpoch() const { return m_startMsecsSinceEpoch; } //!< Epoch timestamp in millisecodns close to elapsed timer start
const MainSettings& getSettings() const { return m_settings; }
MessageQueue *getMainMessageQueue() { return m_mainMessageQueue; }
const PluginManager *getPluginManager() const { return m_pluginManager; }
PluginManager *getPluginManager() const { return m_pluginManager; }
std::vector<DeviceSet*>& getDeviceSets() { return m_deviceSets; }
std::vector<FeatureSet*>& getFeatureeSets() { return m_featureSets; }
void setLoggingOptions();
@ -875,6 +877,8 @@ public:
// pipes
MessagePipes& getMessagePipes() { return m_messagePipes; }
DataPipes& getDataPipes() { return m_dataPipes; }
// Position
const QGeoPositionInfo& getPosition() const;
friend class MainServer;
friend class MainWindow;
@ -883,6 +887,9 @@ public:
friend class DeviceSetPresetsDialog;
friend class ConfigurationsDialog;
public slots:
void positionUpdated(const QGeoPositionInfo &info);
signals:
void deviceSetAdded(int index, DeviceAPI *device);
void deviceChanged(int index);
@ -912,7 +919,10 @@ private:
PluginManager* m_pluginManager;
MessagePipes m_messagePipes;
DataPipes m_dataPipes;
QGeoPositionInfoSource *m_positionSource;
QGeoPositionInfo m_position;
void initPosition();
void debugMaps();
};

View File

@ -66,6 +66,7 @@ public:
int deviceNbItems; //!< Number of items (or streams) in the device. >1 for composite devices.
int deviceItemIndex; //!< For composite devices this is the Rx or Tx stream index. -1 if not initialized
int claimed; //!< This is the device set index if claimed else -1
bool removed; //!< Set if device has been removed
SamplingDevice(const QString& _displayedName,
const QString& _hardwareId,
@ -85,8 +86,17 @@ public:
streamType(_streamType),
deviceNbItems(_deviceNbItems),
deviceItemIndex(_deviceItemIndex),
claimed(-1)
claimed(-1),
removed(false)
{ }
bool operator==(const SamplingDevice& rhs) const
{
return displayedName == rhs.displayedName
&& hardwareId == rhs.hardwareId
&& id == rhs.id
&& serial == rhs.serial;
}
};
typedef QList<SamplingDevice> SamplingDevices;

View File

@ -151,6 +151,12 @@ public:
emit preferenceChanged(Preferences::Altitude);
}
bool getAutoUpdatePosition() const { return m_preferences.getAutoUpdatePosition(); }
void setAutoUpdatePosition(bool autoUpdatePosition)
{
m_preferences.setAutoUpdatePosition(autoUpdatePosition);
}
QtMsgType getConsoleMinLogLevel() const { return m_preferences.getConsoleMinLogLevel(); }
void setConsoleMinLogLevel(const QtMsgType& minLogLevel)
{

View File

@ -17,6 +17,7 @@ void Preferences::resetToDefaults()
m_latitude = 49.012423; // Set an interesting location so map doesn't open up in the middle of the ocean
m_longitude = 8.418125;
m_altitude = 0.0f;
m_autoUpdatePosition = true;
m_useLogFile = false;
m_logFileName = "sdrangel.log";
m_consoleMinLogLevel = QtDebugMsg;
@ -41,6 +42,7 @@ QByteArray Preferences::serialize() const
s.writeFloat((int) Altitude, m_altitude);
s.writeS32((int) SourceItemIndex, m_sourceItemIndex);
s.writeS32((int) Multisampling, m_multisampling);
s.writeBool((int) AutoUpdatePosition, m_autoUpdatePosition);
return s.final();
}
@ -95,9 +97,11 @@ bool Preferences::deserialize(const QByteArray& data)
}
d.readS32((int) Multisampling, &m_multisampling, 0);
d.readBool((int) AutoUpdatePosition, &m_autoUpdatePosition, true);
return true;
} else
}
else
{
resetToDefaults();
return false;

View File

@ -22,7 +22,8 @@ public:
StationName,
Altitude,
SourceItemIndex,
Multisampling
Multisampling,
AutoUpdatePosition
};
Preferences();
@ -60,6 +61,9 @@ public:
float getAltitude() const { return m_altitude; }
void setAltitude(float altitude) { m_altitude = altitude; }
bool getAutoUpdatePosition() const { return m_autoUpdatePosition; }
void setAutoUpdatePosition(bool autoUpdatePosition) { m_autoUpdatePosition = autoUpdatePosition; }
QtMsgType getConsoleMinLogLevel() const { return m_consoleMinLogLevel; }
void setConsoleMinLogLevel(const QtMsgType& minLogLevel) { m_consoleMinLogLevel = minLogLevel; }
@ -87,6 +91,7 @@ protected:
float m_latitude; //!< Position of the station
float m_longitude;
float m_altitude; //!< Altitude in metres
bool m_autoUpdatePosition; //!< Automatically update position from GPS
QtMsgType m_consoleMinLogLevel;
QtMsgType m_fileMinLogLevel;

213
sdrbase/util/android.cpp Normal file
View File

@ -0,0 +1,213 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2022 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 //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifdef ANDROID
#include <QDebug>
#include <android/log.h>
#include "android.h"
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
#include <QtCore/private/qandroidextras_p.h>
#include <QJniObject>
#include <QJniEnvironment>
void Android::sendIntent()
{
QJniObject url = QJniObject::fromString("iqsrc://-f 1090000000 -p 1234 -s 2000000 -a 127.0.0.1 -g 100");
QJniObject intent = QJniObject::callStaticObjectMethod("android/content/Intent", "parseUri", "(Ljava/lang/String;I)Landroid/content/Intent;", url.object<jstring>(), 0x00000001); // Creates Intent(ACTION_VIEW, url)
QtAndroidPrivate::startActivity(intent, 0, [](int requestCode, int resultCode, const QJniObject &data) {
(void) data;
qDebug() << "MainCore::sendIntent " << requestCode << resultCode;
});
}
QStringList Android::listUSBDeviceSerials(int vid, int pid)
{
QStringList serials;
QJniEnvironment jniEnv;
QJniObject activity = QJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;");
if (activity.isValid())
{
QJniObject serialsObj = activity.callObjectMethod("listUSBDeviceSerials", "(II)[Ljava/lang/String;", vid, pid);
int serialsLen = jniEnv->GetArrayLength(serialsObj.object<jarray>());
for (int i = 0; i < serialsLen; i++)
{
QJniObject arrayElement = jniEnv->GetObjectArrayElement(serialsObj.object<jobjectArray>(), i);
QString serial = arrayElement.toString();
serials.append(serial);
}
}
return serials;
}
int Android::openUSBDevice(const QString &serial)
{
int fd = -1;
QJniObject activity = QJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;");
if (activity.isValid())
{
QJniObject serialsObj = QJniObject::fromString(serial);
fd = activity.callMethod<jint>("openUSBDevice", "(Ljava/lang/String;)I", serialsObj.object<jstring>());
}
return fd;
}
void Android::closeUSBDevice(int fd)
{
if (fd >= 0)
{
QJniObject activity = QJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;");
if (activity.isValid()) {
activity.callMethod<void>("closeUSBDevice", "(I)V", fd);
} else {
qCritical() << "MainCore::closeUSBDevice: activity is not valid.";
}
}
}
void Android::moveTaskToBack()
{
QJniObject activity = QJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;");
if (activity.isValid()) {
activity.callMethod<jboolean>("moveTaskToBack", "(Z)Z", true);
}
}
#else // QT_VERSION
#include <QtAndroid>
#include <QAndroidIntent>
#include <QAndroidJniObject>
#include <QAndroidJniEnvironment>
#include <QAndroidActivityResultReceiver>
void Android::sendIntent()
{
QAndroidJniObject url = QAndroidJniObject::fromString("iqsrc://-f 1090000000 -p 1234 -s 2000000 -a 127.0.0.1 -g 100");
QAndroidJniObject intent = QAndroidJniObject::callStaticObjectMethod("android/content/Intent", "parseUri", "(Ljava/lang/String;I)Landroid/content/Intent;", url.object<jstring>(), 0x00000001); // Creates Intent(ACTION_VIEW, url)
QtAndroid::startActivity(intent, 0, [](int requestCode, int resultCode, const QAndroidJniObject &data) {
(void) data;
qDebug() << "MainCore::sendIntent " << requestCode << resultCode;
});
}
QStringList Android::listUSBDeviceSerials(int vid, int pid)
{
QStringList serials;
QAndroidJniEnvironment jniEnv;
QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;");
if (activity.isValid())
{
QAndroidJniObject serialsObj = activity.callObjectMethod("listUSBDeviceSerials", "(II)[Ljava/lang/String;", vid, pid);
int serialsLen = jniEnv->GetArrayLength(serialsObj.object<jarray>());
for (int i = 0; i < serialsLen; i++)
{
QAndroidJniObject arrayElement = jniEnv->GetObjectArrayElement(serialsObj.object<jobjectArray>(), i);
QString serial = arrayElement.toString();
serials.append(serial);
}
}
return serials;
}
int Android::openUSBDevice(const QString &serial)
{
int fd = -1;
QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;");
if (activity.isValid())
{
QAndroidJniObject serialsObj = QAndroidJniObject::fromString(serial);
fd = activity.callMethod<jint>("openUSBDevice", "(Ljava/lang/String;)I", serialsObj.object<jstring>());
}
return fd;
}
void Android::closeUSBDevice(int fd)
{
if (fd >= 0)
{
QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;");
if (activity.isValid()) {
activity.callMethod<void>("closeUSBDevice", "(I)V", fd);
} else {
qCritical() << "MainCore::closeUSBDevice: activity is not valid.";
}
}
}
void Android::moveTaskToBack()
{
QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;");
if (activity.isValid()) {
activity.callMethod<jboolean>("moveTaskToBack", "(Z)Z", true);
}
}
#endif // QT6
// Redirect qDebug/qWarning to Android log, so we can view remotely with adb
void Android::messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg)
{
QString report = msg;
if (context.file && !QString(context.file).isEmpty())
{
report += " in file ";
report += QString(context.file);
report += " line ";
report += QString::number(context.line);
}
if (context.function && !QString(context.function).isEmpty())
{
report += +" function ";
report += QString(context.function);
}
const char * const local = report.toLocal8Bit().constData();
const char * const applicationName = "sdrangel";
switch (type)
{
case QtDebugMsg:
__android_log_write(ANDROID_LOG_DEBUG, applicationName, local);
break;
case QtInfoMsg:
__android_log_write(ANDROID_LOG_INFO, applicationName, local);
break;
case QtWarningMsg:
__android_log_write(ANDROID_LOG_WARN, applicationName, local);
break;
case QtCriticalMsg:
__android_log_write(ANDROID_LOG_ERROR, applicationName, local);
break;
case QtFatalMsg:
default:
__android_log_write(ANDROID_LOG_FATAL, applicationName, local);
abort();
}
}
#endif // ANDROID

44
sdrbase/util/android.h Normal file
View File

@ -0,0 +1,44 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2022 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 //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef SDRBASE_ANDROID_H_
#define SDRBASE_ANDROID_H_
#ifdef ANDROID
#include <QtGlobal>
#include <QString>
#include "export.h"
// Android specific functions
class SDRBASE_API Android
{
public:
static void sendIntent();
static QStringList listUSBDeviceSerials(int vid, int pid);
static int openUSBDevice(const QString &serial);
static void closeUSBDevice(int fd);
static void moveTaskToBack();
static void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg);
};
#endif // ANDROID
#endif // SDRBASE_ANDROID_H_

View File

@ -27,11 +27,26 @@
#include "settings/configuration.h"
ConfigurationsDialog::ConfigurationsDialog(QWidget* parent) :
ConfigurationsDialog::ConfigurationsDialog(bool openOnly, QWidget* parent) :
QDialog(parent),
ui(new Ui::ConfigurationsDialog)
{
ui->setupUi(this);
if (openOnly)
{
ui->buttonBox->setStandardButtons(QDialogButtonBox::Close | QDialogButtonBox::Open);
ui->configurationDelete->setVisible(false);
ui->configurationEdit->setVisible(false);
ui->configurationExport->setVisible(false);
ui->configurationImport->setVisible(false);
ui->configurationLoad->setVisible(false);
ui->configurationSave->setVisible(false);
ui->configurationUpdate->setVisible(false);
}
else
{
ui->description->setVisible(false);
}
}
ConfigurationsDialog::~ConfigurationsDialog()
@ -354,9 +369,7 @@ void ConfigurationsDialog::on_configurationExport_clicked()
tr("Open preset export file"),
".",
tr("Configuration export files (*.cfgx)"),
0,
QFileDialog::DontUseNativeDialog
);
0);
if (fileName != "")
{
@ -404,8 +417,7 @@ void ConfigurationsDialog::on_configurationImport_clicked()
tr("Open preset export file"),
".",
tr("Preset export files (*.cfgx)"),
0,
QFileDialog::DontUseNativeDialog
0
);
if (fileName != "")
@ -497,3 +509,9 @@ void ConfigurationsDialog::deleteConfigurationGroup(const QString& groupName)
}
}
}
void ConfigurationsDialog::accept()
{
on_configurationLoad_clicked();
QDialog::accept();
}

View File

@ -38,7 +38,7 @@ namespace Ui {
class SDRGUI_API ConfigurationsDialog : public QDialog {
Q_OBJECT
public:
explicit ConfigurationsDialog(QWidget* parent = nullptr);
explicit ConfigurationsDialog(bool openOnly, QWidget* parent = nullptr);
~ConfigurationsDialog();
void setConfigurations(QList<Configuration*>* configurations) { m_configurations = configurations; }
void populateTree();
@ -71,6 +71,7 @@ private slots:
void on_configurationLoad_clicked();
void on_configurationTree_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous);
void on_configurationTree_itemActivated(QTreeWidgetItem *item, int column);
void accept() override;
signals:
void saveConfiguration(Configuration*);

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>392</width>
<height>414</height>
<width>410</width>
<height>424</height>
</rect>
</property>
<property name="font">
@ -19,218 +19,207 @@
<property name="windowTitle">
<string>Configurations</string>
</property>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="geometry">
<rect>
<x>40</x>
<y>380</y>
<width>341</width>
<height>32</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
<widget class="QWidget" name="widget" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>10</y>
<width>392</width>
<height>310</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTreeWidget" name="configurationsTree">
<property name="toolTip">
<string>List of configurations</string>
</property>
<property name="indentation">
<number>5</number>
</property>
<property name="allColumnsShowFocus">
<bool>true</bool>
</property>
<property name="columnCount">
<number>1</number>
</property>
<attribute name="headerMinimumSectionSize">
<number>5</number>
</attribute>
<column>
<property name="text">
<string>Description</string>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QWidget" name="widget" native="true">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="description">
<property name="text">
<string>Select configuration to load:</string>
</property>
</widget>
</item>
<item>
<widget class="QTreeWidget" name="configurationsTree">
<property name="toolTip">
<string>List of configurations</string>
</property>
<property name="indentation">
<number>5</number>
</property>
<property name="allColumnsShowFocus">
<bool>true</bool>
</property>
<property name="columnCount">
<number>1</number>
</property>
<attribute name="headerMinimumSectionSize">
<number>5</number>
</attribute>
<column>
<property name="text">
<string>Description</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="configurationsControl">
<item>
<widget class="QToolButton" name="configurationSave">
<property name="toolTip">
<string>Save current workspaces configuration as new configuration</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>330</y>
<width>392</width>
<height>34</height>
</rect>
</property>
<layout class="QHBoxLayout" name="configurationsControl">
<item>
<widget class="QToolButton" name="configurationSave">
<property name="toolTip">
<string>Save current workspaces configuration as new configuration</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../resources/res.qrc">
<normaloff>:/create.png</normaloff>:/create.png</iconset>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="configurationUpdate">
<property name="toolTip">
<string>Update selected configuration with current workspaces configuration</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../resources/res.qrc">
<normaloff>:/recycle.png</normaloff>:/recycle.png</iconset>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="configurationEdit">
<property name="toolTip">
<string>Edit configuration details</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../resources/res.qrc">
<normaloff>:/edit.png</normaloff>:/edit.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="configurationExport">
<property name="toolTip">
<string>Export current configuration to file</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../resources/res.qrc">
<normaloff>:/export.png</normaloff>:/export.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="configurationImport">
<property name="toolTip">
<string>Import configuration from file into current group</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../resources/res.qrc">
<normaloff>:/import.png</normaloff>:/import.png</iconset>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="configurationDelete">
<property name="toolTip">
<string>Delete selected configuration</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../resources/res.qrc">
<normaloff>:/bin.png</normaloff>:/bin.png</iconset>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="configurationLoad">
<property name="toolTip">
<string>Load selected configuration</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../resources/res.qrc">
<normaloff>:/load.png</normaloff>:/load.png</iconset>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../resources/res.qrc">
<normaloff>:/create.png</normaloff>:/create.png</iconset>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="configurationUpdate">
<property name="toolTip">
<string>Update selected configuration with current workspaces configuration</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../resources/res.qrc">
<normaloff>:/recycle.png</normaloff>:/recycle.png</iconset>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="configurationEdit">
<property name="toolTip">
<string>Edit configuration details</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../resources/res.qrc">
<normaloff>:/edit.png</normaloff>:/edit.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="configurationExport">
<property name="toolTip">
<string>Export current configuration to file</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../resources/res.qrc">
<normaloff>:/export.png</normaloff>:/export.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="configurationImport">
<property name="toolTip">
<string>Import configuration from file into current group</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../resources/res.qrc">
<normaloff>:/import.png</normaloff>:/import.png</iconset>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="configurationDelete">
<property name="toolTip">
<string>Delete selected configuration</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../resources/res.qrc">
<normaloff>:/bin.png</normaloff>:/bin.png</iconset>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="configurationLoad">
<property name="toolTip">
<string>Load selected configuration</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../resources/res.qrc">
<normaloff>:/load.png</normaloff>:/load.png</iconset>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../resources/res.qrc"/>

View File

@ -292,8 +292,7 @@ void DeviceSetPresetsDialog::on_presetExport_clicked()
tr("Open preset export file"),
".",
tr("Preset export files (*.prex)"),
0,
QFileDialog::DontUseNativeDialog
0
);
if (fileName != "")
@ -342,8 +341,7 @@ void DeviceSetPresetsDialog::on_presetImport_clicked()
tr("Open preset export file"),
".",
tr("Preset export files (*.prex)"),
0,
QFileDialog::DontUseNativeDialog
0
);
if (fileName != "")

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>324</width>
<height>229</height>
<height>201</height>
</rect>
</property>
<property name="font">
@ -19,44 +19,24 @@
<property name="windowTitle">
<string>My Position</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>My Station Position</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="2" column="0">
<widget class="QLabel" name="latitudeLabel">
<property name="text">
<string>Latitude</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="longitudeLabel">
<property name="text">
<string>Longitude</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QDoubleSpinBox" name="longitudeSpinBox">
<property name="toolTip">
<string>Longitude in decimal degrees</string>
</property>
<property name="decimals">
<number>6</number>
</property>
<property name="minimum">
<double>-180.000000000000000</double>
</property>
<property name="maximum">
<double>180.000000000000000</double>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="latitudeSpinBox">
<property name="toolTip">
<string>Latitude in decimal degrees</string>
@ -72,24 +52,14 @@
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="altitudeSpinBox">
<property name="toolTip">
<string>Altitude in metres</string>
</property>
<property name="maximum">
<number>50000</number>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="altitudeLabel">
<item row="1" column="0">
<widget class="QLabel" name="latitudeLabel">
<property name="text">
<string>Altitude (m)</string>
<string>Latitude</string>
</property>
</widget>
</item>
<item row="0" column="1">
<item row="0" column="1" colspan="2">
<widget class="QLineEdit" name="name">
<property name="toolTip">
<string>Enter the name of your station</string>
@ -99,6 +69,20 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="altitudeLabel">
<property name="text">
<string>Altitude (m)</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="longitudeLabel">
<property name="text">
<string>Longitude</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="nameLabel">
<property name="text">
@ -106,19 +90,66 @@
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QCheckBox" name="autoUpdatePosition">
<property name="toolTip">
<string>Automatically update position using GPS (when available)</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="longitudeSpinBox">
<property name="toolTip">
<string>Longitude in decimal degrees</string>
</property>
<property name="decimals">
<number>6</number>
</property>
<property name="minimum">
<double>-180.000000000000000</double>
</property>
<property name="maximum">
<double>180.000000000000000</double>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="autoUpdatePositionLabel">
<property name="text">
<string>Auto-update from GPS</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QToolButton" name="gps">
<property name="toolTip">
<string>Set position using GPS (if available)</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../resources/res.qrc">
<normaloff>:/gps.png</normaloff>:/gps.png</iconset>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="altitudeSpinBox">
<property name="toolTip">
<string>Altitude in metres</string>
</property>
<property name="maximum">
<number>50000</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
@ -127,7 +158,9 @@
<tabstop>longitudeSpinBox</tabstop>
<tabstop>altitudeSpinBox</tabstop>
</tabstops>
<resources/>
<resources>
<include location="../resources/res.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>

View File

@ -2,9 +2,6 @@
// Copyright (C) 2016 F4EXB //
// written by Edouard Griffiths //
// //
// OpenGL interface modernization. //
// See: http://doc.qt.io/qt-5/qopenglshaderprogram.html //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
@ -21,7 +18,9 @@
#include "gui/mypositiondialog.h"
#include "ui_myposdialog.h"
#include "maincore.h"
#include <QGeoCoordinate>
MyPositionDialog::MyPositionDialog(MainSettings& mainSettings, QWidget* parent) :
QDialog(parent),
@ -33,6 +32,7 @@ MyPositionDialog::MyPositionDialog(MainSettings& mainSettings, QWidget* parent)
ui->latitudeSpinBox->setValue(m_mainSettings.getLatitude());
ui->longitudeSpinBox->setValue(m_mainSettings.getLongitude());
ui->altitudeSpinBox->setValue(m_mainSettings.getAltitude());
ui->autoUpdatePosition->setChecked(m_mainSettings.getAutoUpdatePosition());
}
MyPositionDialog::~MyPositionDialog()
@ -46,5 +46,22 @@ void MyPositionDialog::accept()
m_mainSettings.setLatitude(ui->latitudeSpinBox->value());
m_mainSettings.setLongitude(ui->longitudeSpinBox->value());
m_mainSettings.setAltitude(ui->altitudeSpinBox->value());
m_mainSettings.setAutoUpdatePosition(ui->autoUpdatePosition->isChecked());
QDialog::accept();
}
void MyPositionDialog::on_gps_clicked()
{
const QGeoPositionInfo& position = MainCore::instance()->getPosition();
if (position.isValid())
{
QGeoCoordinate coord = position.coordinate();
ui->latitudeSpinBox->setValue(coord.latitude());
ui->longitudeSpinBox->setValue(coord.longitude());
ui->altitudeSpinBox->setValue(coord.altitude());
}
else
{
qDebug() << "MyPositionDialog::on_gps_clicked: Position is not valid.";
}
}

View File

@ -2,9 +2,6 @@
// Copyright (C) 2016 F4EXB //
// written by Edouard Griffiths //
// //
// OpenGL interface modernization. //
// See: http://doc.qt.io/qt-5/qopenglshaderprogram.html //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
@ -43,6 +40,7 @@ private:
private slots:
void accept();
void on_gps_clicked();
};
#endif /* SDRBASE_GUI_MYPOSITIONDIALOG_H_ */

View File

@ -22,7 +22,7 @@
#include "samplingdevicedialog.h"
#include "ui_samplingdevicedialog.h"
#include "device/deviceenumerator.h"
#include "maincore.h"
SamplingDeviceDialog::SamplingDeviceDialog(int deviceType, QWidget* parent) :
QDialog(parent),
@ -32,19 +32,7 @@ SamplingDeviceDialog::SamplingDeviceDialog(int deviceType, QWidget* parent) :
m_hasChanged(false)
{
ui->setupUi(this);
QList<QString> deviceDisplayNames;
if (m_deviceType == 0) { // Single Rx
DeviceEnumerator::instance()->listRxDeviceNames(deviceDisplayNames, m_deviceIndexes);
} else if (m_deviceType == 1) { // Single Tx
DeviceEnumerator::instance()->listTxDeviceNames(deviceDisplayNames, m_deviceIndexes);
} else if (m_deviceType == 2) { // MIMO
DeviceEnumerator::instance()->listMIMODeviceNames(deviceDisplayNames, m_deviceIndexes);
}
QStringList devicesNamesList(deviceDisplayNames);
ui->deviceSelect->addItems(devicesNamesList);
on_refreshDevices_clicked();
}
SamplingDeviceDialog::~SamplingDeviceDialog()
@ -58,6 +46,23 @@ int SamplingDeviceDialog::exec()
return QDialog::exec();
}
void SamplingDeviceDialog::displayDevices()
{
QList<QString> deviceDisplayNames;
m_deviceIndexes.clear();
if (m_deviceType == 0) { // Single Rx
DeviceEnumerator::instance()->listRxDeviceNames(deviceDisplayNames, m_deviceIndexes);
} else if (m_deviceType == 1) { // Single Tx
DeviceEnumerator::instance()->listTxDeviceNames(deviceDisplayNames, m_deviceIndexes);
} else if (m_deviceType == 2) { // MIMO
DeviceEnumerator::instance()->listMIMODeviceNames(deviceDisplayNames, m_deviceIndexes);
}
ui->deviceSelect->clear();
ui->deviceSelect->addItems(deviceDisplayNames);
}
void SamplingDeviceDialog::setSelectedDeviceIndex(int deviceIndex)
{
ui->deviceSelect->blockSignals(true);
@ -77,6 +82,21 @@ void SamplingDeviceDialog::on_deviceSelect_currentIndexChanged(int index)
m_hasChanged = true;
}
void SamplingDeviceDialog::on_refreshDevices_clicked()
{
PluginManager *pluginManager = MainCore::instance()->getPluginManager();
if (m_deviceType == 0) {
DeviceEnumerator::instance()->enumerateRxDevices(pluginManager);
} else if (m_deviceType == 1) {
DeviceEnumerator::instance()->enumerateTxDevices(pluginManager);
} else if (m_deviceType == 2) {
DeviceEnumerator::instance()->enumerateMIMODevices(pluginManager);
}
displayDevices();
}
void SamplingDeviceDialog::accept()
{
m_selectedDeviceIndex = m_deviceIndexes[ui->deviceSelect->currentIndex()];

View File

@ -50,8 +50,11 @@ private:
std::vector<int> m_deviceIndexes;
bool m_hasChanged;
void displayDevices();
private slots:
void on_deviceSelect_currentIndexChanged(int index);
void on_refreshDevices_clicked();
void accept();
void reject();
};

View File

@ -31,8 +31,8 @@
<property name="title">
<string>Select from list</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QComboBox" name="deviceSelect">
<property name="font">
<font>
@ -42,6 +42,20 @@
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="refreshDevices">
<property name="toolTip">
<string>Refresh list of devices</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../resources/res.qrc">
<normaloff>:/recycle.png</normaloff>:/recycle.png</iconset>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@ -66,7 +80,9 @@
<tabstops>
<tabstop>buttonBox</tabstop>
</tabstops>
<resources/>
<resources>
<include location="../resources/res.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>

View File

@ -18,7 +18,9 @@
#include <QInputDialog>
#include <QMessageBox>
#include <QProgressDialog>
#include <QLabel>
#include <QToolButton>
#include <QFile>
#include <QFileInfo>
#include <QFileDialog>
@ -31,10 +33,11 @@
#include <QStandardPaths>
#include <QDesktopServices>
#include <QProcess>
#include <QDirIterator>
#include <QAction>
#include <QMenuBar>
#include <QStatusBar>
#include <QScreen>
#include "device/devicegui.h"
#include "device/deviceapi.h"
@ -68,6 +71,8 @@
#include "gui/devicesetpresetsdialog.h"
#include "gui/commandsdialog.h"
#include "gui/configurationsdialog.h"
#include "gui/dialogpositioner.h"
#include "gui/welcomedialog.h"
#include "dsp/dspengine.h"
#include "dsp/spectrumvis.h"
#include "dsp/dspcommands.h"
@ -85,6 +90,9 @@
#include "webapi/webapiserver.h"
#include "webapi/webapiadapter.h"
#include "commands/command.h"
#ifdef ANDROID
#include "util/android.h"
#endif
#include "mainwindow.h"
@ -107,9 +115,13 @@ MainWindow::MainWindow(qtwebapp::LoggerWithFile *logger, const MainParser& parse
m_mainCore(MainCore::instance()),
m_dspEngine(DSPEngine::instance()),
m_lastEngineState(DeviceAPI::StNotStarted),
m_dateTimeWidget(nullptr),
m_showSystemWidget(nullptr),
m_commandKeyReceiver(nullptr),
m_fftWisdomProcess(nullptr)
{
bool showWelcome = ANDROID;
qDebug() << "MainWindow::MainWindow: start";
setWindowTitle("SDRangel");
@ -134,10 +146,21 @@ MainWindow::MainWindow(qtwebapp::LoggerWithFile *logger, const MainParser& parse
splash->showStatusMessage("starting...", Qt::white);
setWindowIcon(QIcon(":/sdrangel_icon.png"));
createMenuBar();
createStatusBar();
#ifndef ANDROID
// To save screen space on Android, don't have menu bar. Instead menus are accessed via toolbar button
createMenuBar(nullptr);
createStatusBar();
#endif
#ifdef ANDROID
if (screen()->isLandscape(screen()->primaryOrientation())) {
setTabPosition(Qt::LeftDockWidgetArea, QTabWidget::West);
} else {
setTabPosition(Qt::LeftDockWidgetArea, QTabWidget::South);
}
#else
setTabPosition(Qt::LeftDockWidgetArea, QTabWidget::West);
#endif
setTabPosition(Qt::RightDockWidgetArea, QTabWidget::East);
setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
@ -146,6 +169,12 @@ MainWindow::MainWindow(qtwebapp::LoggerWithFile *logger, const MainParser& parse
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleMessages()), Qt::QueuedConnection);
connect(screen(), &QScreen::orientationChanged, this, &MainWindow::orientationChanged);
screen()->setOrientationUpdateMask(Qt::PortraitOrientation
| Qt::LandscapeOrientation
| Qt::InvertedPortraitOrientation
| Qt::InvertedLandscapeOrientation);
connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus()));
m_statusTimer.start(1000);
@ -209,6 +238,16 @@ MainWindow::MainWindow(qtwebapp::LoggerWithFile *logger, const MainParser& parse
{
qDebug() << "MainWindow::MainWindow: no or empty current configuration, creating empty workspace...";
addWorkspace();
// If no configurations, load some basic examples
if (m_mainCore->m_settings.getConfigurations().size() == 0) {
loadDefaultConfigurations();
}
}
else
{
// Only show welcome dialog first time program is run
showWelcome = false;
}
}
@ -240,6 +279,16 @@ MainWindow::MainWindow(qtwebapp::LoggerWithFile *logger, const MainParser& parse
restoreGeometry(qUncompress(QByteArray::fromBase64(s.value("mainWindowGeometry").toByteArray())));
restoreState(qUncompress(QByteArray::fromBase64(s.value("mainWindowState").toByteArray())));
if (showWelcome)
{
// Show welcome dialog
WelcomeDialog welcomeDialog(this);
new DialogPositioner(&welcomeDialog, true);
welcomeDialog.exec();
// Show configurations
openConfigurationDialog(true);
}
qDebug() << "MainWindow::MainWindow: end";
}
@ -340,6 +389,11 @@ void MainWindow::sampleSourceAdd(Workspace *deviceWorkspace, Workspace *spectrum
deviceWorkspace->addToMdiArea(m_deviceUIs.back()->m_deviceGUI);
spectrumWorkspace->addToMdiArea(m_deviceUIs.back()->m_mainSpectrumGUI);
emit m_mainCore->deviceSetAdded(deviceSetIndex, deviceAPI);
#ifdef ANDROID
// Seemingly needed on some versions of Android, otherwise the new windows aren't always displayed??
deviceWorkspace->repaint();
#endif
}
void MainWindow::sampleSourceCreate(
@ -1165,7 +1219,9 @@ void MainWindow::loadSettings()
m_mainCore->m_settings.load();
m_mainCore->m_settings.sortPresets();
m_mainCore->m_settings.sortCommands();
m_mainCore->setLoggingOptions();
if (m_mainCore->m_logger) {
m_mainCore->setLoggingOptions();
}
}
void MainWindow::loadDeviceSetPresetSettings(const Preset* preset, int deviceSetIndex)
@ -1230,6 +1286,59 @@ void MainWindow::saveFeatureSetPresetSettings(FeatureSetPreset* preset, int feat
featureUI->saveFeatureSetSettings(preset);
}
void MainWindow::loadDefaultConfigurations()
{
QDirIterator configurationsIt(":configurations", QDirIterator::Subdirectories);
while (configurationsIt.hasNext())
{
QString group = configurationsIt.next();
QDirIterator groupIt(group, {"*.cfgx"}, QDir::Files);
while (groupIt.hasNext())
{
QFile file(groupIt.next());
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
{
QByteArray base64Str;
QTextStream instream(&file);
instream >> base64Str;
file.close();
Configuration* configuration = MainCore::instance()->m_settings.newConfiguration("", "");
configuration->deserialize(QByteArray::fromBase64(base64Str));
}
else
{
qDebug() << "MainWindow::loadDefaultConfigurations: Failed to open configuration " << file.fileName();
}
}
}
QDirIterator presetIt(":presets", QDirIterator::Subdirectories);
while (presetIt.hasNext())
{
QString group = presetIt.next();
QDirIterator groupIt(group, {"*.prex"}, QDir::Files);
while (groupIt.hasNext())
{
QFile file(groupIt.next());
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
{
QByteArray base64Str;
QTextStream instream(&file);
instream >> base64Str;
file.close();
Preset* preset = MainCore::instance()->m_settings.newPreset("", "");
preset->deserialize(QByteArray::fromBase64(base64Str));
}
else
{
qDebug() << "MainWindow::loadDefaultConfigurations: Failed to open preset " << file.fileName();
}
}
}
}
void MainWindow::loadConfiguration(const Configuration *configuration, bool fromDialog)
{
qDebug("MainWindow::loadConfiguration: configuration [%s | %s] %d workspace(s) - %d device set(s) - %d feature(s)",
@ -1240,23 +1349,24 @@ void MainWindow::loadConfiguration(const Configuration *configuration, bool from
configuration->getFeatureSetPreset().getFeatureCount()
);
QMessageBox *waitBox = nullptr;
QProgressDialog *waitBox = nullptr;
if (fromDialog)
{
waitBox = new QMessageBox(this);
waitBox->setStandardButtons(QMessageBox::NoButton);
waitBox->setWindowModality(Qt::NonModal);
waitBox->setIcon(QMessageBox::Information);
waitBox->setText("Loading configuration ");
waitBox->setInformativeText("Deleting existing...");
waitBox->setWindowTitle("Please wait");
waitBox->show();
waitBox->raise();
waitBox = new QProgressDialog("Loading configuration...", "", 0, 100, this);
waitBox->setWindowModality(Qt::WindowModal);
waitBox->setAttribute(Qt::WA_DeleteOnClose, true);
waitBox->setMinimumDuration(0);
waitBox->setCancelButton(nullptr);
waitBox->setValue(1);
}
// Wipe out everything first
if (waitBox)
{
waitBox->setLabelText("Deleting existing...");
waitBox->setValue(5);
}
// Device sets
while (m_deviceUIs.size() > 0) {
removeLastDeviceSet();
@ -1276,6 +1386,7 @@ void MainWindow::loadConfiguration(const Configuration *configuration, bool from
{
addWorkspace();
m_workspaces[i]->setAutoStackOption(configuration->getWorkspaceAutoStackOptions()[i]);
m_workspaces[i]->setTabSubWindowsOption(configuration->getWorkspaceTabSubWindowsOptions()[i]);
}
if (m_workspaces.size() <= 0) { // cannot go further if there are no workspaces
@ -1283,8 +1394,10 @@ void MainWindow::loadConfiguration(const Configuration *configuration, bool from
}
// Device sets
if (waitBox) {
waitBox->setInformativeText("Loading device sets...");
if (waitBox)
{
waitBox->setLabelText("Loading device sets...");
waitBox->setValue(25);
}
const QList<Preset>& deviceSetPresets = configuration->getDeviceSetPresets();
@ -1354,11 +1467,17 @@ void MainWindow::loadConfiguration(const Configuration *configuration, bool from
m_deviceUIs.back()->m_deviceGUI->restoreGeometry(deviceSetPreset.getDeviceGeometry());
m_deviceUIs.back()->m_mainSpectrumGUI->restoreGeometry(deviceSetPreset.getSpectrumGeometry());
m_deviceUIs.back()->loadDeviceSetSettings(&deviceSetPreset, m_pluginManager->getPluginAPI(), &m_workspaces, nullptr);
if (waitBox) {
waitBox->setValue(waitBox->value() + 50/deviceSetPresets.size());
}
}
// Features
if (waitBox) {
waitBox->setInformativeText("Loading device sets...");
if (waitBox)
{
waitBox->setLabelText("Loading feature sets...");
waitBox->setValue(75);
}
m_featureUIs[0]->loadFeatureSetSettings(
@ -1381,8 +1500,10 @@ void MainWindow::loadConfiguration(const Configuration *configuration, bool from
}
// Lastly restore workspaces geometry
if (waitBox) {
waitBox->setInformativeText("Finalizing...");
if (waitBox)
{
waitBox->setValue(90);
waitBox->setLabelText("Finalizing...");
}
for (int i = 0; i < configuration->getNumberOfWorkspaceGeometries(); i++)
@ -1390,12 +1511,16 @@ void MainWindow::loadConfiguration(const Configuration *configuration, bool from
m_workspaces[i]->restoreGeometry(configuration->getWorkspaceGeometries()[i]);
m_workspaces[i]->restoreGeometry(configuration->getWorkspaceGeometries()[i]);
m_workspaces[i]->adjustSubWindowsAfterRestore();
#ifdef ANDROID
// On Android, workspaces seem to be restored to 0,20, rather than 0,0
m_workspaces[i]->move(m_workspaces[i]->pos().x(), 0);
// Need to call updateGeometry, otherwise sometimes the layout is corrupted
m_workspaces[i]->updateGeometry();
#endif
}
if (waitBox)
{
waitBox->close();
delete waitBox;
if (waitBox) {
waitBox->setValue(100);
}
}
@ -1430,6 +1555,7 @@ void MainWindow::saveConfiguration(Configuration *configuration)
{
configuration->getWorkspaceGeometries().push_back(workspace->saveGeometry());
configuration->getWorkspaceAutoStackOptions().push_back(workspace->getAutoStackOption());
configuration->getWorkspaceTabSubWindowsOptions().push_back(workspace->getTabSubWindowsOption());
}
}
@ -1461,24 +1587,46 @@ QString MainWindow::openGLVersion()
}
}
void MainWindow::createMenuBar()
void MainWindow::createMenuBar(QToolButton *button)
{
QMenuBar *menuBar = this->menuBar();
QMenu *fileMenu, *viewMenu, *workspacesMenu, *preferencesMenu, *helpMenu;
if (button == nullptr)
{
QMenuBar *menuBar = this->menuBar();
fileMenu = menuBar->addMenu("&File");
viewMenu = menuBar->addMenu("&View");
workspacesMenu = menuBar->addMenu("&Workspaces");
preferencesMenu = menuBar->addMenu("&Preferences");
helpMenu = menuBar->addMenu("&Help");
}
else
{
QMenu *menu = new QMenu();
fileMenu = new QMenu("&File");
menu->addMenu(fileMenu);
viewMenu = new QMenu("&View");
menu->addMenu(viewMenu);
workspacesMenu = new QMenu("&Workspaces");
menu->addMenu(workspacesMenu);
preferencesMenu = new QMenu("&Preferences");
menu->addMenu(preferencesMenu);
helpMenu = new QMenu("&Help");
menu->addMenu(helpMenu);
button->setMenu(menu);
}
QMenu *fileMenu = menuBar->addMenu("&File");
QAction *exitAction = fileMenu->addAction("E&xit");
exitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
exitAction->setToolTip("Exit");
QObject::connect(exitAction, &QAction::triggered, this, &QMainWindow::close);
QMenu *viewMenu = menuBar->addMenu("&View");
QAction *fullscreenAction = viewMenu->addAction("&Fullscreen");
fullscreenAction->setShortcut(QKeySequence(Qt::Key_F11));
fullscreenAction->setToolTip("Toggle fullscreen view");
fullscreenAction->setCheckable(true);
QObject::connect(fullscreenAction, &QAction::triggered, this, &MainWindow::on_action_View_Fullscreen_toggled);
QMenu *workspacesMenu = menuBar->addMenu("&Workspaces");
QAction *newWorkspaceAction = workspacesMenu->addAction("&New");
newWorkspaceAction->setToolTip("Add a new workspace");
QObject::connect(newWorkspaceAction, &QAction::triggered, this, &MainWindow::addWorkspace);
@ -1489,7 +1637,6 @@ void MainWindow::createMenuBar()
removeEmptyWorkspacesAction->setToolTip("Remove empty workspaces");
QObject::connect(removeEmptyWorkspacesAction, &QAction::triggered, this, &MainWindow::removeEmptyWorkspaces);
QMenu *preferencesMenu = menuBar->addMenu("&Preferences");
QAction *configurationsAction = preferencesMenu->addAction("&Configurations...");
configurationsAction->setToolTip("Manage configurations");
QObject::connect(configurationsAction, &QAction::triggered, this, &MainWindow::on_action_Configurations_triggered);
@ -1519,7 +1666,6 @@ void MainWindow::createMenuBar()
saveAllAction->setToolTip("Save all current settings");
QObject::connect(saveAllAction, &QAction::triggered, this, &MainWindow::on_action_saveAll_triggered);
QMenu *helpMenu = menuBar->addMenu("&Help");
QAction *quickStartAction = helpMenu->addAction("&Quick start...");
quickStartAction->setToolTip("Instructions for quick start");
QObject::connect(quickStartAction, &QAction::triggered, this, &MainWindow::on_action_Quick_Start_triggered);
@ -1882,7 +2028,11 @@ void MainWindow::handleWorkspaceVisibility(Workspace *workspace, bool visibility
void MainWindow::addWorkspace()
{
int workspaceIndex = m_workspaces.size();
m_workspaces.push_back(new Workspace(workspaceIndex));
Workspace *workspace = new Workspace(workspaceIndex);
m_workspaces.push_back(workspace);
if (workspace->getMenuButton()) {
createMenuBar(workspace->getMenuButton());
}
QStringList featureNames;
m_pluginManager->listFeatures(featureNames);
m_workspaces.back()->addAvailableFeatures(featureNames);
@ -1923,6 +2073,13 @@ void MainWindow::addWorkspace()
&MainWindow::openFeaturePresetsDialog
);
QObject::connect(
m_workspaces.back(),
&Workspace::configurationPresetsDialogRequested,
this,
&MainWindow::on_action_Configurations_triggered
);
QObject::connect(
m_workspaces.back(),
&Workspace::startAllDevices,
@ -1951,7 +2108,7 @@ void MainWindow::addWorkspace()
// tabBars.back()->setStyleSheet("QTabBar::tab:selected { background: rgb(128,70,0); }"); // change text color so it is visible
// }
}
}
}
void MainWindow::viewAllWorkspaces()
{
@ -2006,6 +2163,13 @@ void MainWindow::removeEmptyWorkspaces()
}
}
}
#ifdef ANDROID
// Need at least one workspace on Android, as no menus without
if (m_workspaces.size() == 0) {
addWorkspace();
}
#endif
}
void MainWindow::on_action_View_Fullscreen_toggled(bool checked)
@ -2063,7 +2227,12 @@ void MainWindow::on_action_Loaded_Plugins_triggered()
void MainWindow::on_action_Configurations_triggered()
{
ConfigurationsDialog dialog(this);
openConfigurationDialog(false);
}
void MainWindow::openConfigurationDialog(bool openOnly)
{
ConfigurationsDialog dialog(openOnly, this);
dialog.setConfigurations(m_mainCore->m_settings.getConfigurations());
dialog.populateTree();
QObject::connect(
@ -2078,24 +2247,28 @@ void MainWindow::on_action_Configurations_triggered()
this,
[=](const Configuration* configuration) { this->loadConfiguration(configuration, true); }
);
new DialogPositioner(&dialog, true);
dialog.exec();
}
void MainWindow::on_action_Audio_triggered()
{
AudioDialogX audioDialog(m_dspEngine->getAudioDeviceManager(), this);
new DialogPositioner(&audioDialog, true);
audioDialog.exec();
}
void MainWindow::on_action_Graphics_triggered()
{
GraphicsDialog graphicsDialog(m_mainCore->m_settings, this);
new DialogPositioner(&graphicsDialog, true);
graphicsDialog.exec();
}
void MainWindow::on_action_Logging_triggered()
{
LoggingDialog loggingDialog(m_mainCore->m_settings, this);
new DialogPositioner(&loggingDialog, true);
loggingDialog.exec();
m_mainCore->setLoggingOptions();
}
@ -2103,6 +2276,7 @@ void MainWindow::on_action_Logging_triggered()
void MainWindow::on_action_My_Position_triggered()
{
MyPositionDialog myPositionDialog(m_mainCore->m_settings, this);
new DialogPositioner(&myPositionDialog, true);
myPositionDialog.exec();
}
@ -2110,6 +2284,7 @@ void MainWindow::on_action_DeviceUserArguments_triggered()
{
qDebug("MainWindow::on_action_DeviceUserArguments_triggered");
DeviceUserArgsDialog deviceUserArgsDialog(DeviceEnumerator::instance(), m_mainCore->m_settings.getDeviceUserArgs(), this);
new DialogPositioner(&deviceUserArgsDialog, true);
deviceUserArgsDialog.exec();
}
@ -2121,6 +2296,7 @@ void MainWindow::on_action_commands_triggered()
commandsDialog.setApiPort(m_apiServer->getPort());
commandsDialog.setCommandKeyReceiver(m_commandKeyReceiver);
commandsDialog.populateTree();
new DialogPositioner(&commandsDialog, true);
commandsDialog.exec();
}
@ -2140,6 +2316,7 @@ void MainWindow::on_action_FFT_triggered()
this,
SLOT(fftWisdomProcessFinished(int, QProcess::ExitStatus)));
FFTWisdomDialog fftWisdomDialog(m_fftWisdomProcess, this);
new DialogPositioner(&fftWisdomDialog, true);
if (fftWisdomDialog.exec() == QDialog::Rejected)
{
@ -2790,6 +2967,7 @@ void MainWindow::openFeaturePresetsDialog(QPoint p, Workspace *workspace)
dialog.setWorkspaces(&m_workspaces);
dialog.populateTree();
dialog.move(p);
new DialogPositioner(&dialog, true);
dialog.exec();
if (dialog.wasPresetLoaded())
@ -2820,6 +2998,7 @@ void MainWindow::openDeviceSetPresetsDialog(QPoint p, DeviceGUI *deviceGUI)
dialog.setWorkspaces(&m_workspaces);
dialog.populateTree((int) deviceGUI->getDeviceType());
dialog.move(p);
new DialogPositioner(&dialog, true);
dialog.exec();
}
@ -2840,7 +3019,9 @@ void MainWindow::on_action_About_triggered()
void MainWindow::updateStatus()
{
m_dateTimeWidget->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss t"));
if (m_dateTimeWidget) {
m_dateTimeWidget->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss t"));
}
}
void MainWindow::commandKeyPressed(Qt::Key key, Qt::KeyboardModifiers keyModifiers, bool release)
@ -2862,3 +3043,30 @@ void MainWindow::commandKeyPressed(Qt::Key key, Qt::KeyboardModifiers keyModifie
}
}
}
void MainWindow::keyPressEvent(QKeyEvent* event)
{
#ifdef ANDROID
if (event->key() == Qt::Key_Back)
{
// On Android, we don't want to exit when back key is pressed, just run in the background
Android::moveTaskToBack();
}
else
#endif
{
QMainWindow::keyPressEvent(event);
}
}
void MainWindow::orientationChanged(Qt::ScreenOrientation orientation)
{
#ifdef ANDROID
// Adjust workspace tab position, to leave max space for MDI windows
if ((orientation == Qt::LandscapeOrientation) || (orientation == Qt::InvertedLandscapeOrientation)) {
setTabPosition(Qt::LeftDockWidgetArea, QTabWidget::West);
} else {
setTabPosition(Qt::LeftDockWidgetArea, QTabWidget::South);
}
#endif
}

View File

@ -34,6 +34,7 @@
class QLabel;
class QTreeWidgetItem;
class QDir;
class QToolButton;
class DSPEngine;
class DSPDeviceSourceEngine;
@ -136,7 +137,7 @@ private:
void saveFeatureSetPresetSettings(FeatureSetPreset* preset, int featureSetIndex);
QString openGLVersion();
void createMenuBar();
void createMenuBar(QToolButton *button);
void createStatusBar();
void closeEvent(QCloseEvent*);
void applySettings();
@ -171,6 +172,9 @@ private:
bool handleMessage(const Message& cmd);
protected:
virtual void keyPressEvent(QKeyEvent* event) override;
private slots:
void handleMessages();
void handleWorkspaceVisibility(Workspace *workspace, bool visibility);
@ -194,6 +198,8 @@ private slots:
void addWorkspace();
void viewAllWorkspaces();
void removeEmptyWorkspaces();
void openConfigurationDialog(bool openOnly);
void loadDefaultConfigurations();
void loadConfiguration(const Configuration *configuration, bool fromDialog = false);
void saveConfiguration(Configuration *configuration);
void sampleSourceAdd(Workspace *deviceWorkspace, Workspace *spectrumWorkspace, int deviceIndex);
@ -215,6 +221,7 @@ private slots:
void openDeviceSetPresetsDialog(QPoint p, DeviceGUI *deviceGUI);
void commandKeyPressed(Qt::Key key, Qt::KeyboardModifiers keyModifiers, bool release);
void fftWisdomProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
void orientationChanged(Qt::ScreenOrientation orientation);
};
#endif // INCLUDE_MAINWINDOW_H

View File

@ -0,0 +1 @@
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

View File

@ -0,0 +1 @@
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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
kAABAXABB1JUTCBTRFJwAgNEQUKAAxuQAAEBcAEHZGVmYXVsdHACB25vIG5hbWUAZAAAZAEBgGVCAdnQywADAAAAAAAAAAAAAAAAAZoAAAMlAAAAAAAAAAAAAAGaAAADJQAAAAAAAAAAAZsAAAAAAAAAAAAAAZoAAAMlAMgBAYHJBB2QAAEBcAEHZGVmYXVsdHACB25vIG5hbWUwAwQNcx2AgAQAgAXikAABAQABAgQAAAIAAAMBBEAEBAAAAABABQRCjAAAYAYBAWAHAQFgCAEAYAkBAAAKAQFgCwEBAA0BEgAOAQEADwEeYBABAQARATJAEgQ/KPXDABMBAQAUAQpgFQEAcBYJMTI3LjAuMC4xEBcCIrdgGAEAYBkBAQAaATJgGwEAABwBAmAdAQAAHgBgHwEAACABA3AhBUFuZ2VsACIBAgAjAAAkAicQACUCJxAAJgInEAAnAQVgKgEBACsBBQAsAQEALQEBAC4AYC8BAGAwAQAAZAAAbgCAKAQAAAAAgCkEAAAAAGAGAQEABwBgCAEBgAlCAdnQywADAAAAABOIAAAAAAAAFQMAAAFuAAATiAAAAAAAABUDAAABbv////8AAAAAAZsAABOIAAAAAAAAFQMAAAFuAAoAgAtCAdnQywADAAAAABOIAAAAAAAAFPMAAAEEAAATiAAAAAAAABTzAAABBP////8AAAAAAZsAABOIAAAAAAAAFPMAAAEEAAwAcA0cc2RyYW5nZWwuc2FtcGxlc291cmNlLnJ0bHNkcnAOCDAwMDAwMDAxAA8AABAAABQBAXAYHHNkcmFuZ2VsLnNhbXBsZXNvdXJjZS5ydGxzZHJwGQgwMDAwMDAwMQAaAIAbXpAAAQEAAgIBpAADABAEAGAFAQBgBgEAAAcBAgAIAx9AAGAJAQBgCgEAYAsBAGAMAQAgDQAQDgMmJaBgDwEAYBABAHARCTEyNy4wLjAuMRASAiK4EBMAYBQBAWAVAQAAyAEBcMkZc2RyYW5nZWwuY2hhbm5lbC5kYWJkZW1vZIHKAZWQAAEBAAEAAAIAcAMAQAQESbufQEAFBECgAABgBgEAcAcVU3lzdGVtIGRlZmF1bHQgZGV2aWNlgAgjkAABAQABABACBP9NaRlwAw9EQUIgRGVtb2R1bGF0b3IABwAQCQT/TWkZcAoPREFCIERlbW9kdWxhdG9yYAsBAHAMCTEyNy4wLjAuMRANAiK4EA4AEA8AgBCeAAAA/wAAAAAAAAAEAAAAIgBzAGUAdAB0AGkAbgBnAHMAQwBvAG4AdABhAGkAbgBlAHIAAAABAAAAIABwAHIAbwBnAHIAYQBtAEMAbwBuAHQAYQBpAG4AZQByAAAAAQAAABwAYwB1AHIAcgBlAG4AdABQAHIAbwBnAHIAYQBtAAAAAQAAABQAcwB0AGEAdABpAHMAdABpAGMAcwAAAAEAEQCAEkIB2dDLAAMAAAAAAAAAAAAAAAABmgAAAvwAAAAAAAAAAP////7////+AAAAAAIAAAABmwAAAAAAAAAAAAABmgAAAvxgEwEAAGQAAGUBAQBmAQIAyAH/AMkB/wDKAf8EASwBAWQBLQEABAGQAQFkAZEBAQ==

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
kAABAXABB1JUTCBTRFJwAgdOT0FBIDE4MAMECDgI0IAEAIEFAWmQAAEBAAECBAAAAgAAAwEEQAQEAAAAAEAFBEKMAABgBgEBYAcBAWAIAQBgCQEAAAoBAWALAQEADQESAA4BAQAPAR5gEAEBABEBMkASBD8o9cMAEwEBABQBCmAVAQBwFgkxMjcuMC4wLjEQFwIit2AYAQBgGQEBABoBMmAbAQAAHAECYB0BAAAeAGAfAQAAIAEDcCEFQW5nZWwAIgECACMAACQCJxAAJQInEAAmAicQACcBBWAqAQEAKwEFACwBAQAtAQEALgBgLwEAYDABAABkAABuAIAoiwAAAAMAAAAACDOcAAAAnEAB//8rKzY2//8AAAAAAAMAAAAOAE4ATwBBAEEAIAAxADUAAAAACDgQoAAAnEAB//8rKzY2//8AAAAAAAMAAAAOAE4ATwBBAEEAIAAxADgAAAAACCuswAAAnEAB//8rKzY2//8AAAAAAAMAAAAOAE4ATwBBAEEAIAAxADmAKQQAAAAAYAYBAQAHAGAIAQGACUIB2dDLAAMAAAAAE4gAAAAAAAAVAwAAAW4AABOIAAAAAAAAFQMAAAFu/////wAAAAABmwAAE4gAAAAAAAAVAwAAAW4ACgCAC0IB2dDLAAMAAAAAAAAAAAAAAAABfwAAARAAAAAAAAAAFAAAAWsAAAEYAAAAAAIAAAABmwAAAAAAAAAAAAABfwAAARAADABwDRxzZHJhbmdlbC5zYW1wbGVzb3VyY2UucnRsc2RycA4IMDAwMDAwMDEADwAAEAAAFAEBcBgcc2RyYW5nZWwuc2FtcGxlc291cmNlLnJ0bHNkcnAZCDAwMDAwMDAxABoAgBtfkAABAQACAgGkAAMAEAQBA2AFAQBgBgEAAAcBAgAIAw9CQGAJAQBgCgEAYAsBAGAMAQAgDQAQDgMmJaBgDwEAYBABAHARCTEyNy4wLjAuMRASAiK4EBMAYBQBAWAVAQAAyAEBcMkZc2RyYW5nZWwuY2hhbm5lbC5hcHRkZW1vZIHKAYmQAAEBAAECVfAAAgBAAwRHHEAAQAQERoTQAGAFAQBgBgEBYAcBAGAIAQBgCQEAYAoBAAALAGAMAQBgDQEBcA4DQWxsYA8BAHAQAAARAgDIYBIBAAATARSAFCWQAAEBAAECVfAQAgT/2HCpcAMPQVBUIERlbW9kdWxhdG9yAAcAEBUE/9hwqXAWD0FQVCBEZW1vZHVsYXRvcmAXAQBwGAkxMjcuMC4wLjEQGQIiuBAaABAbAIAcWgAAAP8AAAAAAAAAAgAAACIAcwBlAHQAdABpAG4AZwBzAEMAbwBuAHQAYQBpAG4AZQByAAAAAQAAABwAaQBtAGEAZwBlAEMAbwBuAHQAYQBpAG4AZQByAAAAAWAdAQFgHgEAAB8BZAAgAgDIcCEAACIAACMBCgAkARRAJQQAAAAAQCYEAAAAAAAnAIAoQgHZ0MsAAwAAAAATiAAAAAAAABUiAAADBwAAE4gAAAAAAAAVIgAAAwf/////AAAAAAGbAAATiAAAAAAAABUiAAADB2ApAQA=

View File

@ -0,0 +1 @@
kAABAXABB1JUTCBTRFJwAgdOT0FBIDE5MAMECCuk8IAEAIEFAWmQAAEBAAECBAAAAgAAAwEEQAQEAAAAAEAFBEKMAABgBgEBYAcBAWAIAQBgCQEAAAoBAWALAQEADQESAA4BAQAPAR5gEAEBABEBMkASBD8o9cMAEwEBABQBCmAVAQBwFgkxMjcuMC4wLjEQFwIit2AYAQBgGQEBABoBMmAbAQAAHAECYB0BAAAeAGAfAQAAIAEDcCEFQW5nZWwAIgECACMAACQCJxAAJQInEAAmAicQACcBBWAqAQEAKwEFACwBAQAtAQEALgBgLwEAYDABAABkAABuAIAoiwAAAAMAAAAACDOcAAAAnEAB//8rKzY2//8AAAAAAAMAAAAOAE4ATwBBAEEAIAAxADUAAAAACDgQoAAAnEAB//8rKzY2//8AAAAAAAMAAAAOAE4ATwBBAEEAIAAxADgAAAAACCuswAAAnEAB//8rKzY2//8AAAAAAAMAAAAOAE4ATwBBAEEAIAAxADmAKQQAAAAAYAYBAQAHAGAIAQGACUIB2dDLAAMAAAAAE4gAAAAAAAAVAwAAAW4AABOIAAAAAAAAFQMAAAFu/////wAAAAABmwAAE4gAAAAAAAAVAwAAAW4ACgCAC0IB2dDLAAMAAAAAAAAAAAAAAAABfwAAARAAAAAAAAAAFAAAAWsAAAEYAAAAAAIAAAABmwAAAAAAAAAAAAABfwAAARAADABwDRxzZHJhbmdlbC5zYW1wbGVzb3VyY2UucnRsc2RycA4IMDAwMDAwMDEADwAAEAAAFAEBcBgcc2RyYW5nZWwuc2FtcGxlc291cmNlLnJ0bHNkcnAZCDAwMDAwMDAxABoAgBtfkAABAQACAgGkAAMAEAQBA2AFAQBgBgEAAAcBAgAIAw9CQGAJAQBgCgEAYAsBAGAMAQAgDQAQDgMmJaBgDwEAYBABAHARCTEyNy4wLjAuMRASAiK4EBMAYBQBAWAVAQAAyAEBcMkZc2RyYW5nZWwuY2hhbm5lbC5hcHRkZW1vZIHKAYmQAAEBAAECVfAAAgBAAwRHHEAAQAQERoTQAGAFAQBgBgEBYAcBAGAIAQBgCQEAYAoBAAALAGAMAQBgDQEBcA4DQWxsYA8BAHAQAAARAgDIYBIBAAATARSAFCWQAAEBAAECVfAQAgT/2HCpcAMPQVBUIERlbW9kdWxhdG9yAAcAEBUE/9hwqXAWD0FQVCBEZW1vZHVsYXRvcmAXAQBwGAkxMjcuMC4wLjEQGQIiuBAaABAbAIAcWgAAAP8AAAAAAAAAAgAAACIAcwBlAHQAdABpAG4AZwBzAEMAbwBuAHQAYQBpAG4AZQByAAAAAQAAABwAaQBtAGEAZwBlAEMAbwBuAHQAYQBpAG4AZQByAAAAAWAdAQFgHgEAAB8BZAAgAgDIcCEAACIAACMBCgAkARRAJQQAAAAAQCYEAAAAAAAnAIAoQgHZ0MsAAwAAAAATiAAAAAAAABUiAAADBwAAE4gAAAAAAAAVIgAAAwf/////AAAAAAGbAAATiAAAAAAAABUiAAADB2ApAQA=

13
settings/settings.qrc Normal file
View File

@ -0,0 +1,13 @@
<RCC>
<qresource prefix="/">
<file>configurations/rtlsdr/adsb.cfgx</file>
<file>configurations/rtlsdr/ais.cfgx</file>
<file>configurations/rtlsdr/apt.cfgx</file>
<file>configurations/rtlsdr/dab.cfgx</file>
<file>configurations/rtlsdr/isspacket.cfgx</file>
<file>configurations/rtlsdr/radiosonde.cfgx</file>
<file>configurations/airspyhf/radioclockeu.cfgx</file>
<file>presets/rtlsdr/noaa18.prex</file>
<file>presets/rtlsdr/noaa19.prex</file>
</qresource>
</RCC>