/** * @RDE_HEADER@ * The ElokaEditDialog adds and updates electronic warfare * $Id$ * $HeadURL$ * $Author$ * Created by Astrid Mueller, SGAS, 2017-10-17 */ #include #include "avm_eloka_edit_dialog.h" #include "ui_avm_eloka_edit_dialog.h" #include #include #include #include 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()); return userData.value(); } 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 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 userData = userData_.value(); 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 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 userData = userData_.value(); 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 &usedCnr, const std::vector &usedTvc, const std::vector &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 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::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 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 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 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 &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