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

636 lines
22 KiB
C++
Executable File

/**
* @RDE_HEADER@
* HMI Plugin for Observer Controller - OcParticipantInfo Dialog
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2018-03-17
*/
#include "osc_participant_info.h"
#include "ui_osc_participant_info.h"
#include <ProjectDataManagement/pdm_to_string.h>
#include <ParticipantManagement/ppm_translation.h>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <LtsSession/lts_session_data.h>
#include <LtsUtilsCore/outdated_position.h>
#include <PluginInterfaces/gui_plugin_interface.h>
namespace OcSituationClient
{
OcParticipantInfo::OcParticipantInfo(int participantId, LtsSession::LtsSession *session, QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::CloseOnly)
, m_roomId(0)
, m_session(session)
, m_ui(new Ui::OcParticipantInfo)
, m_logger(getLogger("OcOcParticipantInfo"))
{
m_ui->setupUi(this);
m_participant.id(participantId);
m_participant.partyId(-1);
m_symbolWatcher = new AdvancedSymbology::SymbolResultWatcherLabel(m_ui->lblIcon);
//hide first
setBuildingPosVisible(false);
setSpecialSensorVisible(false);
setChargeVisible(false);
setKindVisible(false);
m_ui->pbHistory->setVisible(false);
//config movement track button
m_ui->pbMovementTrack->setCheckable(true);
//connects
connect(m_ui->pbFindOnMap, &QToolButton::clicked, this, &OcParticipantInfo::onFindOnMap);
connect(m_ui->pbMovementTrack, &QToolButton::clicked, this, &OcParticipantInfo::onMovementTrack);
}
OcParticipantInfo::~OcParticipantInfo()
{
delete m_ui;
}
bool OcParticipantInfo::init()
{
if (!m_session->getDtc<ParticipantManagement::DataInterface>(m_ppmDtc))
return false;
if (!m_session->getDtc<ProjectDataManagement::DataInterface>(m_pdmDtc))
return false;
if (!m_session->getForeignDataInterface<AdvancedSymbology::DataInterface>(m_asbiIfc))
return false;
//optional
m_session->getForeignGuiInterface<SituationMap::ForeignGuiInterface>(m_sitMapGuiIfc);
m_session->getDtc<InfrastructureManagement::DataInterface>(m_ismDtc);
return setUiValues();
}
void OcParticipantInfo::retranslate()
{
translate(m_ui, tr("Participant Info") );
}
void OcParticipantInfo::setRed(QWidget *w, bool bRed)
{
if (!w)
return;
if (bRed)
{
QPalette pal = QApplication::palette(w);
pal.setColor(QPalette::Window, Qt::red);
w->setPalette(pal);
w->setAutoFillBackground(true);
}
else
{
// reset to default palette
w->setPalette(QApplication::palette(w));
w->setAutoFillBackground(false);
}
}
void OcParticipantInfo::updateIcon(const ParticipantManagement::Participant &participant)
{
m_symbolWatcher->setSymbolResult(m_asbiIfc->findImage(participant));
}
void OcParticipantInfo::updateIcon(const QColor &color, const QString &sidc)
{
AdvancedSymbology::SymbolDataToRender symDataToRender(sidc);
symDataToRender.injury = AdvancedSymbology::Injury::NoInjury;
symDataToRender.injuryColor = QColor();
symDataToRender.fillColor = color;
symDataToRender.fillColorReplace = true;
m_symbolWatcher->setSymbolResult(m_asbiIfc->findImage(symDataToRender));
}
bool OcParticipantInfo::setUiValues()
{
if (!m_ppmDtc || m_participant.id() < 0)
return false;
//hide findOnMap if no interface available
m_ui->pbFindOnMap->setVisible(m_sitMapGuiIfc != nullptr);
m_ui->tbNbc->setVisible(false); //show only if visible
// m_participant.id() was given within ctor
const ParticipantManagement::Participant participantData = m_ppmDtc->participant(m_participant.id());
m_typeClass = m_ppmDtc->type(participantData.typeId()).typeClass();
bool bUpdateDynamicParticipantData = true;
switch (m_typeClass.underlying())
{
case ParticipantManagement::TypeClass::Human:
case ParticipantManagement::TypeClass::GroundVehicle:
case ParticipantManagement::TypeClass::VehicleWithGear:
case ParticipantManagement::TypeClass::WeaponSystem:
case ParticipantManagement::TypeClass::Aircraft:
case ParticipantManagement::TypeClass::SupportEntity:
{
onParticipantChanged(participantData);
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::participantChanged,
this, &OcParticipantInfo::onParticipantChanged);
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::participantPositionChanged,
this, &OcParticipantInfo::onPositionChanged);
onPositionChanged(m_ppmDtc->participantPosition(participantData.id()));
if (m_sitMapGuiIfc)
{
const int32_t participantId = participantData.id();
m_ui->pbFindOnMap->setVisible(true);
m_ui->pbMovementTrack->setVisible(true);
m_ui->pbMovementTrack->setChecked(m_sitMapGuiIfc->isMovementTrackEnabled(participantId));
// set MovementTrackCallback:
std::function<void(const QVector<int32_t> &activeSimIds)> onMovementTrackChangedFunc = [this, participantId](const QVector<int32_t> &activeSimIds)
{
bool checkedNew = activeSimIds.contains(participantId);
if (m_ui->pbMovementTrack->isChecked() != checkedNew)
{
m_ui->pbMovementTrack->setChecked(checkedNew);
}
};
if (!m_sitMapGuiIfc->setMovementTrackCallback(this, onMovementTrackChangedFunc))
ERROR_LOG(m_logger) << LOGFUNCTION << " setMovementTrackCallback failed";
}
break;
}
case ParticipantManagement::TypeClass::Unit:
case ParticipantManagement::TypeClass::SupportUnit:
case ParticipantManagement::TypeClass::Vessel:
case ParticipantManagement::TypeClass::Unknown:
return false;
}
if (bUpdateDynamicParticipantData)
{
const auto dpd = m_ppmDtc->dynamicParticipantData(participantData.id());
if (dpd.participantId() || participantData.id())
{
onDynamicParticipantDataChanged(dpd);
}
else
{
const ParticipantManagement::Party party = m_ppmDtc->party(m_participant.partyId());
const QColor color = QColor::fromRgb(QRgb(party.color()));
updateIcon(color, QString::fromStdString(m_participant.symbol()));
}
}
//other connects
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::typeChanged,
this, &OcParticipantInfo::onTypeChanged);
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::dynamicParticipantDataChanged,
this, &OcParticipantInfo::onDynamicParticipantDataChanged);
connect(m_session, &LtsSession::LtsSession::partitionTimeChanged,
this, &OcParticipantInfo::onPartitionTimeChanged);
return true;
}
void OcParticipantInfo::setChargeVisible(bool vis)
{
m_ui->twGear->setVisible(vis);
}
void OcParticipantInfo::setSpecialSensorVisible(bool vis)
{
m_ui->lblSpecialSensorState->setVisible(vis);
m_ui->lbSpecialSensorState->setVisible(vis);
}
void OcParticipantInfo::setBuildingPosVisible(bool vis)
{
m_ui->lblBuilding->setVisible(vis);
m_ui->lblRoom->setVisible(vis);
}
void OcParticipantInfo::setKindVisible(bool vis)
{
m_ui->lblKind->setVisible(vis);
m_ui->lbKind->setVisible(vis);
}
void OcParticipantInfo::onDynamicParticipantDataChanged(const ParticipantManagement::DynamicParticipantData &data)
{
if (data.participantId() != m_participant.id() && data.participantId() != 0)
return;
//Current State
if (data.stateHistory().size() > 0)
{
const ProjectDataManagement::VulnerabilityClass vc = m_typeClass == ParticipantManagement::TypeClass::Human ?
ProjectDataManagement::VulnerabilityClass_def::SoldierInjuries :
ProjectDataManagement::VulnerabilityClass_def::VehicleDamages;
const ParticipantManagement::StateInformation &lastState = m_ppmDtc->youngestStateInformation(data.stateHistory());
m_ui->lblStatus->setText(ProjectDataManagement::toString(lastState.vulnerabilityState(), vc));
// VBA
setKindVisible(lastState.vulnerabilityKindId() > 0);
m_ui->lblKind->setText(m_pdmDtc->trVulnerabilityKindName(lastState.vulnerabilityKindId(), vc));
}
else
{
m_ui->lblStatus->setText(QStringLiteral("-"));
m_ui->lblKind->setText(QStringLiteral("-"));
}
setRed(m_ui->lblEquipNr, data.manipulation().size());
// Note: This is not transmitted to O/C. If so, we need to add LEDs for Apache.
// So long: Hide, if it's an aircraft.
// Special Sensor State
if (!data.specialSensorDataState() || m_typeClass == ParticipantManagement::TypeClass_def::Aircraft)
{
m_ui->lblSpecialSensorState->hide();
m_ui->lbSpecialSensorState->hide();
}
else
{
showSpecialSensorData(data.specialSensorDataState());
m_ui->lbSpecialSensorState->show();
m_ui->lblSpecialSensorState->show();
}
//Gear
if (data.gear().size() == 0)
{
m_gearList.clear();
m_ui->twGear->clearContents();
m_ui->twGear->hide();
m_ui->pbGearRanges->hide();
}
else if (data.gear() != m_gearList)
{
m_gearList = data.gear();
std::vector<ParticipantManagement::GearInformation> tmpGearList = m_gearList;
m_ui->twGear->show();
m_ui->pbGearRanges->show();
m_ui->twGear->clearContents();
int row = 0;
int rowCount = tmpGearList.size();
m_ui->twGear->setRowCount(rowCount);
m_ui->twGear->setSortingEnabled(false);
constexpr int unknownTasId = 0x80000000;
for (const ParticipantManagement::GearInformation &gearInfo : m_gearList)
{
QTableWidgetItem *item = nullptr;
if (gearInfo.chargeTypeId() <= 0) //chargTypeId 0 is near miss code
{
rowCount--;
continue;
}
const int gearTypeId = gearInfo.gearTypeId();
if ((gearTypeId & unknownTasId) == unknownTasId)
item = new QTableWidgetItem(tr("Unknown gear id %1").arg(gearTypeId & ~unknownTasId));
else if (gearTypeId == 0)
{
// Hack for old systems which neither send gearTasCode/gearType nor gearSerialNumber/gearId
// 1 = Wanne, 2 = Turm
switch (gearInfo.gearId())
{
case 1:
item = new QTableWidgetItem(tr("Tank", "Gear Type"));
break;
case 2:
item = new QTableWidgetItem(tr("Turret", "Gear Type"));
break;
default:
item = new QTableWidgetItem(tr("N/A", "Gear Type"));
break;
}
}
else
item = new QTableWidgetItem(m_pdmDtc->trGearTypeName(gearTypeId));
m_ui->twGear->setItem(row, 0, item);
if (gearInfo.chargeTypeId() != 0 && gearInfo.chargeTypeId() != -1) // hat Charge (and ignore only chargecounts)
{
int chargeTypeId = gearInfo.chargeTypeId();
if ((chargeTypeId & unknownTasId) == unknownTasId)
item = new QTableWidgetItem(tr("Unknown charge id %1").arg(chargeTypeId & ~unknownTasId));
else if (chargeTypeId == 0)
item = new QTableWidgetItem(tr("N/A", "Charge Type"));
else
{
item = new QTableWidgetItem(m_pdmDtc->trChargeTypeShortName(chargeTypeId, true));
item->setToolTip(m_pdmDtc->trChargeTypeName(chargeTypeId, true));
}
m_ui->twGear->setItem(row, 1, item);
//ressourceCount
//: Blank in this case refers to blank ammunition used for training
item = new QTableWidgetItem((gearInfo.remain() < 0) ? tr("N/A", "Blank Ammunition") : QString::number(gearInfo.remain()));
m_ui->twGear->setItem(row, 2, item);
}
row++;
}
m_ui->twGear->setRowCount(rowCount);
m_ui->twGear->setSortingEnabled(true);
} //end Gear
m_ui->tbNbc->setVisible(data.hasNbcProtectionConfigured() && data.hasNbcProtectionActive());
updateIcon(m_participant);
}
void OcParticipantInfo::showSpecialSensorData(int specialSensorData)
{
const int specialSensorDataState = specialSensorData & 0xFF;
QString strSpecialSensorData;
switch (specialSensorDataState)
{
case ParticipantManagement::SpecialSensorStatus_def::ChemicalDetectionFunction_NotOperational:
strSpecialSensorData = toString(ParticipantManagement::SpecialSensorStatus_def::ChemicalDetectionFunction_NotOperational);
break;
case ParticipantManagement::SpecialSensorStatus_def::ChemicalDetectionFunction_Detecting:
strSpecialSensorData = toString(ParticipantManagement::SpecialSensorStatus_def::ChemicalDetectionFunction_Detecting);
break;
case ParticipantManagement::SpecialSensorStatus_def::NBCDetectionAccessory_NotOperational:
strSpecialSensorData = toString(ParticipantManagement::SpecialSensorStatus_def::NBCDetectionAccessory_NotOperational);
break;
case ParticipantManagement::SpecialSensorStatus_def::NBCDetectionAccessory_Test:
strSpecialSensorData = toString(ParticipantManagement::SpecialSensorStatus_def::NBCDetectionAccessory_Test);
break;
case ParticipantManagement::SpecialSensorStatus_def::NBCDetectionAccessory_DetectingAir:
strSpecialSensorData = toString(ParticipantManagement::SpecialSensorStatus_def::NBCDetectionAccessory_DetectingAir);
break;
case ParticipantManagement::SpecialSensorStatus_def::AVLB_Mounted:
strSpecialSensorData = toString(ParticipantManagement::SpecialSensorStatus_def::AVLB_Mounted);
break;
case ParticipantManagement::SpecialSensorStatus_def::AVLB_Deployed:
strSpecialSensorData = toString(ParticipantManagement::SpecialSensorStatus_def::AVLB_Deployed);
break;
case ParticipantManagement::SpecialSensorStatus_def::AVLB_Mounting:
strSpecialSensorData = toString(ParticipantManagement::SpecialSensorStatus_def::AVLB_Mounting);
break;
case ParticipantManagement::SpecialSensorStatus_def::AVLB_Deploying:
strSpecialSensorData = toString(ParticipantManagement::SpecialSensorStatus_def::AVLB_Deploying);
break;
case ParticipantManagement::SpecialSensorStatus_def::MineLayer_Operational:
strSpecialSensorData = toString(ParticipantManagement::SpecialSensorStatus_def::MineLayer_Operational);
break;
case ParticipantManagement::SpecialSensorStatus_def::MineLayer_Laying:
strSpecialSensorData = toString(ParticipantManagement::SpecialSensorStatus_def::MineLayer_Laying);
break;
case ParticipantManagement::SpecialSensorStatus_def::MineClearingFunction_March:
strSpecialSensorData = toString(ParticipantManagement::SpecialSensorStatus_def::MineClearingFunction_March);
break;
case ParticipantManagement::SpecialSensorStatus_def::MineClearingFunction_ReadyToClear:
strSpecialSensorData = toString(ParticipantManagement::SpecialSensorStatus_def::MineClearingFunction_ReadyToClear);
break;
case ParticipantManagement::SpecialSensorStatus_def::MineClearingFunction_Clearing:
strSpecialSensorData = toString(ParticipantManagement::SpecialSensorStatus_def::MineClearingFunction_Clearing);
break;
case ParticipantManagement::SpecialSensorStatus_def::MineTrowingFunction_NotOperational:
strSpecialSensorData = toString(ParticipantManagement::SpecialSensorStatus_def::MineTrowingFunction_NotOperational);
break;
case ParticipantManagement::SpecialSensorStatus_def::MineTrowingFunction_ParameterInput:
strSpecialSensorData = toString(ParticipantManagement::SpecialSensorStatus_def::MineTrowingFunction_ParameterInput);
break;
case ParticipantManagement::SpecialSensorStatus_def::MineTrowingFunction_ReadyToDeploy:
strSpecialSensorData = toString(ParticipantManagement::SpecialSensorStatus_def::MineTrowingFunction_ReadyToDeploy);
break;
case ParticipantManagement::SpecialSensorStatus_def::MineTrowingFunction_Deploying:
strSpecialSensorData = toString(ParticipantManagement::SpecialSensorStatus_def::MineTrowingFunction_Deploying);
break;
case ParticipantManagement::SpecialSensorStatus_def::MineTrowingFunction_Resupply:
strSpecialSensorData = toString(ParticipantManagement::SpecialSensorStatus_def::MineTrowingFunction_Resupply);
break;
case ParticipantManagement::SpecialSensorStatus_def::MineTrowingFunction_FinishDeploying:
strSpecialSensorData = toString(ParticipantManagement::SpecialSensorStatus_def::MineTrowingFunction_FinishDeploying);
break;
case ParticipantManagement::SpecialSensorStatus_def::ADLER_Operational:
strSpecialSensorData = toString(ParticipantManagement::SpecialSensorStatus_def::ADLER_Operational);
break;
case ParticipantManagement::SpecialSensorStatus_def::ADLER_ConditionallyOperational:
strSpecialSensorData = toString(ParticipantManagement::SpecialSensorStatus_def::ADLER_ConditionallyOperational);
break;
case ParticipantManagement::SpecialSensorStatus_def::ADLER_NotOperational:
strSpecialSensorData = toString(ParticipantManagement::SpecialSensorStatus_def::ADLER_NotOperational);
break;
default:
strSpecialSensorData = tr("Unknown (%1)").arg(specialSensorDataState);
break;
}
if ((specialSensorData & (1 << 8)) != 0)
strSpecialSensorData += QStringLiteral(" L");
if ((specialSensorData & (1 << 9)) != 0)
strSpecialSensorData += QStringLiteral(" R");
if ((specialSensorData & (1 << 10)) != 0)
strSpecialSensorData += QStringLiteral(" P");
if ((specialSensorData & (1 << 11)) != 0)
strSpecialSensorData += QStringLiteral(" F");
if (specialSensorDataState == 66) // CSF Spürbetrieb
{
const int type = (specialSensorData >> 12) & 0x0F;
strSpecialSensorData += QLatin1Char(' ');
switch (type)
{
case 1:
case 2:
strSpecialSensorData += tr("FIR");
break;
case 3:
strSpecialSensorData += tr("ZABC");
break;
case 4:
strSpecialSensorData += tr("CSF");
break;
case 5:
strSpecialSensorData += tr("PzBr");
break;
case 6:
strSpecialSensorData += tr("MV");
break;
case 7:
strSpecialSensorData += tr("MRF");
break;
case 8:
strSpecialSensorData += tr("WMV");
break;
case 0:
default:
break;
}
if (type == 4) // CSF
{
const int nbcType = (specialSensorData >> 16) & 0x03;
strSpecialSensorData += QLatin1Char(' ');
switch (nbcType)
{
case 0:
strSpecialSensorData += tr("No C-Agent");
break;
case 1:
strSpecialSensorData += tr("Sarin");
break;
case 2:
strSpecialSensorData += tr("VX");
break;
case 3:
strSpecialSensorData += tr("S-Lost");
break;
}
}
}
m_ui->lblSpecialSensorState->setText(strSpecialSensorData);
}
void OcParticipantInfo::onPositionChanged(const ParticipantManagement::ParticipantPosition &position)
{
if (position.participantId() != m_participant.id() && position.participantId() != 0)
return;
onUpdatePosition(position.participantId(), position.pos(), position.sampleTime());
if (m_ismDtc && m_roomId != position.roomId())
{
if (position.roomId() > 0)
{
const auto mse = m_ismDtc->mainStructureElement(position.buildingId());
QString roomName;
for (const auto &room : mse.elements())
{
if (room.id() == position.roomId())
{
roomName = QString::fromStdString(room.displayName());
break;
}
}
QString buildingName = m_ismDtc->getBuildingDisplayName(mse);
m_roomId = position.roomId();
m_ui->lblBuilding->setText(buildingName);
m_ui->lblRoom->setText(roomName);
}
setBuildingPosVisible(m_roomId > 0);
}
if (position.mountedOn().is_set())
{
const auto mountedOnParticipant = m_ppmDtc->participant(position.mountedOn().get());
if (mountedOnParticipant.equipmentNumber().is_set())
m_ui->pbMountedOn->setText(QString::number(mountedOnParticipant.equipmentNumber().get()));
else
m_ui->pbMountedOn->setText(QString::number(0));
m_ui->pbMountedOn->show();
}
else
m_ui->pbMountedOn->hide();
if (position.mountedParticipants().is_set())
{
m_ui->pbMountedParticipants->setText(QString::number(position.mountedParticipants().get().size()));
m_ui->pbMountedParticipants->show();
}
else
m_ui->pbMountedParticipants->hide();
}
void OcParticipantInfo::onUpdatePosition(int participantId, const Core::GeoPosition &position, qint64 sampleTime)
{
m_lastPositionMSec = sampleTime;
if ((position.lat() == 0 && position.lon() == 0) || participantId == 0 || std::isnan(position.lon()) || std::isnan(position.lat()))
{
m_ui->lblPosition->setText(tr("Invalid Position"));
}
else
{
QString mgrs = LtsCoordTrans::mgrsFromGeographic(position.lon(), position.lat());
if (!qFuzzyIsNull(position.z()))
mgrs += QStringLiteral(" | ") + QString::number(position.z(), 'f', 2);
m_ui->lblPosition->setText(mgrs);
}
}
void OcParticipantInfo::onParticipantChanged(const ParticipantManagement::Participant &participant)
{
if (participant.id() != m_participant.id())
return;
if (m_participant.typeId() != participant.typeId())
m_ui->lblType->setText(ParticipantManagement::trTypeName(m_ppmDtc->type(participant.typeId()).name()));
if (m_participant.partyId() != participant.partyId())
m_ui->lblParty->setText(ParticipantManagement::trPartyName(m_ppmDtc->party(participant.partyId()).name()));
m_ui->lblDesignator->setText(QString::fromStdString(participant.designator()));
m_ui->lblTactitcalIdentifier->setText(QString::fromStdString(participant.tacticalIdentifier()));
if (participant.equipmentNumber().is_set())
m_ui->lblEquipNr->setText(QString::number(participant.equipmentNumber().get()));
else if (participant.isSimulated())
m_ui->lblEquipNr->setText(tr("simulated"));
else
m_ui->lblEquipNr->setText(QLatin1String("-"));
#ifdef LTS_DEBUG
m_ui->lblEquipNr->setToolTip(QString::number(participant.id()));
#endif
m_participant = participant;
//hide Info if not exists
m_ui->lblInfoText->setText(QString::fromStdString(participant.info()));
m_ui->lblInfoText->setVisible(participant.info().size() > 0);
m_ui->lblInfo->setVisible(participant.info().size() > 0);
m_ui->lblInfo->setText(QString::number(participant.info().size()));
onDynamicParticipantDataChanged(m_ppmDtc->dynamicParticipantData(participant.id()));
}
void OcParticipantInfo::onTypeChanged(const ParticipantManagement::Type &type, DataModification modType)
{
Q_UNUSED(modType)
if (m_participant.typeId() != type.id())
return;
m_ui->lblType->setText(ParticipantManagement::trTypeName(type.name()));
}
void OcParticipantInfo::onPartitionTimeChanged(qint64 newPartitionTime)
{
setRed(m_ui->lblPosition, LtsUtils::isPositionTimeOutdated(newPartitionTime, m_lastPositionMSec)); //10minuten
}
void OcParticipantInfo::onFindOnMap()
{
if (m_sitMapGuiIfc)
m_sitMapGuiIfc->centerMapToParticipant(m_participant.id());
}
void OcParticipantInfo::onMovementTrack()
{
if (m_sitMapGuiIfc)
m_sitMapGuiIfc->enableMovementTrack(m_participant.id(), m_ui->pbMovementTrack->isChecked());
}
} // namespace OcSituationClient