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

523 lines
18 KiB
C++
Executable File

/**
* @RDE_HEADER@
* HMI Plugin for EffectShowManagement - Effect Show Overview Dialog Model
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-10.05
*/
#include "esm_effect_show_model.h"
#include "esm_effect_show_actor_model.h"
#include "esm_effect_show_actor_relocation_model.h"
#include <EffectShowManagement/esm_translation.h>
#include <AreaEffectSimulation/aes_translation.h>
#include <ParticipantManagement/ppm_data_plugin_interface.h>
#include <EffectShowManagement/esm_data_plugin_interface.h>
#include <AreaEffectSimulation/aes_data_plugin_interface.h>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <LtsSession/lts_session.h>
#include <ngltools/ngltools_dtg.h>
namespace EffectShowManagement
{
//---------------------------------
// Effect Show Model
//---------------------------------
EffectShowModel::EffectShowModel(QObject *parent)
: LtsWidgets::LtsAbstractTableModel<EffectShowManagement::EffectShow>(
{
tr("Name AES"),
tr("Id"),
tr("Fire"),
tr("Duration"),
tr("Position"),
tr("AesStatus"),
tr("Actor"),
tr("Volley"),
tr("Shots in total"),
tr("Dimension [m]"),
tr("Rotation"),
tr("Status"),
tr("Answer")
},
parent)
, m_dtc(nullptr)
, m_effectShowActorProxyModel(nullptr)
, m_effectShowActorModel(nullptr)
, m_effectShowActorRelocationModel(nullptr)
, m_logger(getLogger("EffectShowModel"))
{}
EffectShowModel::~EffectShowModel()
{
delete m_effectShowActorProxyModel;
delete m_effectShowActorModel;
delete m_effectShowActorRelocationModel;
}
bool EffectShowModel::initModel(LtsSession::LtsSession *session)
{
if (!session->getDtc<EffectShowManagement::DataInterface>(m_dtc))
return false;
if (!session->getDtc<ParticipantManagement::DataInterface>(m_dtcPpm))
return false;
if (!session->getDtc<AreaEffectSimulation::DataInterface>(m_dtcAes))
return false;
connect(m_dtc.get(), &EffectShowManagement::Interface::Dtc::effectShowChanged,
this, &EffectShowModel::onDataChanged);
connect(m_dtc.get(), &EffectShowManagement::Interface::Dtc::effectShowVehicleStatusChanged,
this, &EffectShowModel::onEffectShowVehicleStatusChanged);
// insert Model
m_dtc->effectShows([this](const EffectShowManagement::EffectShow & effectShow) { insertRow(effectShow); });
m_effectShowVehicleStatus = m_dtc->effectShowVehicleStatuss();
m_effectShowActorModel = new EffectShowActorModel(this, this);
m_effectShowActorProxyModel = new EffectShowActorProxyModel(m_effectShowActorModel, this, this);
m_effectShowActorModel->initModel(session);
m_effectShowActorRelocationModel = new EffectShowActorRelocationModel(this, this);
m_effectShowActorRelocationModel->initModel(m_dtc);
m_dtc->effectShowVehicleStatuss([this](const EffectShowManagement::EffectShowVehicleStatus &item) { onEffectShowVehicleStatusChanged(item, DataModification::eAdded);});
return true;
}
QVariant EffectShowModel::data(const QModelIndex &index, int role) const
{
if (role != Qt::DisplayRole || !indexIsValid(index))
return QVariant();
const EffectShowManagement::EffectShow &effectShow = m_vecData.at(index.row());
AreaEffectSimulation::AesItem aesItem;
m_dtcAes->aesItemFromId(effectShow.idAreaEffectSimulation(), aesItem);
switch (index.column())
{
case Id:
return effectShow.id();
case Name_AES:
return QString::fromStdString(effectShow.nameAreaEffectSimulation());
case Duration:
return LtsWidgets::readableDuration(effectShow.duration());;
case StartTime:
return effectShow.startTime().is_set() ? DTG::toStringMSec(effectShow.startTime().get()) : QStringLiteral("---");
case Position:
{
const Core::GeoPosition2D &pos = effectShow.position();
return LtsCoordTrans::mgrsFromGeographic(pos.lon(), pos.lat());
}
case EffectShowActor:
{
int id = effectShow.esmParticipantId();
return (id > 0) ? getParticipantName(id) : QStringLiteral("---");
}
case Volley:
{
if (effectShow.typeOfAmmunition() == 5) //smoke
return QStringLiteral("--");
else
return effectShow.numOfVolley();
}
case ShotsInTotal:
{
if (effectShow.typeOfAmmunition() == 5) //smoke
return QStringLiteral("--");
else
return effectShow.shotsPerVolley();
}
case Size:
return tr("%1 x %2").arg(QString::number(effectShow.areaWidth()), QString::number(effectShow.areaDepth()));
case Rotation:
return effectShow.areaRotation();
case Status:
return EffectShowManagement::toString(effectShow.orderConfirmation());
case Answer:
return QString::fromStdString(effectShow.answerText());
case AesStatus:
return AreaEffectSimulation::toString(aesItem.effectStateId());
}
return QVariant();
}
QMap<int, QString> EffectShowModel::getParticipantList() const
{
QMap<int, QString> ret;
int numRow = m_effectShowActorProxyModel->rowCount(QModelIndex());
for (int i = 0; i < numRow; ++i)
{
const ParticipantManagement::Participant part = m_effectShowActorModel->getRowData(m_effectShowActorProxyModel->mapToSource(m_effectShowActorProxyModel->index(i, 0)).row());
if (hasVehicleReportedOperationalToday(part.equipmentNumber().get()))
ret.insert(part.id(), getParticipantName(part.id()));
}
return ret;
}
QMap<int, QString> EffectShowModel::getParticipantList(bool is_smoke) const
{
QMap<int, QString> ret;
int numRow = m_effectShowActorProxyModel->rowCount(QModelIndex());
for (int i = 0; i < numRow; ++i)
{
int realRow = m_effectShowActorProxyModel->mapToSource(m_effectShowActorProxyModel->index(i, 0)).row();
const ParticipantManagement::Participant part = m_effectShowActorModel->getRowData(realRow);
if (!hasVehicleReportedOperationalToday(part.equipmentNumber().get()))
continue;
EffectShowManagement::Feature_e feature = m_effectShowActorModel->getFeature(realRow);
if (feature != EffectShowManagement::Feature_e_def::NotSpecified &&
(
(feature == EffectShowManagement::Feature_e_def::Smoke && is_smoke) ||
(feature != EffectShowManagement::Feature_e_def::Smoke && !is_smoke)
)
)
ret.insert(part.id(), getParticipantName(part.id()));
}
return ret;
}
QVector<QPair<int, QString>> EffectShowModel::getParticipantListByDistance(bool is_smoke, const Core::GeoPosition2D &origin)
{
QVector<QPair<int, QString>> ret;
//first get the list of all pariticpants and it's name
QMap<int, QString> participantList = getParticipantList(is_smoke);
//reserve
ret.reserve(participantList.size());
QMap<double, int> distanceMapSorted;
for (const auto partId : participantList.keys())
{
int eqNr = m_dtcPpm->equipmentNumberByParticipantId(partId);
if (eqNr <= 0)
continue;
EffectShowManagement::EffectShowVehicleStatus vehicleStatus;
bool isVehicleStatus = getVehicleStatus(eqNr, vehicleStatus);
if (!isVehicleStatus)
continue;
const ParticipantManagement::ParticipantPosition &pos = m_dtcPpm->participantPosition(partId);
//Get Distance to Effect Show (center?)
LtsCoordTrans::UtmCoordinate pPos = LtsCoordTrans::UtmCoordinate::fromGeographic(pos.pos().lon(), pos.pos().lat());
LtsCoordTrans::UtmCoordinate pOrigin = LtsCoordTrans::UtmCoordinate::fromGeographic(origin.lon(), origin.lat());
double distance = LtsCoordTrans::distance(pPos, pOrigin);
// Save distance and particiapnt Id into temporar map.
// the map is sorted so we can use that later instead of writing a sort method vor a vec
// for now
distanceMapSorted.insert(distance, partId);
//get already assigned effect shows
QString currentAssigendEffectShows;
for (const auto &dat : m_vecData)
{
if (dat.esmParticipantId() == partId)
{
if (!currentAssigendEffectShows.isEmpty())
currentAssigendEffectShows.append(QStringLiteral(", "));
currentAssigendEffectShows.append(QString::fromStdString(dat.nameAreaEffectSimulation()));
}
}
//Now we create the new Info String
// they want
// the Name
// Available pyrotechnics/smoke pots (and current load?)
// Distance to Target Area
// already
QString newString = participantList.value(partId);
newString.append(QStringLiteral(" "));
newString.append(tr("Mag: %1 | Avail: %2").arg(vehicleStatus.ammunitionMagazine()).arg(vehicleStatus.ammunitionAvailable()));
newString.append(tr(" | Dist: %1[m]").arg(QString::number(int(distance))));
if (!currentAssigendEffectShows.isEmpty())
newString.append(tr(" | Assigned: %1").arg(currentAssigendEffectShows));
// Update the String from the original list
participantList.insert(partId, newString);
}
QMapIterator<double, int> it(distanceMapSorted);
while(it.hasNext())
{
it.next();
ret.append(QPair<int, QString>(it.value(), participantList.value(it.value())));
}
return ret;
}
QString EffectShowModel::getParticipantName(int id) const
{
auto it = m_effectShowActorModel->getIt(id);
if (it == m_effectShowActorModel->getItEnd()) return QString();
QString eqNumber = QStringLiteral("-");
if (it->equipmentNumber().is_set())
eqNumber = QString::number(it->equipmentNumber().get());
return QStringLiteral("%1 - %2 (%3)").arg(QString::fromStdString(it->designator())).arg(QString::fromStdString(it->tacticalIdentifier())).arg(eqNumber);
}
QString EffectShowModel::getParticipantAmmunition(int id) const
{
auto it = m_effectShowActorModel->getIt(id);
if (it == m_effectShowActorModel->getItEnd()) return QString();
EffectShowManagement::EffectShowVehicleStatus vehicleStatus;
if (!getVehicleStatus(it->equipmentNumber().get(), vehicleStatus)) return QString();
QString res = QString::number(vehicleStatus.ammunitionMagazine());
res.append(QLatin1String(" / "));
res.append(QString::number(vehicleStatus.ammunitionAvailable()));
return res;
}
bool EffectShowModel::isVehicleStatus(int equipmentNum) const
{
auto it = m_effectShowVehicleStatus.find(equipmentNum);
return (it != m_effectShowVehicleStatus.end());
}
bool EffectShowModel::getVehicleStatus(int equipmentNum, EffectShowManagement::EffectShowVehicleStatus &vehicleStatus) const
{
auto it = m_effectShowVehicleStatus.find(equipmentNum);
if (it == m_effectShowVehicleStatus.end())
return false;
vehicleStatus = it.value();
return true;
}
bool EffectShowModel::hasVehicleReportedOperationalToday(int equipmentNum) const
{
EffectShowVehicleStatus vehicleStatus;
getVehicleStatus(equipmentNum, vehicleStatus);
// vehicle is operational ...................................................................................................
if (vehicleStatus.operational())
{
DEBUG_LOG(m_logger) << "Effect show actor " << vehicleStatus.nameEffectShowActor() << " with participantId "
<< vehicleStatus.esmParticipantId() << " is operational.";
return true;
} // if
// vehicle has never reported as operational ................................................................................
if (!m_effectShowVehicleLastTimeOperational.contains(equipmentNum))
{
DEBUG_LOG(m_logger) << "Effect show actor " << vehicleStatus.nameEffectShowActor() << " with participantId "
<< vehicleStatus.esmParticipantId() << " has not reported operational at any time.";
return false;
} // if
// check last time vehicle reported as operational ..........................................................................
bool bRet = QDateTime().addMSecs(m_effectShowVehicleLastTimeOperational[equipmentNum]).date() == QDate::currentDate();
if (bRet)
DEBUG_LOG(m_logger) << "Effect show actor " << vehicleStatus.nameEffectShowActor() << " with participantId "
<< vehicleStatus.esmParticipantId() << " is not operational, but has reported operational today.";
else
DEBUG_LOG(m_logger) << "Effect show actor " << vehicleStatus.nameEffectShowActor() << " with participantId "
<< vehicleStatus.esmParticipantId() << " is not operational and has not reported operational today.";
return bRet;
}
QString EffectShowModel::getTimeAndPositionOfNextEffectShow(int idParticipant) const
{
auto it = m_vecData.begin();
if (it == m_vecData.end())
return QString();
qint64 effectStart = 0;
int numOrder = 0;
Core::GeoPosition2D position;
while (it != m_vecData.end())
{
if (it->orderConfirmation() != OrderConfirmation_e::OrderCarriedOut &&
it->esmParticipantId() == idParticipant)
{
++numOrder;
qint64 start = it->startTime().is_set() ? it->startTime().get() : 0;
if (effectStart == 0)
{
effectStart = start;
position = it->position();
}
else if (start < effectStart)
{
effectStart = start;
position = it->position();
}
}
++it;
}
if ((numOrder == 0) || ((numOrder > 1) && (effectStart == 0)))
return QString(); // no order, or all order without start time
QString res;
res = (effectStart != 0) ? DTG::toStringMSec(effectStart) : tr("---");
res += QLatin1String(", ");
res += LtsCoordTrans::mgrsFromGeographic(position.lon(), position.lat());
return res;
}
QString EffectShowModel::getTimeAndPositionOfNextActorRelocation(int idParticipant) const
{
auto it = m_effectShowActorRelocationModel->getItBegin();
if (it == m_effectShowActorRelocationModel->getItEnd())
return QString();
qint64 arrivalTime = std::numeric_limits<qint64>::max();
Core::GeoPosition2D position;
bool found = false;
while (it != m_effectShowActorRelocationModel->getItEnd())
{
if (it->orderConfirmation() != OrderConfirmation_e::OrderCarriedOut &&
it->orderConfirmation() != OrderConfirmation_e::PositionReached &&
it->orderConfirmation() != OrderConfirmation_e::Abort &&
it->orderConfirmation() != OrderConfirmation_e::Nonacceptance &&
it->esmParticipantId() == idParticipant)
{
if (it->arrival_time().get() < arrivalTime)
{
arrivalTime = it->arrival_time().get();
position = it->position();
found = true;
}
}
++it;
}
if (!found)
return QString();
QString res;
res = (arrivalTime != 0) ? DTG::toStringMSec(arrivalTime) : tr("---");
res += QLatin1String(", ");
res += LtsCoordTrans::mgrsFromGeographic(position.lon(), position.lat());
return res;
}
void EffectShowModel::updateAll()
{
this->update();
m_effectShowActorModel->update();
m_effectShowActorRelocationModel->update();
}
bool EffectShowModel::onEffectShowVehicleStatusChanged(const EffectShowManagement::EffectShowVehicleStatus &data, DataModification modType)
{
int equipmentNumber = m_dtcPpm->equipmentNumberByParticipantId(data.esmParticipantId());
switch (modType)
{
case DataModification::eAdded:
case DataModification::eModified:
if (m_effectShowVehicleStatus.contains(equipmentNumber))
{
if (m_effectShowVehicleStatus[equipmentNumber].operational() && !data.operational())
m_effectShowVehicleLastTimeOperational[equipmentNumber] = data.sampleTime();
} // if
else
m_effectShowVehicleLastTimeOperational[equipmentNumber] = 0;
m_effectShowVehicleStatus[equipmentNumber] = data;
break;
case DataModification::eRemoved:
m_effectShowVehicleStatus.remove(equipmentNumber);
m_effectShowVehicleLastTimeOperational.remove(equipmentNumber);
break;
}
updateAll();
emit effectShowVehicleStatusChanged(data, modType);
return true;
}
void EffectShowProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
{
m_sourceModel = qobject_cast<EffectShowModel *>(sourceModel);
LtsWidgets::LtsColumnFilterProxyModel::setSourceModel(sourceModel);
}
void EffectShowProxyModel::setShowExpired(bool show)
{
if (m_showExpired == show)
return;
m_showExpired = show;
invalidateFilter();
}
bool EffectShowProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
{
if (!m_sourceModel ||
source_left.column() != source_right.column() ||
!source_left.isValid() ||
!source_right.isValid())
return LtsWidgets::LtsColumnFilterProxyModel::lessThan(source_left, source_right);
const auto &dataLeft = m_sourceModel->m_vecData.at(source_left.row());
const auto dataRight = m_sourceModel->m_vecData.at(source_right.row());
switch (source_left.column())
{
case EffectShowModel::StartTime:
if (dataLeft.startTime().is_set() && dataRight.startTime().is_set())
return dataLeft.startTime().get() < dataRight.startTime().get();
if (dataRight.startTime().is_set())
return true;
if (dataLeft.startTime().is_set())
return false;
return dataLeft.id() < dataRight.id();
case EffectShowModel::Name_AES:
case EffectShowModel::Id:
case EffectShowModel::Duration:
case EffectShowModel::Position:
case EffectShowModel::EffectShowActor:
case EffectShowModel::Volley:
case EffectShowModel::ShotsInTotal:
case EffectShowModel::Status:
case EffectShowModel::Answer:
break;
}
return LtsWidgets::LtsColumnFilterProxyModel::lessThan(source_left, source_right);
}
bool EffectShowProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
bool bRet = checkFilter(source_row);
if (!bRet)
return false;
return LtsWidgets::LtsColumnFilterProxyModel::filterAcceptsRow(source_row, source_parent);
}
bool EffectShowProxyModel::checkFilter(int source_row) const
{
// If showExpired: Show all
if (showExpired())
return true;
const auto effectShowSource = m_sourceModel->getRowData(source_row);
// show when not expired
if (effectShowSource.orderConfirmation() != EffectShowManagement::OrderConfirmation_e_def::OrderCarriedOut)
return true;
return false;
}
} // namespace EffectShowModel