488 lines
16 KiB
C++
Executable File
488 lines
16 KiB
C++
Executable File
/**
|
||
* @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 <LtsSession/lts_session_data.h>
|
||
#include <FileManagement/flm_translation.h>
|
||
|
||
#include <PluginInterfaces/gui_plugin_interface.h>
|
||
#include <Plugins/TargetManagement/tgt_data_plugin_interface.h>
|
||
#include <Plugins/FileManagement/flm_explorer_gui_plugin_interface.h>
|
||
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
|
||
|
||
#include "tgt_target_area_assignment_dialog.h"
|
||
|
||
#include <QJsonObject>
|
||
#include <QJsonArray>
|
||
#include <QJsonDocument>
|
||
|
||
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<TargetManagement::DataInterface>(m_dtc))
|
||
return false;
|
||
if (!m_session->getFtc<TargetManagement::DataInterface>(m_ftc))
|
||
return false;
|
||
if (!m_session->getForeignGuiInterface<FileManagement::ForeignGuiInterface>(m_flmGui))
|
||
return false;
|
||
if (!m_session->getForeignGuiInterface<SituationMap::ForeignGuiInterface>(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<TargetManagement::ShootbackArea>& 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<ShootbackArea> 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<TargetManagement::ShootbackArea> 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<LtsWidgets::Button, QString> 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<LtsWidgets::Button, QString> 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<ShootbackArea> &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<TargetManagement::ShootbackArea> vecDataCandidate(fromJson(content));
|
||
for (ShootbackArea area : vecDataCandidate)
|
||
{
|
||
DEBUG_LOG(m_logger) << "area " <<area;
|
||
|
||
area.id(0); // force create
|
||
m_requestHelper->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<int> assignedTargets;
|
||
auto cb = [areaId, &assignedTargets](const TargetManagement::TargetAreaAssignment &assignment)
|
||
{
|
||
if (assignment.areaId() == areaId)
|
||
assignedTargets.push_back(assignment.targetParticipantId());
|
||
};
|
||
m_dtc->targetAreaAssignments(cb);
|
||
|
||
{
|
||
QVector<QPair<SituationMap::MapObjectType, int>> 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<int> 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
|