906 lines
33 KiB
C++
Executable File
906 lines
33 KiB
C++
Executable File
/**
|
||
* @RDE_HEADER@
|
||
* GUI Plugin for ParticipantsMoveDialog
|
||
* $Id$
|
||
* $HeadURL$
|
||
* $Author$
|
||
* Created by Gerlinde Rudolphus, SLSE, 2018-01-02*/
|
||
|
||
#include "participants_move_dialog.h"
|
||
#include "participants_move_model.h"
|
||
#include "ui_participants_move_dialog.h"
|
||
#include <LtsWidgets/lts_column_filter_proxy_model.h>
|
||
#include <AdvancedSymbology/asb_data_plugin_interface.h>
|
||
#include <CentralEffectSimulation/ces_data_plugin_interface.h>
|
||
#include <Plugins/ExerciseManagement/exm_data_plugin_interface.h>
|
||
#include <Plugins/AssetManagement/asm_data_plugin_interface.h>
|
||
#include <AreaEffectSimulation/aes_data_plugin_interface.h>
|
||
#include <LtsUtilsSettings/settings.h>
|
||
|
||
#include "participant_move_dialog.h"
|
||
|
||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||
#include <LtsSession/lts_session_data_dds.h>
|
||
#include <LtsSession/lts_session_data.h>
|
||
#include <FilterManagement/flt_participant_plugin_interface.h>
|
||
#include <FilterManagement/flt_symbol_appearance_settings.h>
|
||
#include <LtsCoordTrans/lts_coord_widget.h>
|
||
#include <QInputDialog>
|
||
#include <QLabel>
|
||
#include <QDoubleSpinBox>
|
||
#include <QDialogButtonBox>
|
||
#include <QDebug>
|
||
|
||
namespace CentralEffectSimulation
|
||
{
|
||
ParticipantsMoveDialog::ParticipantsMoveDialog(const QString &menuGroup, QWidget *parent)
|
||
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::CloseOnly)
|
||
, m_participantModel(nullptr)
|
||
, m_ppmDtc(nullptr)
|
||
, m_ppmCbxIfc(nullptr)
|
||
, m_ftc(nullptr)
|
||
, m_ui(new Ui::ParticipantMoveDialog)
|
||
, m_session(nullptr)
|
||
, m_menuGroup(menuGroup)
|
||
, m_requestHelper(new LtsUtils::RequestHelper(this))
|
||
, m_sitMapGuiIfc(nullptr)
|
||
, m_logger(getLogger("ParticipantsMoveDialog"))
|
||
{
|
||
m_ui->setupUi(this);
|
||
setUnchangeable();
|
||
|
||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Save, this, &ParticipantsMoveDialog::onSetSimulatedMGRSPosition);
|
||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Save, false);
|
||
m_buttonBox->setIcon(LtsWidgets::DialogButton::Save, QIcon(QStringLiteral("icon:position.svg")));
|
||
|
||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Edit, this, &ParticipantsMoveDialog::onClicked);
|
||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, false);
|
||
|
||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Add, this, &ParticipantsMoveDialog::onSetPosition);
|
||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Add, false);
|
||
|
||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Remove, this, &ParticipantsMoveDialog::onRemove);
|
||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, false);
|
||
|
||
|
||
setOnlineHelpFilename(QStringLiteral("Situation-Move_Participant_0"));
|
||
}
|
||
|
||
ParticipantsMoveDialog::~ParticipantsMoveDialog()
|
||
{
|
||
m_sitMapGuiIfc = nullptr;
|
||
delete m_ui;
|
||
}
|
||
|
||
static constexpr int s_maxAngleDeg = 360;
|
||
static constexpr int s_maxAngleMil = 6400;
|
||
inline constexpr int mil2Deg(const int &mil)
|
||
{
|
||
return s_maxAngleDeg * mil / s_maxAngleMil;
|
||
}
|
||
inline constexpr int deg2Mil(const int &angleDeg)
|
||
{
|
||
return s_maxAngleMil * angleDeg / s_maxAngleDeg;
|
||
}
|
||
|
||
void ParticipantsMoveDialog::retranslate()
|
||
{
|
||
translate(m_ui, tr("Move Participant"));
|
||
m_buttonBox->getButton(LtsWidgets::DialogButton::Save)->setText(tr("Set Simulated MGRS Position"));
|
||
m_buttonBox->getButton(LtsWidgets::DialogButton::Add)->setText(tr("Set Simulated Position"));
|
||
m_buttonBox->getButton(LtsWidgets::DialogButton::Edit)->setText(tr("Edit Simulation"));
|
||
m_buttonBox->getButton(LtsWidgets::DialogButton::Remove)->setText(tr("Remove Simulation"));
|
||
}
|
||
|
||
bool ParticipantsMoveDialog::init(LtsSession::LtsSession *session,
|
||
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
|
||
const std::shared_ptr<CentralEffectSimulation::Interface::Dtc> &cesDtc,
|
||
const std::shared_ptr<ParticipantManagement::Interface::Ftc> &ppmFtc)
|
||
{
|
||
m_ppmDtc = ppmDtc;
|
||
m_cesDtc = cesDtc;
|
||
m_session = session;
|
||
m_ppmFtc = ppmFtc;
|
||
|
||
if (!m_ppmDtc)
|
||
return false;
|
||
|
||
if (!m_ppmFtc)
|
||
return false;
|
||
|
||
if (!session->getForeignGuiInterface<ParticipantManagement::ForeignGuiComboboxInterface>(m_ppmCbxIfc))
|
||
return false;
|
||
|
||
if (!m_session->getFtc<CentralEffectSimulation::DataInterface>(m_ftc))
|
||
return false;
|
||
|
||
std::shared_ptr<ExerciseManagement::Interface::Dtc> exmDtc;
|
||
if (!m_session->getDtc<ExerciseManagement::DataInterface>(exmDtc))
|
||
{
|
||
ERROR_LOG(m_logger) << "failed to get exmDtc ";
|
||
return false;
|
||
}
|
||
|
||
std::shared_ptr<AssetManagement::Interface::Dtc> asmDtc;
|
||
if (!m_session->getDtc<AssetManagement::DataInterface>(asmDtc))
|
||
{
|
||
ERROR_LOG(m_logger) << "failed to get asmDtc ";
|
||
return false;
|
||
}
|
||
|
||
if (asmDtc == nullptr || exmDtc == nullptr)
|
||
return false;
|
||
|
||
const ExerciseManagement::Exercise exc = exmDtc->exercise(m_session->exerciseId());
|
||
AssetManagement::TrainingArea ta = asmDtc->trainingArea(exc.trainingAreaId());
|
||
if (ta.id() != exc.trainingAreaId())
|
||
{
|
||
ERROR_LOG(m_logger)<<" couldn't get Training Area with id: "<<exc.trainingAreaId();
|
||
return false;
|
||
}
|
||
|
||
if (!m_session ->getDtc<AreaEffectSimulation::DataInterface>(m_aesDtc))
|
||
{
|
||
ERROR_LOG(m_logger)<<"failed to get aesDtc";
|
||
return false;
|
||
}
|
||
|
||
|
||
|
||
// get training area Rect
|
||
const LtsCoordTrans::UtmCoordinate &bottomLeft = LtsCoordTrans::UtmCoordinate::fromGeographic(ta.bottomLeft().lon(), ta.bottomLeft().lat());
|
||
m_trainingAreaRect = QRectF(bottomLeft.geographic(0, ta.height()), bottomLeft.geographic(ta.width(), 0));
|
||
|
||
|
||
// for relativeMove of units via SetSimulatedPositionRelative:
|
||
m_ppmDtc->enableUnitPosition();
|
||
m_ppmDtc->waitForHistoricalDataUnitPosition(1000);
|
||
|
||
std::shared_ptr<AdvancedSymbology::ForeignDataInterface> asb;
|
||
session->getForeignDataInterface<AdvancedSymbology::DataInterface>(asb);
|
||
m_participantModel = new ParticipantMoveModel(this, m_ppmDtc, asb);
|
||
// only needed to set recursiveFilteringEnabled
|
||
auto proxyModel = new ParticipantManagement::ParticipantTreeFilterProxyModel(this);
|
||
proxyModel->setSourceModel(m_participantModel);
|
||
proxyModel->setRecursiveFilteringEnabled(true);
|
||
m_ui->dvParticipants->setModel(proxyModel);
|
||
m_ui->dvParticipants->setSortIndicator(0, Qt::AscendingOrder);
|
||
|
||
connect(m_ui->cbParty,
|
||
static_cast<void (LtsWidgets::LtsComboBox::*)(int)>(&LtsWidgets::LtsComboBox::currentIndexChanged),
|
||
this, &ParticipantsMoveDialog::changeParty);
|
||
connect(m_ui->cbAll, &QCheckBox::toggled, this, &ParticipantsMoveDialog::changeParty);
|
||
|
||
connect(m_ui->dvParticipants, &LtsDataView::LtsDataView::selectionChanged,
|
||
this, &ParticipantsMoveDialog::onSelectionChanged);
|
||
|
||
connect(m_participantModel, &ParticipantMoveModel::newData,
|
||
this, &ParticipantsMoveDialog::onModelChanged);
|
||
|
||
connect(m_ui->dvParticipants, &LtsDataView::LtsDataView::signalDoubleClicked,
|
||
this, &ParticipantsMoveDialog::onDoubleClicked);
|
||
|
||
|
||
m_ppmCbxIfc->fillPartyComboBox(m_ui->cbParty, ParticipantManagement::ForeignGuiComboboxInterface::CbxPartyFilter::All);
|
||
changeParty();
|
||
|
||
m_session->getForeignGuiInterface<SituationMap::ForeignGuiInterface>(m_sitMapGuiIfc);
|
||
m_buttonBox->getButton(LtsWidgets::DialogButton::Add)->setIcon(QIcon(QStringLiteral("icon:position.svg")));
|
||
|
||
#ifndef LTS_DEBUG
|
||
m_ui->dvParticipants->hideColumn(ParticipantMoveModel::ColParticipantId);
|
||
#endif
|
||
|
||
return true;
|
||
}
|
||
|
||
//private
|
||
|
||
void ParticipantsMoveDialog::closeDialogReceived(int32_t participantId)
|
||
{
|
||
m_participantDialogMap.remove(participantId);
|
||
}
|
||
|
||
|
||
void ParticipantsMoveDialog::onSelectionChanged()
|
||
{
|
||
const QModelIndexList indexList = m_ui->dvParticipants->selectedRows();
|
||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Save, false);
|
||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Add, false);
|
||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, false);
|
||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, false);
|
||
bool isOne = (indexList.size() == 1);
|
||
|
||
// Set remove Btn
|
||
if (!isOne)
|
||
return;
|
||
|
||
const ParticipantManagement::ParticipantData data(participantFromIndex(indexList.first()));
|
||
DEBUG_LOG(m_logger) << "ParticipantId: " << data.id();
|
||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, data.isSimulated());
|
||
// Show preview of selected Simulation
|
||
if (data.isSimulated() && m_participantDialogMap.contains(data.id()))
|
||
m_participantDialogMap.value(data.id())->showPreview(true);
|
||
else
|
||
{
|
||
// Remove Preview
|
||
QMapIterator<int, ParticipantMoveDialog *> i(m_participantDialogMap);
|
||
while (i.hasNext())
|
||
{
|
||
i.next();
|
||
//cout << i.key() << ": " << i.value() << endl;
|
||
i.value()->showPreview(false);
|
||
}
|
||
}
|
||
|
||
// allow moving units (with all its children)
|
||
{
|
||
bool isParticipantInUseOrAdler = participantInUse4ExplosionCluster(indexList.first());
|
||
// Check for Adler Type too
|
||
if (!isParticipantInUseOrAdler)
|
||
isParticipantInUseOrAdler = (m_ppmDtc->isAdlerType(data.typeId()) && !data.name().empty());
|
||
|
||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Add, isOne && !isParticipantInUseOrAdler);
|
||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Save, isOne && !isParticipantInUseOrAdler);
|
||
}
|
||
|
||
if (m_ppmDtc->type(data.typeId()).typeClass() != ParticipantManagement::TypeClass_def::Unit)
|
||
{
|
||
|
||
if (!data.equipmentNumber().is_set() || data.equipmentNumber().get() <= 0)
|
||
{
|
||
//No Sim MoveMent for Adler SAA Participants
|
||
isOne &= !(m_ppmDtc->isAdlerType(data.typeId()) && !data.name().empty());
|
||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, isOne);
|
||
}
|
||
else
|
||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, false);
|
||
}
|
||
|
||
}
|
||
|
||
void ParticipantsMoveDialog::onModelChanged()
|
||
{
|
||
m_ui->dvParticipants->expandAll();
|
||
DEBUG_LOG(m_logger) << "onModelChanged";
|
||
}
|
||
|
||
void ParticipantsMoveDialog::onDoubleClicked()
|
||
{
|
||
if (!m_sitMapGuiIfc)
|
||
return;
|
||
|
||
if (m_sitMapGuiIfc->mapMode() != SituationMap::MapMode::MapMode_2D)
|
||
{
|
||
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Only available in 2D mode"));
|
||
return;
|
||
}
|
||
|
||
if (!m_buttonBox->isButtonEnabled(LtsWidgets::DialogButton::Edit))
|
||
return;
|
||
const QModelIndexList indexList = m_ui->dvParticipants->selectedRows();
|
||
|
||
bool isOne = (indexList.size() == 1);
|
||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, isOne);
|
||
|
||
if (!isOne)
|
||
return;
|
||
|
||
const ParticipantManagement::ParticipantData data(participantFromIndex(indexList.first()));
|
||
DEBUG_LOG(m_logger) << "ParticipantId: " << data.id();
|
||
|
||
if (!m_participantDialogMap.contains(data.id()))
|
||
{
|
||
ParticipantMoveDialog *dialog = new ParticipantMoveDialog(this);
|
||
m_participantDialogMap.insert(data.id(), dialog);
|
||
connect(dialog, &ParticipantMoveDialog::closeDialog,
|
||
this, &ParticipantsMoveDialog::closeDialogReceived);
|
||
|
||
addDialog(LtsWidgets::initDialog(dialog, m_session, m_ppmDtc, m_cesDtc, data),
|
||
m_menuGroup, QStringLiteral("cesNewSimulation%1").arg(data.id()), LtsWidgets::LayoutArea::eDialogTab);
|
||
}
|
||
else
|
||
focusDialog(m_menuGroup, QStringLiteral("cesNewSimulation%1").arg(data.id()), LtsWidgets::LayoutArea::eDialogTab);
|
||
}
|
||
|
||
//Slots
|
||
void ParticipantsMoveDialog::changeParty()
|
||
{
|
||
if (m_ui->cbAll->isChecked())
|
||
{
|
||
m_ui->cbParty->setEnabled(false);
|
||
m_ui->dvParticipants->setEnabled(false);
|
||
m_participantModel->resetModel();
|
||
}
|
||
else
|
||
{
|
||
m_ui->cbParty->setEnabled(true);
|
||
m_ui->dvParticipants->setEnabled(true);
|
||
int partyId = m_ui->cbParty->currentData().toInt();
|
||
m_participantModel->onReinitModel(partyId);
|
||
m_ui->dvParticipants->expandAll();
|
||
}
|
||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Add, m_ui->cbAll->isChecked());
|
||
}
|
||
|
||
void ParticipantsMoveDialog::onClicked()
|
||
{
|
||
onDoubleClicked();
|
||
}
|
||
|
||
void ParticipantsMoveDialog::onRemove()
|
||
{
|
||
const QModelIndexList indexList = m_ui->dvParticipants->selectedRows();
|
||
|
||
bool isOne = (indexList.size() == 1);
|
||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, isOne);
|
||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, false);
|
||
|
||
if (!isOne)
|
||
return;
|
||
|
||
const ParticipantManagement::ParticipantData data(participantFromIndex(indexList.first()));
|
||
INFO_LOG(m_logger) << "onRemove ParticipantId: " << data.id();
|
||
|
||
// Remove (possible) open Dialogs
|
||
delete m_participantDialogMap.value(data.id());
|
||
m_participantDialogMap.remove(data.id());
|
||
|
||
removeFtc(data.id());
|
||
}
|
||
|
||
|
||
void ParticipantsMoveDialog::onSetSimulatedMGRSPosition()
|
||
{
|
||
const QModelIndexList &indexList = m_ui->dvParticipants->selectedRows();
|
||
if (indexList.size() == 1)
|
||
{
|
||
QPointF mgrsCoordinate;
|
||
m_mgrsPosEditCoordinateActive = true;
|
||
if(!participantInUse4ExplosionCluster(indexList.first()))
|
||
{
|
||
onGetCoordinate(mgrsCoordinate);
|
||
m_mgrsPosEditCoordinateActive = false;
|
||
}
|
||
else
|
||
LtsWidgets::LtsMessageDialog::showMessage(this, tr("This Participant Unit is currently in use.\nThe Parameters can't be changed!"));
|
||
}
|
||
}
|
||
|
||
bool ParticipantsMoveDialog::participantInUse4ExplosionCluster(const QModelIndex &participantIndex)
|
||
{
|
||
const ParticipantManagement::ParticipantData participantData(participantFromIndex(participantIndex));
|
||
bool bret=false;
|
||
|
||
const ParticipantManagement::Type &participantType = m_ppmDtc->type(participantData.typeId());
|
||
bool isUnitType = (participantType.typeClass() == ParticipantManagement::TypeClass::Unit) ||
|
||
(participantType.typeClass() == ParticipantManagement::TypeClass::SupportUnit);
|
||
// get parent
|
||
//only units tell us if participants are in used with explosion cluster
|
||
if (!isUnitType)
|
||
{
|
||
const QModelIndex parentIndex = m_participantModel->indexFromParticipantId(participantData.superiorModId());
|
||
const ParticipantManagement::ParticipantData parentParticipantData(participantFromIndex(parentIndex));
|
||
|
||
const ParticipantManagement::Type &partentParticipantType = m_ppmDtc->type(parentParticipantData.typeId());
|
||
isUnitType = (partentParticipantType.typeClass() == ParticipantManagement::TypeClass::Unit) ||
|
||
(partentParticipantType.typeClass() == ParticipantManagement::TypeClass::SupportUnit);
|
||
bret = isUnitType && isParticipantInUseForExplosionCluster(parentParticipantData.id());;
|
||
}
|
||
else
|
||
bret = isParticipantInUseForExplosionCluster(participantData.id());
|
||
|
||
return bret;
|
||
}
|
||
|
||
void ParticipantsMoveDialog::onSimulatedMovementRemoveByParticipantIdReply(const Core::FunctionReplyObject &replyObject)
|
||
{
|
||
m_requestHelper->requestReply(replyObject);
|
||
}
|
||
|
||
void ParticipantsMoveDialog::onSetSimulatedPositionReply(const Core::FunctionReplyObject &replyObject)
|
||
{
|
||
m_requestHelper->requestReply(replyObject);
|
||
}
|
||
|
||
void ParticipantsMoveDialog::onSetSimulatedPositionRelativeReply(const Core::FunctionReplyObject &replyObject)
|
||
{
|
||
m_requestHelper->requestReply(replyObject);
|
||
}
|
||
|
||
void ParticipantsMoveDialog::onSetSimulatedParticipantFormationReply(const Core::FunctionReplyObject &replyObject)
|
||
{
|
||
m_requestHelper->requestReply(replyObject);
|
||
}
|
||
|
||
bool ParticipantsMoveDialog::removeFtc(int32_t participantId)
|
||
{
|
||
if (participantId <= 0)
|
||
return true;
|
||
|
||
CentralEffectSimulation::SimulatedMovementRemoveByParticipantId req(participantId);
|
||
|
||
m_requestHelper->addRequest([req, this]()
|
||
{
|
||
return m_ftc->simulatedMovementRemoveByParticipantIdRequest(req, this);
|
||
});
|
||
return m_requestHelper->startRequests();
|
||
}
|
||
|
||
void ParticipantsMoveDialog::onGetCoordinate(QPointF coordinate)
|
||
{
|
||
const QModelIndexList indexList = m_ui->dvParticipants->selectedRows();
|
||
if (indexList.size() == 0)
|
||
return;
|
||
|
||
const ParticipantManagement::ParticipantData participantData(participantFromIndex(indexList.first()));
|
||
|
||
INFO_LOG(m_logger) << LOGFUNCTION << "ParticipantId=" << participantData.id()
|
||
<< " EquipmentNr=" << participantData.equipmentNumber()
|
||
<< " onGetCoordinate x=" << coordinate.x() << " y=" << coordinate.y();
|
||
if (participantData.id() <= 0)
|
||
return;
|
||
|
||
const ParticipantManagement::Type &participantType = m_ppmDtc->type(participantData.typeId());
|
||
const bool &isUnitType =
|
||
(participantType.typeClass() == ParticipantManagement::TypeClass::Unit) ||
|
||
(participantType.typeClass() == ParticipantManagement::TypeClass::SupportUnit);
|
||
|
||
|
||
// get participant type properties
|
||
// special handling when participant has Artillery as property
|
||
m_formationProps.setFormation(QString::fromStdString(participantType.properties()));
|
||
const bool &withFormation = (isUnitType && m_formationProps.isArtillery);
|
||
if (withFormation || m_mgrsPosEditCoordinateActive)
|
||
setFormationAndPositioningUi(participantData, coordinate, withFormation);
|
||
else if (isUnitType)
|
||
m_shiftModifierWhileOnSetPosition ? doSetSimulatedPositionRequest(participantData, coordinate) :
|
||
doSetSimulatedPositionRelativeRequest(participantData, coordinate);
|
||
else
|
||
doSetSimulatedPositionRequest(participantData, coordinate); // single (human|vehicle)
|
||
|
||
}
|
||
|
||
void ParticipantsMoveDialog::onSetPosition()
|
||
{
|
||
|
||
if (!m_sitMapGuiIfc) //sanity
|
||
return;
|
||
|
||
if (m_sitMapGuiIfc->mapMode() != SituationMap::MapMode::MapMode_2D)
|
||
{
|
||
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Only available in 2D mode"));
|
||
return;
|
||
}
|
||
|
||
if (!m_ui->cbAll->isChecked())
|
||
{
|
||
const QModelIndexList indexList = m_ui->dvParticipants->selectedRows();
|
||
|
||
bool isOne = (indexList.size() == 1);
|
||
if (!isOne)
|
||
return;
|
||
//const ParticipantManagement::ParticipantData participantData(participantFromIndex(indexList.first()));
|
||
if (participantInUse4ExplosionCluster(indexList.first()))
|
||
{
|
||
LtsWidgets::LtsMessageDialog::showMessage(this, tr("This Participant Unit is currently in use.\nThe Parameters can't be changed!"));
|
||
return;
|
||
}
|
||
|
||
}
|
||
|
||
m_shiftModifierWhileOnSetPosition = QApplication::keyboardModifiers().testFlag(Qt::ShiftModifier);
|
||
m_sitMapGuiIfc->getCoordinate(this, SLOT(onGetCoordinate(QPointF)), nullptr);
|
||
}
|
||
|
||
void ParticipantsMoveDialog::setDialogEnable(bool enable)
|
||
{
|
||
m_ui->dvParticipants->setEnabled(enable);
|
||
m_ui->cbParty->setEnabled(enable);
|
||
m_ui->cbAll->setEnabled(enable);
|
||
m_buttonBox->setEnabled(enable);
|
||
}
|
||
|
||
bool ParticipantsMoveDialog::isParticipantInUseForExplosionCluster(int id)
|
||
{
|
||
if (!m_aesDtc)
|
||
{
|
||
ERROR_LOG(m_logger)<<" m_aesDTC is not setted";
|
||
return true;
|
||
}
|
||
|
||
const QMap<qint32, AreaEffectSimulation::ExplosionCluster> &ecMap = m_aesDtc->explosionClusters();
|
||
for(const AreaEffectSimulation::ExplosionCluster &aes : qAsConst(ecMap))
|
||
{
|
||
if (aes.participantId() == id &&
|
||
(aes.effectStateId() == AreaEffectSimulation::AesEffectState::EsPrepared ||
|
||
aes.effectStateId() == AreaEffectSimulation::AesEffectState::EsActivated))
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
void ParticipantsMoveDialog::tableColumnOrganiserSetting()
|
||
{
|
||
//LtsColumnOrganiser
|
||
m_ui->dvParticipants->setColumnsOrganiserEnabled(identifier(), true);
|
||
}
|
||
|
||
/*!
|
||
* \brief ParticipantsMoveDialog::setFormationAndPositioningUi
|
||
* \param withMgrsPos:
|
||
* \param withFormation
|
||
* \param mgrsCoordinate
|
||
* \return
|
||
*/
|
||
void ParticipantsMoveDialog::setFormationAndPositioningUi(const ParticipantManagement::ParticipantData &participantData,
|
||
QPointF &mgrsCoordinate,
|
||
const bool &unitWithFormation)
|
||
{
|
||
if (!unitWithFormation && !m_mgrsPosEditCoordinateActive)
|
||
return;
|
||
|
||
const ParticipantManagement::Type &participantType = m_ppmDtc->type(participantData.typeId());
|
||
const bool isUnitType =
|
||
(participantType.typeClass() == ParticipantManagement::TypeClass::Unit) ||
|
||
(participantType.typeClass() == ParticipantManagement::TypeClass::SupportUnit);
|
||
|
||
m_formationProps.setFormation(QString::fromStdString(participantType.properties()));
|
||
|
||
if (m_formationProps.hasFormationData())
|
||
return;
|
||
|
||
|
||
LtsWidgets::LtsFramelessDialog *dialog = new LtsWidgets::LtsFramelessDialog(this, LtsWidgets::Behaviour::Popup);
|
||
dialog->setFixedSize(390, 300);
|
||
dialog->setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint);
|
||
|
||
int row = 0;
|
||
QGridLayout *gla = new QGridLayout(dialog);
|
||
// Message Infobox
|
||
{
|
||
QLabel *msgLbl = new QLabel(tr("<b> Following Parameter(s) must be set to proceed. </b>"), dialog);
|
||
msgLbl->setWordWrap(true);
|
||
gla->addWidget(msgLbl, row, 0, 1, 2);
|
||
}
|
||
|
||
// set mgrs Postion edit
|
||
LtsCoordWidget::LtsCoordWidget *posEdit = new LtsCoordWidget::LtsCoordWidget(LtsCoordWidget::LtsCoordWidget::DisplayType::MGRS, dialog);
|
||
{
|
||
QLabel *posEditLbl = new QLabel(tr("MGRS Position:"), dialog);
|
||
LtsUtils::ProjectSettings *ps = LtsUtils::ProjectSettings::getInstance();
|
||
const QSize offset = QSize(ps->value(QStringLiteral("MgrsSquaresOffsets"), QStringLiteral("xOffset")).toInt(),
|
||
ps->value(QStringLiteral("MgrsSquaresOffsets"), QStringLiteral("yOffset")).toInt());
|
||
|
||
posEdit->setWithSurroundingMgrsSquares(true);
|
||
posEdit->setMgrsSquareEditable(true);
|
||
QVector<LtsCoordTrans::UtmCoordinate> geoCoords;
|
||
|
||
if (LtsCoordTrans::defaultMgrsSquareWithOffsets().isEmpty())
|
||
{
|
||
const QRectF &trainingAreaWithMargin = LtsCoordTrans::addMarginToArea(m_trainingAreaRect, offset);
|
||
geoCoords = LtsCoordTrans::getMgrsSquares(trainingAreaWithMargin,false,false,true);
|
||
}
|
||
else
|
||
geoCoords = LtsCoordTrans::defaultMgrsSquareWithOffsets();
|
||
|
||
posEdit->setMgrsSquares(geoCoords);
|
||
if (!mgrsCoordinate.isNull())
|
||
posEdit->setCoordinate(mgrsCoordinate, true);
|
||
|
||
++row;
|
||
gla->addWidget(posEditLbl, row, 0, 1, 1);
|
||
gla->addWidget(posEdit, row, 1, 1, 1);
|
||
|
||
QFrame *line = new QFrame(dialog);
|
||
line->setObjectName(QString::fromUtf8("line"));
|
||
line->setGeometry(QRect(110, 110, 118, 3));
|
||
line->setFrameShape(QFrame::HLine);
|
||
line->setFrameShadow(QFrame::Sunken);
|
||
|
||
++row;
|
||
gla->addWidget(line, row, 0, 1, 2);
|
||
}
|
||
|
||
// set Angle
|
||
QSpinBox *angleSBox = nullptr;
|
||
//if (m_formationProps.angle == -1 && unitWithFormation)
|
||
{
|
||
QLabel *angleLbl = new QLabel( tr("Angle:"), dialog); // Grundrichtung
|
||
angleSBox = new QSpinBox(dialog);
|
||
angleSBox->setMinimum(0);
|
||
angleSBox->setMaximum(s_maxAngleMil);
|
||
angleSBox->setSuffix(tr(" mil"));
|
||
++row;
|
||
gla->addWidget(angleLbl, row, 0, 1, 1);
|
||
gla->addWidget(angleSBox, row, 1, 1, 1);
|
||
|
||
}// end setting angle
|
||
|
||
// set Distance
|
||
QSpinBox *distanceSBox = nullptr;
|
||
QComboBox *distanceCBox = nullptr;
|
||
{
|
||
QLabel *distanceLbl = new QLabel(tr("Distance:"), dialog);
|
||
distanceCBox = new QComboBox(dialog);
|
||
for(const auto &dis : m_formationProps.distanceSets.toStdMap())
|
||
{
|
||
QString str;
|
||
if (dis.first == QStringLiteral("Locked")) // Geschlossen
|
||
str = tr("Locked");
|
||
else if (dis.first == QStringLiteral("Unlocked")) // Aufgelockert
|
||
str = tr("Unlocked");
|
||
distanceCBox->addItem(QStringLiteral("%1 (%2m)").arg(str).arg(dis.second.toInt()), dis.second.toInt());
|
||
}
|
||
|
||
++row;
|
||
gla->addWidget(distanceLbl, row, 0, 1, 1);
|
||
gla->addWidget(distanceCBox, row, 1, 1, 1);
|
||
|
||
}
|
||
|
||
// Vertical spacer
|
||
{
|
||
QScopedPointer<QSpacerItem> verticalSpacer(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding));
|
||
row++;
|
||
gla->addItem(verticalSpacer.take(), row, 0, 1, 1);
|
||
}
|
||
|
||
// dialog button
|
||
LtsWidgets::LtsDialogButtonBox *btnBox = new LtsWidgets::LtsDialogButtonBox(dialog);
|
||
btnBox->getButton(LtsWidgets::DialogButton::Ok)->setText(tr("Apply"));
|
||
btnBox->getButton(LtsWidgets::DialogButton::Close)->setText(tr("Abort"));
|
||
// horizontal spacer
|
||
{
|
||
QScopedPointer <QSpacerItem> horizontalSpacer(new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum));
|
||
row++;
|
||
gla->addItem(horizontalSpacer.take(), row, 0, 1, 1);
|
||
gla->addWidget(btnBox, row, 0, 1, 2);
|
||
}
|
||
|
||
// handle Data
|
||
auto applyData = [=]()
|
||
{
|
||
// angle can be get in ° or mil, but we work with angle in degree. so we habe to convert mil value if defined
|
||
// 0° orientation is east ouest
|
||
{ // get angle value
|
||
int angleMil = angleSBox->value();
|
||
// angle in mil: convert in degree, then we work in degree
|
||
m_formationProps.angle = std::fmod((mil2Deg(angleMil) + 90), 360);// 0° ost-west gerichtet
|
||
|
||
DEBUG_LOG(m_logger)<<" angle in deg mil: "<<angleMil
|
||
<<" -> degree: "<< mil2Deg(angleMil)<<" final position(°): "<<m_formationProps.angle;
|
||
}
|
||
|
||
{// get distance value
|
||
// spinbox is enable when there is no distance sets available. The user will enter a desired distance
|
||
if (distanceSBox != nullptr)
|
||
m_formationProps.distance = distanceSBox->value();
|
||
else if(distanceCBox != nullptr)
|
||
m_formationProps.distance = distanceCBox->currentData().toInt();
|
||
}
|
||
|
||
const QPointF mgrsCoordinate = posEdit->coordinate();
|
||
if (mgrsCoordinate.isNull())
|
||
{
|
||
WARNING_LOG(m_logger)<<"MGRS Coordinates invalid!";
|
||
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Coordinates invalid!\nPlease check them and try again."));
|
||
return;
|
||
}
|
||
if (unitWithFormation && (m_formationProps.hasFormationData() || !mgrsCoordinate.isNull()))
|
||
{
|
||
doSetSimulatedParticipantFormationRequest(participantData, mgrsCoordinate, m_formationProps.getFormationDataObjectString());
|
||
}
|
||
else if (isUnitType)
|
||
{
|
||
// set while user is pressing
|
||
m_shiftModifierWhileOnSetPosition ? doSetSimulatedPositionRequest(participantData, mgrsCoordinate) :
|
||
doSetSimulatedPositionRelativeRequest(participantData, mgrsCoordinate);
|
||
}
|
||
else
|
||
doSetSimulatedPositionRequest(participantData, mgrsCoordinate); // single (human|vehicle)
|
||
|
||
setDialogEnable(true);
|
||
dialog->accept();
|
||
};
|
||
|
||
// abort/close
|
||
connect(btnBox->getButton(LtsWidgets::DialogButton::Close), &QPushButton::clicked, dialog, [=](){
|
||
setDialogEnable(true);
|
||
dialog->accept();
|
||
});
|
||
// apply
|
||
connect(btnBox->getButton(LtsWidgets::DialogButton::Ok), &QPushButton::clicked, this, applyData);
|
||
|
||
dialog->setLayout(gla);
|
||
dialog->show();
|
||
setDialogEnable(false);
|
||
}
|
||
|
||
|
||
bool ParticipantsMoveDialog::getUnitPosition(int32_t participantId, Core::GeoPosition &unitPositionOut)
|
||
{
|
||
// flt
|
||
std::shared_ptr<FilterManagement::ForeignFltParticipantGuiInterface> fltParticipantIfc;
|
||
m_session->getForeignGuiInterface<FilterManagement::ForeignFltParticipantGuiInterface>(fltParticipantIfc); // not in global
|
||
|
||
if (!fltParticipantIfc)
|
||
return false;
|
||
|
||
int operatorId = LtsSessionData::LtsSessionData::getInstance()->getOperatorId();
|
||
QString workspaceId = m_session->workspaceId();
|
||
|
||
std::shared_ptr<FilterManagement::SymbolAppearanceSettings> symbolAppearanceSettings =
|
||
fltParticipantIfc->symbolAppearanceForOperator(operatorId, workspaceId);
|
||
|
||
FilterManagement::SymbolAppearanceSettings::Settings settings =
|
||
symbolAppearanceSettings->settings();
|
||
|
||
FilterManagement::SymbolAppearanceSettings::UnitSymbolPosition usp =
|
||
settings.symbolSettings.unitSymbolPosition;
|
||
|
||
ParticipantManagement::UnitPosition up = m_ppmDtc->unitPosition(participantId);
|
||
if (up.participantId() != participantId)
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << ", unitPosition failed for participantId=" << participantId;
|
||
return false;
|
||
}
|
||
|
||
switch (usp)
|
||
{
|
||
case FilterManagement::SymbolAppearanceSettings::UnitSymbolPosition::Center:
|
||
unitPositionOut = up.positionCenter();
|
||
return true;
|
||
break;
|
||
case FilterManagement::SymbolAppearanceSettings::UnitSymbolPosition::Leader:
|
||
unitPositionOut = up.positionLeader();
|
||
return true;
|
||
break;
|
||
} // switch
|
||
|
||
return false;
|
||
}
|
||
|
||
void ParticipantsMoveDialog::doSetSimulatedPositionRequest(const ParticipantManagement::ParticipantData &participantData, const QPointF &coordinate)
|
||
{
|
||
// single participant or unit should be move to _one_ origin:
|
||
const int participantId = participantData.id();
|
||
if (participantId <= 0) // sanity
|
||
return;
|
||
|
||
ParticipantManagement::SetSimulatedPosition req;
|
||
bool bAll = m_ui->cbAll->isChecked();
|
||
bool bAskOutdated = true;
|
||
if (bAll)
|
||
req.participantId(-1);
|
||
else
|
||
{
|
||
const ParticipantManagement::TypeClass tc = m_ppmDtc->type(participantData.typeId()).typeClass();
|
||
|
||
DEBUG_LOG(m_logger) << "ParticipantId=" << participantData.id()
|
||
<< " EquipmentNr=" << participantData.equipmentNumber()
|
||
<< " onGetCoordinate x=" << coordinate.x() << " y=" << coordinate.y()
|
||
<< ", tc=" << tc;
|
||
if (participantData.id() <= 0)
|
||
return;
|
||
req.participantId(participantData.id());
|
||
|
||
bAskOutdated = m_ppmDtc->type(participantData.typeId()).typeClass() == ParticipantManagement::TypeClass_def::Unit;
|
||
}
|
||
|
||
bool bOnlyOutdated = false;
|
||
if (bAskOutdated)
|
||
{
|
||
QHash<LtsWidgets::Button, QString> texts({{LtsWidgets::Button::Yes, tr("All")},
|
||
{LtsWidgets::Button::No, tr("Only outdated")}
|
||
});
|
||
auto b = LtsWidgets::LtsMessageDialog::showMessage(this,
|
||
tr("Do you want to move all participants or only outdated ones?"),
|
||
windowTitle(),
|
||
LtsWidgets::Behaviour::Modal,
|
||
LtsWidgets::Button::Yes | LtsWidgets::Button::No,
|
||
texts);
|
||
if (b == LtsWidgets::Button::Cancel)
|
||
return;
|
||
|
||
bOnlyOutdated = (b == LtsWidgets::Button::No);
|
||
}
|
||
|
||
req.onlyOutdatedParticipants(bOnlyOutdated);
|
||
req.position(Core::GeoPosition(coordinate.x(), coordinate.y(), 0.0));
|
||
|
||
m_requestHelper->startSingleRequest([req, this]()
|
||
{
|
||
return m_ppmFtc->setSimulatedPositionRequest(req, this);
|
||
});
|
||
}
|
||
|
||
|
||
void ParticipantsMoveDialog::doSetSimulatedPositionRelativeRequest(const ParticipantManagement::ParticipantData &participantData, const QPointF &coordinate)
|
||
{
|
||
// Unit is selected and should be moved relative to it´s current origin:
|
||
const int participantId = participantData.id();
|
||
if (participantId <= 0) //sanity
|
||
return;
|
||
|
||
Core::GeoPosition unitPositionOut;
|
||
if (!getUnitPosition(participantId, unitPositionOut))
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << ", getUnitPosition failed for participantId=" << participantId;
|
||
return;
|
||
}
|
||
|
||
INFO_LOG(m_logger) << LOGFUNCTION << ", getUnitPosition for participantId=" << participantId
|
||
<< ", unitPositionOut: lon=" << unitPositionOut.lon() << " - lat=" << unitPositionOut.lat();
|
||
|
||
LtsCoordTrans::UtmCoordinate curUnitPosUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(unitPositionOut.lon(), unitPositionOut.lat());
|
||
LtsCoordTrans::UtmCoordinate desiredUnitPosUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(coordinate);
|
||
QPointF offset = desiredUnitPosUtm.relativeTo(curUnitPosUtm);
|
||
|
||
if (offset.isNull())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << ", required offset is zero. not expected... return";
|
||
return;
|
||
}
|
||
|
||
ParticipantManagement::SetSimulatedPositionRelative req;
|
||
req.participantId(participantId);
|
||
req.positionOffsetX(offset.x());
|
||
req.positionOffsetY(offset.y());
|
||
|
||
DEBUG_LOG(m_logger) << "SetSimulatedPositionRelative = " << req;
|
||
|
||
m_requestHelper->startSingleRequest([req, this]()
|
||
{
|
||
return m_ppmFtc->setSimulatedPositionRelativeRequest(req, this);
|
||
});
|
||
}
|
||
|
||
void ParticipantsMoveDialog::doSetSimulatedParticipantFormationRequest(const ParticipantManagement::ParticipantData &participantData, const QPointF &coordinate, const QString &formationData)
|
||
{
|
||
// Unit is selected and should be moved relative to it´s current origin:
|
||
const int participantId = participantData.id();
|
||
if (participantId <= 0) //sanity
|
||
return;
|
||
|
||
Core::GeoPosition unitPositionOut;
|
||
if (!getUnitPosition(participantId, unitPositionOut))
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << ", getUnitPosition failed for participantId=" << participantId;
|
||
return;
|
||
}
|
||
|
||
INFO_LOG(m_logger) << LOGFUNCTION << ", getUnitPosition for participantId=" << participantId
|
||
<< ", unitPositionOut: lon=" << unitPositionOut.lon() << " - lat=" << unitPositionOut.lat();
|
||
|
||
LtsCoordTrans::UtmCoordinate curUnitPosUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(unitPositionOut.lon(), unitPositionOut.lat());
|
||
LtsCoordTrans::UtmCoordinate desiredUnitPosUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(coordinate);
|
||
const QPointF offset = desiredUnitPosUtm.relativeTo(curUnitPosUtm);
|
||
|
||
if (offset.isNull())
|
||
{
|
||
ERROR_LOG(m_logger) << LOGFUNCTION << ", required offset is zero. not expected... return";
|
||
return;
|
||
}
|
||
|
||
ParticipantManagement::SetSimulatedParticipantFormation req;
|
||
req.participantId(participantId);
|
||
req.position(Core::GeoPosition(coordinate.x(), coordinate.y(), 0.0));
|
||
req.positionOffsetX(offset.x());
|
||
req.positionOffsetY(offset.y());
|
||
req.formation(formationData.toStdString());
|
||
|
||
m_requestHelper->startSingleRequest([req, this]()
|
||
{
|
||
return m_ppmFtc->setSimulatedParticipantFormationRequest(req, this);
|
||
});
|
||
}
|
||
|
||
|
||
ParticipantManagement::ParticipantData ParticipantsMoveDialog::participantFromIndex(const QModelIndex &idx) const
|
||
{
|
||
return m_participantModel->getParticipantData(idx);
|
||
}
|
||
|
||
} // namespace CentralEffectSimulation
|