483 lines
18 KiB
C++
Executable File
483 lines
18 KiB
C++
Executable File
/**
|
|
* @RDE_HEADER@
|
|
* AreaEffectSimulation - Mine Single Virtual Edit Dialog
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
* Created by Hanna E. Rathje, SLSE, 2023-07-14
|
|
*/
|
|
|
|
|
|
#include "aes_booby_trap_edit.h"
|
|
#include "ui_aes_booby_trap_edit.h"
|
|
|
|
#include <LtsWidgets/lts_message_dialog.h>
|
|
#include <LtsSession/lts_session_data.h>
|
|
#include <PluginInterfaces/gui_plugin_interface.h>
|
|
#include <Plugins/AreaEffectSimulation/aes_data_plugin_interface.h>
|
|
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
|
|
#include <Plugins/AreaEffectSimulation/aes_info_gui_plugin_interface.h>
|
|
|
|
#include <AreaEffectSimulation/aes_translation.h>
|
|
#include <LtsUtilsSettings/settings.h>
|
|
|
|
namespace AreaEffectSimulation
|
|
{
|
|
double BoobyTrapEdit::s_minTriggerRadius;
|
|
double BoobyTrapEdit::s_maxTriggerRadius;
|
|
double BoobyTrapEdit::s_defaultTriggerRadius;
|
|
double BoobyTrapEdit::s_minImpactRadius;
|
|
double BoobyTrapEdit::s_maxImpactRadius;
|
|
double BoobyTrapEdit::s_defaultImpactRadius;
|
|
double BoobyTrapEdit::s_stepRadius;
|
|
int BoobyTrapEdit::s_minDurationHours;
|
|
int BoobyTrapEdit::s_maxDurationHours;
|
|
int BoobyTrapEdit::s_defaultCentralAngle;
|
|
static int s_lastChargeTypeBoobyTrap = 251;
|
|
static int s_boobyTrap2 = 252;
|
|
|
|
// Todo: Höhe und Radius in Abhängigkeit der Munitionsart berechnen
|
|
|
|
BoobyTrapEdit::BoobyTrapEdit(const QString &menuGroup, QWidget *parent)
|
|
: BaseEdit(menuGroup, QLatin1String("BoobyTrapEdit"), parent)
|
|
, m_ui(new Ui::BoobyTrapEdit)
|
|
{
|
|
m_ui->setupUi(this);
|
|
|
|
s_minTriggerRadius = 5;
|
|
s_maxTriggerRadius = 5;
|
|
s_defaultTriggerRadius = 5;
|
|
s_minImpactRadius = 10;
|
|
s_maxImpactRadius = 10;
|
|
s_defaultImpactRadius = 10;
|
|
s_stepRadius = 1;
|
|
s_minDurationHours = 1;
|
|
s_maxDurationHours = 4;
|
|
s_defaultCentralAngle = 90;
|
|
|
|
m_ui->sbTriggerRadius->setMinimum(s_minTriggerRadius);
|
|
m_ui->sbTriggerRadius->setMaximum(s_maxTriggerRadius);
|
|
m_ui->sbTriggerRadius->setSingleStep(s_stepRadius);
|
|
m_ui->sbTriggerRadius->setValue(s_defaultTriggerRadius);
|
|
|
|
m_ui->sbImpactRadius->setMinimum(s_minImpactRadius);
|
|
m_ui->sbImpactRadius->setMaximum(s_maxImpactRadius);
|
|
m_ui->sbImpactRadius->setSingleStep(s_stepRadius);
|
|
m_ui->sbImpactRadius->setValue(s_defaultImpactRadius);
|
|
|
|
#if GUEZ_MODE
|
|
m_ui->sbCentralAngle->setMaximum(90.0);
|
|
#endif
|
|
m_ui->sbCentralAngle->setValue(s_defaultCentralAngle);
|
|
|
|
m_ui->sbDurationHours->setMinimum(s_minDurationHours);
|
|
m_ui->sbDurationHours->setMaximum(s_maxDurationHours);
|
|
m_ui->rotationAngleEdit->initAngleEditWidget(1); // need to be done to create spinboxes.
|
|
|
|
#ifndef LTS_DEBUG
|
|
m_ui->lblTriggerRadius->setHidden(true);
|
|
m_ui->sbTriggerRadius->setHidden(true);
|
|
m_ui->lblImpactRadius->setHidden(true);
|
|
m_ui->sbImpactRadius->setHidden(true);
|
|
m_ui->sbCentralAngle->setHidden(true);
|
|
#endif
|
|
|
|
m_uiRequirements->addRequirement({m_ui->lblPosition, [this]() { return (!m_ui->positionEdit->coordinate().isNull()); }});
|
|
m_uiRequirements->addRequirement({m_ui->lblIdentifier, [this]() { return (!m_ui->leIdentifier->text().isEmpty()); }});
|
|
m_uiRequirements->addRequirement({m_ui->lblEffectStart, [this]() { return hasValidEffectStart(m_ui->dteEffectStart); }});
|
|
m_uiRequirements->addRequirement({m_ui->lblChargeType, [this]() { return (m_ui->cbChargeType->currentData().toInt() > 0); }});
|
|
|
|
connect(m_ui->pbClear, &QPushButton::clicked, m_ui->positionEdit, &LtsCoordWidget::LtsCoordWidget::clear);
|
|
|
|
//connect(m_ui->sbTriggerRadius, &QSpinBox::editingFinished, this, &BoobyTrapEdit::correctSpinBoxValue);
|
|
connect(m_ui->sbImpactRadius, &QSpinBox::editingFinished, this, &BoobyTrapEdit::correctSpinBoxValue);
|
|
|
|
|
|
// Not yet needed, as no step is defined:
|
|
// connect(m_ui->sbAltitude, &QSpinBox::editingFinished, this, &BoobyTrapEdit::correctSpinBoxValue);
|
|
// connect(m_ui->sbDurationMinutes, &QSpinBox::editingFinished, this, &BoobyTrapEdit::correctSpinBoxValue);
|
|
|
|
enaDisa();
|
|
|
|
setOnlineHelpFilename(QStringLiteral("Situation-Add_Mine_VLad"));
|
|
}
|
|
|
|
BoobyTrapEdit::~BoobyTrapEdit()
|
|
{
|
|
delete m_ui;
|
|
}
|
|
|
|
void BoobyTrapEdit::retranslate()
|
|
{
|
|
translate(m_ui, m_aesItem, tr("BoobyTrap"));
|
|
|
|
m_pdmGuiIfc->fillBoobyTrapComboBox(m_ui->cbChargeType);
|
|
setCombobxToValueIfPossible(m_ui->cbChargeType, s_lastChargeTypeBoobyTrap );
|
|
}
|
|
|
|
void BoobyTrapEdit::enableUiElements(bool enable)
|
|
{
|
|
m_ui->leIdentifier->setMaxLength(30);
|
|
|
|
m_ui->cbChargeType->setEnabled(enable);
|
|
m_ui->sbDurationHours->setEnabled(enable);
|
|
m_ui->cbParty->setEnabled(enable);
|
|
setEffectStartEnabled(m_ui->dteEffectStart, enable);
|
|
|
|
m_ui->pbPosition->setEnabled(m_sitMapGuiIfc && enable);
|
|
m_ui->positionEdit->setEnabled(enable);
|
|
m_ui->rotationAngleEdit->setEnabled(enable);
|
|
m_ui->sbTriggerRadius->setEnabled(enable);
|
|
m_ui->sbImpactRadius->setEnabled(enable);
|
|
m_ui->leIdentifier->setEnabled(enable || isOnlyNameModifiable());
|
|
|
|
m_ui->pbClear->setEnabled(enable);
|
|
if (m_aesItem.effectStateId() == AesEffectState_def::EsExpired)
|
|
{
|
|
m_ui->leIdentifier->setText(QString::fromStdString(m_aesItem.name()));
|
|
__unchange__();
|
|
}
|
|
if (m_aesItem.effectStateId() == AesEffectState_def::EsActivated)
|
|
{
|
|
QString name = m_ui->leIdentifier->text();
|
|
auto baseData = m_dtc->boobyTrap(m_aesItem.id());
|
|
setData(baseData, false);
|
|
__unchange__();
|
|
if (name != m_ui->leIdentifier->text())
|
|
m_ui->leIdentifier->setText(name);
|
|
}
|
|
|
|
}
|
|
|
|
bool BoobyTrapEdit::init(int aesItemId, bool copy,
|
|
LtsSession::LtsSession *session)
|
|
{
|
|
if (!BaseEdit::init(aesItemId, session))
|
|
return false;
|
|
|
|
bool editable = (LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::MineSingleVirtualEdit)) ||
|
|
m_session->app() == LtsAppDescriptor::App::OC;
|
|
|
|
bool readable = (LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::MineSingleVirtualShow));
|
|
;
|
|
|
|
if (!readable && !editable)
|
|
return false;
|
|
|
|
// FIXME: in GUI plugin, nicht ausserhalb!
|
|
if (!m_session->getForeignGuiInterface<ProjectDataManagement::ForeignGuiInterface>(m_pdmGuiIfc))
|
|
return false;
|
|
|
|
m_ui->dteEffectStart->setMinimumTimeMSec(m_session->partitionTime());
|
|
m_ui->dteEffectStart->setRetrieveCurrentTimeCallback([this]() { return m_session->partitionTime(); });
|
|
|
|
if (m_sitMapGuiIfc)
|
|
connect(m_ui->pbPosition, &QPushButton::clicked, this, &BoobyTrapEdit::getPosition);
|
|
else
|
|
m_ui->pbPosition->setEnabled(false);
|
|
|
|
m_pdmGuiIfc->fillBoobyTrapComboBox(m_ui->cbChargeType);
|
|
m_ppmGuiCbxIfc->fillPartyComboBox(m_ui->cbParty);
|
|
|
|
connect(m_ui->cbChargeType,static_cast<void (LtsWidgets::LtsComboBox::*)(int)>(&LtsWidgets::LtsComboBox::currentIndexChanged),
|
|
this, &BoobyTrapEdit::onChargeTypeChanged);
|
|
|
|
if (aesItemId > 0)
|
|
{
|
|
auto baseData = m_dtc->boobyTrap(aesItemId);
|
|
setData(baseData, copy);
|
|
}
|
|
onChargeTypeChanged(0);
|
|
|
|
enableUiElements(editable && isModifiable() && !isOnlyNameModifiable());
|
|
|
|
connect(m_dtc.get(), &AreaEffectSimulation::Interface::Dtc::boobyTrapChanged,
|
|
this, &BaseEdit::onAreaChanged);
|
|
|
|
return true;
|
|
}
|
|
|
|
void BoobyTrapEdit::onChargeTypeChanged(int index)
|
|
{
|
|
Q_UNUSED(index);
|
|
|
|
int chargeType = m_ui->cbChargeType->currentData().toInt();
|
|
|
|
if ( chargeType != s_boobyTrap2)
|
|
{
|
|
m_ui->lblRotation->hide();
|
|
m_ui->rotationAngleEdit->hide();
|
|
m_ui->lblCentralAngle->hide();
|
|
m_ui->sbCentralAngle->hide();
|
|
}
|
|
else
|
|
{
|
|
m_ui->lblRotation->show();
|
|
m_ui->rotationAngleEdit->show();
|
|
#ifdef LTS_DEBUG
|
|
m_ui->lblCentralAngle->show();
|
|
m_ui->sbCentralAngle->show();
|
|
#else
|
|
m_ui->lblCentralAngle->hide();
|
|
m_ui->sbCentralAngle->hide();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
void BoobyTrapEdit::setData(const BoobyTrap &bt, bool copy)
|
|
{
|
|
m_aesItem = bt;
|
|
if (copy)
|
|
{
|
|
m_aesItem.id(0);
|
|
m_aesItem.effectStateId(AreaEffectSimulation::AesEffectState_def::get_default());
|
|
}
|
|
m_ui->leIdentifier->setText(QString::fromStdString(bt.name()));
|
|
m_ui->dteEffectStart->setMsecsSinceEpoch(bt.effectStart().is_set() ? bt.effectStart().get() : 0);
|
|
m_ui->cbChargeType->setCurrentIndex(m_ui->cbChargeType->findData(bt.chargeStruct().chargeTypeId()));
|
|
s_lastChargeTypeBoobyTrap = bt.chargeStruct().chargeTypeId();
|
|
m_ui->sbDurationHours->setValue(bt.effectDuration() / 1000 / 60/ 60); // msecs -> mins -> hours
|
|
m_ui->sbTriggerRadius->setValue(bt.triggerRadius());
|
|
m_ui->sbImpactRadius->setValue(bt.impactRadius());
|
|
|
|
if (bt.rotationAngle().is_set())
|
|
{
|
|
// assumed that angle is in degree else need to be converted first
|
|
m_ui->rotationAngleEdit->setValue(bt.rotationAngle().get(), LtsAngleEditBase::AngleUnitType::Deg);
|
|
}
|
|
|
|
if (bt.centralAngle().is_set())
|
|
m_ui->sbCentralAngle->setValue(bt.centralAngle().get());
|
|
|
|
m_ui->cbParty->setCurrentIndex(m_ui->cbParty->findData(bt.partyId().is_set() ? bt.partyId().get() : 0));
|
|
|
|
QPointF impactPosition(bt.impactPosition().lon(), bt.impactPosition().lat());
|
|
if (!impactPosition.isNull())
|
|
m_ui->positionEdit->setCoordinate(impactPosition);
|
|
}
|
|
|
|
void BoobyTrapEdit::getPosition()
|
|
{
|
|
if (!has2DMap())
|
|
return;
|
|
|
|
// convert angle in degree before displaying
|
|
const double &rotation = m_ui->rotationAngleEdit->getAngleConverted(m_ui->rotationAngleEdit->getAngle(),
|
|
LtsAngleEditBase::AngleUnitType::Deg,
|
|
m_ui->rotationAngleEdit->getAngleCurrentUnit());
|
|
const double &angle = m_ui->sbCentralAngle->value();
|
|
const int chargeType = m_ui->cbChargeType->currentData().toInt();
|
|
|
|
if (chargeType == s_boobyTrap2)
|
|
{
|
|
// sector:
|
|
|
|
double trigger = m_ui->sbTriggerRadius->value();
|
|
double triggerMin = s_minTriggerRadius;
|
|
double triggerMax = s_maxTriggerRadius;
|
|
// if all 3 are more or less equal, the screenresolution leads to problems at checkMinMaxRadiusConstraints
|
|
// so in that case skip tranfering to rubberband and let the user enter just one CircleSector:
|
|
const bool bTriggerRelevant = (!qFuzzyCompare(trigger, triggerMin) && !qFuzzyCompare(trigger, triggerMax)); // Maybe this has to be improved
|
|
|
|
double impact = m_ui->sbImpactRadius->value();
|
|
double impactMin = s_minImpactRadius;
|
|
double impactMax = s_maxImpactRadius;
|
|
const bool bImpactRelevant = (!qFuzzyCompare(impact, impactMin) && !qFuzzyCompare(impact, impactMax)); // Maybe this has to be improved
|
|
|
|
if (bTriggerRelevant && bImpactRelevant)
|
|
{
|
|
if (!m_sitMapGuiIfc->getTwoCircleSector(this,
|
|
SLOT(onTwoCircleSectorData(QPointF, double, double, double, double)),
|
|
nullptr,
|
|
m_ui->sbTriggerRadius->value(), s_minTriggerRadius, s_maxTriggerRadius,
|
|
m_ui->sbImpactRadius->value(), s_minImpactRadius, s_maxImpactRadius,
|
|
m_ui->positionEdit->coordinate(),
|
|
angle,
|
|
rotation)) //max
|
|
{
|
|
ERROR_LOG(m_logger) << LOGFUNCTION << " getTwoCircleSector failed, checkSlots??";
|
|
}
|
|
|
|
} else if (!bTriggerRelevant && bImpactRelevant)
|
|
{
|
|
// enter impactRadius
|
|
if (!m_sitMapGuiIfc->getCircleSector(this,
|
|
SLOT(onCircleSectorData(QPointF, double, double, double)),
|
|
nullptr,
|
|
m_ui->sbImpactRadius->value(), s_minImpactRadius, s_maxImpactRadius,
|
|
m_ui->positionEdit->coordinate(),
|
|
angle,
|
|
rotation)) //max
|
|
{
|
|
ERROR_LOG(m_logger) << LOGFUNCTION << " getCircleSector failed, checkSlots??";
|
|
}
|
|
|
|
} else if (!bTriggerRelevant && !bImpactRelevant)
|
|
{
|
|
if (!m_sitMapGuiIfc->getCircleSectorFixRadius(this,
|
|
SLOT(onCircleSectorFixRadiusData(QPointF, double, double, double)),
|
|
nullptr,
|
|
m_ui->sbImpactRadius->value(),
|
|
m_ui->positionEdit->coordinate(),
|
|
angle,
|
|
rotation))
|
|
{
|
|
ERROR_LOG(m_logger) << LOGFUNCTION << " getCircleSectorFixRadius failed, checkSlots??";
|
|
}
|
|
|
|
} else if (bTriggerRelevant && !bImpactRelevant)
|
|
{
|
|
ERROR_LOG(m_logger) << LOGFUNCTION << " not supported yet";
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// circle
|
|
if (!m_sitMapGuiIfc->getCircle(this,
|
|
SLOT(onCircleData(QPointF, double)),
|
|
nullptr,
|
|
s_minTriggerRadius,
|
|
s_maxTriggerRadius,
|
|
m_ui->positionEdit->coordinate(),
|
|
m_ui->sbTriggerRadius->value())) //max
|
|
{
|
|
ERROR_LOG(m_logger) << LOGFUNCTION << " getCircle failed, checkSlots??";
|
|
}
|
|
}
|
|
}
|
|
|
|
void BoobyTrapEdit::onCircleData(const QPointF &position, double radius)
|
|
{
|
|
m_previewCircleCenter = position;
|
|
|
|
// SB corrects value acc. singleStep
|
|
m_ui->sbTriggerRadius->setValue(radius);
|
|
m_previewCircleRadius = m_ui->sbTriggerRadius->value();
|
|
|
|
m_ui->positionEdit->setCoordinate(position);
|
|
DEBUG_LOG(m_logger) << "Pos X: " << position.x() << " Y: " << position.y() << " R: " << radius;
|
|
|
|
showPreviewObject();
|
|
}
|
|
|
|
void BoobyTrapEdit::onCircleSectorFixRadiusData(const QPointF &position, double radius, double rotationDeg, double centralAngleDeg)
|
|
{
|
|
// radius may modified, use original:
|
|
Q_UNUSED(radius);
|
|
onCircleSectorData(position, m_ui->sbImpactRadius->value(), rotationDeg, centralAngleDeg);
|
|
}
|
|
|
|
|
|
void BoobyTrapEdit::onCircleSectorData(const QPointF &position, double radius, double rotationDeg, double centralAngleDeg)
|
|
{
|
|
m_previewCircleCenter = position;
|
|
|
|
// SB corrects value acc. singleStep
|
|
if (radius > 0)
|
|
m_ui->sbImpactRadius->setValue(radius);
|
|
|
|
m_previewCircleRadius = m_ui->sbTriggerRadius->value();
|
|
m_previewRotationDeg = rotationDeg;
|
|
m_previewCentralAngleDeg = centralAngleDeg;
|
|
|
|
m_ui->positionEdit->setCoordinate(position);
|
|
m_ui->rotationAngleEdit->setValue(rotationDeg, LtsAngleEditBase::AngleUnitType::Deg);
|
|
m_ui->sbCentralAngle->setValue(std::ceil(centralAngleDeg));
|
|
DEBUG_LOG(m_logger) << "Pos X: " << position.x() << " Y: " << position.y()
|
|
<< ", R1: " << radius
|
|
<<", rotation[deg]:" << rotationDeg << ", angle[deg]:" << centralAngleDeg;
|
|
|
|
showPreviewObject();
|
|
}
|
|
|
|
void BoobyTrapEdit::onTwoCircleSectorData(const QPointF &position, double radius1, double radius2, double rotationDeg, double centralAngleDeg)
|
|
{
|
|
m_previewCircleCenter = position;
|
|
|
|
// SB corrects value acc. singleStep
|
|
if (radius1 > 0)
|
|
m_ui->sbTriggerRadius->setValue(radius1);
|
|
|
|
if (radius2 > 0)
|
|
m_ui->sbImpactRadius->setValue(radius2);
|
|
|
|
m_previewCircleRadius = m_ui->sbTriggerRadius->value();
|
|
m_previewRotationDeg = rotationDeg;
|
|
m_previewCentralAngleDeg = centralAngleDeg;
|
|
|
|
m_ui->positionEdit->setCoordinate(position);
|
|
m_ui->rotationAngleEdit->setValue(rotationDeg, LtsAngleEditBase::AngleUnitType::Deg);
|
|
m_ui->sbCentralAngle->setValue(std::ceil(centralAngleDeg));
|
|
DEBUG_LOG(m_logger) << "Pos X: " << position.x() << " Y: " << position.y()
|
|
<< ", R1: " << radius1 << " R2: " << radius2
|
|
<<", rotation[deg]:" << rotationDeg << ", angle[deg]:" << centralAngleDeg;
|
|
showPreviewObject();
|
|
}
|
|
|
|
bool BoobyTrapEdit::apply()
|
|
{
|
|
std::string name = m_ui->leIdentifier->text().toStdString();
|
|
qint64 effectStart = m_ui->dteEffectStart->msecsSinceEpoch();
|
|
int duration = m_ui->sbDurationHours->value() * 60 * 1000 * 60; //hours -> mins -> msecs
|
|
int chargeType = m_ui->cbChargeType->currentData().toInt();
|
|
s_lastChargeTypeBoobyTrap = chargeType;
|
|
int partyId = m_ui->cbParty->currentData().toInt();
|
|
int triggerRadius = m_ui->sbTriggerRadius->value();
|
|
int impactRadius = m_ui->sbImpactRadius->value();
|
|
|
|
QPointF p(m_ui->positionEdit->coordinate());
|
|
const Core::GeoPosition2D pos(p.x(), p.y());
|
|
|
|
BoobyTrapModifyRequest req(m_aesItem.id(),
|
|
name,
|
|
duration,
|
|
chargeType,
|
|
pos,
|
|
impactRadius,
|
|
triggerRadius,
|
|
dds::core::optional<double>(),
|
|
dds::core::optional<double>(),
|
|
LtsUtils::toOptional(effectStart),
|
|
LtsUtils::toOptional(partyId)
|
|
);
|
|
|
|
if (chargeType == s_boobyTrap2)
|
|
{
|
|
// the angle is sent in deg. Check if value is in degree
|
|
double rotValue = m_ui->rotationAngleEdit->getAngleConverted(m_ui->rotationAngleEdit->getAngle(),
|
|
LtsAngleEditBase::AngleUnitType::Deg,
|
|
m_ui->rotationAngleEdit->getAngleCurrentUnit());
|
|
req.rotationAngle().set(rotValue);
|
|
|
|
req.centralAngle().set(m_ui->sbCentralAngle->value());
|
|
}
|
|
|
|
m_requestHelper->addRequest([this,req]()
|
|
{
|
|
return m_ftc->boobyTrapModifyRequest(req, this);
|
|
});
|
|
|
|
return m_requestHelper->startRequests();
|
|
}
|
|
|
|
void BoobyTrapEdit::showPreviewObject()
|
|
{
|
|
if (!m_sitMapGuiIfc)
|
|
return;
|
|
|
|
if (m_previewCircleCenter.isNull())
|
|
return;
|
|
if (m_ui->cbChargeType->currentData().toInt() == s_boobyTrap2)
|
|
{
|
|
m_sitMapGuiIfc->displayPreviewObject(this, m_previewCircleCenter, m_previewCircleRadius, m_previewRotationDeg, m_previewCentralAngleDeg);
|
|
}
|
|
else
|
|
{
|
|
m_sitMapGuiIfc->displayPreviewObject(this, m_previewCircleCenter, m_previewCircleRadius);
|
|
}
|
|
}
|
|
|
|
} // namespace AreaEffectSimulation
|