diff --git a/sdrbase/CMakeLists.txt b/sdrbase/CMakeLists.txt index 81131f0ac..1b7369a08 100644 --- a/sdrbase/CMakeLists.txt +++ b/sdrbase/CMakeLists.txt @@ -207,6 +207,7 @@ set(sdrbase_SOURCES settings/configuration.cpp settings/featuresetpreset.cpp + settings/pluginpreset.cpp settings/preferences.cpp settings/preset.cpp settings/mainsettings.cpp @@ -437,6 +438,7 @@ set(sdrbase_HEADERS settings/configuration.h settings/featuresetpreset.h + settings/pluginpreset.h settings/preferences.h settings/preset.h settings/mainsettings.h diff --git a/sdrbase/device/deviceapi.cpp b/sdrbase/device/deviceapi.cpp index e019bbd3a..a4de6cbe8 100644 --- a/sdrbase/device/deviceapi.cpp +++ b/sdrbase/device/deviceapi.cpp @@ -25,6 +25,7 @@ #include "dsp/devicesamplemimo.h" #include "settings/preset.h" #include "channel/channelapi.h" +#include "util/simpleserializer.h" #include "deviceapi.h" @@ -467,6 +468,115 @@ ChannelAPI *DeviceAPI::getMIMOChannelAPIAt(int index) } } +QList DeviceAPI::getCenterFrequency() const +{ + QList frequencies; + + if (m_deviceSourceEngine && m_deviceSourceEngine->getSource()) + { + frequencies.append(m_deviceSourceEngine->getSource()->getCenterFrequency()); + } + else if (m_deviceSinkEngine && m_deviceSinkEngine->getSink()) + { + frequencies.append(m_deviceSinkEngine->getSink()->getCenterFrequency()); + } + else if (m_deviceMIMOEngine && m_deviceMIMOEngine->getMIMO()) + { + for (int i = 0; i < m_deviceMIMOEngine->getMIMO()->getNbSourceStreams(); i++) { + frequencies.append(m_deviceMIMOEngine->getMIMO()->getSourceCenterFrequency(i)); + } + for (int i = 0; i < m_deviceMIMOEngine->getMIMO()->getNbSinkStreams(); i++) { + frequencies.append(m_deviceMIMOEngine->getMIMO()->getSinkCenterFrequency(i)); + } + } + return frequencies; +} + +void DeviceAPI::setCenterFrequency(QList centerFrequency) +{ + if (m_deviceSourceEngine && m_deviceSourceEngine->getSource()) + { + m_deviceSourceEngine->getSource()->setCenterFrequency(centerFrequency[0]); + } + else if (m_deviceSinkEngine && m_deviceSinkEngine->getSink()) + { + m_deviceSinkEngine->getSink()->setCenterFrequency(centerFrequency[0]); + } + else if (m_deviceMIMOEngine && m_deviceMIMOEngine->getMIMO()) + { + int idx = 0; + for (int i = 0; i < m_deviceMIMOEngine->getMIMO()->getNbSourceStreams(); i++, idx++) { + m_deviceMIMOEngine->getMIMO()->setSourceCenterFrequency(centerFrequency[idx], i); + } + for (int i = 0; i < m_deviceMIMOEngine->getMIMO()->getNbSinkStreams(); i++) { + m_deviceMIMOEngine->getMIMO()->setSinkCenterFrequency(centerFrequency[idx], i); + } + } +} + +// Serialization is only currently used for saving device settings as part of a Device preset +// loadSamplingDeviceSettings/saveSamplingDeviceSettings is used for Device Set presets (which includes channel settings) + +QByteArray DeviceAPI::serialize() const +{ + SimpleSerializer s(1); + + if (m_deviceSourceEngine && m_deviceSourceEngine->getSource()) { + s.writeBlob(1, m_deviceSourceEngine->getSource()->serialize()); + } + if (m_deviceSinkEngine && m_deviceSinkEngine->getSink()) { + s.writeBlob(2, m_deviceSinkEngine->getSink()->serialize()); + } + if (m_deviceMIMOEngine && m_deviceMIMOEngine->getMIMO()) { + s.writeBlob(3, m_deviceMIMOEngine->getMIMO()->serialize()); + } + s.writeList(4, getCenterFrequency()); + return s.final(); +} + +bool DeviceAPI::deserialize(const QByteArray& data) +{ + SimpleDeserializer d(data); + + if (!d.isValid()) { + return false; + } + + if (d.getVersion() == 1) + { + QByteArray data; + QList centerFrequency; + + if (m_deviceSourceEngine && m_deviceSourceEngine->getSource()) + { + d.readBlob(1, &data); + if (data.size() > 0) { + m_deviceSourceEngine->getSource()->deserialize(data); + } + } + if (m_deviceSinkEngine && m_deviceSinkEngine->getSink()) + { + d.readBlob(2, &data); + if (data.size() > 0) { + m_deviceSinkEngine->getSink()->deserialize(data); + } + } + if (m_deviceMIMOEngine && m_deviceMIMOEngine->getMIMO()) + { + d.readBlob(3, &data); + if (data.size() > 0) { + m_deviceMIMOEngine->getMIMO()->deserialize(data); + } + } + d.readList(4, ¢erFrequency); + setCenterFrequency(centerFrequency); + } + else + { + return false; + } +} + void DeviceAPI::loadSamplingDeviceSettings(const Preset* preset) { if (m_deviceSourceEngine && (preset->isSourcePreset())) diff --git a/sdrbase/device/deviceapi.h b/sdrbase/device/deviceapi.h index a351913af..4c1f488f5 100644 --- a/sdrbase/device/deviceapi.h +++ b/sdrbase/device/deviceapi.h @@ -22,6 +22,7 @@ #include #include +#include "settings/serializableinterface.h" #include "export.h" class BasebandSampleSink; @@ -38,7 +39,7 @@ class DSPDeviceSinkEngine; class DSPDeviceMIMOEngine; class Preset; -class SDRBASE_API DeviceAPI : public QObject { +class SDRBASE_API DeviceAPI : public QObject, public SerializableInterface { Q_OBJECT public: enum StreamType //!< This is the same enum as in PluginInterface @@ -146,6 +147,13 @@ public: // void saveSourceSettings(Preset* preset); // void saveSinkSettings(Preset* preset); + QByteArray serialize() const override; + bool deserialize(const QByteArray& data) override; + + // List of one frequency for Single Rx / Tx or one frequency per stream for MIMO + QList getCenterFrequency() const; + void setCenterFrequency(QList centerFrequency); + DSPDeviceSourceEngine *getDeviceSourceEngine() { return m_deviceSourceEngine; } DSPDeviceSinkEngine *getDeviceSinkEngine() { return m_deviceSinkEngine; } DSPDeviceMIMOEngine *getDeviceMIMOEngine() { return m_deviceMIMOEngine; } diff --git a/sdrbase/maincore.h b/sdrbase/maincore.h index c7672b2af..4baf3fe92 100644 --- a/sdrbase/maincore.h +++ b/sdrbase/maincore.h @@ -848,6 +848,7 @@ public: qint64 getElapsedNsecs() const { return m_masterElapsedTimer.nsecsElapsed(); } //!< Elapsed nanoseconds since main core construction qint64 getStartMsecsSinceEpoch() const { return m_startMsecsSinceEpoch; } //!< Epoch timestamp in millisecodns close to elapsed timer start const MainSettings& getSettings() const { return m_settings; } + MainSettings& getMutableSettings() { return m_settings; } MessageQueue *getMainMessageQueue() { return m_mainMessageQueue; } PluginManager *getPluginManager() const { return m_pluginManager; } std::vector& getDeviceSets() { return m_deviceSets; } diff --git a/sdrbase/settings/mainsettings.cpp b/sdrbase/settings/mainsettings.cpp index f4d988d59..f4d71ff90 100644 --- a/sdrbase/settings/mainsettings.cpp +++ b/sdrbase/settings/mainsettings.cpp @@ -31,6 +31,10 @@ MainSettings::~MainSettings() { delete m_featureSetPresets[i]; } + for (int i = 0; i < m_pluginPresets.count(); ++i) + { + delete m_pluginPresets[i]; + } } QString MainSettings::getFileLocation() const @@ -108,6 +112,22 @@ void MainSettings::load() delete featureSetPreset; } + s.endGroup(); + } + else if (groups[i].startsWith("pluginpreset")) + { + s.beginGroup(groups[i]); + PluginPreset* pluginPreset = new PluginPreset; + + if (pluginPreset->deserialize(qUncompress(QByteArray::fromBase64(s.value("data").toByteArray())))) + { + m_pluginPresets.append(pluginPreset); + } + else + { + delete pluginPreset; + } + s.endGroup(); } else if (groups[i].startsWith("configuration")) @@ -176,6 +196,14 @@ void MainSettings::save() const s.endGroup(); } + for (int i = 0; i < m_pluginPresets.count(); ++i) + { + QString group = QString("pluginpreset-%1").arg(i + 1); + s.beginGroup(group); + s.setValue("data", qCompress(m_pluginPresets[i]->serialize()).toBase64()); + s.endGroup(); + } + for (int i = 0; i < m_configurations.count(); ++i) { QString group = QString("configuration-%1").arg(i + 1); @@ -193,6 +221,7 @@ void MainSettings::initialize() clearCommands(); clearPresets(); clearFeatureSetPresets(); + clearPluginPresets(); clearConfigurations(); } @@ -201,6 +230,7 @@ void MainSettings::resetToDefaults() m_preferences.resetToDefaults(); m_workingPreset.resetToDefaults(); m_workingFeatureSetPreset.resetToDefaults(); + m_workingPluginPreset.resetToDefaults(); m_workingConfiguration.resetToDefaults(); } @@ -452,6 +482,86 @@ void MainSettings::clearFeatureSetPresets() m_featureSetPresets.clear(); } +// FeatureSet presets + +PluginPreset* MainSettings::newPluginPreset(const QString& group, const QString& description) +{ + PluginPreset* preset = new PluginPreset(); + preset->setGroup(group); + preset->setDescription(description); + addPluginPreset(preset); + return preset; +} + +void MainSettings::addPluginPreset(PluginPreset *preset) +{ + m_pluginPresets.append(preset); +} + +void MainSettings::deletePluginPreset(const PluginPreset* preset) +{ + m_pluginPresets.removeAll((PluginPreset*) preset); + delete (PluginPreset*) preset; +} + +void MainSettings::deletePluginPresetGroup(const QString& groupName) +{ + PluginPresets::iterator it = m_pluginPresets.begin(); + + while (it != m_pluginPresets.end()) + { + if ((*it)->getGroup() == groupName) { + it = m_pluginPresets.erase(it); + } else { + ++it; + } + } +} + +void MainSettings::sortPluginPresets() +{ + std::sort(m_pluginPresets.begin(), m_pluginPresets.end(), PluginPreset::presetCompare); +} + +void MainSettings::renamePluginPresetGroup(const QString& oldGroupName, const QString& newGroupName) +{ + int nbPresets = getPluginPresetCount(); + + for (int i = 0; i < nbPresets; i++) + { + if (getPluginPreset(i)->getGroup() == oldGroupName) + { + PluginPreset *preset_mod = const_cast(getPluginPreset(i)); + preset_mod->setGroup(newGroupName); + } + } +} + +const PluginPreset* MainSettings::getPluginPreset(const QString& groupName, const QString& description) const +{ + int nbPresets = getPluginPresetCount(); + + for (int i = 0; i < nbPresets; i++) + { + if ((getPluginPreset(i)->getGroup() == groupName) && + (getPluginPreset(i)->getDescription() == description)) + { + return getPluginPreset(i); + } + } + + return nullptr; +} + +void MainSettings::clearPluginPresets() +{ + foreach (PluginPreset *preset, m_pluginPresets) { + delete preset; + } + + m_pluginPresets.clear(); +} + // Configurations Configuration* MainSettings::newConfiguration(const QString& group, const QString& description) diff --git a/sdrbase/settings/mainsettings.h b/sdrbase/settings/mainsettings.h index a53f6d53d..7b99be917 100644 --- a/sdrbase/settings/mainsettings.h +++ b/sdrbase/settings/mainsettings.h @@ -7,6 +7,7 @@ #include "preferences.h" #include "preset.h" #include "featuresetpreset.h" +#include "pluginpreset.h" #include "configuration.h" #include "export.h" #include "plugin/pluginmanager.h" @@ -72,6 +73,20 @@ public: FeatureSetPreset* getWorkingFeatureSetPreset() { return &m_workingFeatureSetPreset; } QList *getFeatureSetPresets() { return &m_featureSetPresets; } + PluginPreset* newPluginPreset(const QString& group, const QString& description); + void addPluginPreset(PluginPreset *preset); + void deletePluginPreset(const PluginPreset* preset); + int getPluginPresetCount() const { return m_pluginPresets.count(); } + const PluginPreset* getPluginPreset(int index) const { return m_pluginPresets[index]; } + const PluginPreset* getPluginPreset(const QString& groupName, const QString& description) const; + void sortPluginPresets(); + void renamePluginPresetGroup(const QString& oldGroupName, const QString& newGroupName); + void deletePluginPresetGroup(const QString& groupName); + void clearPluginPresets(); + const PluginPreset& getWorkingPluginPresetConst() const { return m_workingPluginPreset; } + PluginPreset* getWorkingPluginPreset() { return &m_workingPluginPreset; } + QList *getPluginPresets() { return &m_pluginPresets; } + Configuration* newConfiguration(const QString& group, const QString& description); void addConfiguration(Configuration *configuration); void deleteConfiguration(const Configuration *configuration); @@ -231,6 +246,9 @@ protected: FeatureSetPreset m_workingFeatureSetPreset; typedef QList FeatureSetPresets; FeatureSetPresets m_featureSetPresets; + PluginPreset m_workingPluginPreset; + typedef QList PluginPresets; + PluginPresets m_pluginPresets; Configuration m_workingConfiguration; typedef QList Configurations; Configurations m_configurations; diff --git a/sdrbase/settings/pluginpreset.cpp b/sdrbase/settings/pluginpreset.cpp new file mode 100644 index 000000000..696e0f1e2 --- /dev/null +++ b/sdrbase/settings/pluginpreset.cpp @@ -0,0 +1,79 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// Copyright (C) 2023 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "util/simpleserializer.h" + +#include "pluginpreset.h" + +PluginPreset::PluginPreset() +{ + resetToDefaults(); +} + +PluginPreset::PluginPreset(const PluginPreset& other) : + m_group(other.m_group), + m_description(other.m_description), + m_pluginIdURI(other.m_pluginIdURI), + m_config(other.m_config) +{} + +void PluginPreset::resetToDefaults() +{ + m_group = "default"; + m_description = "no name"; + m_pluginIdURI = ""; + m_config = QByteArray(); +} + +QByteArray PluginPreset::serialize() const +{ + SimpleSerializer s(1); + + s.writeString(1, m_group); + s.writeString(2, m_description); + s.writeString(3, m_pluginIdURI); + s.writeBlob(4, m_config); + + return s.final(); +} + +bool PluginPreset::deserialize(const QByteArray& data) +{ + SimpleDeserializer d(data); + + if (!d.isValid()) + { + resetToDefaults(); + return false; + } + + if (d.getVersion() == 1) + { + d.readString(1, &m_group, "default"); + d.readString(2, &m_description, "no name"); + d.readString(3, &m_pluginIdURI, ""); + d.readBlob(4, &m_config); + + return true; + } + else + { + resetToDefaults(); + return false; + } +} diff --git a/sdrbase/settings/pluginpreset.h b/sdrbase/settings/pluginpreset.h new file mode 100644 index 000000000..9f4027e71 --- /dev/null +++ b/sdrbase/settings/pluginpreset.h @@ -0,0 +1,70 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// Copyright (C) 2023 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef SDRBASE_SETTINGS_PLUGINPRESET_H_ +#define SDRBASE_SETTINGS_PLUGINPRESET_H_ + +#include +#include +#include + +#include "export.h" + +class SDRBASE_API PluginPreset { +public: + + PluginPreset(); + PluginPreset(const PluginPreset& other); + void resetToDefaults(); + + QByteArray serialize() const; + bool deserialize(const QByteArray& data); + + void setGroup(const QString& group) { m_group = group; } + const QString& getGroup() const { return m_group; } + void setDescription(const QString& description) { m_description = description; } + const QString& getDescription() const { return m_description; } + void setConfig(const QString& pluginIdURI, const QByteArray& config) { m_pluginIdURI = pluginIdURI; m_config = config; } + const QByteArray& getConfig() const { return m_config; } + const QString& getPluginIdURI() const { return m_pluginIdURI; } + + static bool presetCompare(const PluginPreset *p1, PluginPreset *p2) + { + if (p1->m_group != p2->m_group) + { + return p1->m_group < p2->m_group; + } + else + { + return p1->m_description < p2->m_description; + } + } + +private: + // group and preset description + QString m_group; + QString m_description; + QString m_pluginIdURI; //!< Plugin type ID in URI form + QByteArray m_config; + +}; + +Q_DECLARE_METATYPE(const PluginPreset*) +Q_DECLARE_METATYPE(PluginPreset*) + +#endif // SDRBASE_SETTINGS_PLUGINPRESET_H_ diff --git a/sdrgui/CMakeLists.txt b/sdrgui/CMakeLists.txt index 8ec2ba10c..d7ab6122f 100644 --- a/sdrgui/CMakeLists.txt +++ b/sdrgui/CMakeLists.txt @@ -68,6 +68,7 @@ set(sdrgui_SOURCES gui/mypositiondialog.cpp gui/nanosecondsdelegate.cpp gui/pluginsdialog.cpp + gui/pluginpresetsdialog.cpp gui/presetitem.cpp gui/profiledialog.cpp gui/rollupcontents.cpp @@ -188,7 +189,9 @@ set(sdrgui_HEADERS gui/nanosecondsdelegate.h gui/physicalunit.h gui/pluginsdialog.h + gui/pluginpresetsdialog.h gui/presetitem.h + gui/presets/dialog.h gui/profiledialog.h gui/qtcompatibility.h gui/rollupcontents.h @@ -266,6 +269,7 @@ set(sdrgui_FORMS gui/glspectrumgui.ui gui/graphicsdialog.ui gui/pluginsdialog.ui + gui/pluginpresetsdialog.ui gui/profiledialog.ui gui/audiodialog.ui gui/audioselectdialog.ui diff --git a/sdrgui/channel/channelgui.h b/sdrgui/channel/channelgui.h index eedc0ed3e..0708a91af 100644 --- a/sdrgui/channel/channelgui.h +++ b/sdrgui/channel/channelgui.h @@ -23,6 +23,7 @@ #include "gui/qtcompatibility.h" #include "gui/framelesswindowresizer.h" +#include "settings/serializableinterface.h" #include "export.h" class QCloseEvent; @@ -35,7 +36,7 @@ class QSizeGrip; class RollupContents; class ChannelMarker; -class SDRGUI_API ChannelGUI : public QMdiSubWindow +class SDRGUI_API ChannelGUI : public QMdiSubWindow, public SerializableInterface { Q_OBJECT public: @@ -57,8 +58,6 @@ public: virtual void destroy() = 0; virtual void resetToDefaults() = 0; - virtual QByteArray serialize() const = 0; - virtual bool deserialize(const QByteArray& data) = 0; // Data saved in the derived settings virtual void setWorkspaceIndex(int index)= 0; virtual int getWorkspaceIndex() const = 0; diff --git a/sdrgui/device/devicegui.h b/sdrgui/device/devicegui.h index 1a392851d..8e7a35ffb 100644 --- a/sdrgui/device/devicegui.h +++ b/sdrgui/device/devicegui.h @@ -28,6 +28,7 @@ #include "gui/channeladddialog.h" #include "gui/framelesswindowresizer.h" +#include "settings/serializableinterface.h" #include "export.h" class QCloseEvent; @@ -39,7 +40,7 @@ class QHBoxLayout; class QSizeGrip; class DeviceUISet; -class SDRGUI_API DeviceGUI : public QMdiSubWindow { +class SDRGUI_API DeviceGUI : public QMdiSubWindow, public SerializableInterface { Q_OBJECT public: enum DeviceType @@ -60,8 +61,6 @@ public: virtual void destroy() = 0; virtual void resetToDefaults() = 0; - virtual QByteArray serialize() const = 0; - virtual bool deserialize(const QByteArray& data) = 0; void setWorkspaceIndex(int index); int getWorkspaceIndex() const { return m_workspaceIndex; } @@ -78,6 +77,7 @@ public: int getIndex() const { return m_deviceSetIndex; } void setCurrentDeviceIndex(int index) { m_currentDeviceIndex = index; } //!< index in plugins list void setChannelNames(const QStringList& channelNames) { m_channelAddDialog.addChannelNames(channelNames); } + DeviceUISet* getDeviceUISet() { return m_deviceUISet; } protected: void closeEvent(QCloseEvent *event) override; diff --git a/sdrgui/device/deviceuiset.cpp b/sdrgui/device/deviceuiset.cpp index 59025ecc4..3cb4fd9d7 100644 --- a/sdrgui/device/deviceuiset.cpp +++ b/sdrgui/device/deviceuiset.cpp @@ -38,6 +38,7 @@ #include "channel/channelgui.h" #include "mainspectrum/mainspectrumgui.h" #include "settings/preset.h" +#include "util/simpleserializer.h" #include "mainwindow.h" #include "deviceuiset.h" @@ -196,6 +197,45 @@ ChannelGUI *DeviceUISet::getChannelGUIAt(int channelIndex) return m_channelInstanceRegistrations[channelIndex].m_gui; } +// Serialization is only used for Device and Spectrum settings in a Device preset +// To include channels, use a Device Set preset via loadDeviceSetSettings/saveDeviceSetSettings + +QByteArray DeviceUISet::serialize() const +{ + SimpleSerializer s(1); + + s.writeBlob(1, m_deviceAPI->serialize()); + s.writeBlob(2, m_deviceGUI->serialize()); + s.writeBlob(3, m_spectrumGUI->serialize()); + + return s.final(); +} + +bool DeviceUISet::deserialize(const QByteArray& data) +{ + SimpleDeserializer d(data); + + if (!d.isValid()) { + return false; + } + + if (d.getVersion() == 1) + { + QByteArray data; + + d.readBlob(1, &data); + m_deviceAPI->deserialize(data); + d.readBlob(2, &data); + m_deviceGUI->deserialize(data); + d.readBlob(3, &data); + m_spectrumGUI->deserialize(data); + } + else + { + return false; + } +} + void DeviceUISet::loadDeviceSetSettings( const Preset* preset, PluginAPI *pluginAPI, diff --git a/sdrgui/device/deviceuiset.h b/sdrgui/device/deviceuiset.h index 547525206..d07ef91c9 100644 --- a/sdrgui/device/deviceuiset.h +++ b/sdrgui/device/deviceuiset.h @@ -22,6 +22,7 @@ #include #include +#include "settings/serializableinterface.h" #include "export.h" class SpectrumVis; @@ -48,7 +49,7 @@ namespace SWGSDRangel { class SWGSuccessResponse; }; -class SDRGUI_API DeviceUISet : public QObject +class SDRGUI_API DeviceUISet : public QObject, public SerializableInterface { Q_OBJECT public: @@ -84,6 +85,9 @@ public: ChannelAPI *getChannelAt(int channelIndex); ChannelGUI *getChannelGUIAt(int channelIndex); + QByteArray serialize() const override; + bool deserialize(const QByteArray& data) override; + void loadDeviceSetSettings( const Preset* preset, PluginAPI *pluginAPI, diff --git a/sdrgui/feature/featuregui.h b/sdrgui/feature/featuregui.h index bc53e6079..7af072c02 100644 --- a/sdrgui/feature/featuregui.h +++ b/sdrgui/feature/featuregui.h @@ -23,6 +23,7 @@ #include "gui/framelesswindowresizer.h" #include "gui/rollupcontents.h" +#include "settings/serializableinterface.h" #include "export.h" class QCloseEvent; @@ -34,7 +35,7 @@ class QHBoxLayout; class QSizeGrip; class Feature; -class SDRGUI_API FeatureGUI : public QMdiSubWindow +class SDRGUI_API FeatureGUI : public QMdiSubWindow, public SerializableInterface { Q_OBJECT public: @@ -49,8 +50,6 @@ public: virtual void destroy() = 0; virtual void resetToDefaults() = 0; - virtual QByteArray serialize() const = 0; - virtual bool deserialize(const QByteArray& data) = 0; // Data saved in the derived settings virtual void setWorkspaceIndex(int index)= 0; virtual int getWorkspaceIndex() const = 0; diff --git a/sdrgui/gui/basicchannelsettingsdialog.cpp b/sdrgui/gui/basicchannelsettingsdialog.cpp index f252b5094..bd041e10f 100644 --- a/sdrgui/gui/basicchannelsettingsdialog.cpp +++ b/sdrgui/gui/basicchannelsettingsdialog.cpp @@ -1,6 +1,11 @@ #include #include "dsp/channelmarker.h" +#include "gui/pluginpresetsdialog.h" +#include "gui/dialogpositioner.h" +#include "channel/channelapi.h" +#include "channel/channelgui.h" +#include "maincore.h" #include "basicchannelsettingsdialog.h" #include "ui_basicchannelsettingsdialog.h" @@ -154,6 +159,28 @@ void BasicChannelSettingsDialog::on_titleReset_clicked() ui->title->setText(m_defaultTitle); } +void BasicChannelSettingsDialog::on_presets_clicked() +{ + ChannelGUI *channelGUI = qobject_cast(parent()); + if (!channelGUI) + { + qDebug() << "BasicChannelSettingsDialog::on_presets_clicked: parent not a ChannelGUI"; + return; + } + ChannelAPI *channel = MainCore::instance()->getChannel(channelGUI->getDeviceSetIndex(), channelGUI->getIndex()); + const QString& id = channel->getURI(); + + PluginPresetsDialog dialog(id); + dialog.setPresets(MainCore::instance()->getMutableSettings().getPluginPresets()); + dialog.setSerializableInterface(channelGUI); + dialog.populateTree(); + new DialogPositioner(&dialog, true); + dialog.exec(); + if (dialog.wasPresetLoaded()) { + QDialog::reject(); // Settings may have changed, so GUI will be inconsistent. Just close it + } +} + void BasicChannelSettingsDialog::accept() { m_channelMarker->blockSignals(true); diff --git a/sdrgui/gui/basicchannelsettingsdialog.h b/sdrgui/gui/basicchannelsettingsdialog.h index c7274ad1f..d1e099cbf 100644 --- a/sdrgui/gui/basicchannelsettingsdialog.h +++ b/sdrgui/gui/basicchannelsettingsdialog.h @@ -43,6 +43,7 @@ private slots: void on_reverseAPIDeviceIndex_editingFinished(); void on_reverseAPIChannelIndex_editingFinished(); void on_streamIndex_valueChanged(int value); + void on_presets_clicked(); void accept(); private: diff --git a/sdrgui/gui/basicchannelsettingsdialog.ui b/sdrgui/gui/basicchannelsettingsdialog.ui index ecd1748bc..33f99ecd0 100644 --- a/sdrgui/gui/basicchannelsettingsdialog.ui +++ b/sdrgui/gui/basicchannelsettingsdialog.ui @@ -301,14 +301,32 @@ - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - + + + + + Open channel presets dialog + + + + + + + :/star.png:/star.png + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + diff --git a/sdrgui/gui/basicdevicesettingsdialog.cpp b/sdrgui/gui/basicdevicesettingsdialog.cpp index 8b2fa6b52..fca60d531 100644 --- a/sdrgui/gui/basicdevicesettingsdialog.cpp +++ b/sdrgui/gui/basicdevicesettingsdialog.cpp @@ -1,3 +1,10 @@ +#include "gui/pluginpresetsdialog.h" +#include "gui/dialogpositioner.h" +#include "device/deviceapi.h" +#include "device/devicegui.h" +#include "device/deviceuiset.h" +#include "maincore.h" + #include "basicdevicesettingsdialog.h" #include "ui_basicdevicesettingsdialog.h" @@ -81,6 +88,30 @@ void BasicDeviceSettingsDialog::on_reverseAPIDeviceIndex_editingFinished() } } +void BasicDeviceSettingsDialog::on_presets_clicked() +{ + DeviceGUI *deviceGUI = qobject_cast(parent()); + if (!deviceGUI) + { + qDebug() << "BasicDeviceSettingsDialog::on_presets_clicked: parent not a DeviceGUI"; + return; + } + DeviceAPI *device = MainCore::instance()->getDevice(deviceGUI->getIndex()); + const QString& id = device->getSamplingDeviceId(); + // To include spectrum settings, we need to serialize DeviceUISet rather than just the DeviceGUI + DeviceUISet *deviceUISet = deviceGUI->getDeviceUISet(); + + PluginPresetsDialog dialog(id); + dialog.setPresets(MainCore::instance()->getMutableSettings().getPluginPresets()); + dialog.setSerializableInterface(deviceUISet); + dialog.populateTree(); + new DialogPositioner(&dialog, true); + dialog.exec(); + if (dialog.wasPresetLoaded()) { + QDialog::reject(); // Settings may have changed, so GUI will be inconsistent. Just close it + } +} + void BasicDeviceSettingsDialog::accept() { m_hasChanged = true; diff --git a/sdrgui/gui/basicdevicesettingsdialog.h b/sdrgui/gui/basicdevicesettingsdialog.h index 1bd885a83..991555632 100644 --- a/sdrgui/gui/basicdevicesettingsdialog.h +++ b/sdrgui/gui/basicdevicesettingsdialog.h @@ -31,6 +31,7 @@ private slots: void on_reverseAPIAddress_editingFinished(); void on_reverseAPIPort_editingFinished(); void on_reverseAPIDeviceIndex_editingFinished(); + void on_presets_clicked(); void accept(); private: diff --git a/sdrgui/gui/basicdevicesettingsdialog.ui b/sdrgui/gui/basicdevicesettingsdialog.ui index dcbec788b..185bf9b0c 100644 --- a/sdrgui/gui/basicdevicesettingsdialog.ui +++ b/sdrgui/gui/basicdevicesettingsdialog.ui @@ -134,18 +134,38 @@ - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - + + + + + Open device presets dialog + + + + + + + :/star.png:/star.png + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + - + + + buttonBox diff --git a/sdrgui/gui/basicfeaturesettingsdialog.cpp b/sdrgui/gui/basicfeaturesettingsdialog.cpp index 8ff5b51d6..0f2da9820 100644 --- a/sdrgui/gui/basicfeaturesettingsdialog.cpp +++ b/sdrgui/gui/basicfeaturesettingsdialog.cpp @@ -1,5 +1,11 @@ #include +#include "gui/pluginpresetsdialog.h" +#include "gui/dialogpositioner.h" +#include "feature/feature.h" +#include "feature/featuregui.h" +#include "maincore.h" + #include "basicfeaturesettingsdialog.h" #include "ui_basicfeaturesettingsdialog.h" @@ -82,6 +88,28 @@ void BasicFeatureSettingsDialog::on_reverseAPIFeatureIndex_editingFinished() } } +void BasicFeatureSettingsDialog::on_presets_clicked() +{ + FeatureGUI *featureGUI = qobject_cast(parent()); + if (!featureGUI) + { + qDebug() << "BasicFeatureSettingsDialog::on_presets_clicked: parent not a FeatureGUI"; + return; + } + Feature *feature = MainCore::instance()->getFeature(0, featureGUI->getIndex()); + const QString& id = feature->getURI(); + + PluginPresetsDialog dialog(id); + dialog.setPresets(MainCore::instance()->getMutableSettings().getPluginPresets()); + dialog.setSerializableInterface(featureGUI); + dialog.populateTree(); + new DialogPositioner(&dialog, true); + dialog.exec(); + if (dialog.wasPresetLoaded()) { + QDialog::reject(); // Settings may have changed, so GUI will be inconsistent. Just close it + } +} + void BasicFeatureSettingsDialog::accept() { m_hasChanged = true; diff --git a/sdrgui/gui/basicfeaturesettingsdialog.h b/sdrgui/gui/basicfeaturesettingsdialog.h index 20617ef3c..847c2a596 100644 --- a/sdrgui/gui/basicfeaturesettingsdialog.h +++ b/sdrgui/gui/basicfeaturesettingsdialog.h @@ -56,6 +56,7 @@ private slots: void on_reverseAPIPort_editingFinished(); void on_reverseAPIFeatureSetIndex_editingFinished(); void on_reverseAPIFeatureIndex_editingFinished(); + void on_presets_clicked(); void accept(); private: diff --git a/sdrgui/gui/basicfeaturesettingsdialog.ui b/sdrgui/gui/basicfeaturesettingsdialog.ui index e8149bd16..c22afb2fb 100644 --- a/sdrgui/gui/basicfeaturesettingsdialog.ui +++ b/sdrgui/gui/basicfeaturesettingsdialog.ui @@ -201,14 +201,32 @@ - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - + + + + + Open feature presets dialog + + + + + + + :/star.png:/star.png + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + diff --git a/sdrgui/gui/pluginpresetsdialog.cpp b/sdrgui/gui/pluginpresetsdialog.cpp new file mode 100644 index 000000000..710f12ff0 --- /dev/null +++ b/sdrgui/gui/pluginpresetsdialog.cpp @@ -0,0 +1,430 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// Copyright (C) 2023 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include "gui/addpresetdialog.h" +#include "settings/serializableinterface.h" +#include "settings/pluginpreset.h" +#include "maincore.h" + +#include "pluginpresetsdialog.h" +#include "ui_pluginpresetsdialog.h" + +PluginPresetsDialog::PluginPresetsDialog(const QString& pluginId, QWidget* parent) : + QDialog(parent), + ui(new Ui::PluginPresetsDialog), + m_pluginId(pluginId), + m_pluginPresets(nullptr), + m_serializableInterface(nullptr), + m_presetLoaded(false) +{ + ui->setupUi(this); +} + +PluginPresetsDialog::~PluginPresetsDialog() +{ + delete ui; +} + +void PluginPresetsDialog::populateTree() +{ + if (!m_pluginPresets) { + return; + } + + QList::const_iterator it = m_pluginPresets->begin(); + int middleIndex = m_pluginPresets->size() / 2; + QTreeWidgetItem *treeItem; + ui->presetsTree->clear(); + + for (int i = 0; it != m_pluginPresets->end(); ++it, i++) + { + const PluginPreset *preset = *it; + treeItem = addPresetToTree(preset); + + if (i == middleIndex) { + ui->presetsTree->setCurrentItem(treeItem); + } + } + + updatePresetControls(); +} + +QTreeWidgetItem* PluginPresetsDialog::addPresetToTree(const PluginPreset* preset) +{ + QTreeWidgetItem* group = nullptr; + + for (int i = 0; i < ui->presetsTree->topLevelItemCount(); i++) + { + if (ui->presetsTree->topLevelItem(i)->text(0) == preset->getGroup()) + { + group = ui->presetsTree->topLevelItem(i); + break; + } + } + + if (!group) + { + QStringList sl; + sl.append(preset->getGroup()); + group = new QTreeWidgetItem(ui->presetsTree, sl, PGroup); + group->setFirstColumnSpanned(true); + group->setExpanded(true); + ui->presetsTree->sortByColumn(0, Qt::AscendingOrder); + // Only show group when it contains presets for this pluging + if (preset->getPluginIdURI() != m_pluginId) { + group->setHidden(true); + } + } + else + { + if (preset->getPluginIdURI() == m_pluginId) { + group->setHidden(false); + } + } + + QStringList sl; + sl.append(preset->getDescription()); + QTreeWidgetItem* item = new QTreeWidgetItem(group, sl, PItem); // description column + item->setTextAlignment(0, Qt::AlignLeft); + item->setData(0, Qt::UserRole, QVariant::fromValue(preset)); + // Only show presets for this plugin + if (preset->getPluginIdURI() != m_pluginId) { + item->setHidden(true); + } + + updatePresetControls(); + return item; +} + +void PluginPresetsDialog::updatePresetControls() +{ + ui->presetsTree->resizeColumnToContents(0); + + if (ui->presetsTree->currentItem()) + { + ui->presetDelete->setEnabled(true); + ui->presetLoad->setEnabled(true); + } + else + { + ui->presetDelete->setEnabled(false); + ui->presetLoad->setEnabled(false); + } +} + +void PluginPresetsDialog::on_presetSave_clicked() +{ + QStringList groups; + QString group; + QString description = ""; + + for (int i = 0; i < ui->presetsTree->topLevelItemCount(); i++) { + groups.append(ui->presetsTree->topLevelItem(i)->text(0)); + } + + QTreeWidgetItem* item = ui->presetsTree->currentItem(); + + if (item) + { + if (item->type() == PGroup) + { + group = item->text(0); + } + else if (item->type() == PItem) + { + group = item->parent()->text(0); + description = item->text(0); + } + } + + AddPresetDialog dlg(groups, group, this); + + if (description.length() > 0) { + dlg.setDescription(description); + } + + if (dlg.exec() == QDialog::Accepted) + { + PluginPreset* preset = newPreset(dlg.group(), dlg.description()); + savePresetSettings(preset); + ui->presetsTree->setCurrentItem(addPresetToTree(preset)); + } + + sortPresets(); +} + +void PluginPresetsDialog::on_presetUpdate_clicked() +{ + QTreeWidgetItem* item = ui->presetsTree->currentItem(); + const PluginPreset* changedPreset = nullptr; + + if (item) + { + if( item->type() == PItem) + { + const PluginPreset* preset = qvariant_cast(item->data(0, Qt::UserRole)); + + if (preset) + { + PluginPreset* preset_mod = const_cast(preset); + savePresetSettings(preset_mod); + changedPreset = preset; + } + } + } + + sortPresets(); + ui->presetsTree->clear(); + + for (int i = 0; i < m_pluginPresets->size(); ++i) + { + QTreeWidgetItem *item_x = addPresetToTree(m_pluginPresets->at(i)); + const PluginPreset* preset_x = qvariant_cast(item_x->data(0, Qt::UserRole)); + + if (changedPreset && (preset_x == changedPreset)) { // set cursor on changed preset + ui->presetsTree->setCurrentItem(item_x); + } + } +} + +void PluginPresetsDialog::on_presetEdit_clicked() +{ + QTreeWidgetItem* item = ui->presetsTree->currentItem(); + QStringList groups; + bool change = false; + const PluginPreset *changedPreset = nullptr; + QString newGroupName; + + for (int i = 0; i < ui->presetsTree->topLevelItemCount(); i++) { + groups.append(ui->presetsTree->topLevelItem(i)->text(0)); + } + + if (item) + { + if (item->type() == PItem) + { + const PluginPreset* preset = qvariant_cast(item->data(0, Qt::UserRole)); + AddPresetDialog dlg(groups, preset->getGroup(), this); + dlg.setDescription(preset->getDescription()); + + if (dlg.exec() == QDialog::Accepted) + { + PluginPreset* preset_mod = const_cast(preset); + preset_mod->setGroup(dlg.group()); + preset_mod->setDescription(dlg.description()); + change = true; + changedPreset = preset; + } + } + else if (item->type() == PGroup) + { + AddPresetDialog dlg(groups, item->text(0), this); + dlg.showGroupOnly(); + dlg.setDialogTitle("Edit preset group"); + + if (dlg.exec() == QDialog::Accepted) + { + renamePresetGroup(item->text(0), dlg.group()); + newGroupName = dlg.group(); + change = true; + } + } + } + + if (change) + { + sortPresets(); + ui->presetsTree->clear(); + + for (int i = 0; i < m_pluginPresets->size(); ++i) + { + QTreeWidgetItem *item_x = addPresetToTree(m_pluginPresets->at(i)); + const PluginPreset* preset_x = qvariant_cast(item_x->data(0, Qt::UserRole)); + + if (changedPreset && (preset_x == changedPreset)) { // set cursor on changed preset + ui->presetsTree->setCurrentItem(item_x); + } + } + + if (!changedPreset) // on group name change set cursor on the group that has been changed + { + for(int i = 0; i < ui->presetsTree->topLevelItemCount(); i++) + { + QTreeWidgetItem* item = ui->presetsTree->topLevelItem(i); + + if (item->text(0) == newGroupName) { + ui->presetsTree->setCurrentItem(item); + } + } + } + } +} + +void PluginPresetsDialog::on_presetDelete_clicked() +{ + QTreeWidgetItem* item = ui->presetsTree->currentItem(); + + if (item == 0) + { + updatePresetControls(); + return; + } + else + { + if (item->type() == PItem) + { + const PluginPreset* preset = qvariant_cast(item->data(0, Qt::UserRole)); + + if (preset) + { + if(QMessageBox::question(this, tr("Delete Preset"), tr("Do you want to delete preset '%1'?").arg(preset->getDescription()), QMessageBox::No | QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) { + delete item; + deletePreset(preset); + } + } + } + else if (item->type() == PGroup) + { + if (QMessageBox::question(this, + tr("Delete preset group"), + tr("Do you want to delete preset group '%1'?") + .arg(item->text(0)), QMessageBox::No | QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) + { + deletePresetGroup(item->text(0)); + + ui->presetsTree->clear(); + + for (int i = 0; i < m_pluginPresets->size(); ++i) { + addPresetToTree(m_pluginPresets->at(i)); + } + } + } + } +} + +void PluginPresetsDialog::on_presetLoad_clicked() +{ + qDebug() << "PluginPresetsDialog::on_presetLoad_clicked"; + + QTreeWidgetItem* item = ui->presetsTree->currentItem(); + + if (!item) + { + qDebug("PluginPresetsDialog::on_presetLoad_clicked: item null"); + updatePresetControls(); + return; + } + + const PluginPreset* preset = qvariant_cast(item->data(0, Qt::UserRole)); + + if (!preset) + { + qDebug("PluginPresetsDialog::on_presetLoad_clicked: preset null"); + return; + } + + loadPresetSettings(preset); +} + +void PluginPresetsDialog::on_presetTree_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous) +{ + (void) current; + (void) previous; + updatePresetControls(); +} + +void PluginPresetsDialog::on_presetTree_itemActivated(QTreeWidgetItem *item, int column) +{ + (void) item; + (void) column; + on_presetLoad_clicked(); +} + +PluginPreset* PluginPresetsDialog::newPreset(const QString& group, const QString& description) +{ + PluginPreset* preset = new PluginPreset(); + preset->setGroup(group); + preset->setDescription(description); + addPreset(preset); + return preset; +} + +void PluginPresetsDialog::addPreset(PluginPreset *preset) +{ + m_pluginPresets->append(preset); +} + +void PluginPresetsDialog::savePresetSettings(PluginPreset* preset) +{ + qDebug("PluginPresetsDialog::savePresetSettings: preset [%s | %s]", + qPrintable(preset->getGroup()), + qPrintable(preset->getDescription())); + + preset->setConfig(m_pluginId, m_serializableInterface->serialize()); +} + +void PluginPresetsDialog::loadPresetSettings(const PluginPreset* preset) +{ + qDebug("PluginPresetsDialog::loadPresetSettings: preset [%s | %s]", + qPrintable(preset->getGroup()), + qPrintable(preset->getDescription())); + + m_serializableInterface->deserialize(preset->getConfig()); + + m_presetLoaded = true; +} + +void PluginPresetsDialog::sortPresets() +{ + std::sort(m_pluginPresets->begin(), m_pluginPresets->end(), PluginPreset::presetCompare); +} + +void PluginPresetsDialog::renamePresetGroup(const QString& oldGroupName, const QString& newGroupName) +{ + for (int i = 0; i < m_pluginPresets->size(); i++) + { + if (m_pluginPresets->at(i)->getGroup() == oldGroupName) + { + PluginPreset *preset_mod = const_cast(m_pluginPresets->at(i)); + preset_mod->setGroup(newGroupName); + } + } +} + +void PluginPresetsDialog::deletePreset(const PluginPreset* preset) +{ + m_pluginPresets->removeAll((PluginPreset*) preset); + delete (PluginPreset*) preset; +} + +void PluginPresetsDialog::deletePresetGroup(const QString& groupName) +{ + QList::iterator it = m_pluginPresets->begin(); + + while (it != m_pluginPresets->end()) + { + if ((*it)->getGroup() == groupName) { + it = m_pluginPresets->erase(it); + } else { + ++it; + } + } +} diff --git a/sdrgui/gui/pluginpresetsdialog.h b/sdrgui/gui/pluginpresetsdialog.h new file mode 100644 index 000000000..c8f5a6ae0 --- /dev/null +++ b/sdrgui/gui/pluginpresetsdialog.h @@ -0,0 +1,81 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// Copyright (C) 2023 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef SDRGUI_GUI_PLUGINPRESETSDIALOG_H_ +#define SDRGUI_GUI_PLUGINPRESETSDIALOG_H_ + +#include +#include +#include + +#include "export.h" + +class PluginPreset; +class SerializableInterface; +class WebAPIAdapterInterface; +class PluginAPI; +class Workspace; + +namespace Ui { + class PluginPresetsDialog; +} + +class SDRGUI_API PluginPresetsDialog : public QDialog { + Q_OBJECT +public: + explicit PluginPresetsDialog(const QString& pluginId, QWidget* parent = nullptr); + ~PluginPresetsDialog(); + void setPresets(QList* presets) { m_pluginPresets = presets; } + void setSerializableInterface(SerializableInterface *serializableInterface) { m_serializableInterface = serializableInterface; } + void populateTree(); + bool wasPresetLoaded() const { return m_presetLoaded; } + +private: + enum { + PGroup, + PItem + }; + + Ui::PluginPresetsDialog* ui; + QString m_pluginId; + QList *m_pluginPresets; + SerializableInterface *m_serializableInterface; + bool m_presetLoaded; + + QTreeWidgetItem* addPresetToTree(const PluginPreset* preset); + void updatePresetControls(); + PluginPreset* newPreset(const QString& group, const QString& description); + void addPreset(PluginPreset *preset); + void savePresetSettings(PluginPreset* preset); + void loadPresetSettings(const PluginPreset* preset); + void sortPresets(); + void renamePresetGroup(const QString& oldGroupName, const QString& newGroupName); + void deletePreset(const PluginPreset* preset); + void deletePresetGroup(const QString& groupName); + +private slots: + void on_presetSave_clicked(); + void on_presetUpdate_clicked(); + void on_presetEdit_clicked(); + void on_presetDelete_clicked(); + void on_presetLoad_clicked(); + void on_presetTree_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous); + void on_presetTree_itemActivated(QTreeWidgetItem *item, int column); +}; + +#endif // SDRGUI_GUI_PLUGINPRESETSDIALOG_H_ diff --git a/sdrgui/gui/pluginpresetsdialog.ui b/sdrgui/gui/pluginpresetsdialog.ui new file mode 100644 index 000000000..eba927e41 --- /dev/null +++ b/sdrgui/gui/pluginpresetsdialog.ui @@ -0,0 +1,235 @@ + + + PluginPresetsDialog + + + + 0 + 0 + 376 + 399 + + + + + 0 + 0 + + + + + Liberation Sans + 9 + + + + Plugin presets + + + + + + + 0 + 0 + + + + + + + 5 + + + true + + + 1 + + + 5 + + + + Description + + + + + + + + + + + + + Save current settings as new preset + + + ... + + + + :/create.png:/create.png + + + + 16 + 16 + + + + + + + + Update selected preset with current settings + + + ... + + + + :/recycle.png:/recycle.png + + + + 16 + 16 + + + + + + + + Edit preset details + + + + + + + :/edit.png:/edit.png + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Delete selected preset + + + ... + + + + :/bin.png:/bin.png + + + + 16 + 16 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Load selected preset + + + ... + + + + :/load.png:/load.png + + + + 16 + 16 + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + + + + + + buttonBox + accepted() + PluginPresetsDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + PluginPresetsDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/sdrgui/mainwindow.cpp b/sdrgui/mainwindow.cpp index 7935bb3f9..37545f84e 100644 --- a/sdrgui/mainwindow.cpp +++ b/sdrgui/mainwindow.cpp @@ -92,6 +92,7 @@ #include "webapi/webapiserver.h" #include "webapi/webapiadapter.h" #include "commands/command.h" +#include "settings/serializableinterface.h" #ifdef ANDROID #include "util/android.h" #endif @@ -403,6 +404,7 @@ void MainWindow::sampleSourceAdd(Workspace *deviceWorkspace, Workspace *spectrum deviceWorkspace->addToMdiArea(m_deviceUIs.back()->m_deviceGUI); spectrumWorkspace->addToMdiArea(m_deviceUIs.back()->m_mainSpectrumGUI); + loadDefaultPreset(deviceAPI->getSamplingDeviceId(), m_deviceUIs.back()); emit m_mainCore->deviceSetAdded(deviceSetIndex, deviceAPI); #ifdef ANDROID @@ -638,6 +640,7 @@ void MainWindow::sampleSinkAdd(Workspace *deviceWorkspace, Workspace *spectrumWo deviceWorkspace->addToMdiArea(m_deviceUIs.back()->m_deviceGUI); spectrumWorkspace->addToMdiArea(m_deviceUIs.back()->m_mainSpectrumGUI); + loadDefaultPreset(deviceAPI->getSamplingDeviceId(), m_deviceUIs.back()); emit m_mainCore->deviceSetAdded(deviceSetIndex, deviceAPI); } @@ -869,6 +872,7 @@ void MainWindow::sampleMIMOAdd(Workspace *deviceWorkspace, Workspace *spectrumWo deviceWorkspace->addToMdiArea(m_deviceUIs.back()->m_deviceGUI); spectrumWorkspace->addToMdiArea(m_deviceUIs.back()->m_mainSpectrumGUI); + loadDefaultPreset(deviceAPI->getSamplingDeviceId(), m_deviceUIs.back()); emit m_mainCore->deviceSetAdded(deviceSetIndex, deviceAPI); } @@ -2777,13 +2781,13 @@ void MainWindow::channelAddClicked(Workspace *workspace, int deviceSetIndex, int { DeviceUISet *deviceUI = m_deviceUIs[deviceSetIndex]; ChannelGUI *gui = nullptr; + ChannelAPI *channelAPI; DeviceAPI *deviceAPI = deviceUI->m_deviceAPI; if (deviceUI->m_deviceSourceEngine) // source device => Rx channels { PluginAPI::ChannelRegistrations *channelRegistrations = m_pluginManager->getRxChannelRegistrations(); // Available channel plugins PluginInterface *pluginInterface = (*channelRegistrations)[channelPluginIndex].m_plugin; - ChannelAPI *channelAPI; BasebandSampleSink *rxChannel; pluginInterface->createRxChannel(deviceUI->m_deviceAPI, &rxChannel, &channelAPI); gui = pluginInterface->createRxChannelGUI(deviceUI, rxChannel); @@ -2796,7 +2800,6 @@ void MainWindow::channelAddClicked(Workspace *workspace, int deviceSetIndex, int { PluginAPI::ChannelRegistrations *channelRegistrations = m_pluginManager->getTxChannelRegistrations(); // Available channel plugins PluginInterface *pluginInterface = (*channelRegistrations)[channelPluginIndex].m_plugin; - ChannelAPI *channelAPI; BasebandSampleSource *txChannel; pluginInterface->createTxChannel(deviceUI->m_deviceAPI, &txChannel, &channelAPI); gui = pluginInterface->createTxChannelGUI(deviceUI, txChannel); @@ -2817,7 +2820,6 @@ void MainWindow::channelAddClicked(Workspace *workspace, int deviceSetIndex, int { PluginAPI::ChannelRegistrations *channelRegistrations = m_pluginManager->getMIMOChannelRegistrations(); // Available channel plugins PluginInterface *pluginInterface = (*channelRegistrations)[channelPluginIndex].m_plugin; - ChannelAPI *channelAPI; MIMOChannel *mimoChannel; pluginInterface->createMIMOChannel(deviceUI->m_deviceAPI, &mimoChannel, &channelAPI); gui = pluginInterface->createMIMOChannelGUI(deviceUI, mimoChannel); @@ -2829,7 +2831,6 @@ void MainWindow::channelAddClicked(Workspace *workspace, int deviceSetIndex, int { PluginAPI::ChannelRegistrations *channelRegistrations = m_pluginManager->getRxChannelRegistrations(); // Available channel plugins PluginInterface *pluginInterface = (*channelRegistrations)[channelPluginIndex - nbMIMOChannels].m_plugin; - ChannelAPI *channelAPI; BasebandSampleSink *rxChannel; pluginInterface->createRxChannel(deviceUI->m_deviceAPI, &rxChannel, &channelAPI); gui = pluginInterface->createRxChannelGUI(deviceUI, rxChannel); @@ -2841,7 +2842,6 @@ void MainWindow::channelAddClicked(Workspace *workspace, int deviceSetIndex, int { PluginAPI::ChannelRegistrations *channelRegistrations = m_pluginManager->getTxChannelRegistrations(); // Available channel plugins PluginInterface *pluginInterface = (*channelRegistrations)[channelPluginIndex - nbMIMOChannels - nbRxChannels].m_plugin; - ChannelAPI *channelAPI; BasebandSampleSource *txChannel; pluginInterface->createTxChannel(deviceUI->m_deviceAPI, &txChannel, &channelAPI); gui = pluginInterface->createTxChannelGUI(deviceUI, txChannel); @@ -2881,6 +2881,7 @@ void MainWindow::channelAddClicked(Workspace *workspace, int deviceSetIndex, int qPrintable(gui->getTitle()), workspace->getIndex()); workspace->addToMdiArea((QMdiSubWindow*) gui); //gui->restoreGeometry(gui->getGeometryBytes()); + loadDefaultPreset(channelAPI->getURI(), gui); } } } @@ -2901,6 +2902,7 @@ void MainWindow::featureAddClicked(Workspace *workspace, int featureIndex) gui->setWorkspaceIndex(workspace->getIndex()); gui->setDisplayedame(pluginInterface->getPluginDescriptor().displayedName); workspace->addToMdiArea((QMdiSubWindow*) gui); + loadDefaultPreset(feature->getURI(), gui); QObject::connect( gui, @@ -3087,6 +3089,23 @@ void MainWindow::deleteFeature(int featureSetIndex, int featureIndex) } } +// Look for and load a preset named Defaults/Default for the given plugin id +void MainWindow::loadDefaultPreset(const QString& pluginId, SerializableInterface *serializableInterface) +{ + QList* presets = m_mainCore->m_settings.getPluginPresets(); + + for (const auto preset : *presets) + { + if (preset->getGroup() == "Defaults" + && preset->getDescription() == "Default" + && preset->getPluginIdURI() == pluginId) + { + qDebug() << "MainWindow::loadDefaultPreset: Loading " << preset->getGroup() << preset->getDescription() << "for" << pluginId; + serializableInterface->deserialize(preset->getConfig()); + } + } +} + void MainWindow::on_action_About_triggered() { AboutDialog dlg(m_apiHost.isEmpty() ? "127.0.0.1" : m_apiHost, m_apiPort, m_mainCore->m_settings, this); diff --git a/sdrgui/mainwindow.h b/sdrgui/mainwindow.h index 70da0ddea..388e65ebc 100644 --- a/sdrgui/mainwindow.h +++ b/sdrgui/mainwindow.h @@ -60,6 +60,7 @@ class FeatureSetPreset; class CommandKeyReceiver; class ConfigurationsDialog; class ProfileDialog; +class SerializableInterface; class QMenuBar; class Workspace; @@ -171,6 +172,7 @@ private: DeviceUISet *deviceUISet ); void deleteFeature(int featureSetIndex, int featureIndex); + void loadDefaultPreset(const QString& pluginId, SerializableInterface *serializableInterface); bool handleMessage(const Message& cmd);