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

358 lines
10 KiB
C++
Executable File

/**
* @RDE_HEADER@
* AreaEffectSimulation - Contamination Edit Dialog
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-07-07
*/
#include "aes_base_edit.h"
#include <Plugins/AreaEffectSimulation/aes_data_plugin_interface.h>
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_data_plugin_interface.h>
#include <Plugins/ExerciseManagement/exm_data_plugin_interface.h>
#include <PluginInterfaces/gui_plugin_interface.h>
#include <LtsWidgets/lts_date_time_edit.h>
#include <LtsCoordTrans/lts_coord_widget.h>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <QSpinBox>
#include <QJsonDocument>
namespace AreaEffectSimulation
{
BaseEdit::BaseEdit(const QString &menuGroup, const QString &loggerName, QWidget *parent, LtsWidgets::ButtonCombination buttonCombination)
: LtsWidgets::LtsDialog(parent, buttonCombination)
, m_aesItem()
, m_dtc(nullptr)
, m_ftc(nullptr)
, m_sitMapGuiIfc(nullptr)
, m_ppmGuiCbxIfc(nullptr)
, m_session(nullptr)
, m_menuGroup(menuGroup)
, m_requestHelper(new LtsUtils::RequestHelper(this))
, m_logger(getLogger(loggerName))
{
m_aesItem.id(0);
connect(this, &BaseEdit::visibilityChanged, this, &BaseEdit::onVisibilityChanged);
}
void BaseEdit::setCombobxToValueIfPossible(QComboBox *cbx, int val)
{
int idx = cbx->findData(val);
if (idx >= 0)
cbx->setCurrentIndex(idx);
}
void BaseEdit::onAesItemCreateReply(const Core::FunctionReplyObject &replyObject)
{
m_requestHelper->requestReply(replyObject);
if (!replyObject.error() && m_sitMapGuiIfc)
m_sitMapGuiIfc->removePreviewObject();
}
void BaseEdit::onAesItemModifyReply(const Core::FunctionReplyObject &replyObject)
{
m_requestHelper->requestReply(replyObject);
if (!replyObject.error() && m_sitMapGuiIfc )
m_sitMapGuiIfc->removePreviewObject();
}
bool BaseEdit::isModifiable() const
{
AesEffectState effectState = m_aesItem.effectStateId();
return (effectState == AreaEffectSimulation::AesEffectState_def::EsPaused ||
effectState == AreaEffectSimulation::AesEffectState_def::EsActivated ||
effectState == AreaEffectSimulation::AesEffectState_def::EsPrepared ||
effectState == AreaEffectSimulation::AesEffectState_def::EsCreated ||
effectState == AreaEffectSimulation::AesEffectState_def::EsUnknown ||
effectState == AreaEffectSimulation::AesEffectState_def::EsReceived) &&
(!m_session->isReplayPartition()) &&
(m_session->app() != LtsAppDescriptor::App::OC); // not OC-App
}
bool BaseEdit::isOnlyNameModifiable() const
{
AesEffectState effectState = m_aesItem.effectStateId();
return (effectState == AreaEffectSimulation::AesEffectState_def::EsPaused ||
effectState == AreaEffectSimulation::AesEffectState_def::EsActivated) &&
(!m_session->isReplayPartition()) &&
(m_session->app() != LtsAppDescriptor::App::OC); // not OC-App
}
void BaseEdit::correctSpinBoxValue()
{
QSpinBox *sb = qobject_cast<QSpinBox*>(sender());
if (sb)
return correctSpinBoxValueInternal(sb);
QDoubleSpinBox *dsb = qobject_cast<QDoubleSpinBox*>(sender());
if (dsb)
return correctSpinBoxValueInternal(dsb);
}
void BaseEdit::onVisibilityChanged(bool visible)
{
if (!m_sitMapGuiIfc)
return;
if (!visible)
m_sitMapGuiIfc->removePreviewObject();
else
showPreviewObject();
}
void BaseEdit::correctSpinBoxValueInternal(QSpinBox *sb)
{
if (!sb)
return;
int step = sb->singleStep();
if (step == 1)
return;
int value = sb->value();
int remainder = (value - sb->minimum()) % step;
if (remainder == 0)
return;
if (2 * remainder > step)
value += (step - remainder);
else
value -= remainder;
if (value > sb->maximum())
value -= step;
if(value < sb->minimum())
value = sb->minimum();
sb->setValue(value);
}
void BaseEdit::correctSpinBoxValueInternal(QDoubleSpinBox *sb)
{
if (!sb)
return;
double step = sb->singleStep();
if (qFuzzyCompare(step, pow(10, sb->decimals())))
return;
double value = sb->value();
double remainder = fmod(value - sb->minimum(), step);
if (qFuzzyCompare(remainder, 0))
return;
if (2 * remainder > step)
value += (step - remainder);
else
value -= remainder;
if (value > sb->maximum())
value -= step;
if (value < sb->minimum())
value = sb->minimum();
sb->setValue(value);
}
bool BaseEdit::hasValidEffectStart(LtsWidgets::LtsDateTimeEdit *dte) const
{
if (isOnlyNameModifiable())
return true;
// if there is visible a enabled/disable checkbox -> also allow 0 as effect start
if (dte->isCheckable() && !dte->isChecked())
return true;
const auto ms = dte->msecsSinceEpoch();
return ms > m_session->partitionTime();
}
void BaseEdit::setEffectStartEnabled(LtsWidgets::LtsDateTimeEdit *dte, bool enable)
{
if (enable)
{
int exerciseId = m_session->exerciseId();
std::shared_ptr<ExerciseManagement::Interface::Dtc> exmDtc;
m_session->getDtc<ExerciseManagement::DataInterface>(exmDtc);
ExerciseManagement::Exercise exercise = exmDtc->exercise(exerciseId);
// Enablen der gesamten Checkbox nur, wenn Übung läuft:
enable = (exercise.state() == ExerciseManagement::ExerciseState_def::Started ||
exercise.state() == ExerciseManagement::ExerciseState_def::Paused);
// In Übungsvorbereitung keine Eingabe einer Zeit möglich:
if (exercise.state() == ExerciseManagement::ExerciseState_def::Created)
dte->setChecked(false);
else // Ansonsten Status gemäß eingetragener Zeit.
dte->setChecked(dte->msecsSinceEpoch() > 0);
}
else // Ansonsten Status gemäß eingetragener Zeit.
dte->setChecked(dte->msecsSinceEpoch() > 0);
// Gesamtstatus übernehmen.
dte->setEnabled(enable);
}
bool BaseEdit::has2DMap(bool showMsgBoxIfNot2D)
{
if (!m_sitMapGuiIfc)
return false;
if (m_sitMapGuiIfc->mapMode() != SituationMap::MapMode::MapMode_2D)
{
if (showMsgBoxIfNot2D)
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Only available in 2D mode"));
return false;
}
return true;
}
void BaseEdit::setCoordinates(const QVector<QPointF> &coords, bool reverse)
{
// Reverse if Frontline is chosen and width is taken to the right (like drawing an L)
clearCoordinates();
const auto cWidgets(coordWidgets());
if (!reverse)
{
for (size_t i = 0; i < cWidgets.size() && i < static_cast<size_t>(coords.size()); ++i)
cWidgets.at(i)->setCoordinate(coords.at(i));
}
else
{
auto copy(coords);
std::reverse(std::begin(copy), std::end(copy));
for (size_t i = 0; i < cWidgets.size() && i < static_cast<size_t>(copy.size()); ++i)
cWidgets.at(i)->setCoordinate(copy.at(i));
}
}
void BaseEdit::setCoordinates(const std::vector<Core::GeoPosition2D> &coords)
{
clearCoordinates();
const auto cWidgets(coordWidgets());
for (size_t i = 0; i < cWidgets.size() && i < static_cast<size_t>(coords.size()); ++i)
cWidgets.at(i)->setCoordinate(coords.at(i).lon(), coords.at(i).lat());
}
std::vector<Core::GeoPosition2D> BaseEdit::getCoordinates() const
{
std::vector<Core::GeoPosition2D> segments;
const auto cWidgets(coordWidgets());
segments.reserve(cWidgets.size());
for (const auto cw : cWidgets)
{
const QPointF coord = cw->coordinate();
if (coord.isNull())
break;
segments.emplace_back(Core::GeoPosition2D(coord.x(), coord.y()));
}
return segments;
}
QVector<QPointF> BaseEdit::getCoordinatesQPointF() const
{
QVector<QPointF> segments;
const auto cWidgets(coordWidgets());
segments.reserve(cWidgets.size());
for (const auto *cw : cWidgets)
{
const QPointF coord = cw->coordinate();
if (coord.isNull())
break;
segments.push_back(coord);
}
return segments;
}
void BaseEdit::clearCoordinates()
{
for (auto *cw : coordWidgets())
cw->clear();
}
void BaseEdit::enabledCoordinates(bool enable)
{
for (auto *cw : coordWidgets())
cw->setEnabled(enable);
}
void BaseEdit::onAreaChanged(const AesItem &data, DataModification modType)
{
// No, we don't update the UI elements (yet). If we wanted to, we had to
// implement a virtual method such as enableUiElements...
if (data.id() != m_aesItem.id())
return;
if (modType == DataModification::eRemoved || data.effectStateId() == AesEffectState_def::EsRemoved)
{
// As a simple 'close()' does not work:
__unchange__();
closeRequest();
return;
}
m_aesItem = data;
enableUiElements(isModifiable() && !isOnlyNameModifiable());
}
bool BaseEdit::init(int aesItemId, LtsSession::LtsSession *session)
{
if (m_session)
{
ERROR_LOG(m_logger) << "double init()!";
return false;
}
m_session = session;
m_aesItem.id(aesItemId);
if (!m_session->getDtc<AreaEffectSimulation::DataInterface>(m_dtc))
return false;
if (!m_session->getFtc<AreaEffectSimulation::DataInterface>(m_ftc))
return false;
m_session->getForeignGuiInterface<SituationMap::ForeignGuiInterface>(m_sitMapGuiIfc);
if (!m_session->getForeignGuiInterface<ParticipantManagement::ForeignGuiComboboxInterface>(m_ppmGuiCbxIfc))
return false;
if (m_session->isReplayPartition() || (LtsAppDescriptor::App::OC == m_session->app()))
setUnchangeable();
if (aesItemId == 0)
{
m_aesItem.effectSourceId(ProjectDataManagement::EffectSource_def::ES_Internal);
m_buttonBox->setText(LtsWidgets::DialogButton::Ok, tr("Add"));
}
return true;
}
double BaseEdit::distance(const Core::GeoPosition2D &p1, const Core::GeoPosition2D &p2)
{
LtsCoordTrans::UtmCoordinate start = LtsCoordTrans::UtmCoordinate::fromGeographic(p1.lon(), p1.lat());
LtsCoordTrans::UtmCoordinate end = LtsCoordTrans::UtmCoordinate::fromGeographic(p2.lon(), p2.lat(), start.zone);
double dx = start.x - end.x;
double dy = start.y - end.y;
return std::sqrt(dx*dx + dy*dy);
}
bool BaseEdit::checkSegementLengths(QWidget *parent) const
{
auto segments = getCoordinates();
for (auto i=0; i<((int) segments.size() - 1); ++i)
{
double dis = distance(segments[i], segments[i+1]);
if (getMaxLength() != 0 && dis > getMaxLength())
{
LtsWidgets::LtsMessageDialog::showMessage(parent, tr("The distance between Coordinate %1 and %2 is too long.\nThe segment is %3m long, but the maximum segment length is %4m.")
.arg(i+1).arg(i+2).arg(QString::number(dis,'d',2),QString::number(getMaxLength(),'d',2)));
return false;
}
}
return true;
}
} // namespace AreaEffectSimulation