Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
+829
@@ -0,0 +1,829 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Dialog to edit drone Simulation
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Steve Kemayou, ESZS, 2025-04-08
|
||||
*/
|
||||
|
||||
#include <LtsWidgets/lts_message_dialog.h>
|
||||
#include <Common/LtsCoordTrans/lts_coord_widget.h>
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
#include <ParticipantManagement/ppm_data_plugin_interface.h>
|
||||
|
||||
#include <Plugins/CentralEffectSimulation/ces_data_plugin_interface.h>
|
||||
#include <Plugins/ProjectDataManagement/pdm_gui_plugin_interface.h>
|
||||
#include <PluginInterfaces/gui_plugin_interface.h>
|
||||
|
||||
#include <ParticipantManagement/ppm_translation.h>
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
#include <ProjectDataManagement/pdm_translation.h>
|
||||
#include <ProjectDataManagement/pdm_to_string.h>
|
||||
#include <FileManagement/flm_translation.h>
|
||||
|
||||
#include <LtsSession/lts_session_data.h>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QTimer>
|
||||
#include "mission_plan_edit.h"
|
||||
#include "ui_mission_plan_edit.h"
|
||||
|
||||
namespace CentralEffectSimulation
|
||||
{
|
||||
//static constexpr double s_msConversion = 3.6; // = 3.6 Convert from [km/h] to [m/s]
|
||||
//static constexpr int s_timeMilliConversion = 1000; // 1000 Convert from [s] to [ms]
|
||||
|
||||
MissionPlanEdit::MissionPlanEdit(QWidget *parent)
|
||||
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel)
|
||||
, m_missionPlanId(0)
|
||||
, m_uiEnabled(false)
|
||||
, m_sitMapGuiIfc(nullptr)
|
||||
, m_ppmCbxGui(nullptr)
|
||||
, m_requestHelper(new LtsUtils::RequestHelper(this))
|
||||
, m_participantTimer(new QTimer(this))
|
||||
, m_logger(getLogger("MissionPlanEdit"))
|
||||
, m_ui(new Ui::MissionPlanEdit)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
m_ui->nameLineEdit->clear();
|
||||
m_ui->lePrefix->setText(tr("Waypoint"));
|
||||
m_uiRequirements->addRequirement({m_ui->lblMoveStart, [this]() { return hasValidEffectStart(m_ui->dteStartTime); }, tr("Begin time is smaller than current time")});
|
||||
m_uiRequirements->addRequirement({m_ui->lblUASParty, [this]() {return ( !m_ui->cbParty->currentData().isNull());}});
|
||||
m_uiRequirements->addRequirement({m_ui->lblUasParticipant, [this]() {return ( !m_ui->participantCBox->currentData().isNull());}});
|
||||
|
||||
if (!QGuiApplication::keyboardModifiers().testFlag(Qt::ControlModifier))
|
||||
{
|
||||
m_uiRequirements->addRequirement({m_ui->lblParticipantStateText, [this]() { return m_participantReady; }});
|
||||
}
|
||||
|
||||
connect(this, &MissionPlanEdit::signalFocused, this, &MissionPlanEdit::onFocus);
|
||||
m_participantTimer->setSingleShot(true);
|
||||
m_participantTimer->setInterval(500);
|
||||
|
||||
connect(m_participantTimer, &QTimer::timeout, this, &MissionPlanEdit::onParticipantTimerTimedout);
|
||||
|
||||
setOnlineHelpFilename(QStringLiteral("Situation-UAS-Mission-Edit"));
|
||||
}
|
||||
|
||||
MissionPlanEdit::~MissionPlanEdit()
|
||||
{
|
||||
m_sitMapGuiIfc = nullptr;
|
||||
delete m_ui;
|
||||
emit editUasDialogClosed(m_participantData.id());
|
||||
}
|
||||
|
||||
bool MissionPlanEdit::init(const int missionPlanId, LtsSession::LtsSessionDataDds *session, bool asCopy)
|
||||
{
|
||||
m_session = session;
|
||||
m_missionPlanId = missionPlanId;
|
||||
|
||||
if (!m_session->getDtc<ProjectDataManagement::DataInterface>(m_pdmDtc))
|
||||
{
|
||||
ERROR_LOG(m_logger) << " failed to get pdmDtc";
|
||||
return false;
|
||||
}
|
||||
if (!m_session->getDtc<ParticipantManagement::DataInterface>(m_ppmDtc))
|
||||
{
|
||||
ERROR_LOG(m_logger) << " failed to get ppmDtc";
|
||||
return false;
|
||||
}
|
||||
if (!m_session->getFtc<ParticipantManagement::DataInterface>(m_ppmFtc))
|
||||
{
|
||||
ERROR_LOG(m_logger) << " failed to get ppmFtc";
|
||||
return false;
|
||||
}
|
||||
if (!m_session->getForeignGuiInterface<ParticipantManagement::ForeignGuiComboboxInterface>(m_ppmCbxGui))
|
||||
{
|
||||
ERROR_LOG(m_logger) << " failed to get ppmCbxGui";
|
||||
return false;
|
||||
}
|
||||
// Hide Unused Buttons for now
|
||||
m_ui->cbJumpToStart->hide();
|
||||
m_ui->cbRepeat->hide();
|
||||
//m_ui->chargesCBox->hide();
|
||||
//m_ui->chargesLabel->hide();
|
||||
|
||||
m_session->getForeignGuiInterface<SituationMap::ForeignGuiInterface>(m_sitMapGuiIfc);
|
||||
m_buttonBox->setText(LtsWidgets::DialogButton::Edit, tr("Start Now"));
|
||||
m_buttonBox->setIcon(LtsWidgets::DialogButton::Edit, QIcon(QStringLiteral("icon:media-play.svg")));
|
||||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Edit, this, &MissionPlanEdit::onApplyNow);
|
||||
|
||||
m_missionPlan = m_ppmDtc->missionPlan(m_missionPlanId);
|
||||
auto cb = [this, asCopy](const ParticipantManagement::MissionPlan &mission)
|
||||
{
|
||||
//allow participant id of current mission to be displayed.
|
||||
//for other missions if mission start is in future, and not abortet uas participants will not be displayed in the combobox
|
||||
if ((((mission.participantId() == m_missionPlan.participantId()) && !asCopy ) || mission.participantId() <= 0)
|
||||
&& mission.missionStart() <= m_missionPlan.missionStart() && !mission.aborted())
|
||||
return;
|
||||
// if mission is completed or aborted uas participant should be available.
|
||||
if (static_cast<int>(mission.items().size()) == mission.itemsFulfilled() || mission.aborted())
|
||||
return;
|
||||
|
||||
m_usedUasSet.insert(mission.participantId());
|
||||
};
|
||||
m_ppmDtc->missionPlans(cb);
|
||||
|
||||
m_ppmDtc->waitForHistoricalDataParty(1000);
|
||||
m_ppmDtc->waitForHistoricalDataUAS(1000);
|
||||
m_ppmDtc->waitForHistoricalDataParticipant(1000);
|
||||
|
||||
|
||||
connect(m_ui->participantCBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int /*index*/)
|
||||
{
|
||||
setReady(false);
|
||||
const auto pId = m_ui->participantCBox->currentData().toInt();
|
||||
m_participant = m_ppmDtc->participant(pId);
|
||||
const auto dpd = m_ppmDtc->dynamicParticipantData(m_participant.id());
|
||||
DEBUG_LOG(m_logger) << "idx changed! pId: " << pId << ", m_participant.id(): " << m_participant.id() << ", dpd.participantId(): " << dpd.participantId();
|
||||
|
||||
if (dpd.participantId() < 1) // aka. no data for that uas yet, aka. not ready
|
||||
{
|
||||
ERROR_LOG(m_logger) << "no dynamic pdata yet for pId " << pId;
|
||||
setReady(false);
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "calling onDynamicParticipantDataChanged !";
|
||||
onDynamicParticipantDataChanged(dpd, DataModification::eAdded);
|
||||
});
|
||||
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::dynamicParticipantDataChanged,
|
||||
this, &MissionPlanEdit::onDynamicParticipantDataChanged);
|
||||
|
||||
|
||||
connect(m_ui->cbParty, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
this, &MissionPlanEdit::onPartyChanged);
|
||||
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::uASChanged,
|
||||
this, &MissionPlanEdit::onUasChanged);
|
||||
// set Party & UAS Participants Combobox
|
||||
fillParties();
|
||||
setUASCharges();
|
||||
|
||||
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::missionPlanChanged,
|
||||
this, &MissionPlanEdit::onMissionPlanChanged);
|
||||
|
||||
|
||||
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::participantChanged,
|
||||
this, &MissionPlanEdit::onParticipantChanged);
|
||||
if (m_sitMapGuiIfc)
|
||||
{
|
||||
connect(m_ui->pbPosition, &QPushButton::clicked, this, &MissionPlanEdit::onGetPolyline);
|
||||
connect(m_ui->pbClear, &QPushButton::clicked, this, &MissionPlanEdit::clearCoordinates);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ui->pbPosition->setEnabled(false);
|
||||
m_ui->pbClear->setEnabled(false);
|
||||
}
|
||||
|
||||
// use missionplan data as default if exist
|
||||
setData(missionPlanId);
|
||||
|
||||
enaDisa();
|
||||
|
||||
if(m_participant.id() <= 0 )
|
||||
setReady(false);
|
||||
|
||||
if (m_missionPlanId > 0 && m_session->partitionTime() > m_missionPlan.missionStart() && !asCopy)
|
||||
{
|
||||
enableUiElements(false);
|
||||
m_buttonBox->getButton(LtsWidgets::DialogButton::Edit)->setEnabled(false);
|
||||
m_buttonBox->getButton(LtsWidgets::DialogButton::Ok)->setEnabled(false);
|
||||
m_buttonBox->getButton(LtsWidgets::DialogButton::Apply)->setEnabled(false);
|
||||
}
|
||||
|
||||
if (asCopy)
|
||||
{
|
||||
m_missionPlanId = 0; // mark the edit dialog as new, which makes it a create dialog
|
||||
// if the UAS from the copy already is in used we need to reset to default again
|
||||
if (m_ui->participantCBox->currentIndex()<0)
|
||||
m_ui->participantCBox->setCurrentIndex(0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MissionPlanEdit::retranslate()
|
||||
{
|
||||
translate(m_ui, ((m_missionPlanId <= 0) ? QString() : QString::fromStdString(m_missionPlan.name())), m_missionPlanId <= 0, tr("UAS-Waypoints"));
|
||||
}
|
||||
|
||||
|
||||
void MissionPlanEdit::setReady(bool isReady)
|
||||
{
|
||||
m_participantReady = isReady;
|
||||
m_ui->lblParticipantState->setText(QStringLiteral("<span style=\"color:#%1;\">%2</span>")
|
||||
.arg(isReady ? QStringLiteral("00dd00") : QStringLiteral("dd0000"))
|
||||
.arg(isReady ? tr("Ready") : tr("Not ready")));
|
||||
}
|
||||
|
||||
// stolen from Lts/Plugins/ParticipantManagement/Gui/ParticipantInfo/participant_info_dialog.cpp
|
||||
void MissionPlanEdit::onDynamicParticipantDataChanged(const ParticipantManagement::DynamicParticipantData &data, DataModification modType)
|
||||
{
|
||||
if (data.participantId() != m_participant.id() && data.participantId() != 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "### " << data.participantId() << " != " << m_participant.id() << " (" << (int)modType << ")";
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "### " << data.participantId() << " == " << m_participant.id() << " (" << (int)modType << ") !!!";
|
||||
|
||||
// Do not continue on modType == DataModification::eRemove
|
||||
// otherwise for example the icon would look bad (clover with black on black...)
|
||||
if (modType == DataModification::eRemoved)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//Current State
|
||||
if (data.stateHistory().empty())
|
||||
{
|
||||
setReady(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &history = data.stateHistory();
|
||||
|
||||
//LasState is the last "real" state, that has a VBG <=8 (Castastrophic)
|
||||
//It's not the last state received, as there can be other state changes like Sanitation, or NearMiss
|
||||
auto lastState = m_ppmDtc->youngestStateInformation(history/*, true*/ /* debug */);
|
||||
decltype(lastState) youngestState;
|
||||
youngestState.stateTime(0);
|
||||
for (const auto &si : history)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "StateInformation "
|
||||
<< " time=" << si.stateTime()
|
||||
<< " vulnerabilityBits=" << si.vulnerabilityBits()
|
||||
<< " vulnerabilityKindId=" << si.vulnerabilityKindId();
|
||||
if ( youngestState.stateTime() < si.stateTime())
|
||||
youngestState = si;
|
||||
}
|
||||
|
||||
setReady(youngestState.vulnerabilityState() == ProjectDataManagement::VulnerabilityState::CombatReady);
|
||||
}
|
||||
|
||||
void MissionPlanEdit::onMissionPlanChanged(const ParticipantManagement::MissionPlan &data, const DataModification modType)
|
||||
{
|
||||
Q_UNUSED(modType)
|
||||
if (data.id() != m_missionPlanId)
|
||||
{
|
||||
// Check, if mission is completed
|
||||
if (static_cast<int>(data.items().size()) != data.itemsFulfilled())
|
||||
return;
|
||||
if (m_usedUasSet.contains(data.participantId()))
|
||||
{
|
||||
m_usedUasSet.remove(data.participantId());
|
||||
fillParticipants();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
bool enabled;
|
||||
if (m_session->partitionTime() > m_missionPlan.missionStart() && !m_missionPlan.aborted())
|
||||
enabled = false;
|
||||
else
|
||||
enabled = true;
|
||||
|
||||
enableUiElements(enabled);
|
||||
m_buttonBox->getButton(LtsWidgets::DialogButton::Edit)->setEnabled(enabled);
|
||||
m_buttonBox->getButton(LtsWidgets::DialogButton::Ok)->setEnabled(enabled);
|
||||
m_buttonBox->getButton(LtsWidgets::DialogButton::Apply)->setEnabled(enabled);
|
||||
|
||||
if (static_cast<int>(data.items().size()) == data.itemsFulfilled()
|
||||
&& m_usedUasSet.remove(data.participantId()))
|
||||
fillParticipants();
|
||||
|
||||
}
|
||||
|
||||
void MissionPlanEdit::onModifyMissionPlanReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
m_requestHelper->requestReply(replyObject);
|
||||
if (!replyObject.error())
|
||||
m_sitMapGuiIfc->removePreviewObject();
|
||||
}
|
||||
|
||||
void MissionPlanEdit::onSetMissionActionFulfilledReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
DEBUG_LOG(m_logger)<<" -- MissionPlanEdit - onSetMissionActionFulfilledReply: "<<replyObject.error();
|
||||
}
|
||||
|
||||
QStringList MissionPlanEdit::tableColLabelList() const
|
||||
{
|
||||
QStringList wayPointsHeaders;
|
||||
wayPointsHeaders << tr("Identifier")
|
||||
<< tr("Position")
|
||||
<< tr("Altitude")
|
||||
<< tr("Idle Time [s]")
|
||||
<< tr("Charges");
|
||||
return wayPointsHeaders;
|
||||
}
|
||||
|
||||
void MissionPlanEdit::setAllUiElementsEnabled(bool enable)
|
||||
{
|
||||
enableUiElements(enable);
|
||||
}
|
||||
|
||||
ParticipantManagement::MissionPlan MissionPlanEdit::missionPlan() const
|
||||
{
|
||||
return m_missionPlan;
|
||||
}
|
||||
|
||||
bool MissionPlanEdit::isUiEnabled() const
|
||||
{
|
||||
return m_uiEnabled;
|
||||
}
|
||||
void MissionPlanEdit::enaDisa()
|
||||
{
|
||||
m_buttonBox->getButton(LtsWidgets::DialogButton::Edit)->setEnabled((m_ui->tableWidget->rowCount() > 0));
|
||||
m_buttonBox->getButton(LtsWidgets::DialogButton::Ok)->setEnabled((m_ui->tableWidget->rowCount() > 0));
|
||||
}
|
||||
|
||||
bool MissionPlanEdit::apply()
|
||||
{
|
||||
// check uas switched to manual mode before proceeding
|
||||
ParticipantManagement::UAS uasP = m_ppmDtc->getUasByParticipantId(m_ui->participantCBox->currentData().toInt(), m_session->exerciseId());
|
||||
|
||||
if (uasP.uasState() == ProjectDataManagement::UasState_def::Manual
|
||||
&& uasP.participantId() != m_missionPlan.participantId())
|
||||
{
|
||||
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Waypoints can't be saved!: Uas switched to %1-Mode").arg(ProjectDataManagement::toString(uasP.uasState())));
|
||||
return false;
|
||||
}
|
||||
ParticipantManagement::ModifyMissionPlanRequest req;
|
||||
req.id(m_missionPlanId);
|
||||
req.missionStart(m_ui->dteStartTime->msecsSinceEpoch());
|
||||
req.participantId(m_ui->participantCBox->currentData().toInt());
|
||||
req.jumpToStart(false);
|
||||
req.repeat(false);
|
||||
req.name(m_ui->nameLineEdit->text().toStdString());
|
||||
req.items(itemsRequestContent());
|
||||
|
||||
return m_requestHelper->startSingleRequest([this, req]()
|
||||
{
|
||||
return m_ppmFtc->modifyMissionPlanRequest(req, this);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
void MissionPlanEdit::clearCoordinates()
|
||||
{
|
||||
if (m_ui)
|
||||
{
|
||||
m_ui->tableWidget->clearContents();
|
||||
m_ui->tableWidget->setRowCount(0);
|
||||
enaDisa();
|
||||
}
|
||||
// remove PreviewObject:
|
||||
if ( m_sitMapGuiIfc && this->amIFocused())
|
||||
m_sitMapGuiIfc->removePreviewObject();
|
||||
}
|
||||
|
||||
void MissionPlanEdit::clearContent()
|
||||
{
|
||||
m_ui->lePrefix->clear();
|
||||
m_ui->cbRepeat->setChecked(false);
|
||||
//m_ui->cbJump->setChecked(false);
|
||||
|
||||
clearCoordinates();
|
||||
}
|
||||
|
||||
void MissionPlanEdit::enableUiElements(bool enable)
|
||||
{
|
||||
m_ui->tableWidget->setEnabled(enable);
|
||||
m_ui->pbPosition->setEnabled(enable);
|
||||
m_ui->pbClear->setEnabled(enable);
|
||||
m_ui->spIdleTime->setEnabled(enable);
|
||||
m_ui->dteStartTime->setEnabled(enable);
|
||||
m_ui->cbParty->setEnabled(enable);
|
||||
m_ui->participantCBox->setEnabled(enable);
|
||||
m_ui->chargesCBox->setEnabled(enable);
|
||||
m_ui->nameLineEdit->setEnabled(enable);
|
||||
m_ui->lePrefix->setEnabled(enable);
|
||||
m_ui->cbRepeat->setEnabled(enable);
|
||||
m_ui->cbJumpToStart->setEnabled(enable);
|
||||
m_ui->spAltitude->setEnabled(false);
|
||||
m_uiEnabled = enable;
|
||||
|
||||
|
||||
m_buttonBox->getButton(LtsWidgets::DialogButton::Edit)->setEnabled((m_ui->tableWidget->rowCount() > 0 && !enable)); // in case edit is blocked by user
|
||||
m_buttonBox->getButton(LtsWidgets::DialogButton::Ok)->setEnabled((m_ui->tableWidget->rowCount() > 0 && !enable)); // in case edit is blocked by user
|
||||
}
|
||||
|
||||
bool MissionPlanEdit::hasValidEffectStart(LtsWidgets::LtsDateTimeEdit *dte) const
|
||||
{ // if there is visible a enabled/disable checkbox -> also allow 0 as effect start
|
||||
const bool bEmptyAllowed = dte->isCheckable();
|
||||
const auto ms = dte->msecsSinceEpoch();
|
||||
// no effect start -> ok
|
||||
if (bEmptyAllowed && ms == 0)
|
||||
return true;
|
||||
return ms > m_session->partitionTime();
|
||||
}
|
||||
|
||||
void MissionPlanEdit::initTableHeader()
|
||||
{
|
||||
m_ui->tableWidget->setColumnCount(tableColLabelList().count());
|
||||
m_ui->tableWidget->setHorizontalHeaderLabels(tableColLabelList());
|
||||
m_ui->tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
|
||||
}
|
||||
|
||||
void MissionPlanEdit::insertPos(const WayPointParam &wpp)
|
||||
{
|
||||
const int rowCount = m_ui->tableWidget->rowCount();
|
||||
// insert waypoint label
|
||||
m_ui->tableWidget->insertRow(rowCount);
|
||||
QLineEdit *le = new QLineEdit;
|
||||
le->setText(wpp.identifier);
|
||||
m_ui->tableWidget->setCellWidget(rowCount, Name, le);
|
||||
|
||||
//insert Coordinates
|
||||
LtsCoordWidget::LtsCoordWidget *wdg = new LtsCoordWidget::LtsCoordWidget();
|
||||
wdg->setCoordinate(wpp.lon, wpp.lat);
|
||||
wdg->setObjectName(QStringLiteral("positionEdit_") + QString::number(rowCount));
|
||||
wdg->setDisplayType(LtsCoordWidget::LtsCoordWidget::DisplayType::MGRS);
|
||||
m_ui->tableWidget->setCellWidget(rowCount, Position, wdg);
|
||||
|
||||
// insert Altitude [m]
|
||||
QSpinBox *sbAltitude = new QSpinBox;
|
||||
sbAltitude->setMinimum(0);
|
||||
sbAltitude->setMaximum(120);
|
||||
sbAltitude->setValue(wpp.z);
|
||||
m_ui->tableWidget->setCellWidget(rowCount, Altitude, sbAltitude);
|
||||
|
||||
// insert Idle Time [sec]
|
||||
QSpinBox *sbDelay = new QSpinBox;
|
||||
sbDelay->setMinimum(m_ui->spIdleTime->minimum());
|
||||
sbDelay->setMaximum(m_ui->spIdleTime->maximum());
|
||||
sbDelay->setValue(wpp.idleTime);
|
||||
m_ui->tableWidget->setCellWidget(rowCount, IdleTime, sbDelay);
|
||||
|
||||
// insert charges
|
||||
QComboBox *ccbox = new QComboBox;
|
||||
|
||||
ccbox->insertItem(m_ui->chargesCBox->count(), tr("Undefined"));
|
||||
for(const auto &c : m_uasCharges.toStdMap())
|
||||
{
|
||||
ccbox->addItem(c.second, c.first);
|
||||
}
|
||||
int idx = ccbox->findData(QVariant::fromValue(wpp.chargeTypeId));
|
||||
ccbox->setCurrentIndex(idx > 0 ? idx : 0 );
|
||||
m_ui->tableWidget->setCellWidget(rowCount, Charges, ccbox);
|
||||
}
|
||||
|
||||
void MissionPlanEdit::showPreview(bool show)
|
||||
{
|
||||
if (m_sitMapGuiIfc)
|
||||
{
|
||||
if (show)
|
||||
m_sitMapGuiIfc->displayPreviewObject(this, m_polyline, false);
|
||||
else
|
||||
m_sitMapGuiIfc->removePreviewObject();
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<ParticipantManagement::MissionItem> MissionPlanEdit::itemsRequestContent()
|
||||
{
|
||||
const int missionItemCount = m_ui->tableWidget->rowCount();
|
||||
std::vector<ParticipantManagement::MissionItem> missionItems;
|
||||
using ParticipantManagement::MissionActionType;
|
||||
|
||||
const QVector<MissionActionType> actiontypes{
|
||||
MissionActionType::MoveTo, MissionActionType::Loiter, MissionActionType::Attack}; // first action always MoveTo
|
||||
int itemNumber = 0;
|
||||
for (int i = 0; i < missionItemCount; i++)
|
||||
{
|
||||
ParticipantManagement::MissionItem msi;
|
||||
QWidget *nameWidget = m_ui->tableWidget->cellWidget(i, Name);
|
||||
const QString name = static_cast<QLineEdit *>(nameWidget)->text();
|
||||
|
||||
QWidget *altitudeWidget = m_ui->tableWidget->cellWidget(i, Altitude);
|
||||
const int altitude = static_cast<QSpinBox *>(altitudeWidget)->value();
|
||||
|
||||
QWidget *posWidget = m_ui->tableWidget->cellWidget(i, Position);
|
||||
const QPointF point = static_cast<LtsCoordWidget::LtsCoordWidget *>(posWidget)->coordinate();
|
||||
Core::GeoPosition geoPos(point.x(), point.y(), altitude);
|
||||
|
||||
|
||||
QWidget *idleTimeWidget = m_ui->tableWidget->cellWidget(i, IdleTime);
|
||||
const int idleTime = static_cast<QSpinBox *>(idleTimeWidget)->value();
|
||||
|
||||
QWidget *chargesWidget = m_ui->tableWidget->cellWidget(i, Charges);
|
||||
const int chargeTypeId = static_cast<QComboBox *>(chargesWidget)->currentData().toInt();
|
||||
|
||||
// phase 1 // moveTo
|
||||
// phase 2 // idleTime move
|
||||
// phase 3 // attack
|
||||
|
||||
const QString &msiName = name;
|
||||
int actionNumber = 0;
|
||||
const QString &msaName = QStringLiteral("%1_%2").arg(m_ui->nameLineEdit->text()).arg(name);
|
||||
|
||||
{
|
||||
ParticipantManagement::MissionAction actionMoveTo;
|
||||
actionMoveTo.actionType(ParticipantManagement::MissionActionType::MoveTo);
|
||||
actionMoveTo.duration(0); // not define hier
|
||||
actionMoveTo.actionNumber(actionNumber++);
|
||||
actionMoveTo.name(msaName.toStdString());
|
||||
actionMoveTo.itemNumber(itemNumber);
|
||||
actionMoveTo.planId(m_missionPlan.id());
|
||||
|
||||
QJsonObject jsoMoveTo;
|
||||
jsoMoveTo.insert(QStringLiteral("location_x"), point.x());
|
||||
jsoMoveTo.insert(QStringLiteral("location_y"), point.y());
|
||||
jsoMoveTo.insert(QStringLiteral("location_z"), altitude); //
|
||||
const QString props = QString::fromUtf8(QJsonDocument(jsoMoveTo).toJson(QJsonDocument::Compact));
|
||||
actionMoveTo.properties(props.toStdString());
|
||||
msi.actions().push_back(actionMoveTo);
|
||||
}
|
||||
|
||||
|
||||
if (idleTime > 0)
|
||||
{
|
||||
ParticipantManagement::MissionAction actionLoiter;
|
||||
actionLoiter.actionType(ParticipantManagement::MissionActionType::Loiter);
|
||||
actionLoiter.duration(idleTime); // idleTime
|
||||
actionLoiter.actionNumber(actionNumber++);
|
||||
actionLoiter.itemNumber(itemNumber);
|
||||
actionLoiter.name(msaName.toStdString());
|
||||
actionLoiter.planId(m_missionPlan.id());
|
||||
msi.actions().push_back(actionLoiter);
|
||||
}
|
||||
|
||||
|
||||
if (chargeTypeId > 0)
|
||||
{
|
||||
ParticipantManagement::MissionAction actionAttack;
|
||||
actionAttack.actionType(ParticipantManagement::MissionActionType::Attack);
|
||||
actionAttack.duration(idleTime); // idleTime
|
||||
actionAttack.actionNumber(actionNumber++);
|
||||
actionAttack.itemNumber(itemNumber);
|
||||
actionAttack.name(msaName.toStdString());
|
||||
actionAttack.planId(m_missionPlan.id());
|
||||
|
||||
QJsonObject jsoAttack;
|
||||
jsoAttack.insert(QStringLiteral("location_x"), point.x());
|
||||
jsoAttack.insert(QStringLiteral("location_y"), point.y());
|
||||
jsoAttack.insert(QStringLiteral("location_z"), 0); //
|
||||
jsoAttack.insert(QStringLiteral("chargeTypeId"), chargeTypeId); // chargeTypeID
|
||||
const QString props = QString::fromUtf8(QJsonDocument(jsoAttack).toJson(QJsonDocument::Compact));
|
||||
actionAttack.properties(props.toStdString());
|
||||
|
||||
msi.actions().push_back(actionAttack);
|
||||
}
|
||||
|
||||
|
||||
msi.itemNumber(itemNumber++);
|
||||
msi.location(geoPos);
|
||||
msi.name(msiName.toStdString());
|
||||
missionItems.push_back(msi);
|
||||
|
||||
}
|
||||
|
||||
return missionItems;
|
||||
}
|
||||
|
||||
void MissionPlanEdit::setUASCharges()
|
||||
{
|
||||
const auto chargesForGearClass = m_pdmDtc->chargeTypes();
|
||||
m_ui->chargesCBox->clear();
|
||||
m_ui->chargesCBox->insertItem(m_ui->chargesCBox->count(), tr("Undefined"));
|
||||
for (const ProjectDataManagement::ChargeType &chargeType : qAsConst(chargesForGearClass))
|
||||
{
|
||||
// NOTE: igniterType/IgniterFunciton = 0 as long as MissionPlan does not contain values
|
||||
if (!m_pdmDtc->isUasDroppable(chargeType.id(),0,0))
|
||||
continue;
|
||||
DEBUG_LOG(m_logger) << " fillCharges"
|
||||
<< ", id=" << chargeType.id()
|
||||
<< ", name= " << chargeType.name();
|
||||
|
||||
m_ui->chargesCBox->addItem(QString::fromStdString(chargeType.name()), chargeType.id());
|
||||
m_uasCharges.insert(chargeType.id(), QString::fromStdString(chargeType.name()));
|
||||
}
|
||||
m_ui->chargesCBox->setCurrentIndex(0);
|
||||
}
|
||||
|
||||
void MissionPlanEdit::setData(int mpId)
|
||||
{
|
||||
initTableHeader();
|
||||
|
||||
if (mpId < 0 )
|
||||
return;
|
||||
|
||||
m_missionPlan = m_ppmDtc->missionPlan(mpId);
|
||||
m_participantData = m_ppmDtc->participant(m_missionPlan.participantId());
|
||||
m_ui->dteStartTime->setMinimumTimeMSec(m_session->partitionTime());
|
||||
m_ui->dteStartTime->setRetrieveCurrentTimeCallback([this](){return m_session->partitionTime();});
|
||||
m_ui->dteStartTime->setMsecsSinceEpoch(m_missionPlan.missionStart());
|
||||
m_ui->nameLineEdit->setText(QString::fromStdString(m_missionPlan.name()));
|
||||
|
||||
// get/set current party
|
||||
if (m_participantData.partyId() > 0)
|
||||
{
|
||||
const int partyIdx = m_ui->cbParty->findData(QVariant::fromValue(m_participantData.partyId()));
|
||||
m_ui->cbParty->setCurrentIndex(partyIdx);
|
||||
|
||||
const int ppIdx = m_ui->participantCBox->findData(QVariant::fromValue(m_missionPlan.participantId()));
|
||||
m_ui->participantCBox->setCurrentIndex(ppIdx);
|
||||
}
|
||||
|
||||
for (const auto &item : qAsConst(m_missionPlan.items()) )
|
||||
{
|
||||
const std::vector<ParticipantManagement::MissionAction> &msaVec = item.actions();
|
||||
WayPointParam wpp;
|
||||
wpp.identifier = QString::fromStdString(item.name());
|
||||
wpp.lat = item.location().lat();
|
||||
wpp.lon = item.location().lon();
|
||||
wpp.z = item.location().z();
|
||||
for (auto const &msa : msaVec)
|
||||
{
|
||||
if (msa.actionType() == ParticipantManagement::MissionActionType::Loiter)
|
||||
wpp.idleTime = msa.duration();
|
||||
|
||||
if (msa.actionType() == ParticipantManagement::MissionActionType::Attack)
|
||||
{
|
||||
const QJsonObject &obj = QJsonDocument::fromJson(QByteArray::fromStdString(msa.properties())).object();
|
||||
wpp.chargeTypeId = obj.value(QLatin1String("chargeTypeId")).toInt();
|
||||
}
|
||||
}
|
||||
|
||||
insertPos(wpp);
|
||||
}
|
||||
|
||||
//
|
||||
m_buttonBox->getButton(LtsWidgets::DialogButton::Edit)->setEnabled((m_ui->tableWidget->rowCount() > 0));
|
||||
|
||||
}
|
||||
|
||||
void MissionPlanEdit::fillParties()
|
||||
{
|
||||
m_ppmCbxGui->fillPartyComboBox(m_ui->cbParty);
|
||||
m_ui->cbParty->setCurrentIndex(0);
|
||||
fillParticipants();
|
||||
}
|
||||
|
||||
void MissionPlanEdit::fillParticipants()
|
||||
{
|
||||
QVector<ParticipantManagement::Participant> participants;
|
||||
const int partyId = m_ui->cbParty->currentData().toInt();
|
||||
gatherUASParticipants(partyId, participants);
|
||||
|
||||
m_ui->participantCBox->clear();
|
||||
for (const auto &participant : participants)
|
||||
{
|
||||
QString uasString = QStringLiteral("%1 (%2)").arg(m_ppmDtc->hierarchyFromParticipant(participant.id()));
|
||||
if (uasString.isEmpty() || m_usedUasSet.contains(participant.id()))
|
||||
continue;
|
||||
const ParticipantManagement::UAS &uasP = m_ppmDtc->getUasByParticipantId(participant.id(), m_session->exerciseId());
|
||||
uasString = uasString.arg(ProjectDataManagement::toString(uasP.uasState()));
|
||||
m_ui->participantCBox->addItem(uasString, participant.id());
|
||||
}
|
||||
if (m_missionPlan.id() > 0)
|
||||
m_ui->participantCBox->setCurrentIndex(m_ui->participantCBox->findData(QVariant::fromValue(m_missionPlan.participantId())));
|
||||
//Fallback to first entry
|
||||
if (m_ui->participantCBox->currentIndex()<0)
|
||||
m_ui->participantCBox->setCurrentIndex(0);
|
||||
|
||||
}
|
||||
|
||||
void MissionPlanEdit::gatherUASParticipants(int partyId, QVector<ParticipantManagement::Participant> &participant)
|
||||
{
|
||||
auto cb = [this, &partyId, &participant](const ParticipantManagement::Participant &p)
|
||||
{
|
||||
if (p.isDeleted() || p.partyId() != partyId)
|
||||
return;
|
||||
const ParticipantManagement::ParticipantData &ppData = m_ppmDtc->convertParticipantToParticipantData(p);
|
||||
const ParticipantManagement::Type &&ppType = m_ppmDtc->type(ppData.typeId());
|
||||
const QJsonObject typeProperties(QJsonDocument::fromJson(QByteArray::fromStdString(ppType.properties())).object());
|
||||
if (typeProperties.isEmpty()
|
||||
|| ppType.typeClass() != ParticipantManagement::TypeClass::Aircraft
|
||||
|| !typeProperties[QStringLiteral("isUAS")].toBool(false))
|
||||
return;
|
||||
|
||||
participant.push_back(p);
|
||||
};
|
||||
m_ppmDtc->participants(cb);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief ParticipantUASEdit::onParticipantTimerTimedout
|
||||
* method is called when an participant is updated. Note that onParticipantTimerTimedout()
|
||||
* will be called by once even if many onParticipantChanged signal come in.
|
||||
*/
|
||||
void MissionPlanEdit::onParticipantTimerTimedout()
|
||||
{
|
||||
fillParticipants();
|
||||
}
|
||||
|
||||
void MissionPlanEdit::onParticipantChanged(const ParticipantManagement::Participant &data, DataModification modType)
|
||||
{
|
||||
Q_UNUSED(data)
|
||||
Q_UNUSED(modType)
|
||||
|
||||
m_participantTimer->start();
|
||||
}
|
||||
|
||||
void MissionPlanEdit::onPartyChanged()
|
||||
{
|
||||
m_ui->participantCBox->clear();
|
||||
fillParticipants();
|
||||
}
|
||||
|
||||
void MissionPlanEdit::onGetPolyline()
|
||||
{
|
||||
if (!m_sitMapGuiIfc)
|
||||
return;
|
||||
|
||||
if (m_sitMapGuiIfc->mapMode() != SituationMap::MapMode::MapMode_2D)
|
||||
{
|
||||
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Only available in 2D mode"));
|
||||
return;
|
||||
}
|
||||
|
||||
QPolygonF coordinates;
|
||||
int i = 0;
|
||||
while (true)
|
||||
{
|
||||
LtsCoordWidget::LtsCoordWidget *w = findChild<LtsCoordWidget::LtsCoordWidget *>(QStringLiteral("positionEdit_%1").arg(i));
|
||||
if (!w)
|
||||
break;
|
||||
if (!w->coordinate().isNull())
|
||||
coordinates << w->coordinate();
|
||||
++i;
|
||||
}
|
||||
|
||||
m_sitMapGuiIfc->getPolyline(this,
|
||||
SLOT(onPolylineData(QPolygonF)),
|
||||
nullptr,
|
||||
2,
|
||||
11,
|
||||
-1,
|
||||
-1,
|
||||
coordinates);
|
||||
}
|
||||
|
||||
void MissionPlanEdit::onPolylineData(const QPolygonF &polyline)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " numberOfPoints: " << polyline.size();
|
||||
|
||||
if (polyline.size() < 2)
|
||||
return;
|
||||
|
||||
m_polyline = polyline;
|
||||
|
||||
clearCoordinates();
|
||||
|
||||
for (int i = 0; i < polyline.size(); i++)
|
||||
{
|
||||
WayPointParam wp;
|
||||
wp.lon = polyline.at(i).x();
|
||||
wp.lat = polyline.at(i).y();
|
||||
wp.identifier = m_ui->lePrefix->text() + QLatin1Char('_') + QString::number(i + 1);
|
||||
wp.z = m_ui->spAltitude->value();
|
||||
wp.idleTime = m_ui->spIdleTime->value();
|
||||
wp.chargeTypeId = m_ui->chargesCBox->currentIndex();
|
||||
insertPos(wp);
|
||||
}
|
||||
|
||||
// create PreviewObject:
|
||||
m_sitMapGuiIfc->displayPreviewObject(this, polyline, false);
|
||||
enaDisa();
|
||||
|
||||
}
|
||||
|
||||
void MissionPlanEdit::onFocus()
|
||||
{
|
||||
showPreview(true);
|
||||
m_sitMapGuiIfc->displayPreviewObject(this, m_polyline, false);
|
||||
}
|
||||
|
||||
void MissionPlanEdit::onApplyNow()
|
||||
{
|
||||
QDateTime dateTime = QDateTime::fromMSecsSinceEpoch(m_session->partitionTime());
|
||||
m_ui->dteStartTime->setMsecsSinceEpoch(dateTime.addSecs(10).toMSecsSinceEpoch()); //set time first THEN check for requirements
|
||||
if (m_ui->tableWidget->rowCount() < 2 || !m_uiRequirements->checkRequirements())
|
||||
return;
|
||||
if (apply())
|
||||
{
|
||||
enableUiElements(false);
|
||||
m_buttonBox->getButton(LtsWidgets::DialogButton::Edit)->setEnabled(false);
|
||||
m_buttonBox->getButton(LtsWidgets::DialogButton::Ok)->setEnabled(false);
|
||||
m_buttonBox->getButton(LtsWidgets::DialogButton::Apply)->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void MissionPlanEdit::onUasChanged(const ParticipantManagement::UAS &uas)
|
||||
{
|
||||
Q_UNUSED(uas)
|
||||
const int ppId = m_ui->participantCBox->currentData().toInt();
|
||||
fillParticipants();
|
||||
|
||||
const int index = m_ui->participantCBox->findData(ppId);
|
||||
if( index < 0)
|
||||
return;
|
||||
m_ui->participantCBox->setCurrentIndex(index);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}// namspace CentralEffectSimulation
|
||||
Reference in new issue
Block a user