/** * @RDE_HEADER@ * Target Configuration * $Id$ * $HeadURL$ * $Author$ * Created by Norbert Thoden, NLE, 2020-06-29 */ #include "tgt_target_part_dialog.h" #include "ui_tgt_target_part_dialog.h" #include "tgt_shootback_target_edit.h" #include "tgt_telegrams.h" #include #include #include #include #include #include #include #include #include "tgt_target_area_assignment_dialog.h" #include #include #include #include namespace TargetManagement { TargetPartDialog::TargetPartDialog(const QString &menuGroup, LtsSession::LtsSession *session, QWidget *parent) : LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel) , m_session(session) , m_ui(new Ui::TargetPartDialog) , m_menuGroup(menuGroup) , m_requestHelper(new LtsUtils::RequestHelper(this)) , m_logger(getLogger("TargetPartDialog")) { m_ui->setupUi(this); setOnlineHelpFilename(QStringLiteral("Situation-Assign/Configure_Targets")); } TargetPartDialog::~TargetPartDialog() { clearSelectionOfMapObjects(); delete m_ui; } bool TargetPartDialog::init(TargetManagement::TargetPartDialog::MODE mode) { if (!m_session) return false; if (!m_session->getDtc(m_dtc)) return false; if (!m_session->getFtc(m_ftc)) return false; if (!m_session->getDtc(m_ppmDtc)) return false; if (!m_session->getForeignGuiInterface(m_ppmGuiCbxIfc)) return false; if (!m_session->getForeignGuiInterface(m_flmGui)) return false; if (!m_session->getForeignGuiInterface(m_sitMapGuiIfc)) return false; // initialize model: INFO_LOG(m_logger) << "TargetPartDialog::init"; m_targetParticipantModel = new TargetParticipantModel(this); m_targetParticipantModel->initModel(m_dtc, m_ppmDtc, m_ppmGuiCbxIfc, m_session); // proxyModel: auto proxyModel = new TargetParticipantProxyModel(this); proxyModel->setSourceModel(m_targetParticipantModel); proxyModel->setDynamicSortFilter(false); // set view: (LtsDataView) m_ui->widget->setModel(m_targetParticipantModel); // to allow remove off some rows at once. Anoying in all other cases -> stay at singleSelection // m_ui->widget->setSelectionMode(QAbstractItemView::SelectionMode::MultiSelection); m_assignAreaBtn = m_buttonBox->getButton(LtsWidgets::DialogButton::Import); m_buttonBox->connectButton(LtsWidgets::DialogButton::Import, this, &TargetPartDialog::onAssignAreaClicked); // connects for gui connect(m_ui->widget, &LtsDataView::LtsDataView::signalSelectionChanged, this, &TargetPartDialog::onSelectionChanged); connect(m_ui->widget, &LtsDataView::LtsDataView::signalDoubleClicked, this, &TargetPartDialog::onEditTargetPart); connect(this, &TargetPartDialog::escapePressed, this, &TargetPartDialog::onEscapePressed, Qt::UniqueConnection); // Create Add-Button m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::Add, true); m_buttonBox->connectButton(LtsWidgets::DialogButton::Add, this, &TargetPartDialog::onNewTargetPart); // Create Remove-Button m_buttonBox->connectButton(LtsWidgets::DialogButton::Remove, this, &TargetPartDialog::onRemoveTargetPart); m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, false); // Create Modify-Button m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, false); m_buttonBox->connectButton(LtsWidgets::DialogButton::Edit, this, &TargetPartDialog::onEditTargetPart); // connect signals of TableView/CustomView: connect(m_ui->widget, &LtsDataView::LtsDataView::clicked, this, &TargetPartDialog::onTableViewClicked); // it´s possible to evaluate signalEntered, but seems to be overkill here: // connect(m_ui->widget, &LtsDataView::LtsDataView::signalEntered, this, &TargetPartDialog::onObjectEntered); #ifndef LTS_DEBUG m_ui->widget->hideColumn(TargetParticipantModel::Columns::Id); m_ui->widget->hideColumn(TargetParticipantModel::Columns::TargetPartipantId); #endif // Save/Load from Library Button m_buttonBox->connectLibraryButton(this, &TargetPartDialog::onImportButtonClicked, &TargetPartDialog::onExportButtonClicked); if (!m_flmGui) m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Library, false); // 'Map' Button(s) m_buttonBox->connectButton(LtsWidgets::DialogButton::CenterMap, this, &TargetPartDialog::onMapCenterClicked); m_buttonBox->connectButton(LtsWidgets::DialogButton::ZoomMapTo, this, &TargetPartDialog::onMapZoomToClicked); // call eneDisa / onSelectionChanged once: onSelectionChanged(); setMode(mode); return true; } void TargetPartDialog::keyPressEvent(QKeyEvent *event) { if (event->key() == Qt::Key_Escape) emit escapePressed(); return BaseClass::keyPressEvent(event); } void TargetPartDialog::setMode(TargetPartDialog::MODE mode) { m_mode = mode; switch (m_mode) { case MODE::TARGET_BASE_CONFIGURATION: m_assignAreaBtn->setVisible(false); break; case MODE::TARGET_OVERVIEW: m_assignAreaBtn->setVisible(true); m_ui->widget->hideColumn(TargetParticipantModel::Columns::TargetPartipantId); m_ui->widget->hideColumn(TargetParticipantModel::Columns::ActivateLaserDesignation); m_ui->widget->hideColumn(TargetParticipantModel::Columns::ActivateLights); m_ui->widget->hideColumn(TargetParticipantModel::Columns::ActivatePopupAutomatic); m_ui->widget->hideColumn(TargetParticipantModel::Columns::HitsToKill); m_ui->widget->hideColumn(TargetParticipantModel::Columns::PermanentInstalledTarget); m_ui->widget->hideColumn(TargetParticipantModel::Columns::VisibleParticipants); break; } // switch m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::Add, (m_mode == MODE::TARGET_BASE_CONFIGURATION)); m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::Edit, (m_mode == MODE::TARGET_BASE_CONFIGURATION)); m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::Remove, (m_mode == MODE::TARGET_BASE_CONFIGURATION)); m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::Library, (m_mode == MODE::TARGET_BASE_CONFIGURATION)); m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::CenterMap, m_sitMapGuiIfc && (m_mode == MODE::TARGET_BASE_CONFIGURATION)); m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::ZoomMapTo, m_sitMapGuiIfc && (m_mode == MODE::TARGET_BASE_CONFIGURATION)); } void TargetPartDialog::retranslate() { switch (m_mode) { case MODE::TARGET_BASE_CONFIGURATION: translate(m_ui, tr("Assign/Configure Targets")); m_assignAreaBtn->setText(tr("Assign Area")); break; case MODE::TARGET_OVERVIEW: translate(m_ui, tr("Configure Shootback")); m_assignAreaBtn->setText(tr("Assign Area")); break; } } void TargetPartDialog::onNewTargetPart() { INFO_LOG(m_logger) << "onNewTargetPart"; ShootbackTargetEdit *dialog = new ShootbackTargetEdit(this); if (!dialog->init(m_dtc, m_ftc, m_targetParticipantModel)) { ERROR_LOG(m_logger) << QLatin1String("Can't initialize shootbackTargetEdit!"); delete dialog; return; } addDialog(dialog, m_menuGroup, QStringLiteral("Add Target"), LtsWidgets::LayoutArea::eDialogTab, true, true); } void TargetPartDialog::onRemoveTargetPart() { const QModelIndexList &selectedRows = m_ui->widget->selectedRows(); for (const auto &mi : selectedRows) { Core::RemoveElementRequest req; req.id(m_targetParticipantModel->getRowData(mi.row()).id()); m_requestHelper->addRequest([req, this]() { return m_ftc->shootbackTargetRemoveRequest(req, this); }); } m_requestHelper->startRequests(); } void TargetPartDialog::onEditTargetPart() { if (m_mode == MODE::TARGET_OVERVIEW) return; QModelIndexList selectedRows = m_ui->widget->selectedRows(); if (selectedRows.isEmpty()) return; const QModelIndex curIdx = selectedRows.first(); if (!curIdx.isValid()) return; INFO_LOG(m_logger) << " onEditTargetPart"; ShootbackTargetEdit *dialog = new ShootbackTargetEdit(this); const TargetManagement::ShootbackTarget &tgt = m_targetParticipantModel->getRowData(curIdx.row()); if (!dialog->init(m_dtc, m_ftc, m_targetParticipantModel, tgt)) { ERROR_LOG(m_logger) << LOGFUNCTION << QLatin1String("Can't initialize shootbackTargetEdit!"); delete dialog; return; } addDialog(dialog, m_menuGroup, QStringLiteral("Edit Target"), LtsWidgets::LayoutArea::eDialogTab, true, true); } QByteArray TargetPartDialog::toJson() const { QJsonObject obj; // operatorId just for convenience: const int operatorId = LtsSessionData::LtsSessionData::getInstance()->getOperatorId(); obj[QStringLiteral("OperatorId")] = operatorId; obj[QStringLiteral("XmlType")] = FileManagement::toString(FileManagement::XmlType::TGTShootbackTargetBaseConfiguration); { const QVector &modelData = m_targetParticipantModel->getData(); QJsonArray jArray; for (const TargetManagement::ShootbackTarget &sbt : modelData) { ShootbackTargetData sbtd; sbtd.id = sbt.id(); sbtd.name = QString::fromStdString(sbt.name()); sbtd.targetParticipantEquipmentNumber = -1; if (m_ppmDtc) { const ParticipantManagement::Participant &participant = m_ppmDtc->participant(sbt.targetParticipantId()); if (participant.id() == sbt.targetParticipantId() && participant.equipmentNumber().is_set()) sbtd.targetParticipantEquipmentNumber = participant.equipmentNumber().get(); } sbtd.activateLaserDesignation = sbt.activateLaserDesignation(); sbtd.activateLights = sbt.activateLights(); sbtd.activatePopupAutomatic = sbt.activatePopupAutomatic(); sbtd.hitsToKill = sbt.hitsToKill(); sbtd.permanentInstalledTarget = sbt.permanentInstalledTarget(); // volatile data: position, visibleParticipants -> do not save -> skip jArray.append(sbtd.toJson()); } obj[QStringLiteral("ShootbackTargets")] = jArray; } QJsonDocument doc(obj); DEBUG_LOG(m_logger) << " json = " << doc.toJson(); return doc.toJson(QJsonDocument::Compact); } QVector TargetPartDialog::fromJson(const QByteArray &content) { const QJsonDocument doc(QJsonDocument::fromJson(content)); const QJsonObject obj(doc.object()); // operatorId just for convenience: const int operatorId = obj[QStringLiteral("operatorId")].toInt(); Q_UNUSED(operatorId); const QJsonArray &jArray = obj[QStringLiteral("ShootbackTargets")].toArray(); QVector vecData; vecData.reserve(jArray.size()); for (const auto &item : jArray) { const ShootbackTargetData &sbtd = ShootbackTargetData::fromJson(item.toObject()); TargetManagement::ShootbackTarget sbt; sbt.id(sbtd.id); sbt.name(sbtd.name.toStdString()); if (m_ppmDtc) sbt.targetParticipantId(m_ppmDtc->participantIdByEquipmentNumber(sbtd.targetParticipantEquipmentNumber)); sbt.activateLaserDesignation(sbtd.activateLaserDesignation); sbt.activateLights(sbtd.activateLights); sbt.activatePopupAutomatic(sbtd.activatePopupAutomatic); sbt.hitsToKill(sbtd.hitsToKill); sbt.permanentInstalledTarget(sbtd.permanentInstalledTarget); vecData.push_back(std::move(sbt)); } return vecData; } void TargetPartDialog::onEscapePressed() { m_ui->widget->clearSelection(); } void TargetPartDialog::onExportButtonClicked() { QByteArray byteArray = toJson(); int fileId = m_flmGui->saveFileContent(this, FileManagement::FileType::Xml, m_session->exerciseId(), byteArray); if (fileId > 0) DEBUG_LOG(m_logger) << LOGFUNCTION << "Saved file with id = " << fileId; else ERROR_LOG(m_logger) << LOGFUNCTION << "Could not save file in library "; } void TargetPartDialog::onImportButtonClicked() { QHash buttonTexts; buttonTexts.insert(LtsWidgets::Button::Ok, tr("Overwrite")); buttonTexts.insert(LtsWidgets::Button::Cancel, tr("Cancel")); LtsWidgets::LtsMessageDialogNew *dlg = new LtsWidgets::LtsMessageDialogNew(this, tr("Overwrite existing data?"), tr("Load from Library"), LtsWidgets::Behaviour::Popup, LtsWidgets::Button::Ok | LtsWidgets::Button::Cancel, buttonTexts); connect(dlg, &LtsWidgets::LtsMessageDialogNew::ok, this, &TargetPartDialog::onImport); } void TargetPartDialog::onImport() { INFO_LOG(m_logger) << LOGFUNCTION << "--- onImportButtonClicked() "; QByteArray content; int fileId = m_flmGui->loadFileContent(this, content, {FileManagement::FileType::Xml}, m_session->exerciseId(), FileManagement::toString(FileManagement::XmlType::TGTShootbackTargetBaseConfiguration)); if (fileId > 0) { if (!m_flmGui->isXmlType(content, FileManagement::toString(FileManagement::XmlType::TGTShootbackTargetBaseConfiguration))) { QHash texts({{LtsWidgets::Button::Yes, tr("Ok")}}); LtsWidgets::LtsMessageDialog::showMessage(this, tr("Invalid xml file content"), windowTitle(), LtsWidgets::Behaviour::Modal, LtsWidgets::Button::Yes, texts); } else { // update svc via clear and (re-)insert: // 1) clear svc: const QVector &curData = m_targetParticipantModel->getData(); for (auto item : curData) { Core::RemoveElementRequest req(item.id()); m_requestHelper->addRequest([this, req]() { return m_ftc->shootbackTargetRemoveRequest(req, this); }); } // 2) re-insert: const QVector vecDataCandidate(fromJson(content)); for (ShootbackTarget shootbackTargetCandidate : vecDataCandidate) { shootbackTargetCandidate.id(0); // force create m_requestHelper->addRequest([this, shootbackTargetCandidate]() { return m_ftc->shootbackTargetModifyRequest(shootbackTargetCandidate, this); }); } // clear view *before* performing the requests: m_targetParticipantModel->clear(); m_requestHelper->startRequests(); } } } void TargetPartDialog::onAssignAreaClicked() { QModelIndexList selectedRows = m_ui->widget->selectedRows(); if (selectedRows.isEmpty()) return; const QModelIndex curIdx = selectedRows.first(); if (!curIdx.isValid()) return; const int targetParticipantId = m_targetParticipantModel->getRowData(curIdx.row()).targetParticipantId(); // instead of emit a signal, create the according dialog frome here directly //emit assignAreasRequested(targetParticipantId); auto dlg = new AssignmentDialog(menuGroup(), m_session, this->parentWidget()); if (!dlg->init(AssignmentDialog::MODE::FILTERED_TO_SINGLE_TARGET_PARTICPANT, targetParticipantId)) { dlg->deleteLater(); return; } if (!m_session->addWidget(dlg, menuGroup(), QStringLiteral("ConfigureAreasToTargetParticipantId_%1").arg(targetParticipantId), LtsWidgets::LayoutArea::eDialogTab)) dlg->deleteLater(); } void TargetPartDialog::onMapCenterClicked() { if (!m_sitMapGuiIfc) return; QModelIndexList selectedRows = m_ui->widget->selectedRows(); if (selectedRows.isEmpty()) return; const QModelIndex curIdx = selectedRows.first(); if (!curIdx.isValid()) return; const int pId = m_targetParticipantModel->getRowData(curIdx.row()).targetParticipantId(); m_sitMapGuiIfc->centerMapToMapObject(SituationMap::MapObjectType::MOT_Participant, pId); } void TargetPartDialog::onMapZoomToClicked() { QModelIndexList selectedRows = m_ui->widget->selectedRows(); if (selectedRows.isEmpty()) return; QModelIndex index = selectedRows.first(); if (!index.isValid()) return; if (!m_targetParticipantModel || !m_sitMapGuiIfc) return; int pId = m_targetParticipantModel->getRowData(index.row()).targetParticipantId(); if (pId<=0) return; // Assigned Areas: QVector assignedAreas; auto cb = [pId, &assignedAreas](const TargetManagement::TargetAreaAssignment &assignment) { if (assignment.targetParticipantId() == pId) assignedAreas.push_back(assignment.areaId()); }; m_dtc->targetAreaAssignments(cb); { QVector> entities; entities.reserve(assignedAreas.size()+1); entities.push_back({SituationMap::MapObjectType::MOT_Participant, pId}); for (auto item : assignedAreas) entities.push_back({SituationMap::MapObjectType::MOT_ShootbackArea, item}); m_sitMapGuiIfc->zoomMapTo(entities); } } void TargetPartDialog::onObjectEntered(const QModelIndex &index) { if (!m_sitMapGuiIfc) return; if (!index.isValid()) { m_sitMapGuiIfc->removeObjectIndicator(); return; } int pId = m_targetParticipantModel->getRowData(index.row()).targetParticipantId(); if (pId>0) { // Target/Participant m_sitMapGuiIfc->objectIndicatorToMapObject(SituationMap::MapObjectType::MOT_Participant, pId, true); // Assigned Areas: QVector assignedAreas; auto cb = [pId, &assignedAreas](const TargetManagement::TargetAreaAssignment &assignment) { if (assignment.targetParticipantId() == pId) assignedAreas.push_back(assignment.areaId()); }; m_dtc->targetAreaAssignments(cb); m_sitMapGuiIfc->setMapObjectSelected(SituationMap::MapObjectType::MOT_ShootbackArea, assignedAreas, true); } else m_sitMapGuiIfc->removeObjectIndicator(); } void TargetPartDialog::onTableViewClicked(const QModelIndex &index) { if (!index.isValid()) return; if (QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ShiftModifier)) onMapCenterClicked(); } void TargetPartDialog::clearSelectionOfMapObjects() { if (!m_sitMapGuiIfc) return; // remove MapObjectIndicator: m_sitMapGuiIfc->removeObjectIndicator(); } void TargetPartDialog::onSelectionChanged() { QModelIndexList selectedRows = m_ui->widget->selectedRows(); const int cntSelectedRows = selectedRows.size(); m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, cntSelectedRows == 1); m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, cntSelectedRows == 1); m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::CenterMap, cntSelectedRows == 1); m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::ZoomMapTo, cntSelectedRows == 1); m_assignAreaBtn->setEnabled(cntSelectedRows == 1); // LtsWidgets::DialogButton::Library if (selectedRows.isEmpty()) onObjectEntered({}); // use invalid Idx to removeObjectIndicator else onObjectEntered(selectedRows.first()); } //----------------------------------------------------------------------------- } // namespace TargetManagement