From 231b829660767fd9b1977b2bb13f67ba22b19459 Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Tue, 18 Mar 2025 21:37:24 -0400 Subject: [PATCH] add batch manipulation operations for adding a peer to inclusion and always lists for all TGs; --- src/tged/PeerEntryWnd.h | 142 ++++++++++++++++++++++++++++++++++++++++ src/tged/TGEdMainWnd.h | 14 ++++ src/tged/TGListWnd.h | 141 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 297 insertions(+) create mode 100644 src/tged/PeerEntryWnd.h diff --git a/src/tged/PeerEntryWnd.h b/src/tged/PeerEntryWnd.h new file mode 100644 index 00000000..21aacaa7 --- /dev/null +++ b/src/tged/PeerEntryWnd.h @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Digital Voice Modem - Talkgroup Editor + * GPLv2 Open Source. Use is subject to license terms. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright (C) 2025 Bryan Biedenkapp, N2PLL + * + */ +/** + * @file PeerEntryWnd.h + * @ingroup tged + */ +#if !defined(__PEER_ENTRY_WND_H__) +#define __PEER_ENTRY_WND_H__ + +#include "common/Log.h" + +#include "tged/CloseWndBase.h" +#include "tged/TGEdMain.h" +#include "tged/TGEditPeerListWnd.h" + +#include +using namespace finalcut; + +/** + * @brief This class implements the peer ID entry window. + * @ingroup tged + */ +class HOST_SW_API PeerEntryWnd final : public CloseWndBase { +public: + /** + * @brief Initializes a new instance of the TGEditWnd class. + * @param rule + * @param peerList + * @param title + * @param widget + */ + explicit PeerEntryWnd(std::string title = "Peer Entry", FWidget *widget = nullptr) : CloseWndBase{widget} + { + m_title = title; + peerId = 0U; + } + + /** + * @brief Entered peer Id. + */ + uint32_t peerId; + +private: + std::string m_title; + + FLabel m_entryLabel{"Peer ID: ", this}; + PeerLineEdit m_entry{this}; + + /** + * @brief Initializes the window layout. + */ + void initLayout() override + { + FDialog::setText(m_title); + FDialog::setSize(FSize{40, 6}); + + m_enableSetButton = false; + CloseWndBase::initLayout(); + } + + /** + * @brief Initializes window controls. + */ + void initControls() override + { + m_closeButton.setText("&OK"); + + m_entryLabel.setGeometry(FPoint(2, int(getHeight() - 4)), FSize(10, 1)); + m_entry.setGeometry(FPoint(12, int(getHeight() - 4)), FSize(15, 1)); + m_entry.setShadow(false); + m_entry.addCallback("up-pressed", [&]() { + peerId = ::atoi(m_entry.getText().c_str()); + peerId++; + if (peerId > 999999999U) { + peerId = 999999999U; + } + + m_entry.setText(std::to_string(peerId)); + redraw(); + }); + m_entry.addCallback("down-pressed", [&]() { + peerId = ::atoi(m_entry.getText().c_str()); + peerId--; + if (peerId < 1U) { + peerId = 1U; + } + + m_entry.setText(std::to_string(peerId)); + redraw(); + }); + + CloseWndBase::initControls(); + + m_closeButton.setGeometry(FPoint(int(getWidth()) - 12, int(getHeight()) - 4), FSize(9, 1)); + m_closeButton.setText("OK"); + + setFocusWidget(&m_entry); + redraw(); + } + + /* + ** Event Handlers + */ + + /** + * @brief Event that occurs on keyboard key press. + * @param e Keyboard Event. + */ + void onKeyPress(finalcut::FKeyEvent* e) override + { + const auto key = e->key(); + if (key == FKey::Enter || key == FKey::Return) { + this->close(); + } else if (key == FKey::Escape) { + this->close(); + } + } + + /** + * @brief Event that occurs when the window is closed. + * @param e Close event. + */ + void onClose(FCloseEvent* e) override + { + if (m_entry.getText() != "") { + peerId = ::atoi(m_entry.getText().c_str()); + } else { + peerId = 0U; + } + + CloseWndBase::onClose(e); + } +}; + +#endif // __PEER_ENTRY_WND_H__ \ No newline at end of file diff --git a/src/tged/TGEdMainWnd.h b/src/tged/TGEdMainWnd.h index 2182f720..62b2ba44 100644 --- a/src/tged/TGEdMainWnd.h +++ b/src/tged/TGEdMainWnd.h @@ -78,6 +78,13 @@ public: m_backupOnSave.setChecked(); + // batch menu + m_batchMenuSeparator1.setSeparator(); + m_batchAddPeerInclusion.addCallback("clicked", this, [&]() { m_wnd->addPeerToInclusion(); }); + m_batchRemovePeerInclusion.addCallback("clicked", this, [&]() { m_wnd->removePeerFromInclusion(); }); + m_batchAddPeerAlways.addCallback("clicked", this, [&]() { m_wnd->addPeerToAlways(); }); + m_batchRemovePeerAlways.addCallback("clicked", this, [&]() { m_wnd->removePeerFromAlways(); }); + // help menu m_aboutItem.addCallback("clicked", this, [&]() { const FString line(2, UniChar::BoxDrawingsHorizontal); @@ -109,6 +116,13 @@ private: FMenuItem m_fileMenuSeparator1{&m_fileMenu}; FMenuItem m_quitItem{"&Quit", &m_fileMenu}; + FMenu m_batchMenu{"&Batch", &m_menuBar}; + FMenuItem m_batchAddPeerInclusion{"Add Peer to Inclusions...", &m_batchMenu}; + FMenuItem m_batchRemovePeerInclusion{"Remove Peer from Inclusions...", &m_batchMenu}; + FMenuItem m_batchMenuSeparator1{&m_batchMenu}; + FMenuItem m_batchAddPeerAlways{"Add Peer to Always...", &m_batchMenu}; + FMenuItem m_batchRemovePeerAlways{"Remove Peer from Always...", &m_batchMenu}; + FMenu m_helpMenu{"&Help", &m_menuBar}; FMenuItem m_aboutItem{"&About", &m_helpMenu}; diff --git a/src/tged/TGListWnd.h b/src/tged/TGListWnd.h index ca059240..de1b2465 100644 --- a/src/tged/TGListWnd.h +++ b/src/tged/TGListWnd.h @@ -19,6 +19,7 @@ #include "FDblDialog.h" #include "TGEdMainWnd.h" #include "TGEditWnd.h" +#include "PeerEntryWnd.h" #include using namespace finalcut; @@ -152,6 +153,146 @@ public: redraw(); } + /** + * @brief + */ + void addPeerToInclusion() + { + PeerEntryWnd wnd{"Add Peer to Inclusions", this}; + wnd.show(); + + uint32_t peerId = wnd.peerId; + if (peerId > 0U) { + auto groupVoice = g_tidLookups->groupVoice(); + for (auto rule : groupVoice) { + uint32_t tgId = rule.source().tgId(); + uint8_t tgSlot = rule.source().tgSlot(); + + auto config = rule.config(); + + std::vector inclusions = config.inclusion(); + auto it = std::find_if(inclusions.begin(), inclusions.end(), [&](uint32_t x) { return x == wnd.peerId; }); + if (it == inclusions.end()) { + LogMessage(LOG_HOST, "Updating TG %s (%u) adding inclusion peer %u", rule.name().c_str(), rule.source().tgId(), peerId); + inclusions.push_back(peerId); + } + + config.inclusion(inclusions); + rule.config(config); + + g_tidLookups->eraseEntry(tgId, tgSlot); + g_tidLookups->addEntry(rule); + } + } + + loadListView(); + } + + /** + * @brief + */ + void removePeerFromInclusion() + { + PeerEntryWnd wnd{"Remove Peer from Inclusions", this}; + wnd.show(); + + uint32_t peerId = wnd.peerId; + if (peerId > 0U) { + auto groupVoice = g_tidLookups->groupVoice(); + for (auto rule : groupVoice) { + uint32_t tgId = rule.source().tgId(); + uint8_t tgSlot = rule.source().tgSlot(); + + auto config = rule.config(); + + std::vector inclusions = config.inclusion(); + auto it = std::find_if(inclusions.begin(), inclusions.end(), [&](uint32_t x) { return x == wnd.peerId; }); + if (it != inclusions.end()) { + LogMessage(LOG_HOST, "Updating TG %s (%u) removing inclusion peer %u", rule.name().c_str(), rule.source().tgId(), peerId); + inclusions.erase(it); + } + + config.inclusion(inclusions); + rule.config(config); + + g_tidLookups->eraseEntry(tgId, tgSlot); + g_tidLookups->addEntry(rule); + } + } + + loadListView(); + } + + /** + * @brief + */ + void addPeerToAlways() + { + PeerEntryWnd wnd{"Add Peer to Always", this}; + wnd.show(); + + uint32_t peerId = wnd.peerId; + if (peerId > 0U) { + auto groupVoice = g_tidLookups->groupVoice(); + for (auto rule : groupVoice) { + uint32_t tgId = rule.source().tgId(); + uint8_t tgSlot = rule.source().tgSlot(); + + auto config = rule.config(); + + std::vector alwaysSend = config.alwaysSend(); + auto it = std::find_if(alwaysSend.begin(), alwaysSend.end(), [&](uint32_t x) { return x == wnd.peerId; }); + if (it == alwaysSend.end()) { + LogMessage(LOG_HOST, "Updating TG %s (%u) adding always peer %u", rule.name().c_str(), rule.source().tgId(), peerId); + alwaysSend.push_back(peerId); + } + + config.alwaysSend(alwaysSend); + rule.config(config); + + g_tidLookups->eraseEntry(tgId, tgSlot); + g_tidLookups->addEntry(rule); + } + } + + loadListView(); + } + + /** + * @brief + */ + void removePeerFromAlways() + { + PeerEntryWnd wnd{"Remove Peer from Always", this}; + wnd.show(); + + uint32_t peerId = wnd.peerId; + if (peerId > 0U) { + auto groupVoice = g_tidLookups->groupVoice(); + for (auto rule : groupVoice) { + uint32_t tgId = rule.source().tgId(); + uint8_t tgSlot = rule.source().tgSlot(); + + auto config = rule.config(); + + std::vector alwaysSend = config.alwaysSend(); + auto it = std::find_if(alwaysSend.begin(), alwaysSend.end(), [&](uint32_t x) { return x == wnd.peerId; }); + if (it != alwaysSend.end()) { + LogMessage(LOG_HOST, "Updating TG %s (%u) removing always peer %u", rule.name().c_str(), rule.source().tgId(), peerId); + alwaysSend.erase(it); + } + + config.alwaysSend(alwaysSend); + rule.config(config); + + g_tidLookups->eraseEntry(tgId, tgSlot); + g_tidLookups->addEntry(rule); + } + } + + loadListView(); + } + private: lookups::TalkgroupRuleGroupVoice m_selected; uint32_t m_selectedTgId;