/** * @RDE_HEADER@ * Target Configuration * $Id$ * $HeadURL$ * $Author$ * Created by Norbert Thoden, NLE, 2020-06-29 */ #include "tgt_area_dialog.h" #include "ui_tgt_area_dialog.h" #include "tgt_area_edit.h" #include "tgt_telegrams.h" #include #include #include #include #include #include #include "tgt_target_area_assignment_dialog.h" #include #include #include namespace TargetManagement { AreaDialog::AreaDialog(const QString &menuGroup, LtsSession::LtsSession *session, QWidget *parent) : LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel) , m_session(session) , m_ui(new Ui::AreaDialog) , m_menuGroup(menuGroup) , m_requestHelper(new LtsUtils::RequestHelper(this)) , m_logger(getLogger("AreaDialog")) { m_ui->setupUi(this); setOnlineHelpFilename(QStringLiteral("Situation-Assign/Configure_Targets")); } AreaDialog::~AreaDialog() { clearSelectionOfMapObjects(); delete m_ui; } bool AreaDialog::init() { if (!m_session) return false; if (!m_session->getDtc(m_dtc)) return false; if (!m_session->getFtc(m_ftc)) return false; if (!m_session->getForeignGuiInterface(m_flmGui)) return false; if (!m_session->getForeignGuiInterface(m_sitMapGuiIfc)) return false; // initialize model: INFO_LOG(m_logger) << "AreaDialog::init"; m_areaModel = new AreaModel(this); m_areaModel->initModel(m_dtc); // proxyModel: auto proxyModel = new AreaProxyModel(this); proxyModel->setSourceModel(m_areaModel); proxyModel->setDynamicSortFilter(false); // set view: (LtsDataView) m_ui->widget->setModel(proxyModel); // to allow remove off some rows at once. Anoying in all other cases -> stay at singleSelection // m_ui->widget->setSelectionMode(QAbstractItemView::SelectionMode::MultiSelection); m_assignTargetBtn = m_buttonBox->getButton(LtsWidgets::DialogButton::Import); m_buttonBox->connectButton(LtsWidgets::DialogButton::Import, this, &AreaDialog::onAssignTargetButtonClicked); // connects for gui connect(m_ui->widget, &LtsDataView::LtsDataView::signalSelectionChanged, this, &AreaDialog::onSelectionChanged); connect(m_ui->widget, &LtsDataView::LtsDataView::signalDoubleClicked, this, &AreaDialog::onEditArea); connect(this, &AreaDialog::escapePressed, this, &AreaDialog::onEscapePressed, Qt::UniqueConnection); // Create Add-Button m_buttonBox->connectButton(LtsWidgets::DialogButton::Add, this, &AreaDialog::onNewArea); // Create Remove-Button m_buttonBox->connectButton(LtsWidgets::DialogButton::Remove, this, &AreaDialog::onRemoveArea); // Create Modify-Button m_buttonBox->connectButton(LtsWidgets::DialogButton::Edit, this, &AreaDialog::onEditArea); // connect signals of TableView/CustomView: connect(m_ui->widget, &LtsDataView::LtsDataView::clicked, this, &AreaDialog::onTableViewClicked); // it´s possible to evaluate signalEntered, but seems to be overkill here: // connect(m_ui->widget, &LtsDataView::LtsDataView::signalEntered, this, &AreaDialog::onObjectEntered); #ifndef LTS_DEBUG m_ui->widget->hideColumn(AreaModel::Columns::Id); #endif // Save/Load from Library Button m_buttonBox->connectLibraryButton(this, &AreaDialog::onImportButtonClicked, &AreaDialog::onExportButtonClicked); if (!m_flmGui) m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Library, false); // 'Map' Button(s) m_buttonBox->connectButton(LtsWidgets::DialogButton::CenterMap, this, &AreaDialog::onMapCenterClicked); m_buttonBox->connectButton(LtsWidgets::DialogButton::ZoomMapTo, this, &AreaDialog::onMapZoomToClicked); if (!m_sitMapGuiIfc) { m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::CenterMap, false); m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::ZoomMapTo, false); } // call eneDisa / onSelectionChanged once: onSelectionChanged(); return true; } void AreaDialog::retranslate() { translate(m_ui, tr("Configure Areas")); m_assignTargetBtn->setText(tr("Assign Targets")); } void AreaDialog::keyPressEvent(QKeyEvent *event) { if (event->key() == Qt::Key_Escape) emit escapePressed(); return BaseClass::keyPressEvent(event); } void AreaDialog::onNewArea() { INFO_LOG(m_logger) << "onNewArea"; AreaEdit *dialog = new AreaEdit(this); if (!dialog->init(m_dtc, m_ftc, m_sitMapGuiIfc, m_areaModel)) { ERROR_LOG(m_logger) << QLatin1String("Can't initialize AreaEdit!"); delete dialog; return; } addDialog(dialog, m_menuGroup, QStringLiteral("Add Target"), LtsWidgets::LayoutArea::eDialogTab, true, true); } void AreaDialog::onRemoveArea() { const QModelIndexList &selectedRows = m_ui->widget->selectedRows(); for (const auto &mi : selectedRows) { Core::RemoveElementRequest req; req.id(m_areaModel->getRowData(mi.row()).id()); m_requestHelper->addRequest([req, this]() { return m_ftc->shootbackAreaRemoveRequest(req, this); }); } m_requestHelper->startRequests(); } void AreaDialog::onEditArea() { QModelIndexList selectedRows = m_ui->widget->selectedRows(); if (selectedRows.isEmpty()) return; const QModelIndex curIdx = selectedRows.first(); if (!curIdx.isValid()) return; INFO_LOG(m_logger) << " onEditTargetPart"; AreaEdit *dialog = new AreaEdit(this); const TargetManagement::ShootbackArea &area = m_areaModel->getRowData(curIdx.row()); if (!dialog->init(m_dtc, m_ftc, m_sitMapGuiIfc, m_areaModel, area)) { ERROR_LOG(m_logger) << LOGFUNCTION << QLatin1String("Can't initialize AreaEdit!"); delete dialog; return; } addDialog(dialog, m_menuGroup, QStringLiteral("Edit Area"), LtsWidgets::LayoutArea::eDialogTab, true, true); } QByteArray AreaDialog::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::TGTShootbackArea); { const QVector& modelData = m_areaModel->getData(); QJsonArray jArray; for (const TargetManagement::ShootbackArea &area : modelData) { ShootbackAreaData sbad; sbad.id = area.id(); sbad.name = QString::fromStdString(area.name()); sbad.position = GeoPosition2D(area.position()); sbad.width = area.width(); sbad.height = area.height(); jArray.append(sbad.toJson()); } obj[QStringLiteral("ShootbackAreas")] = jArray; } QJsonDocument doc(obj); DEBUG_LOG(m_logger) << " json = " << doc.toJson(); return doc.toJson(QJsonDocument::Compact); } QVector AreaDialog::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("ShootbackAreas")].toArray(); QVector vecData; vecData.reserve(jArray.size()); for (const auto &item : jArray) { const ShootbackAreaData &sbad = ShootbackAreaData::fromJson(item.toObject()); TargetManagement::ShootbackArea area; area.id(sbad.id); area.name(sbad.name.toStdString()); area.position({sbad.position.lon, sbad.position.lat}); // GeoPosition2D( double lon, double lat); area.width(sbad.width); area.height(sbad.height); vecData.push_back(std::move(area)); } return vecData; } void AreaDialog::onEscapePressed() { m_ui->widget->clearSelection(); } void AreaDialog::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 AreaDialog::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, &AreaDialog::onImport); } void AreaDialog::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::TGTShootbackArea)); if (fileId > 0) { if (!m_flmGui->isXmlType(content, FileManagement::toString(FileManagement::XmlType::TGTShootbackArea))) { 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_areaModel->getData(); for (auto item : curData) { Core::RemoveElementRequest req(item.id()); m_requestHelper->addRequest([this, req]() { return m_ftc->shootbackAreaRemoveRequest(req, this); }); } // 2) re-insert: const QVector vecDataCandidate(fromJson(content)); for (ShootbackArea area : vecDataCandidate) { DEBUG_LOG(m_logger) << "area " <addRequest([this, area]() { return m_ftc->shootbackAreaModifyRequest(area, this); }); } // clear view *before* performing the requests: m_areaModel->clear(); m_requestHelper->startRequests(); } } } void AreaDialog::onAssignTargetButtonClicked() { QModelIndexList selectedRows = m_ui->widget->selectedRows(); if (selectedRows.isEmpty()) return; const QModelIndex curIdx = selectedRows.first(); if (!curIdx.isValid()) return; const int areaId = m_areaModel->getRowData(curIdx.row()).id(); // instead of emit a signal, create the according dialog frome here directly // emit assignTargetsRequested(areaId); auto dlg = new AssignmentDialog(menuGroup(), m_session, this->parentWidget()); if (!dlg->init(AssignmentDialog::MODE::FILTERED_TO_SINGLE_AREA, areaId)) { dlg->deleteLater(); return; } if (!m_session->addWidget(dlg, menuGroup(), QStringLiteral("ConfigureTargetsToAreaId_%1").arg(areaId), LtsWidgets::LayoutArea::eDialogTab)) dlg->deleteLater(); } void AreaDialog::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 id = m_areaModel->getRowData(curIdx.row()).id(); m_sitMapGuiIfc->centerMapToMapObject(SituationMap::MapObjectType::MOT_ShootbackArea, id); } void AreaDialog::onMapZoomToClicked() { QModelIndexList selectedRows = m_ui->widget->selectedRows(); if (selectedRows.isEmpty()) return; QModelIndex index = selectedRows.first(); if (!index.isValid()) return; if (!m_areaModel || !m_sitMapGuiIfc) return; int areaId = m_areaModel->getRowData(index.row()).id(); if (areaId<=0) return; // Assigned Targets: QVector assignedTargets; auto cb = [areaId, &assignedTargets](const TargetManagement::TargetAreaAssignment &assignment) { if (assignment.areaId() == areaId) assignedTargets.push_back(assignment.targetParticipantId()); }; m_dtc->targetAreaAssignments(cb); { QVector> entities; entities.reserve(assignedTargets.size()+1); entities.push_back({SituationMap::MapObjectType::MOT_ShootbackArea, areaId}); for (auto item : assignedTargets) entities.push_back({SituationMap::MapObjectType::MOT_Participant, item}); m_sitMapGuiIfc->zoomMapTo(entities); } } void AreaDialog::onObjectEntered(const QModelIndex &index) { if (!m_sitMapGuiIfc) return; if (!index.isValid()) { m_sitMapGuiIfc->removeObjectIndicator(); return; } int areaId = m_areaModel->getRowData(index.row()).id(); if (areaId>0) { // Area m_sitMapGuiIfc->objectIndicatorToMapObject(SituationMap::MapObjectType::MOT_ShootbackArea, areaId, true); // Assigned Targets: QVector assignedTargets; auto cb = [areaId, &assignedTargets](const TargetManagement::TargetAreaAssignment &assignment) { if (assignment.areaId() == areaId) assignedTargets.push_back(assignment.targetParticipantId()); }; m_dtc->targetAreaAssignments(cb); m_sitMapGuiIfc->setMapObjectSelected(SituationMap::MapObjectType::MOT_Participant, assignedTargets, true); } else m_sitMapGuiIfc->removeObjectIndicator(); } void AreaDialog::onTableViewClicked(const QModelIndex &index) { if (!index.isValid()) return; if (QGuiApplication::keyboardModifiers().testFlag(Qt::KeyboardModifier::ShiftModifier)) onMapCenterClicked(); } void AreaDialog::clearSelectionOfMapObjects() { if (!m_sitMapGuiIfc) return; // remove MapObjectIndicator: m_sitMapGuiIfc->removeObjectIndicator(); } void AreaDialog::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_assignTargetBtn->setEnabled(cntSelectedRows == 1); // LtsWidgets::DialogButton::Library if (selectedRows.isEmpty()) onObjectEntered({}); // use invalid Idx to removeObjectIndicator else onObjectEntered(selectedRows.first()); } //----------------------------------------------------------------------------- } // namespace TargetManagement