diff --git a/sdrgui/channel/channelgui.cpp b/sdrgui/channel/channelgui.cpp index d7ae3ab46..89f008f96 100644 --- a/sdrgui/channel/channelgui.cpp +++ b/sdrgui/channel/channelgui.cpp @@ -91,6 +91,12 @@ ChannelGUI::ChannelGUI(QWidget *parent) : m_closeButton->setIcon(closeIcon); m_closeButton->setToolTip("Close channel"); + m_duplicateButton = new QPushButton(); + m_duplicateButton->setFixedSize(20, 20); + QIcon m_duplicateIcon(":/duplicate.png"); + m_duplicateButton->setIcon(m_duplicateIcon); + m_duplicateButton->setToolTip("Duplicate channel"); + m_statusFrequency = new QLabel(); // QFont font = m_statusFrequency->font(); // font.setPointSize(8); @@ -135,7 +141,8 @@ ChannelGUI::ChannelGUI(QWidget *parent) : m_bottomLayout = new QHBoxLayout(); m_bottomLayout->setContentsMargins(0, 0, 0, 0); - m_bottomLayout->addWidget(m_statusFrequency ); + m_bottomLayout->addWidget(m_duplicateButton); + m_bottomLayout->addWidget(m_statusFrequency); m_bottomLayout->addWidget(m_statusLabel); m_sizeGripBottomRight = new QSizeGrip(this); m_sizeGripBottomRight->setStyleSheet("QSizeGrip { background-color: rgb(128, 128, 128); width: 10px; height: 10px; }"); @@ -157,6 +164,7 @@ ChannelGUI::ChannelGUI(QWidget *parent) : connect(this, SIGNAL(forceShrink()), this, SLOT(shrinkWindow())); connect(m_hideButton, SIGNAL(clicked()), this, SLOT(hide())); connect(m_closeButton, SIGNAL(clicked()), this, SLOT(close())); + connect(m_duplicateButton, SIGNAL(clicked()), this, SLOT(duplicateChannel())); connect( m_rollupContents, @@ -270,6 +278,12 @@ void ChannelGUI::onWidgetRolled(QWidget *widget, bool show) } } +void ChannelGUI::duplicateChannel() +{ + qDebug("ChannelGUI::duplicateChannel"); + emit duplicateChannelEmitted(); +} + void ChannelGUI::shrinkWindow() { qDebug("ChannelGUI::shrinkWindow"); diff --git a/sdrgui/channel/channelgui.h b/sdrgui/channel/channelgui.h index cc0116fa4..7ab78dc6d 100644 --- a/sdrgui/channel/channelgui.h +++ b/sdrgui/channel/channelgui.h @@ -78,7 +78,7 @@ public: void setIndex(int index); int getIndex() const { return m_channelIndex; } void setDeviceSetIndex(int index); - int getDeviceSetIndex() const { return m_channelIndex; } + int getDeviceSetIndex() const { return m_deviceSetIndex; } void setStatusFrequency(qint64 frequency); void setStatusText(const QString& text); @@ -113,6 +113,7 @@ private: QPushButton *m_shrinkButton; QPushButton *m_hideButton; QPushButton *m_closeButton; + QPushButton *m_duplicateButton; QLabel *m_statusFrequency; QLabel *m_statusLabel; QVBoxLayout *m_layouts; @@ -130,11 +131,13 @@ private slots: void showHelp(); void openMoveToWorkspaceDialog(); void onWidgetRolled(QWidget *widget, bool show); + void duplicateChannel(); signals: void closing(); void moveToWorkspace(int workspaceIndex); void forceShrink(); + void duplicateChannelEmitted(); }; #endif // SDRGUI_CHANNEL_CHANNELGUI_H_ diff --git a/sdrgui/device/devicegui.h b/sdrgui/device/devicegui.h index 595a0a112..aee35e306 100644 --- a/sdrgui/device/devicegui.h +++ b/sdrgui/device/devicegui.h @@ -141,7 +141,7 @@ signals: void deviceChange(int newDeviceIndex); void showSpectrum(int deviceSetIndex); void showAllChannels(int deviceSetIndex); - void addChannelEmitted(int channelIndex); + void addChannelEmitted(int channelPluginIndex); void deviceSetPresetsDialogRequested(QPoint, DeviceGUI*); }; diff --git a/sdrgui/device/deviceuiset.cpp b/sdrgui/device/deviceuiset.cpp index e04f387ed..1ecd73d63 100644 --- a/sdrgui/device/deviceuiset.cpp +++ b/sdrgui/device/deviceuiset.cpp @@ -330,6 +330,12 @@ void DeviceUISet::loadRxChannelSettings(const Preset *preset, PluginAPI *pluginA this, [=](int wsIndexDest){ MainWindow::getInstance()->channelMove(rxChannelGUI, wsIndexDest); } ); + QObject::connect( + rxChannelGUI, + &ChannelGUI::duplicateChannelEmitted, + this, + [=](){ MainWindow::getInstance()->channelDuplicate(rxChannelGUI); } + ); } } } @@ -444,6 +450,12 @@ void DeviceUISet::loadTxChannelSettings(const Preset *preset, PluginAPI *pluginA this, [=](int wsIndexDest){ MainWindow::getInstance()->channelMove(txChannelGUI, wsIndexDest); } ); + QObject::connect( + txChannelGUI, + &ChannelGUI::duplicateChannelEmitted, + this, + [=](){ MainWindow::getInstance()->channelDuplicate(txChannelGUI); } + ); } } } @@ -560,6 +572,12 @@ void DeviceUISet::loadMIMOChannelSettings(const Preset *preset, PluginAPI *plugi this, [=](int wsIndexDest){ MainWindow::getInstance()->channelMove(mimoChannelGUI, wsIndexDest); } ); + QObject::connect( + mimoChannelGUI, + &ChannelGUI::duplicateChannelEmitted, + this, + [=](){ MainWindow::getInstance()->channelDuplicate(mimoChannelGUI); } + ); } } } diff --git a/sdrgui/gui/channeladddialog.h b/sdrgui/gui/channeladddialog.h index 6959f1bbe..f0a8fefaa 100644 --- a/sdrgui/gui/channeladddialog.h +++ b/sdrgui/gui/channeladddialog.h @@ -48,7 +48,7 @@ private slots: void apply(QAbstractButton*); signals: - void addChannel(int); + void addChannel(int channelPluginIndex); }; #endif /* SDRGUI_GUI_CHANNELADDDIALOG_H_ */ diff --git a/sdrgui/mainwindow.cpp b/sdrgui/mainwindow.cpp index 89e298a3d..66963e309 100644 --- a/sdrgui/mainwindow.cpp +++ b/sdrgui/mainwindow.cpp @@ -316,7 +316,7 @@ void MainWindow::sampleSourceAdd(Workspace *deviceWorkspace, Workspace *spectrum m_deviceUIs.back()->m_deviceGUI, &DeviceGUI::addChannelEmitted, this, - [=](int channelIndex){ this->channelAddClicked(deviceWorkspace, deviceSetIndex, channelIndex); } + [=](int channelPluginIndex){ this->channelAddClicked(deviceWorkspace, deviceSetIndex, channelPluginIndex); } ); deviceWorkspace->addToMdiArea(m_deviceUIs.back()->m_deviceGUI); @@ -531,7 +531,7 @@ void MainWindow::sampleSinkAdd(Workspace *deviceWorkspace, Workspace *spectrumWo m_deviceUIs.back()->m_deviceGUI, &DeviceGUI::addChannelEmitted, this, - [=](int channelIndex){ this->channelAddClicked(deviceWorkspace, deviceSetIndex, channelIndex); } + [=](int channelPluginIndex){ this->channelAddClicked(deviceWorkspace, deviceSetIndex, channelPluginIndex); } ); deviceWorkspace->addToMdiArea(m_deviceUIs.back()->m_deviceGUI); @@ -754,7 +754,7 @@ void MainWindow::sampleMIMOAdd(Workspace *deviceWorkspace, Workspace *spectrumWo m_deviceUIs.back()->m_deviceGUI, &DeviceGUI::addChannelEmitted, this, - [=](int channelIndex){ this->channelAddClicked(deviceWorkspace, deviceSetIndex, channelIndex); } + [=](int channelPluginIndex){ this->channelAddClicked(deviceWorkspace, deviceSetIndex, channelPluginIndex); } ); deviceWorkspace->addToMdiArea(m_deviceUIs.back()->m_deviceGUI); @@ -2059,7 +2059,7 @@ void MainWindow::sampleSourceChange(int deviceSetIndex, int newDeviceIndex, Work deviceUISet->m_deviceGUI, &DeviceGUI::addChannelEmitted, this, - [=](int channelIndex){ this->channelAddClicked(workspace, deviceSetIndex, channelIndex); } + [=](int channelPluginIndex){ this->channelAddClicked(workspace, deviceSetIndex, channelPluginIndex); } ); } } @@ -2088,7 +2088,7 @@ void MainWindow::sampleSinkChange(int deviceSetIndex, int newDeviceIndex, Worksp deviceUISet->m_deviceGUI, &DeviceGUI::addChannelEmitted, this, - [=](int channelIndex){ this->channelAddClicked(workspace, deviceSetIndex, channelIndex); } + [=](int channelPluginIndex){ this->channelAddClicked(workspace, deviceSetIndex, channelPluginIndex); } ); } } @@ -2116,14 +2116,189 @@ void MainWindow::sampleMIMOChange(int deviceSetIndex, int newDeviceIndex, Worksp deviceUISet->m_deviceGUI, &DeviceGUI::addChannelEmitted, this, - [=](int channelIndex){ this->channelAddClicked(workspace, deviceSetIndex, channelIndex); } + [=](int channelPluginIndex){ this->channelAddClicked(workspace, deviceSetIndex, channelPluginIndex); } ); } } -void MainWindow::channelAddClicked(Workspace *workspace, int deviceSetIndex, int channelIndex) +void MainWindow::channelDuplicate(ChannelGUI *sourceChannelGUI) { - if (deviceSetIndex >= 0) + int deviceSetIndex = sourceChannelGUI->getDeviceSetIndex(); + int channelIndex = sourceChannelGUI->getIndex(); + + qDebug("MainWindow::channelDuplicate: %s at %d:%d in workspace %d", + qPrintable(sourceChannelGUI->getTitle()), deviceSetIndex, channelIndex, sourceChannelGUI->getWorkspaceIndex()); + + if (deviceSetIndex < (int) m_deviceUIs.size()) + { + DeviceUISet *deviceUI = m_deviceUIs[deviceSetIndex]; + ChannelAPI *sourceChannelAPI = deviceUI->getChannelAt(channelIndex); + DeviceAPI *deviceAPI = deviceUI->m_deviceAPI; + ChannelGUI *gui = nullptr; + + if (deviceUI->m_deviceSourceEngine) // source device => Rx channels + { + PluginAPI::ChannelRegistrations *channelRegistrations = m_pluginManager->getRxChannelRegistrations(); + PluginInterface *pluginInterface = nullptr; + + for (const auto& channelRegistration : *channelRegistrations) + { + if (channelRegistration.m_channelIdURI == sourceChannelAPI->getURI()) + { + pluginInterface = channelRegistration.m_plugin; + break; + } + } + + if (pluginInterface) + { + ChannelAPI *channelAPI; + BasebandSampleSink *rxChannel; + pluginInterface->createRxChannel(deviceUI->m_deviceAPI, &rxChannel, &channelAPI); + gui = pluginInterface->createRxChannelGUI(deviceUI, rxChannel); + deviceUI->registerRxChannelInstance(channelAPI, gui); + gui->setDeviceType(ChannelGUI::DeviceRx); + gui->setIndex(channelAPI->getIndexInDeviceSet()); + QByteArray b = sourceChannelGUI->serialize(); + gui->deserialize(b); + } + } + else if (deviceUI->m_deviceSinkEngine) // sink device => Tx channels + { + PluginAPI::ChannelRegistrations *channelRegistrations = m_pluginManager->getTxChannelRegistrations(); // Available channel plugins + PluginInterface *pluginInterface = nullptr; + + for (const auto& channelRegistration : *channelRegistrations) + { + if (channelRegistration.m_channelIdURI == sourceChannelAPI->getURI()) + { + pluginInterface = channelRegistration.m_plugin; + break; + } + } + + if (pluginInterface) + { + ChannelAPI *channelAPI; + BasebandSampleSource *txChannel; + pluginInterface->createTxChannel(deviceUI->m_deviceAPI, &txChannel, &channelAPI); + gui = pluginInterface->createTxChannelGUI(deviceUI, txChannel); + deviceUI->registerTxChannelInstance(channelAPI, gui); + gui->setDeviceType(ChannelGUI::DeviceTx); + gui->setIndex(channelAPI->getIndexInDeviceSet()); + QByteArray b = sourceChannelGUI->serialize(); + gui->deserialize(b); + } + } + else if (deviceUI->m_deviceMIMOEngine) // MIMO device => Any type of channel is possible + { + PluginAPI::ChannelRegistrations *rxChannelRegistrations = m_pluginManager->getRxChannelRegistrations(); + PluginAPI::ChannelRegistrations *txChannelRegistrations = m_pluginManager->getTxChannelRegistrations(); + PluginAPI::ChannelRegistrations *mimoChannelRegistrations = m_pluginManager->getMIMOChannelRegistrations(); + PluginInterface *pluginInterface = nullptr; + + for (const auto& channelRegistration : *rxChannelRegistrations) + { + if (channelRegistration.m_channelIdURI == sourceChannelAPI->getURI()) + { + pluginInterface = channelRegistration.m_plugin; + break; + } + } + + if (pluginInterface) // Rx channel + { + ChannelAPI *channelAPI; + BasebandSampleSink *rxChannel; + pluginInterface->createRxChannel(deviceUI->m_deviceAPI, &rxChannel, &channelAPI); + gui = pluginInterface->createRxChannelGUI(deviceUI, rxChannel); + deviceUI->registerRxChannelInstance(channelAPI, gui); + gui->setDeviceType(ChannelGUI::DeviceMIMO); + gui->setIndex(channelAPI->getIndexInDeviceSet()); + QByteArray b = sourceChannelGUI->serialize(); + gui->deserialize(b); + } + else + { + for (const auto& channelRegistration : *txChannelRegistrations) + { + if (channelRegistration.m_channelIdURI == sourceChannelAPI->getURI()) + { + pluginInterface = channelRegistration.m_plugin; + break; + } + } + + if (pluginInterface) // Tx channel + { + ChannelAPI *channelAPI; + BasebandSampleSource *txChannel; + pluginInterface->createTxChannel(deviceUI->m_deviceAPI, &txChannel, &channelAPI); + gui = pluginInterface->createTxChannelGUI(deviceUI, txChannel); + deviceUI->registerTxChannelInstance(channelAPI, gui); + gui->setDeviceType(ChannelGUI::DeviceMIMO); + gui->setIndex(channelAPI->getIndexInDeviceSet()); + QByteArray b = sourceChannelGUI->serialize(); + gui->deserialize(b); + } + else + { + for (const auto& channelRegistration : *mimoChannelRegistrations) + { + if (channelRegistration.m_channelIdURI == sourceChannelAPI->getURI()) + { + pluginInterface = channelRegistration.m_plugin; + break; + } + } + + if (pluginInterface) + { + ChannelAPI *channelAPI; + MIMOChannel *mimoChannel; + pluginInterface->createMIMOChannel(deviceUI->m_deviceAPI, &mimoChannel, &channelAPI); + gui = pluginInterface->createMIMOChannelGUI(deviceUI, mimoChannel); + deviceUI->registerChannelInstance(channelAPI, gui); + gui->setDeviceType(ChannelGUI::DeviceMIMO); + gui->setIndex(channelAPI->getIndexInDeviceSet()); + QByteArray b = sourceChannelGUI->serialize(); + gui->deserialize(b); + } + } + } + } + + int workspaceIndex = sourceChannelGUI->getWorkspaceIndex(); + Workspace *workspace = workspaceIndex < m_workspaces.size() ? m_workspaces[sourceChannelGUI->getWorkspaceIndex()] : nullptr; + + if (gui && workspace) + { + QObject::connect( + gui, + &ChannelGUI::moveToWorkspace, + this, + [=](int wsIndexDest){ this->channelMove(gui, wsIndexDest); } + ); + QObject::connect( + gui, + &ChannelGUI::duplicateChannelEmitted, + this, + [=](){ this->channelDuplicate(gui); } + ); + + gui->setDeviceSetIndex(deviceSetIndex); + gui->setToolTip(deviceAPI->getSamplingDeviceDisplayName()); + gui->setWorkspaceIndex(workspace->getIndex()); + qDebug("MainWindow::channelDuplicate: adding %s to workspace #%d", + qPrintable(gui->getTitle()), workspace->getIndex()); + workspace->addToMdiArea((QMdiSubWindow*) gui); + } + } +} + +void MainWindow::channelAddClicked(Workspace *workspace, int deviceSetIndex, int channelPluginIndex) +{ + if (deviceSetIndex < (int) m_deviceUIs.size()) { DeviceUISet *deviceUI = m_deviceUIs[deviceSetIndex]; ChannelGUI *gui = nullptr; @@ -2132,7 +2307,7 @@ void MainWindow::channelAddClicked(Workspace *workspace, int deviceSetIndex, int if (deviceUI->m_deviceSourceEngine) // source device => Rx channels { PluginAPI::ChannelRegistrations *channelRegistrations = m_pluginManager->getRxChannelRegistrations(); // Available channel plugins - PluginInterface *pluginInterface = (*channelRegistrations)[channelIndex].m_plugin; + PluginInterface *pluginInterface = (*channelRegistrations)[channelPluginIndex].m_plugin; ChannelAPI *channelAPI; BasebandSampleSink *rxChannel; pluginInterface->createRxChannel(deviceUI->m_deviceAPI, &rxChannel, &channelAPI); @@ -2144,7 +2319,7 @@ void MainWindow::channelAddClicked(Workspace *workspace, int deviceSetIndex, int else if (deviceUI->m_deviceSinkEngine) // sink device => Tx channels { PluginAPI::ChannelRegistrations *channelRegistrations = m_pluginManager->getTxChannelRegistrations(); // Available channel plugins - PluginInterface *pluginInterface = (*channelRegistrations)[channelIndex].m_plugin; + PluginInterface *pluginInterface = (*channelRegistrations)[channelPluginIndex].m_plugin; ChannelAPI *channelAPI; BasebandSampleSource *txChannel; pluginInterface->createTxChannel(deviceUI->m_deviceAPI, &txChannel, &channelAPI); @@ -2159,12 +2334,12 @@ void MainWindow::channelAddClicked(Workspace *workspace, int deviceSetIndex, int int nbRxChannels = deviceUI->getNumberOfAvailableRxChannels(); int nbTxChannels = deviceUI->getNumberOfAvailableTxChannels(); qDebug("MainWindow::channelAddClicked: MIMO: dev %d : nbMIMO: %d nbRx: %d nbTx: %d selected: %d", - deviceSetIndex, nbMIMOChannels, nbRxChannels, nbTxChannels, channelIndex); + deviceSetIndex, nbMIMOChannels, nbRxChannels, nbTxChannels, channelPluginIndex); - if (channelIndex < nbMIMOChannels) + if (channelPluginIndex < nbMIMOChannels) { PluginAPI::ChannelRegistrations *channelRegistrations = m_pluginManager->getMIMOChannelRegistrations(); // Available channel plugins - PluginInterface *pluginInterface = (*channelRegistrations)[channelIndex].m_plugin; + PluginInterface *pluginInterface = (*channelRegistrations)[channelPluginIndex].m_plugin; ChannelAPI *channelAPI; MIMOChannel *mimoChannel; pluginInterface->createMIMOChannel(deviceUI->m_deviceAPI, &mimoChannel, &channelAPI); @@ -2172,10 +2347,10 @@ void MainWindow::channelAddClicked(Workspace *workspace, int deviceSetIndex, int deviceUI->registerChannelInstance(channelAPI, gui); gui->setIndex(channelAPI->getIndexInDeviceSet()); } - else if (channelIndex < nbMIMOChannels + nbRxChannels) // Rx + else if (channelPluginIndex < nbMIMOChannels + nbRxChannels) // Rx { PluginAPI::ChannelRegistrations *channelRegistrations = m_pluginManager->getRxChannelRegistrations(); // Available channel plugins - PluginInterface *pluginInterface = (*channelRegistrations)[channelIndex - nbMIMOChannels].m_plugin; + PluginInterface *pluginInterface = (*channelRegistrations)[channelPluginIndex - nbMIMOChannels].m_plugin; ChannelAPI *channelAPI; BasebandSampleSink *rxChannel; pluginInterface->createRxChannel(deviceUI->m_deviceAPI, &rxChannel, &channelAPI); @@ -2183,10 +2358,10 @@ void MainWindow::channelAddClicked(Workspace *workspace, int deviceSetIndex, int deviceUI->registerRxChannelInstance(channelAPI, gui); gui->setIndex(channelAPI->getIndexInDeviceSet()); } - else if (channelIndex < nbMIMOChannels + nbRxChannels + nbTxChannels) + else if (channelPluginIndex < nbMIMOChannels + nbRxChannels + nbTxChannels) { PluginAPI::ChannelRegistrations *channelRegistrations = m_pluginManager->getTxChannelRegistrations(); // Available channel plugins - PluginInterface *pluginInterface = (*channelRegistrations)[channelIndex - nbMIMOChannels - nbRxChannels].m_plugin; + PluginInterface *pluginInterface = (*channelRegistrations)[channelPluginIndex - nbMIMOChannels - nbRxChannels].m_plugin; ChannelAPI *channelAPI; BasebandSampleSource *txChannel; pluginInterface->createTxChannel(deviceUI->m_deviceAPI, &txChannel, &channelAPI); @@ -2206,6 +2381,12 @@ void MainWindow::channelAddClicked(Workspace *workspace, int deviceSetIndex, int this, [=](int wsIndexDest){ this->channelMove(gui, wsIndexDest); } ); + QObject::connect( + gui, + &ChannelGUI::duplicateChannelEmitted, + this, + [=](){ this->channelDuplicate(gui); } + ); gui->setDeviceSetIndex(deviceSetIndex); gui->setToolTip(deviceAPI->getSamplingDeviceDisplayName()); diff --git a/sdrgui/mainwindow.h b/sdrgui/mainwindow.h index d3b407054..adf825bc3 100644 --- a/sdrgui/mainwindow.h +++ b/sdrgui/mainwindow.h @@ -82,6 +82,7 @@ public: public slots: void channelMove(ChannelGUI *gui, int wsIndexDestnation); + void channelDuplicate(ChannelGUI *gui); private: enum { @@ -198,7 +199,7 @@ private slots: void sampleSinkAdd(Workspace *workspace, Workspace *spectrumWorkspace, int deviceIndex); void sampleMIMOAdd(Workspace *workspace, Workspace *spectrumWorkspace, int deviceIndex); void samplingDeviceChangeHandler(DeviceGUI *deviceGUI, int newDeviceIndex); - void channelAddClicked(Workspace *workspace, int deviceSetIndex, int channelIndex); + void channelAddClicked(Workspace *workspace, int deviceSetIndex, int channelPluginIndex); void featureAddClicked(Workspace *workspace, int featureIndex); void featureMove(FeatureGUI *gui, int wsIndexDestnation); void openFeaturePresetsDialog(QPoint p, Workspace *workspace);