Files
qt5-legatus-legacy/Lts/Plugins/AreaEffectSimulation/Gui/BCContamination/aes_bccontamination_edit.cpp
T
2026-08-13 18:33:10 +02:00

398 lines
15 KiB
C++
Executable File

/**
* @RDE_HEADER@
* AreaEffectSimulation - Contamination Edit Dialog
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-07-07
*/
#include "aes_bccontamination_edit.h"
#include "ui_aes_bccontamination_edit.h"
#include "../AesInfo/aes_danger_area_aes_item_info.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>
#include <Services/AreaEffectSimulation/Utils/polygons.h>
namespace AreaEffectSimulation
{
double BCContaminationEdit::s_minRadius;
double BCContaminationEdit::s_maxRadius;
double BCContaminationEdit::s_stepRadius;
int BCContaminationEdit::s_minDurationHours;
int BCContaminationEdit::s_maxDurationHours;
double BCContaminationEdit::s_minAltitude;
double BCContaminationEdit::s_maxAltitude;
static int s_lastChargeTypeB = 0;
static int s_lastChargeTypeC = 0;
// Todo: Höhe und Radius in Abhängigkeit der Munitionsart berechnen
BCContaminationEdit::BCContaminationEdit(const QString &menuGroup, bool isChemical, QWidget *parent)
: BaseEdit(menuGroup, QLatin1String("BCContaminationEdit"), parent)
, m_isChemical(isChemical)
, m_ui(new Ui::BCContaminationEdit)
{
m_ui->setupUi(this);
s_minRadius = 50;
s_maxRadius = 2500;
s_stepRadius = 5;
s_minDurationHours = 1;
s_maxDurationHours = 4;
s_minAltitude = 2;
s_maxAltitude = 50;
m_ui->sbRadius->setMinimum(s_minRadius);
m_ui->sbRadius->setMaximum(s_maxRadius);
m_ui->sbRadius->setSingleStep(s_stepRadius);
m_ui->sbDurationHours->setMinimum(s_minDurationHours);
m_ui->sbDurationHours->setMaximum(s_maxDurationHours);
m_ui->sbAltitude->setMinimum(s_minAltitude);
m_ui->sbAltitude->setMaximum(s_maxAltitude);
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->pbDangerArea, &QPushButton::clicked, this, &BCContaminationEdit::onPbDangerAreaClicked);
connect(m_ui->pbClear, &QPushButton::clicked, m_ui->positionEdit, &LtsCoordWidget::LtsCoordWidget::clear);
connect(m_ui->sbRadius, &QSpinBox::editingFinished, this, &BCContaminationEdit::correctSpinBoxValue);
// [GUEZE-2833] Inkonsistenz - Wetter Einstellungen bei A und C Feldern
// Order changed AwsDynamic = 0, AwsStatic = 1,
m_ui->cbWeather->addItem(toString(AesWeatherSource::AwsDynamic), AesWeatherSource::AwsDynamic);
m_ui->cbWeather->addItem(toString(AesWeatherSource::AwsStatic), AesWeatherSource::AwsStatic);
LtsUtils::ProjectSettings *ps = LtsUtils::ProjectSettings::getInstance();
const bool enableShowMeteoDataStations = ps->value(QStringLiteral("mdm"),
QStringLiteral("enableShowMeteoDataStations")).toBool();
if (!enableShowMeteoDataStations)
{
m_ui->cbWeather->hide();
m_ui->lblWeather->hide();
// cbWeather per default auf AesWeatherSource::AwsStatic
}
m_ui->lblAltitude->show();
m_ui->sbAltitude->show();
// Not yet needed, as no step is defined:
// connect(m_ui->sbAltitude, &QSpinBox::editingFinished, this, &BCContaminationEdit::correctSpinBoxValue);
// connect(m_ui->sbDurationMinutes, &QSpinBox::editingFinished, this, &BCContaminationEdit::correctSpinBoxValue);
// party is (currently) not user-visible
// m_ui->lblParty->setVisible(false);
// m_ui->cbParty->setVisible(false);
enaDisa();
if (m_isChemical)
setOnlineHelpFilename(QStringLiteral("Situation-Add_C-Contamination"));
else
setOnlineHelpFilename(QStringLiteral("Situation-Add_B-Contamination"));
}
BCContaminationEdit::~BCContaminationEdit()
{
delete m_ui;
}
void BCContaminationEdit::retranslate()
{
translate(m_ui, m_aesItem, m_isChemical ? tr("C-Contamination") : tr("B-Contamination"));
if (m_isChemical)
m_pdmGuiIfc->fillCComboBox(m_ui->cbChargeType);
else
m_pdmGuiIfc->fillBComboBox(m_ui->cbChargeType);
setCombobxToValueIfPossible(m_ui->cbChargeType, m_isChemical ? s_lastChargeTypeC : s_lastChargeTypeB);
}
void BCContaminationEdit::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->sbAltitude->setEnabled(enable);
m_ui->cbLowerLimit->setEnabled(enable);
m_ui->sbRadius->setEnabled(enable);
m_ui->leIdentifier->setEnabled(enable || isOnlyNameModifiable());
m_ui->cbWeather->setEnabled(enable);
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->bCContamination(m_aesItem.id());
setData(baseData, false);
__unchange__();
if (name != m_ui->leIdentifier->text())
m_ui->leIdentifier->setText(name);
}
}
bool BCContaminationEdit::init(int aesItemId, bool copy,
LtsSession::LtsSession *session)
{
if (!BaseEdit::init(aesItemId, session))
return false;
bool editable = (LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::CContaminationsEdit) && m_isChemical) ||
(LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::BContaminationsEdit) && !m_isChemical) ||
m_session->app() == LtsAppDescriptor::App::OC;
bool readable = (LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::CContaminationsShow) && m_isChemical) ||
(LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::BContaminationsShow) && !m_isChemical) ;
setPbDangerAreaText();
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, &BCContaminationEdit::getPosition);
else
m_ui->pbPosition->setEnabled(false);
if (m_isChemical)
m_pdmGuiIfc->fillCComboBox(m_ui->cbChargeType);
else
m_pdmGuiIfc->fillBComboBox(m_ui->cbChargeType);
m_ppmGuiCbxIfc->fillPartyComboBox(m_ui->cbParty);
if (aesItemId > 0)
{
auto baseData = m_dtc->bCContamination(aesItemId);
setData(baseData, copy);
}
auto cb = [this](const DangerAreaCorrelatedAesItem &item)
{
if (item.aesItemId() == m_aesItem.id())
m_dangerAreaIds << item.dangerAreaId();
};
m_dtc->dangerAreaCorrelatedAesItems(cb);
setPbDangerAreaText();
enableUiElements(editable && isModifiable() && !isOnlyNameModifiable());
connect(m_dtc.get(), &AreaEffectSimulation::Interface::Dtc::dangerAreaCorrelatedAesItemChanged,
this, &BCContaminationEdit::onDangerAreaChanged);
connect(m_dtc.get(), &AreaEffectSimulation::Interface::Dtc::bCContaminationChanged,
this, &BaseEdit::onAreaChanged);
auto cbDangerArea = [this](const DangerArea &data)
{
if (data.effectStateId() != AesEffectState::EsRemoved && data.associatedAesId() == m_aesItem.id())
m_associatedDangerId = data.id();
};
m_dtc->dangerAreas(cbDangerArea);
if (m_associatedDangerId)
{
m_ui->chbDangerArea->setChecked(true);
m_ui->chbDangerArea->setEnabled(false);
}
return true;
}
void BCContaminationEdit::setPbDangerAreaText()
{
QStringList sl;
sl.reserve(m_dangerAreaIds.size());
for (int idx : qAsConst(m_dangerAreaIds))
{
sl << QString::fromStdString(m_dtc->dangerArea(idx).name());
}
m_ui->pbDangerArea->setEnabled(sl.size());
m_ui->pbDangerArea->setText(sl.join(QStringLiteral(", ")));
}
void BCContaminationEdit::onDangerAreaChanged(const DangerAreaCorrelatedAesItem &data, DataModification modType)
{
if (data.aesItemId() != m_aesItem.id())
return;
if (modType == DataModification::eAdded)
m_dangerAreaIds += data.dangerAreaId();
if (modType == DataModification::eRemoved)
m_dangerAreaIds -= data.dangerAreaId();
// Note: Modification cannot happen as the key is unique for the combination.
setPbDangerAreaText();
}
void BCContaminationEdit::onPbDangerAreaClicked()
{
if (m_dangerAreaIds.isEmpty())
return;
std::shared_ptr<ForeignInfoGuiInterface> infoGuiInterface;
if (!m_session->getForeignGuiInterface<ForeignInfoGuiInterface>(infoGuiInterface))
return;
LtsWidgets::LtsDialog *dialog = infoGuiInterface->showDangerAreaAesItemInfo(m_dangerAreaIds, {m_aesItem.id()});
addDialog(dialog, m_menuGroup, tr("Danger Areas for %1 %2").arg(m_isChemical ? tr("C-Contamination") : tr("B-Contamination"), m_ui->leIdentifier->text()), LtsWidgets::LayoutArea::eInfoTab);
}
void BCContaminationEdit::setData(const BCContamination &contamination, bool copy)
{
m_aesItem = contamination;
if (copy)
{
m_aesItem.id(0);
m_aesItem.effectStateId(AreaEffectSimulation::AesEffectState_def::get_default());
}
m_ui->leIdentifier->setText(QString::fromStdString(contamination.name()));
m_ui->dteEffectStart->setMsecsSinceEpoch(contamination.effectStart().is_set() ? contamination.effectStart().get() : 0);
m_ui->cbChargeType->setCurrentIndex(m_ui->cbChargeType->findData(contamination.chargeStruct().chargeTypeId())); // not user-visible
m_ui->sbDurationHours->setValue(contamination.effectDuration() / 1000 / 60/ 60); // msecs -> mins -> hours
m_ui->sbRadius->setValue(contamination.impactRadius());
m_ui->cbParty->setCurrentIndex(m_ui->cbParty->findData(contamination.partyId().is_set() ? contamination.partyId().get() : 0));
m_ui->cbWeather->setCurrentIndex(contamination.weatherSource().underlying());
QPointF impactPosition(contamination.impactPosition().lon(), contamination.impactPosition().lat());
if (!impactPosition.isNull())
m_ui->positionEdit->setCoordinate(impactPosition);
m_ui->sbAltitude->setValue(contamination.upperOffset());
m_ui->cbLowerLimit->setChecked(qFuzzyIsNull(contamination.lowerOffset()));
}
void BCContaminationEdit::getPosition()
{
if (!has2DMap())
return;
m_sitMapGuiIfc->getCircle(this,
SLOT(onCircleData(QPointF, double)),
nullptr,
s_minRadius,
s_maxRadius,
m_ui->positionEdit->coordinate(),
m_ui->sbRadius->value()); //max
}
void BCContaminationEdit::onCircleData(const QPointF &position, double radius)
{
m_previewCircleCenter = position;
// SB corrects value acc. singleStep
m_ui->sbRadius->setValue(radius);
m_previewCircleRadius = m_ui->sbRadius->value();
m_ui->positionEdit->setCoordinate(position);
DEBUG_LOG(m_logger) << "Pos X: " << position.x() << " Y: " << position.y() << " R: " << radius;
showPreviewObject();
}
bool BCContaminationEdit::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();
if (m_isChemical)
s_lastChargeTypeC = chargeType;
else
s_lastChargeTypeB = chargeType;
int partyId = m_ui->cbParty->currentData().toInt();
int participantId = 0;
int radius = m_ui->sbRadius->value();
int weathersource = m_ui->cbWeather->currentData().toInt();
double extrusionHeight = m_ui->sbAltitude->value();
double lowerOffset = 0.0;
if (!m_ui->cbLowerLimit->isChecked())
lowerOffset = -1000.0;
QPointF p(m_ui->positionEdit->coordinate());
const Core::GeoPosition2D pos(p.x(), p.y());
const BCContaminationModifyRequest req(m_aesItem.id(),
name,
LtsUtils::toOptional(effectStart),
duration,
chargeType,
pos,
radius,
static_cast<AesWeatherSource::inner_enum>(weathersource),
LtsUtils::toOptional(partyId),
LtsUtils::toOptional(participantId),
dds::core::optional<double>(),
dds::core::optional<double>(),
dds::core::optional<Core::GeoPosition2D>(),
dds::core::optional<rti::core::int64>(),
dds::core::optional<rti::core::int64>(),
extrusionHeight,
lowerOffset,
m_ui->chbDangerArea->isChecked());
INFO_LOG(m_logger) << "apply "
<< " extrusionHeight=" << extrusionHeight
<< " req.upperOffset=" << req.upperOffset()
<< " lowerOf"
"fset=" << lowerOffset
<< " req.lowerOffset=" << req.lowerOffset();
m_requestHelper->addRequest([this,req]()
{
return m_ftc->bCContaminationModifyRequest(req, this);
});
bool ret= m_requestHelper->startRequests();
if (m_ui->chbDangerArea->isChecked() && ret)
m_ui->chbDangerArea->setEnabled(false);
return ret;
}
void BCContaminationEdit::showPreviewObject()
{
if (!m_sitMapGuiIfc)
return;
if (m_previewCircleCenter.isNull())
return;
m_sitMapGuiIfc->displayPreviewObject(this, m_previewCircleCenter, m_previewCircleRadius);
}
} // namespace AreaEffectSimulation