Initial commit

This commit is contained in:
torsten committed 2026-08-13 18:33:10 +02:00
commit b7d90b9afe
16245 files changed
+3396666

No files matched your search

+41
View File
@@ -0,0 +1,41 @@
#
# $Id$
# $HeadURL$
# $Author$
# Created by Astrid Mueller, SGAS, 2017-10-17
#
SET(avm_eloka_gui_SRCS
avm_eloka_gui_plugin.cpp
avm_eloka_gui_plugin.h
avm_eloka_dialog.cpp
avm_eloka_dialog.h
avm_eloka_edit_dialog.cpp
avm_eloka_edit_dialog.h
avm_eloka_model.cpp
avm_eloka_model.h
)
NGL_WRAP_UI(avm_eloka_gui_SRCS
avm_eloka_dialog.ui
avm_eloka_edit_dialog.ui
)
NGL_ADD_LIBRARY(WS AvmElokaGuiPlugin MODULE ${avm_eloka_gui_SRCS})
NGL_TARGET_LINK_LIBRARIES(AvmElokaGuiPlugin
LtsPrinting
NGLLogger
LtsSession
LtsSessionData
LtsUtilsSettings
AvmDataPluginInterface
PpmDataPluginInterface
svcAvmCommon
Qt5::Widgets
LtsWidgets
LtsDataView
LtsUtilsGuiDds
ngltools
)
NGL_INSTALL_TARGET(AvmElokaGuiPlugin)
@@ -0,0 +1,335 @@
/**
* @RDE_HEADER@
* The ElokaDialog shows all electronic warfare and offers options to creating, updating and deleting
* $Id$
* $HeadURL$
* $Author$
* Created by Astrid Mueller, SGAS, 2017-10-17
*/
#include "avm_eloka_dialog.h"
#include "ui_avm_eloka_dialog.h"
#include <avm_eloka_edit_dialog.h>
#include <AudioVideoManagement/ava_session.h>
#include <AudioVideoManagement/ava_control.h>
#include <AudioVideoManagement/av_helper.h>
#include <AudioVideoManagement/stream_name_mapping.h>
#include <LtsSession/lts_session_data.h>
#include <LtsPrinting/printing.h>
#include <QTreeView>
namespace AudioVideoManagement
{
ElokaDialog::ElokaDialog(LtsSession::LtsSession *session, AvaSession *avaSession, Interface::Dtc *avmDtc, StreamNameMapping *streamNameMapping,
const QString &menuGroup, QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::CloseOnly)
, m_ui(new Ui::ElokaDialog)
, m_menuGroup(menuGroup)
, m_elokaModel(new ElokaModel(session, this))
, m_session(session)
, m_avaSession(avaSession)
, m_elokaListCollector(m_avaSession->control()->comm(), [this] (QVector<AvaEloka> &&eloka) { onQueryElokaResponse(std::move(eloka)); })
, m_streamNameMapping(streamNameMapping)
, m_avmDtc(avmDtc)
, m_avaSessionEstablished(false)
, m_usedCnr()
, m_usedTvc()
, m_usedAnnouncement()
, m_logger(getLogger("ElokaDialog"))
{
Q_ASSERT(session);
Q_ASSERT(avaSession);
Q_ASSERT(streamNameMapping);
Q_ASSERT(avmDtc);
m_ui->setupUi(this);
connect(m_avaSession, &AvaSession::sessionEstablished,
this, &ElokaDialog::onAvaSessionEstablished);
connect(m_avaSession, &AvaSession::disconnected,
this, &ElokaDialog::onAvaSessionDisconnected);
m_elokaListCollector.start();
m_buttonBox->connectButton(LtsWidgets::DialogButton::Add,
this, &ElokaDialog::onAddClicked);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Edit,
this, &ElokaDialog::onEditClicked);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Remove,
this, &ElokaDialog::onRemoveClicked);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Print,
this, &ElokaDialog::onPrint);
m_ui->tvEloka->setModel(m_elokaModel);
connect(m_ui->tvEloka, &LtsDataView::LtsDataView::signalSelectionChanged,
this, &ElokaDialog::onSelectionChanged);
onSelectionChanged();
connect(m_ui->tvEloka, &LtsDataView::LtsDataView::signalDoubleClicked,
this, &ElokaDialog::onEditClicked);
setAvaSessionStatus(m_avaSession->isEstablished());
setOnlineHelpFilename(QStringLiteral("Situation-Electronic_Warfare_Measures"));
}
ElokaDialog::~ElokaDialog()
{
delete m_elokaModel;
delete m_ui;
m_avaSession->control()->queryEloka(AvaQueryElokaMode::Stop);
}
void ElokaDialog::retranslate()
{
translate(m_ui, tr("Eloka"));
}
void ElokaDialog::onAvaSessionEstablished()
{
setAvaSessionStatus(true);
}
void ElokaDialog::onAvaSessionDisconnected()
{
m_elokaListCollector.reset();
m_elokaListCollector.start();
setAvaSessionStatus(false);
}
void ElokaDialog::setAvaSessionStatus(bool established)
{
m_avaSessionEstablished = established;
// get all active eloka
if (established)
m_avaSession->control()->queryEloka(AvaQueryElokaMode::Push);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Add, established);
m_ui->lblAvaSessionStatus->setVisible(!established);
onSelectionChanged();
}
void ElokaDialog::onAddClicked()
{
DEBUG_LOG(m_logger) << "**** onAddClicked() ";
ElokaEditDialog *dialog = new ElokaEditDialog(m_session, m_avaSession, m_avmDtc, m_streamNameMapping,
ElokaData(), this);
connect(dialog, &ElokaEditDialog::signalNewEloka, this,
[this](const ElokaData & data)
{
m_elokaModel->insertRow(data);
});
getUsedRadioCircuits();
dialog->init(m_usedCnr, m_usedTvc, m_usedAnnouncement);
addDialog(dialog, m_menuGroup, QStringLiteral("AddEloka"));
}
void ElokaDialog::onEditClicked()
{
DEBUG_LOG(m_logger) << "**** onEditClicked() ";
const QModelIndex idx = m_ui->tvEloka->currentIndex();
if (!idx.isValid())
return;
const ElokaData data = m_elokaModel->getRowData(idx.row());
ElokaEditDialog *dialog = new ElokaEditDialog(m_session, m_avaSession, m_avmDtc, m_streamNameMapping,
data, this);
connect(dialog, &ElokaEditDialog::signalNewEloka, this,
[ = ](const ElokaData & data)
{
m_elokaModel->setRowData(idx.row(), data);
});
getUsedRadioCircuits();
dialog->init(m_usedCnr, m_usedTvc, m_usedAnnouncement);
addDialog(dialog, m_menuGroup, QStringLiteral("EditEloka"));
}
void ElokaDialog::onRemoveClicked()
{
DEBUG_LOG(m_logger) << "**** onRemoveClicked() ";
const QModelIndex idx = m_ui->tvEloka->currentIndex();
if (!idx.isValid())
return;
m_avaSession->control()->releaseEloka(m_elokaModel->getRowData(idx.row()).internalName);
m_elokaModel->removeRow(idx.row());
}
void ElokaDialog::onSelectionChanged()
{
QModelIndexList selectedRows = m_ui->tvEloka->selectedRows();
const int cntSelectedRows = selectedRows.size();
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit,
cntSelectedRows == 1 && m_avaSessionEstablished);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove,
cntSelectedRows > 0 && m_avaSessionEstablished);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Add,
!(m_elokaModel->rowCount() >= 20));
}
void ElokaDialog::onPrint()
{
LtsPrinting::printView(m_session, this, m_ui->tvEloka->treeView() );
}
void ElokaDialog::onQueryElokaResponse(const QVector<AvaEloka> &&eloka)
{
DEBUG_LOG(m_logger) << "onQueryElokaResponse";
m_elokaListCollector.start(); // re-start the collector
m_elokaModel->clear();
if (eloka.isEmpty())
return;
const auto cnrTvcProfiles = m_avmDtc->cnrTvcProfiles();
QMultiMap<qint32, ElokaCircuitType> userProfile;
int operatorId = LtsSessionData::LtsSessionData::getInstance()->getOperatorId();
int exerciseId = m_session->exerciseId();
for (const auto &cnrTvcProfile : cnrTvcProfiles)
{
if (cnrTvcProfile.exerciseId() == exerciseId &&
cnrTvcProfile.operatorId() == operatorId)
{
for (const auto &cnrTvcProfileData : cnrTvcProfile.data())
{
if (cnrTvcProfileData.radioSystemId() == RadioSystem::inner_enum::Cnr)
userProfile.insert(cnrTvcProfileData.radioCircuitId(), ElokaCircuitType::Cnr);
else
userProfile.insert(cnrTvcProfileData.radioCircuitId(), ElokaCircuitType::Tvc);
}
break;
}
}
ElokaData data;
for (const auto &elokaData : eloka)
{
data.internalName = elokaData.stream;
data.displayName = elokaData.stream; // Can differ from internalName only for AnnouncementUnits; in this case displayName will be set in isAnnouncement().
data.action = elokaData.signal;
data.mode = AvaElokaMode::EndlessLoop;
data.startTime = toMSecSinceEpoch(elokaData.time);
if (isCnr(data, userProfile) ||
isTvc(data, userProfile) ||
isAnnouncement(data))
m_elokaModel->insertRow(data);
}
}
void ElokaDialog::tableColumnOrganiserSetting()
{
//LtsColumnOrganiser
m_ui->tvEloka->setColumnsOrganiserEnabled(identifier(), true);
}
bool ElokaDialog::isCnr(ElokaData& data, const QMultiMap<qint32, ElokaCircuitType>& userProfile)
{
const QMap<qint32, CnrConfig> cnrs = m_avmDtc->cnrConfigs();
for (const auto &cnr : cnrs)
{
if ((QString::fromStdString(cnr.radioCircuit()) == data.internalName) &&
(userProfile.contains(cnr.id(), ElokaCircuitType::Cnr)))
{
data.circuitType = ElokaCircuitType::Cnr;
data.party = cnr.partyId();
data.id = cnr.id();
return true;
}
}
return false;
}
bool ElokaDialog::isTvc(ElokaData& data, const QMultiMap<qint32, ElokaCircuitType>& userProfile)
{
const QMap<qint32, TvcConfig> tvcs = m_avmDtc->tvcConfigs();
for (const auto &tvc : tvcs)
{
if (tvc.exerciseId() != m_session->exerciseId())
continue;
if ((QString::fromStdString(tvc.radioCircuit()) == data.internalName) &&
(userProfile.contains(tvc.id(), ElokaCircuitType::Tvc)))
{
data.circuitType = ElokaCircuitType::Tvc;
data.party = 0;
data.id = tvc.id();
return true;
}
}
return false;
}
bool ElokaDialog::isAnnouncement(ElokaData& data)
{
QMap<qint32, Stream> announcements;
QMap<qint32, Stream> streams = m_avmDtc->streams();
for (const Stream &stream : qAsConst(streams))
{
if ((stream.type() == StreamType_def::AudioOut) ||
(stream.type() == StreamType_def::AudioInOut))
announcements.insert(stream.id(), stream);
}
for (const auto &announcement : announcements)
{
if (QString::fromStdString(announcement.name()) == data.internalName)
{
data.circuitType = ElokaCircuitType::Announcement;
data.party = -1; //
data.id = announcement.id();
data.exerciseId = m_session->exerciseId();
data.displayName = m_streamNameMapping->displayName(data.internalName);
return true;
}
}
return false;
}
void ElokaDialog::getUsedRadioCircuits()
{
m_usedAnnouncement.clear();
m_usedCnr.clear();
m_usedTvc.clear();
for (int i=0; i < m_elokaModel->rowCount(); ++i)
{
ElokaData elokaData = m_elokaModel->getRowData(i);
switch (elokaData.circuitType)
{
case ElokaCircuitType::Cnr:
m_usedCnr.push_back(elokaData.id);
break;
case ElokaCircuitType::Tvc:
m_usedTvc.push_back(elokaData.id);
break;
case ElokaCircuitType::Announcement:
m_usedAnnouncement.push_back(elokaData.id);
break;
default:
break;
}
}
}
} // namespace AudioVideoManagement
@@ -0,0 +1,80 @@
/**
* @RDE_HEADER@
* The ElokaDialog shows all electronic warfare and offers options to creating, updating and deleting
* $Id$
* $HeadURL$
* $Author$
* Created by Astrid Mueller, SGAS, 2017-10-17
*/
#pragma once
#include <set>
#include <LtsWidgets/lts_dialog.h>
#include <AudioVideoManagement/logger.h>
#include <AudioVideoManagement/avm_dtc.h>
#include <AudioVideoManagement/ava_types.h>
#include <AudioVideoManagement/list_response_collector.h>
#include <avm_eloka_model.h>
namespace Ui
{
class ElokaDialog;
}
namespace AudioVideoManagement
{
class AvaSession;
class StreamNameMapping;
class ElokaDialog : public LtsWidgets::LtsDialog
{
Q_OBJECT
public:
ElokaDialog(LtsSession::LtsSession *session, AvaSession *avaSession, Interface::Dtc *avmDtc, StreamNameMapping *streamNameMapping,
const QString &menuGroup, QWidget *parent = nullptr);
~ElokaDialog();
private slots:
void onAvaSessionEstablished();
void onAvaSessionDisconnected();
void onAddClicked();
void onEditClicked();
void onRemoveClicked();
void onSelectionChanged();
void onPrint();
private:
void retranslate() override;
void setAvaSessionStatus(bool established);
void getUsedRadioCircuits();
bool isCnr(ElokaData& data, const QMultiMap<qint32, ElokaCircuitType>& userProfile);
bool isTvc(ElokaData& data, const QMultiMap<qint32, ElokaCircuitType>& userProfile);
bool isAnnouncement(ElokaData& data);
void onQueryElokaResponse(const QVector<AvaEloka> &&eloka);
void tableColumnOrganiserSetting() override;
private:
Ui::ElokaDialog *m_ui;
QString m_menuGroup;
ElokaModel *m_elokaModel;
LtsSession::LtsSession *m_session;
AvaSession *m_avaSession;
QueryElokaListCollector m_elokaListCollector;
StreamNameMapping *m_streamNameMapping;
Interface::Dtc *m_avmDtc;
bool m_avaSessionEstablished;
std::vector<qint32> m_usedCnr;
std::vector<qint32> m_usedTvc;
std::vector<qint32> m_usedAnnouncement;
LOGGER_T m_logger;
};
} // namespace
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ElokaDialog</class>
<widget class="QWidget" name="ElokaDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>566</width>
<height>457</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="lblAvaSessionStatus">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#cc0000;&quot;&gt;No connection to Ava Session !&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item>
<widget class="LtsDataView::LtsDataView" name="tvEloka"/>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsDataView::LtsDataView</class>
<extends>QWidget</extends>
<header>LtsDataView/lts_data_view.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,568 @@
/**
* @RDE_HEADER@
* The ElokaEditDialog adds and updates electronic warfare
* $Id$
* $HeadURL$
* $Author$
* Created by Astrid Mueller, SGAS, 2017-10-17
*/
#include <LtsSession/lts_session_data.h>
#include "avm_eloka_edit_dialog.h"
#include "ui_avm_eloka_edit_dialog.h"
#include <AudioVideoManagement/ava_session.h>
#include <AudioVideoManagement/ava_control.h>
#include <AudioVideoManagement/stream_name_mapping.h>
#include <boost/optional.hpp>
namespace
{
/**
* Used as UserData for the entries in cmbCircuit.
*/
struct ComboBoxUserData
{
QString internalName; // the text itself in the ComboBox is the displayName
AudioVideoManagement::ElokaCircuitType circuitType;
int id;
};
ComboBoxUserData userDataAt(QComboBox *cb, int index)
{
Q_ASSERT(cb);
Q_ASSERT(index >= 0 && index < cb->count());
QVariant userData = cb->itemData(index);
Q_ASSERT(userData.canConvert<ComboBoxUserData>());
return userData.value<ComboBoxUserData>();
}
ComboBoxUserData currentUserData(QComboBox* cb)
{
Q_ASSERT(cb);
return userDataAt(cb, cb->currentIndex());
}
/**
* Get the id of the currently selected item in the ComboBox.
* @return boost::none if there is no item selected or its type does not match circuitType
*/
boost::optional<int> currentId(QComboBox *comboBox, AudioVideoManagement::ElokaCircuitType circuitType)
{
Q_ASSERT(comboBox);
int selectedIndex = comboBox->currentIndex();
if (selectedIndex == -1)
return boost::none;
QVariant userData_ = comboBox->itemData(selectedIndex);
Q_ASSERT(userData_.canConvert<ComboBoxUserData>());
ComboBoxUserData userData = userData_.value<ComboBoxUserData>();
if (userData.circuitType != circuitType)
return boost::none;
return userData.id;
}
/**
* Try to select the item with the given id.
* If no id is given or the item is not available for selection the first item is selected.
*/
void selectItemWithId(QComboBox *comboBox, boost::optional<int> id)
{
Q_ASSERT(comboBox);
if (comboBox->count() == 0)
return;
if (!id.is_initialized())
{
comboBox->setCurrentIndex(0);
return;
}
for (int i = 0; i < comboBox->count(); ++i)
{
QVariant userData_ = comboBox->itemData(i);
Q_ASSERT(userData_.canConvert<ComboBoxUserData>());
ComboBoxUserData userData = userData_.value<ComboBoxUserData>();
if (userData.id == *id)
{
comboBox->setCurrentIndex(i);
return;
}
}
comboBox->setCurrentIndex(0);
}
} // anonymous namespace
// in order to use it with QVariant
Q_DECLARE_METATYPE(ComboBoxUserData)
namespace AudioVideoManagement
{
ElokaEditDialog::ElokaEditDialog(LtsSession::LtsSession *session, AvaSession *avaSession, Interface::Dtc *avmDtc, StreamNameMapping *streamNameMapping,
const ElokaData &data, QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel)
, m_ui(new Ui::ElokaEditDialog)
, m_session(session)
, m_streamNameMapping(streamNameMapping)
, m_avaCtrl(avaSession->control())
, m_avmDtc(avmDtc)
, m_elokaData(data)
, m_cnrConfigMap()
, m_tvcConfigMap()
, m_announcementMap()
, m_userProfile()
, m_logger(getLogger("ElokaEditDialog"))
{
Q_ASSERT(session);
Q_ASSERT(avaSession);
Q_ASSERT(streamNameMapping);
Q_ASSERT(avmDtc);
m_ui->setupUi(this);
m_uiRequirements->addRequirement( { m_ui->lbAction, [this]() { return !m_ui->cmbAction->currentText().isEmpty(); } });
m_uiRequirements->addRequirement( { m_ui->lbCircuit, [this]() { return !m_ui->cmbCircuit->currentText().isEmpty(); } });
setOnlineHelpFilename(QStringLiteral("Situation-Electronic_Warfare_Measures"));
}
ElokaEditDialog::~ElokaEditDialog()
{
delete m_ui;
}
void ElokaEditDialog::retranslate()
{
bool isNew = true;
if (!m_elokaData.internalName.isEmpty())
isNew = false;
translate(m_ui, QString(), isNew, tr("Eloka"));
}
bool ElokaEditDialog::init(const std::vector<qint32> &usedCnr,
const std::vector<qint32> &usedTvc,
const std::vector<qint32> &usedAnnouncement)
{
setUnchangeable(true);
#ifndef LTS_DEBUG
m_ui->rbTvc->hide();
#endif
// get the user profile of the accessible radio circuits
getUserProfile();
// get all CNR's
getActiveCnrs();
// new CNR
if (m_elokaData.internalName.isEmpty())
{
for (int used : usedCnr)
m_cnrConfigMap.remove(used);
}
else // edit CNR
{
m_cnrConfigMap.remove(m_elokaData.id);
}
// get all TVC's
m_tvcConfigMap = m_avmDtc->tvcConfigs();
// new TVC
if (m_elokaData.internalName.isEmpty())
{
for (int used : usedTvc)
m_tvcConfigMap.remove(used);
}
else // edit TVC
{
m_tvcConfigMap.remove(m_elokaData.id);
}
// get all Announcements
const QMap<qint32, Stream> streams = m_avmDtc->streams();
for (const Stream &stream : streams)
{
if ((stream.type() == StreamType_def::AudioOut) ||
(stream.type() == StreamType_def::AudioInOut))
m_announcementMap.insert(stream.id(), stream);
}
// new announcement
if (m_elokaData.internalName.isEmpty())
{
for (int used : usedAnnouncement)
m_announcementMap.remove(used);
}
else // edit announcement
{
m_announcementMap.remove(m_elokaData.id);
}
connect(m_avmDtc,
&AudioVideoManagement::Interface::Dtc::cnrConfigChanged,
this, &ElokaEditDialog::onCnrConfigChanged);
connect(m_avmDtc,
&AudioVideoManagement::Interface::Dtc::tvcConfigChanged,
this, &ElokaEditDialog::onTvcConfigChanged);
connect(m_avmDtc,
&AudioVideoManagement::Interface::Dtc::cnrTvcProfileChanged,
this, &ElokaEditDialog::onCnrTvcProfileChanged);
connect(m_avmDtc,
&AudioVideoManagement::Interface::Dtc::streamChanged,
this, &ElokaEditDialog::onStreamChanged);
connect(m_ui->cmbCircuit,
QOverload<int>::of(&LtsWidgets::LtsComboBox::currentIndexChanged),
this, &ElokaEditDialog::onCmbCircuitChanged);
connect(m_ui->rbCnr, &QRadioButton::toggled,
this, &ElokaEditDialog::onCbCnrToggled);
connect(m_ui->rbAnnouncement, &QRadioButton::toggled,
this, &ElokaEditDialog::onCbAnnouncementToggled);
connect(m_ui->rbTvc, &QRadioButton::toggled,
this, &ElokaEditDialog::onCbTvcToggled);
connect(m_avaCtrl, &AvaControl::getElokaListResponse,
this, &ElokaEditDialog::onGetElokaListResponse);
if (m_elokaData.internalName.isEmpty())
{
// get as default CNR
checkedRadioButtons(true, false, false);
enabledRadioButtons(true, true, true);
}
else
{
if (m_elokaData.circuitType == ElokaCircuitType::Cnr)
{
checkedRadioButtons(true, false, false);
enabledRadioButtons(true, false, false);
}
if (m_elokaData.circuitType == ElokaCircuitType::Tvc)
{
checkedRadioButtons(false, true, false);
enabledRadioButtons(false, true, false);
}
if (m_elokaData.circuitType == ElokaCircuitType::Announcement)
{
checkedRadioButtons(false, false, true);
enabledRadioButtons(false, false, true);
}
if (m_elokaData.mode == AvaElokaMode::EndlessLoop)
m_ui->chbEndlessPlayback->setChecked(true);
setCurrentCircuit(m_elokaData);
m_ui->cmbAction->setCurrentText(m_elokaData.action);
}
setUnchangeable(false);
return true;
}
void ElokaEditDialog::checkedRadioButtons(bool cnr, bool tvc, bool announcement)
{
m_ui->rbCnr->setChecked(cnr);
m_ui->rbTvc->setChecked(tvc);
m_ui->rbAnnouncement->setChecked(announcement);
}
void ElokaEditDialog::enabledRadioButtons(bool cnr, bool tvc, bool announcement)
{
m_ui->rbCnr->setEnabled(cnr);
m_ui->rbTvc->setEnabled(tvc);
m_ui->rbAnnouncement->setEnabled(announcement);
}
void ElokaEditDialog::onCmbCircuitChanged(int index)
{
Q_UNUSED(index);
m_ui->cmbAction->clear();
if (m_ui->cmbCircuit->currentText().isEmpty())
return;
// get Actions from AVS Workstation
ComboBoxUserData userData = currentUserData(m_ui->cmbCircuit);
m_avaCtrl->getElokaList(userData.internalName);
}
bool ElokaEditDialog::apply()
{
ComboBoxUserData userData = currentUserData(m_ui->cmbCircuit);
ElokaData data;
data.id = userData.id;
data.internalName = userData.internalName;
data.displayName = m_ui->cmbCircuit->currentText();
data.party = -1;
data.exerciseId = m_session->exerciseId();
data.circuitType = userData.circuitType;
data.action = m_ui->cmbAction->currentText();
data.mode = m_ui->chbEndlessPlayback->isChecked() ? AvaElokaMode::EndlessLoop : AvaElokaMode::Once;
data.startTime = m_session->partitionTime();
if (userData.circuitType == ElokaCircuitType::Cnr)
data.party = m_cnrConfigMap.value(userData.id).partyId();
if (m_elokaData.internalName.isEmpty())
m_avaCtrl->chooseEloka(data.internalName, data.action, data.mode);
else if (m_elokaData.action != data.action)
{
m_avaCtrl->releaseEloka(m_elokaData.internalName);
m_avaCtrl->chooseEloka(data.internalName, data.action, data.mode);
}
m_elokaData = data;
emit signalNewEloka(data);
return true;
}
void ElokaEditDialog::onCbCnrToggled(bool checked)
{
if (!checked)
return;
fillComboBoxCircuit(ElokaCircuitType::Cnr);
}
void ElokaEditDialog::onCbAnnouncementToggled(bool checked)
{
if (!checked)
return;
fillComboBoxCircuit(ElokaCircuitType::Announcement);
}
void ElokaEditDialog::onCbTvcToggled(bool checked)
{
if (!checked)
return;
fillComboBoxCircuit(ElokaCircuitType::Tvc);
}
void ElokaEditDialog::getActiveCnrs()
{
const QMap<qint32, CnrConfig> cnrs = m_avmDtc->cnrConfigs();
for (const CnrConfig &cnr : cnrs)
{
if (cnr.isActive() == true)
m_cnrConfigMap.insert(cnr.id(), cnr);
}
}
void ElokaEditDialog::onCnrConfigChanged(const CnrConfig &data,
DataModification modType)
{
DEBUG_LOG(m_logger) << "onCnrConfigChanged";
switch (modType)
{
case DataModification::eAdded:
case DataModification::eModified:
{
m_cnrConfigMap.insert(data.id(), data);
break;
}
case DataModification::eRemoved:
{
m_cnrConfigMap.remove(data.id());
break;
}
} // end switch
if (m_ui->rbCnr->isChecked())
fillComboBoxCircuit(ElokaCircuitType::Cnr);
}
void ElokaEditDialog::onTvcConfigChanged(const TvcConfig &data,
DataModification modType)
{
DEBUG_LOG(m_logger) << "onTvcConfigChanged";
switch (modType)
{
case DataModification::eAdded:
case DataModification::eModified:
{
m_tvcConfigMap.insert(data.id(), data);
break;
}
case DataModification::eRemoved:
{
m_tvcConfigMap.remove(data.id());
break;
}
} // end switch
if (m_ui->rbTvc->isChecked())
fillComboBoxCircuit(ElokaCircuitType::Tvc);
}
void ElokaEditDialog::onStreamChanged(const Stream &data,
DataModification modType)
{
DEBUG_LOG(m_logger) << "onStreamChanged";
if ((data.type() != StreamType_def::AudioOut) &&
(data.type() != StreamType_def::AudioInOut))
return;
switch (modType)
{
case DataModification::eAdded:
case DataModification::eModified:
{
m_announcementMap.insert(data.id(), data);
break;
}
case DataModification::eRemoved:
{
m_announcementMap.remove(data.id());
break;
}
} // end switch
if (m_ui->rbAnnouncement->isChecked())
fillComboBoxCircuit(ElokaCircuitType::Announcement);
}
void ElokaEditDialog::onCnrTvcProfileChanged(const CnrTvcProfile &data,
DataModification modType)
{
Q_UNUSED(modType);
DEBUG_LOG(m_logger) << "onCnrTvcProfileChanged";
if (data.exerciseId() != m_session->exerciseId() ||
data.operatorId() != LtsSessionData::LtsSessionData::getInstance()->getOperatorId())
return;
getUserProfile();
if (m_ui->rbCnr->isChecked())
fillComboBoxCircuit(ElokaCircuitType::Cnr);
else if (m_ui->rbTvc->isChecked())
fillComboBoxCircuit(ElokaCircuitType::Tvc);
}
void ElokaEditDialog::getUserProfile()
{
m_userProfile.clear();
const QMap<qint32, AudioVideoManagement::CnrTvcProfile> cnrTvcProfiles = m_avmDtc->cnrTvcProfiles();
int operatorId = LtsSessionData::LtsSessionData::getInstance()->getOperatorId();
int exerciseId = m_session->exerciseId();
for (const auto &cnrTvcProfile : cnrTvcProfiles)
{
if (cnrTvcProfile.exerciseId() == exerciseId &&
cnrTvcProfile.operatorId() == operatorId)
{
for (const auto &cnrTvcProfileData : cnrTvcProfile.data())
if (cnrTvcProfileData.radioSystemId() == RadioSystem::inner_enum::Cnr)
m_userProfile.insert(cnrTvcProfileData.radioCircuitId(), ElokaCircuitType::Cnr);
else
m_userProfile.insert(cnrTvcProfileData.radioCircuitId(), ElokaCircuitType::Tvc);
break;
}
}
}
void ElokaEditDialog::fillComboBoxCircuit(ElokaCircuitType type)
{
boost::optional<int> selectedId = currentId(m_ui->cmbCircuit, type);
m_ui->cmbCircuit->clear();
switch (type)
{
case ElokaCircuitType::Cnr:
{
for (const CnrConfig &cnr : qAsConst(m_cnrConfigMap))
{
if (!m_userProfile.contains(cnr.id(), ElokaCircuitType::Cnr))
continue;
QString internalName = QString::fromStdString(cnr.radioCircuit());
QVariant userData = QVariant::fromValue(ComboBoxUserData{internalName, ElokaCircuitType::Cnr, cnr.id()});
m_ui->cmbCircuit->addItem(internalName, userData);
}
break;
}
case ElokaCircuitType::Tvc:
{
for (const TvcConfig &tvc : qAsConst(m_tvcConfigMap))
{
if (!m_userProfile.contains(tvc.id(), ElokaCircuitType::Tvc))
continue;
QString internalName = QString::fromStdString(tvc.radioCircuit());
QVariant userData = QVariant::fromValue(ComboBoxUserData{internalName, ElokaCircuitType::Tvc, tvc.id()});
m_ui->cmbCircuit->addItem(internalName, userData);
}
break;
}
case ElokaCircuitType::Announcement:
{
for (const Stream &stream : qAsConst(m_announcementMap))
{
QString internalName = QString::fromStdString(stream.name());
QString displayName = m_streamNameMapping->displayName(internalName);
QVariant userData = QVariant::fromValue(ComboBoxUserData{internalName, ElokaCircuitType::Announcement, stream.id()});
m_ui->cmbCircuit->addItem(displayName, userData);
}
break;
}
} // end switch
m_ui->cmbCircuit->model()->sort(0);
selectItemWithId(m_ui->cmbCircuit, selectedId);
}
void ElokaEditDialog::setCurrentCircuit(const ElokaData &data)
{
for (int i = 0; i < m_ui->cmbCircuit->count(); ++i)
{
ComboBoxUserData userData = userDataAt(m_ui->cmbCircuit, i);
if (userData.circuitType != data.circuitType)
continue;
if (userData.id != data.id)
continue;
m_ui->cmbCircuit->setCurrentIndex(i);
return;
}
Q_ASSERT(false);
}
void ElokaEditDialog::onGetElokaListResponse(const QVector<QString> &actions)
{
DEBUG_LOG(m_logger) << "onGetElokaListResponse";
if (!m_elokaData.internalName.isEmpty())
setUnchangeable(true);
m_ui->cmbAction->clear();
if (actions.isEmpty())
return;
for (const QString &action : actions)
m_ui->cmbAction->addItem(action);
if(m_elokaData.action.isEmpty() == false)
m_ui->cmbAction->setCurrentText(m_elokaData.action);
if (!m_elokaData.internalName.isEmpty())
setUnchangeable(false);
}
} // namespace AudioVideoManagement
@@ -0,0 +1,87 @@
/**
* @RDE_HEADER@
* The ElokaEditDialog adds or updates electronic warfare
* $Id$
* $HeadURL$
* $Author$
* Created by Astrid Mueller, SGAS, 2017-10-17
*/
#pragma once
#include <LtsWidgets/lts_dialog.h>
#include <AudioVideoManagement/logger.h>
#include <AudioVideoManagement/avm_dtc.h>
#include <LtsSession/lts_session.h>
#include "avm_eloka_model.h"
namespace Ui
{
class ElokaEditDialog;
}
namespace AudioVideoManagement
{
class AvaSession;
class AvaControl;
class StreamNameMapping;
class ElokaEditDialog : public LtsWidgets::LtsDialog
{
Q_OBJECT
public:
ElokaEditDialog(LtsSession::LtsSession *session, AvaSession *avaSession, Interface::Dtc *avmDtc, StreamNameMapping *streamNameMapping,
const ElokaData &data, QWidget *parent = nullptr);
~ElokaEditDialog();
bool init(const std::vector<qint32> &usedCnr,
const std::vector<qint32> &usedTvc,
const std::vector<qint32> &usedAnnouncement);
signals:
void signalNewEloka(const ElokaData &data);
protected:
bool apply() override;
private slots:
void onCmbCircuitChanged(int index);
void onCbCnrToggled(bool checked);
void onCbAnnouncementToggled(bool checked);
void onCbTvcToggled(bool checked);
void onCnrConfigChanged(const CnrConfig &data, DataModification modType);
void onTvcConfigChanged(const TvcConfig &data, DataModification modType);
void onStreamChanged(const Stream &data, DataModification modType);
void onCnrTvcProfileChanged(const CnrTvcProfile &data, DataModification modType);
void onGetElokaListResponse(const QVector<QString> &actions);
private:
void retranslate() override;
void checkedRadioButtons(bool cnr, bool tvc, bool announcement);
void enabledRadioButtons(bool cnr, bool tvc, bool announcement);
void getUserProfile();
void getActiveCnrs();
void fillComboBoxCircuit(ElokaCircuitType type);
void setCurrentCircuit(const ElokaData &data);
private:
Ui::ElokaEditDialog *m_ui;
LtsSession::LtsSession *m_session;
StreamNameMapping *m_streamNameMapping;
AvaControl *m_avaCtrl;
Interface::Dtc *m_avmDtc;
ElokaData m_elokaData; //!< default-constructed in case we are creating a new Eloka
QMap<qint32, CnrConfig> m_cnrConfigMap;
QMap<qint32, TvcConfig> m_tvcConfigMap;
QMap<qint32, Stream> m_announcementMap;
QMultiMap<qint32, ElokaCircuitType> m_userProfile;
LOGGER_T m_logger;
};
} // namespace
@@ -0,0 +1,121 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ElokaEditDialog</class>
<widget class="QWidget" name="ElokaEditDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>661</width>
<height>144</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="lbCircuit">
<property name="text">
<string>Circuit:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QRadioButton" name="rbCnr">
<property name="text">
<string>&amp;CNR</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="rbAnnouncement">
<property name="text">
<string>Announce&amp;ment</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="rbTvc">
<property name="text">
<string>&amp;TVC</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="1">
<widget class="LtsWidgets::LtsComboBox" name="cmbCircuit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lbAction">
<property name="text">
<string>Action:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="LtsWidgets::LtsComboBox" name="cmbAction">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="chbEndlessPlayback">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Endless Playback</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>118</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsWidgets::LtsComboBox</class>
<extends>QComboBox</extends>
<header>LtsWidgets/lts_combo_box.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>rbCnr</tabstop>
<tabstop>rbAnnouncement</tabstop>
<tabstop>rbTvc</tabstop>
<tabstop>cmbCircuit</tabstop>
<tabstop>cmbAction</tabstop>
<tabstop>chbEndlessPlayback</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,91 @@
/**
* @RDE_HEADER@
* Gui Plugin for AudioVideoManagement - Eloka
* $Id$
* $HeadURL$
* $Author$
* Created by Astrid Mueller, SGAS, 2017-10-17
*/
#include "avm_eloka_gui_plugin.h"
#include <LtsSession/lts_session.h>
#include <Services/AudioVideoManagement/avm_operator_rights.h>
#include <avm_eloka_dialog.h>
#include <LtsUtilsSettings/settings.h>
namespace AudioVideoManagement
{
std::shared_ptr<GuiPluginBase::Interface> GuiPlugin::createGuiInterface(LtsSession::LtsSession *session)
{
return std::make_shared<InterfaceImpl>(session);
}
InterfaceImpl::InterfaceImpl(LtsSession::LtsSession *session)
: GuiPluginBase::Interface(session, getLogger("Plugins.Gui.avm.Eloka"))
, m_dtc(nullptr)
, m_avmDataIfc(nullptr)
{}
bool InterfaceImpl::fetchInterfaces()
{
if (!m_session->getDtc<AudioVideoManagement::DataInterface>(m_dtc))
return false;
if (!m_session->getForeignDataInterface_NEW<AudioVideoManagement::DataInterface>(m_avmDataIfc))
return false;
return true;
}
void InterfaceImpl::clearInterfaces()
{
m_dtc = nullptr;
m_avmDataIfc = nullptr;
}
QString InterfaceImpl::menuGroup() const
{
return tr("Audio / Video");
}
QVector<LtsWidgets::PluginData> InterfaceImpl::getActions()
{
if (!m_avmDataIfc->hasAvsSession())
return {}; // Someone else has access to the AvaSession in a different exercise context.
QVector<LtsWidgets::PluginData> actions;
LtsUtils::ProjectSettings *ps = LtsUtils::ProjectSettings::getInstance();
const bool enableElectronicWarfareMeasures = ps->value(QStringLiteral("avm"),
QStringLiteral("enableElectronicWarfareMeasures")).toBool();
if (enableElectronicWarfareMeasures)
{
LtsWidgets::PluginData plData;
plData.menuGroup = menuGroup();
plData.menuText = tr("Electronic Warfare Measures");
plData.identifier = QLatin1String("avmEwm");
plData.menuIcon = QIcon(QLatin1String("icon:electronical_warfare_measures.svg"));
plData.operatorRight = OperatorRights::ElectronicWarfareMeasures::AvmEwmEdit;
plData.exercisePart = LtsWidgets::ExercisePart::eExecution;
plData.createWidgetFunc = [this](QWidget *parent)
{
return onShowEloka(parent);
};
actions.append(plData);
}
return actions;
}
LtsWidgets::LtsDialog *InterfaceImpl::onShowEloka(QWidget *parent)
{
return new ElokaDialog(m_session, m_avmDataIfc->avaSession(), m_dtc.get(), m_avmDataIfc->streamNameMapping(),
menuGroup(), parent);
}
} // namespace AudioVideoManagement
@@ -0,0 +1,59 @@
/**
* @RDE_HEADER@
* Gui Plugin for AudioVideoManagement - Eloka
* $Id$
* $HeadURL$
* $Author$
* Created by Astrid Mueller, SGAS, 2017-10-17
*/
#pragma once
#include <AudioVideoManagement/logger.h>
#include <AudioVideoManagement/avm_dtc.h>
#include <PluginInterfaces/gui_plugin_interface.h>
#include <Plugins/AudioVideoManagement/avm_data_plugin_interface.h>
namespace AudioVideoManagement
{
class GuiPlugin final : public QObject, public GuiPluginBase::Plugin
{
Q_PLUGIN_METADATA(IID "gui:3:avm.eloka")
Q_INTERFACES(GuiPluginBase::Plugin)
Q_OBJECT
public:
GuiPlugin() = default;
~GuiPlugin() = default;
QString pluginName() override { return QStringLiteral("AudioVideoManagement.GuiPlugin.Eloka"); }
std::shared_ptr<GuiPluginBase::Interface> createGuiInterface(LtsSession::LtsSession *session) override;
bool availableInPartition(IDL::PartitionType partition) const override
{
return (partition == IDL::PartitionType::Exercise);
}
};
class InterfaceImpl final : public QObject, public GuiPluginBase::Interface
{
Q_OBJECT
public:
explicit InterfaceImpl(LtsSession::LtsSession *session);
bool fetchInterfaces() override;
void clearInterfaces() override;
QString menuGroup() const override;
QVector<LtsWidgets::PluginData> getActions() override;
bool availableInPartition(IDL::PartitionType partition) const override { return partition == IDL::PartitionType::Global || partition == IDL::PartitionType::Exercise; }
private:
LtsWidgets::LtsDialog *onShowEloka(QWidget *parent);
std::shared_ptr<AudioVideoManagement::Interface::Dtc> m_dtc;
std::shared_ptr<AudioVideoManagement::DataInterface> m_avmDataIfc;
};
} // namespace AudioVideoManagement
@@ -0,0 +1,68 @@
/**
* @RDE_HEADER@
* Model for electronic warfare (Eloka)
* $Id$
* $HeadURL$
* $Author$
* Created by Astrid Mueller, SGAS, 2017-10-18
*/
#include "avm_eloka_model.h"
#include <ngltools/ngltools_dtg.h>
#include <ParticipantManagement/ppm_data_plugin_interface.h>
#include <ParticipantManagement/ppm_translation.h>
#include <QDateTime>
namespace AudioVideoManagement
{
ElokaModel::ElokaModel(LtsSession::LtsSession *session, QObject *parent)
: LtsWidgets::LtsAbstractTableModel<ElokaData>(
{
tr("Party"),
tr("Radio Circuit"),
tr("Action"),
tr("Endless Playback"),
tr("Start Time")
},
parent)
, m_logger(getLogger("ElokaModel"))
{
Q_ASSERT(session);
// optional
session->getDtc<ParticipantManagement::DataInterface>(m_ppmDtc);
}
QVariant ElokaModel::data(const QModelIndex &index,
int role) const
{
if (role != Qt::DisplayRole || !indexIsValid(index))
return QVariant();
const ElokaData &data = m_vecData.at(index.row());
switch (index.column())
{
case Party:
{
if (!m_ppmDtc)
return QString::number(data.party);
if (data.party >= 0)
return ParticipantManagement::trPartyName(m_ppmDtc->party(data.party).name());
return QVariant(QLatin1Char('-'));
}
case RadioCircuit:
return data.displayName;
case Action:
return data.action;
case EndlessPlayback:
return QVariant(data.mode == AvaElokaMode::EndlessLoop ? QLatin1Char('+') : QLatin1Char('-'));
case StartTime:
return QDateTime::fromMSecsSinceEpoch(data.startTime);
}
return QVariant();
}
} // namespace
@@ -0,0 +1,69 @@
/**
* @RDE_HEADER@
* Model for electronic warfare (Eloka)
* $Id$
* $HeadURL$
* $Author$
* Created by Astrid Mueller, SGAS, 2017-10-18
*/
#pragma once
#include <LtsWidgets/lts_abstract_table_model.h>
#include <LtsSession/lts_session.h>
#include <Plugins/AudioVideoManagement/avm_data_plugin_interface.h>
#include <AudioVideoManagement/logger.h>
#include <AudioVideoManagement/ava_types.h>
#include <ParticipantManagement/ppm_dtc.h>
namespace AudioVideoManagement
{
enum class ElokaCircuitType
{
Cnr = 1,
Tvc = 2,
Announcement = 3
};
struct ElokaData
{
QString internalName;
QString displayName;
QString action;
qint64 startTime = 0;
qint32 id = 0;
qint32 exerciseId = 0;
qint32 party = 0;
ElokaCircuitType circuitType = ElokaCircuitType::Cnr;
AvaElokaMode mode = AvaElokaMode::EndlessLoop;
};
// --------------------------------------------------------
// ElokaModel
// --------------------------------------------------------
class ElokaModel : public LtsWidgets::LtsAbstractTableModel<ElokaData>
{
Q_OBJECT
public:
enum Columns
{
Party,
RadioCircuit,
Action,
EndlessPlayback,
StartTime
};
ElokaModel(LtsSession::LtsSession *session, QObject *parent = nullptr);
QVariant data(const QModelIndex &index, int role) const override;
private:
LOGGER_T &m_logger;
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
};
} // namespace